在基于TypeScript的Vue中将vuex状态和变量绑定到复选框组件属性

Gur*_*ofu 8 javascript typescript vue.js vue-component vuex

问题

创建复选框作为Vue组件,方法如下:

  1. 复选框组件内部不允许有逻辑:所有事件处理程序以及checked属性都完全取决于外部逻辑,而外部逻辑可以是vuex存储区。
  2. 我们不应该查看复选框“ checked”的状态:是否选中它,它还是取决于外部逻辑,例如vuex状态或吸气剂。

尝试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 }}
Run Code Online (Sandbox Code Playgroud)
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 }}
Run Code Online (Sandbox Code Playgroud)

店铺模块

import { Vue, Component, Prop } from 'vue-property-decorator';

@Component
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;
}
Run Code Online (Sandbox Code Playgroud)

用法

SimpleCheckbox(
  :checked="relatedStoreModule.doNotPreProcessMarkupEntryPointsFlag"
  :onClick="relatedStoreModule.toggleDoNotPreProcessMarkupEntryPointsFlag"
  parentElementCssClass="RegularCheckbox"
)
Run Code Online (Sandbox Code Playgroud)
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;
  }
}
Run Code Online (Sandbox Code Playgroud)

警惕

如果单击复选框,则显示。Checkbox可以根据需要工作,但是某些Vue概念已被违反。

在此处输入图片说明

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

found in

---> <SimpleCheckbox> at hikari-frontend/UiComponents/Checkboxes/MaterialDesign/SimpleCheckbox.vue
       <MarkupPreProcessingSettings>
         <Application> at ProjectInitializer/ElectronRendererProcess/RootComponent.vue
           <Root>

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

found in

---> <SimpleCheckbox> at hikari-frontend/UiComponents/Checkboxes/MaterialDesign/SimpleCheckbox.vue
       <MarkupPreProcessingSettings>
         <Application> at ProjectInitializer/ElectronRendererProcess/RootComponent.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/UiComponents/Checkboxes/MaterialDesign/SimpleCheckbox.vue
       <MarkupPreProcessingSettings>
         <Application> at ProjectInitializer/ElectronRendererProcess/RootComponent.vue
           <Root>
Run Code Online (Sandbox Code Playgroud)

缪斯

该警告被频繁发出是因为组件内部已分配了某些Vue属性的新值。明确地说,我没有这样的操作。

问题出在:onClick="relatedStoreModule.toggleDoNotPreProcessMarkupEntryPointsFlag"。看起来它可以编译为类似的东西<component>.$props.onClick="<vuex store manipulations ...>"-如果是这样,则它是组件内部的隐式属性突变。

试试2

概念

基于Vue文档,“自定义组件”部分

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)"
    >
  `
})
Run Code Online (Sandbox Code Playgroud)

具有vue-property-decorator的 TypeScript的等效项为:

SimpleCheckbox(
  :checked="relatedStoreModule.doNotPreProcessMarkupEntryPointsFlag"
  :onClick="relatedStoreModule.toggleDoNotPreProcessMarkupEntryPointsFlag"
  parentElementCssClass="RegularCheckbox"
)
Run Code Online (Sandbox Code Playgroud) 零件
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
    // ...
Run Code Online (Sandbox Code Playgroud)
import { Component, 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 "@Components/Checkboxes/MaterialDesign/SimpleCheckbox.vue";

@Component({ components: { SimpleCheckbox } })
export default class MarkupPreProcessingSettings extends Vue {
  private readonly relatedStoreModule: ExampleStoreModule = getModule(ExampleStoreModule);
}
Run Code Online (Sandbox Code Playgroud)

用法

SimpleCheckbox(
  v-model="doNotPreProcessMarkupEntryPointsFlag"
  rootElementCssClass="RegularCheckbox"
)
Run Code Online (Sandbox Code Playgroud)

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

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

found in

---> <SimpleCheckbox> at hikari-frontend/UiComponents/Checkboxes/MaterialDesign/SimpleCheckbox.vue
       <MarkupPreProcessingSettings>
         <Application> at ProjectInitializer/ElectronRendererProcess/RootComponent.vue
           <Root>

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

found in

---> <SimpleCheckbox> at hikari-frontend/UiComponents/Checkboxes/MaterialDesign/SimpleCheckbox.vue
       <MarkupPreProcessingSettings>
         <Application> at ProjectInitializer/ElectronRendererProcess/RootComponent.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/UiComponents/Checkboxes/MaterialDesign/SimpleCheckbox.vue
       <MarkupPreProcessingSettings>
         <Application> at ProjectInitializer/ElectronRendererProcess/RootComponent.vue
           <Root>
Run Code Online (Sandbox Code Playgroud)

警告事项

设置了相同的错误:

在此处输入图片说明

局限性

首先,我们需要在Vue Component类中创建新的getter和setter。如果可能的话,避免id是很酷的。不幸的是,对于vuex类(通过vuex-module-decorators),TypeScript设置器不可用,我们需要使用@Mutation-decorated方法。

此外,此解决方案不适用于渲染的元素v-for。它使该解决方案无用。

试试3

概念

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

零件

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

用法

SimpleCheckbox(
  :checked="relatedStoreModule.doNotPreProcessMarkupEntryPointsFlag"
  @toggled="relatedStoreModule.toggleDoNotPreProcessMarkupEntryPointsFlag"
  rootElementCssClass="RegularCheckbox"
)
Run Code Online (Sandbox Code Playgroud)

警告事项

在此处输入图片说明


更新资料

仍然有一些谜语,但是问题已经解决。请参阅下面的答案。

Gur*_*ofu 3

此警告发生在 Electron 应用程序中。来自,SimpleCheckbox但是node_modules该库仍在开发中,因此它是由 提供的npm link

当我尝试进行复制时,我为浏览器创建了 SPA,并将其放置SimpleCheckbox到同一项目中(未从 获取node_modules)。第一个解决方案有效!(我不关心第二个和第三个 - 我只需要从果皮优雅的解决方案中提炼出来)。

我建议原因是npm link,发布我的库并通过安装它npm install。警告消失了!

结论

npm link造成这样的问题已经不是第一次了。这是另一个案例

我仍然没有深入理解这个案例 - 我刚刚发布了一些实验数据。“那么,如果库还在开发中怎么办?” 问题仍然没有答案。我尝试了Lerna - 第一次警告消失了,但是当我将项目移至 Lerna 时,警告再次出现 - 我还不清楚规律性。