问题

将复选框创建为Vue组件,如下所示:

  1. 复选框组件内部不允许逻辑:所有事件处理程序和checked属性都完全依赖于外部逻辑,可以是vuex存储.
  2. 我们不应该观察复选框的"checked"状态:是否选中,这同样取决于外部逻辑,例如vuex状态或getter.

试试1

概念

复选框组件有checkedonClick个属性,它们的值是不正常的,可以是动态的.

组成部分

Pug种语言的模板:

label.SvgCheckbox-LabelAsWrapper(:class="rootElementCssClass" @click.prevent="onClick")
  input.SvgCheckbox-InvisibleAuthenticCheckbox(
    type="checkbox"
    :checked="checked"
    :disabled="disabled"
  )
  svg(viewbox='0 0 24 24').SvgCheckbox-SvgCanvas
    path(
      v-if="!checked"
      d='M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3M19,5V19H5V5H19Z'
    ).SvgCheckbox-SvgPath.SvgCheckbox-SvgPath__Unchecked
    path(
      v-else
      d='M10,17L5,12L6.41,10.58L10,14.17L17.59,6.58L19,8M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3Z'
    ).SvgCheckbox-SvgPath.SvgCheckbox-SvgPath__Checked
  span(v-if="text").SvgCheckbox-AppendedText {{ text }}
import { Vue, 组成部分, Prop } from 'vue-property-decorator';

@组成部分
export default class SimpleCheckbox extends Vue {

  @Prop({ type: Boolean, required: true }) private readonly checked!: boolean;

  @Prop({ type: Boolean, default: false }) private readonly disabled!: boolean;

  @Prop({ type: String }) private readonly text?: string;
  @Prop({ type: String }) private readonly parentElementCssClass?: string;

  @Prop({ type: Function, default: () => {} }) private readonly onClick!: () => void;
}

存储模块

import { VuexModule, Module, Mutation } from "vuex-module-decorators";
import store, { StoreModuleNames } from "@Store/Store";


@Module({ name: StoreModuleNames.example, store, dynamic: true, namespaced: true })
export default class ExampleStoreModule extends VuexModule {

  private _doNotPreProcessMarkupEntryPointsFlag: boolean = true;

  public get doNotPreProcessMarkupEntryPointsFlag(): boolean {
    return this._doNotPreProcessMarkupEntryPointsFlag;
  }

  @Mutation
  public toggleDoNotPreProcessMarkupEntryPointsFlag(): void {
    this._doNotPreProcessMarkupEntryPointsFlag = !this._doNotPreProcessMarkupEntryPointsFlag;
  }
}

用法

SimpleCheckbox(
  :checked="relatedStoreModule.doNotPreProcessMarkupEntryPointsFlag"
  :onClick="relatedStoreModule.toggleDoNotPreProcessMarkupEntryPointsFlag"
  parentElementCssClass="RegularCheckbox"
)
import { 组成部分, Vue } from "vue-property-decorator";
import { getModule } from "vuex-module-decorators";
import ExampleStoreModule from "@Store/modules/ExampleStoreModule";
import template from "@Templates/ExampleTemplate.pug";
import SimpleCheckbox from "@组成部分s/Checkboxes/MaterialDesign/SimpleCheckbox.vue";

@组成部分({ components: { SimpleCheckbox } })
export default class MarkupPreProcessingSettings extends Vue {
  private readonly relatedStoreModule: ExampleStoreModule = getModule(ExampleStoreModule);
}

警告

单击复选框时出现.复选框按我们的需要工作,但Vue的一些概念已被违反.

enter image description here

vue.common.dev.js:630 [Vue warn]: $attrs is readonly.

found in

---> <SimpleCheckbox> at hikari-frontend/Ui组成部分s/Checkboxes/MaterialDesign/SimpleCheckbox.vue
       <MarkupPreProcessingSettings>
         <Application> at ProjectInitializer/ElectronRendererProcess/Root组成部分.vue
           <Root>

vue.common.dev.js:630 [Vue warn]: $listeners is readonly.

found in

---> <SimpleCheckbox> at hikari-frontend/Ui组成部分s/Checkboxes/MaterialDesign/SimpleCheckbox.vue
       <MarkupPreProcessingSettings>
         <Application> at ProjectInitializer/ElectronRendererProcess/Root组成部分.vue
           <Root>

vue.common.dev.js:630 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "checked"

found in

---> <SimpleCheckbox> at hikari-frontend/Ui组成部分s/Checkboxes/MaterialDesign/SimpleCheckbox.vue
       <MarkupPreProcessingSettings>
         <Application> at ProjectInitializer/ElectronRendererProcess/Root组成部分.vue
           <Root>

沉思

频繁发出此警告的原因是组件内部为某些vue属性分配了新值.明确地说,我不喜欢这样的操纵.

问题出在:onClick="relatedStoreModule.toggleDoNotPreProcessMarkupEntryPointsFlag".它看起来像是编译成了类似<component>.$props.onClick="<vuex store manipulations ...>"的东西——如果是这样,那就是组件内部的隐式属性Mutations .

试试2

概念

基于Vue documentation, Customizing 组成部分 section:

Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})

TypeScript的等效值为vue-property-decorator:

import { Vue, 组成部分, Model } from 'vue-property-decorator'

@组成部分
export default class Your组成部分 extends Vue {
  @Model('change', { type: Boolean }) readonly checked!: boolean
}
组成部分
label.SvgCheckbox-LabelAsWrapper(:class="rootElementCssClass")
  input.SvgCheckbox-InvisibleAuthenticCheckbox(
    type="checkbox"
    :checked="checked"
    :disabled="disabled"
    @change="$emit('change', $event.target.checked)"
  )
  svg(viewbox='0 0 24 24').SvgCheckbox-SvgCanvas
    // ...
import { Vue, 组成部分, Prop, Model } from "vue-property-decorator";

@组成部分
export default class SimpleCheckbox extends Vue {

  @Model('change', { type: Boolean }) readonly checked!: boolean;

  @Prop({ type: Boolean, default: false }) private readonly disabled!: boolean;

  @Prop({ type: String }) private readonly text?: string;
  @Prop({ type: String }) private readonly rootElementCssClass?: string;
}

用法

SimpleCheckbox(
  v-model="doNotPreProcessMarkupEntryPointsFlag"
  rootElementCssClass="RegularCheckbox"
)

在TypeScript中,要使用v-model,我们需要声明getter和同名setter:

@组成部分({
  template,
  components: {
    SimpleCheckbox,
    // ...
  }
})
export default class MarkupPreProcessingSettings extends Vue {

  private readonly relatedStoreModule: MarkupPreProcessingSettingsStoreModule =
      getModule(MarkupPreProcessingSettingsStoreModule);
  //...
  private get doNotPreProcessMarkupEntryPointsFlag(): boolean {
    return this.relatedStoreModule.doNotPreProcessMarkupEntryPointsFlag;
  }

  private set doNotPreProcessMarkupEntryPointsFlag(_newValue: boolean) {
    this.relatedStoreModule.toggleDoNotPreProcessMarkupEntryPointsFlag();
  }
}

警告

相同的错误集:

enter image description here

局限性

首先,我们需要在Vue组件类中创建新的getter和setter.如果可能的话,避免id是很酷的.不幸的是,对于vuex类(vuex-module-decorators),排字脚本设置器不可用,我们需要使用@Mutation修饰方法.

此外,此解决方案不适用于由v-for渲染的元素.这使得这个解决方案毫无用处.

试试3

概念

事件emits 器和自定义事件侦听器的用法.此解决方案也可以正常工作,但Vue会发出警告.

组成部分

label.SvgCheckbox-LabelAsWrapper(:class="rootElementCssClass" @click.prevent="$emit('toggled')")
  // ...

用法

SimpleCheckbox(
  :checked="relatedStoreModule.doNotPreProcessMarkupEntryPointsFlag"
  @toggled="relatedStoreModule.toggleDoNotPreProcessMarkupEntryPointsFlag"
  rootElementCssClass="RegularCheckbox"
)

警告

enter image description here


使现代化

尽管问题已经解决,但仍有一些谜团尚未解开.见下面我的答案.

推荐答案

此警告发生在Electron 应用程序中.SimpleCheckbox来自node_modules,但是这个库仍在开发中,所以它由npm link提供.

当我try 从一个地方复制到另一个地方时(我try 了从一个地方复制到另一个地方,但没有复制到另一个地方).第一个解决方案有效!(我不在乎第二个和第三个——我只需要从peel优雅的解决方案中提炼出来).

我建议cause是npm link,发布我的库并通过npm install安装.警告消失了!

结论

这不是npm link第一次引发这样的问题.这是another case美元.

我仍然没有深入理解这个 case ——我只是发表了一些实验数据."那么,如果图书馆还在开发中呢?"这个问题仍然没有答案.我try 了Lerna次——第一次警告消失了,但当我把我的项目转移到勒纳时,警告再次出现——规律性对我来说还不清楚.

Vue.js相关问答推荐

将 html 文件移出 dist vite 中的 src 文件夹

为什么在 Vue2 中调用 this.$emit() 后 props 没有立即更新?

视图中的 vue 样式不适用于 html

有什么理由不在 vue3 中使用