Vue .sync 仅适用于 v-model,但会出现突变错误

Posted

技术标签:

【中文标题】Vue .sync 仅适用于 v-model,但会出现突变错误【英文标题】:Vue .sync only works with v-model, but gives mutation error 【发布时间】:2021-04-04 21:01:23 【问题描述】:

// 注意:问题是由 VueFormulate 的 FormulaInput(自定义输入)引起的。

检查代码沙箱以获取.sync 的 3 个工作示例

用例

我的应用将多个动态组件注入到视图中,然后将每个组件中的多个输入绑定到父级中的数据。

由于v-model 仅适用于单个值,我发现.sync(在 Vue 2.3 之后再次添加)是将每个子组件中的多个输入双向绑定到我父级数据的唯一方法。

问题

我遵循了 Vue 文档和许多教程中的确切语法,但是当我在我的子组件中使用 :value="value 时,它会在我的数据中输入 undefined,并且在控制台中没有错误。

如果我使用v-model,它会按预期工作,但是每次按下按键都会在控制台中产生no-mutate-props 错误。

预期结果

我希望双向绑定能够正常工作,而不会在控制台中产生任何 no-mutate-props 错误。

我想我需要某种观察者来检查引用我的道具的值,但这似乎有点混乱,我必须为大约 30 个组件实现它......如果我更喜欢更清洁的东西可能。

Code Sandbox Example of issue

在儿童中

// input1
<input
  type="text"
  :value="value" <----- this will work if I make it a v-model, but produces mutation error in console
  @input="$emit('update:value', value)"
/>

// input2
<input
  type="text"
  :value2="value2" <----- again, will work with v-model only
  @input="$emit('update:value2', value2)"
/>

props: 
  value: 
    type: String
  ,
  value2: 
    type: String
  

在父母中

<component
  :is="step.component"
  :value.sync="step.value"
  :value2.sync="step.value2"
  :value3.sync="step.value3"
/>

【问题讨论】:

【参考方案1】:

value 不起作用的原因仅仅是因为您发出了相同的未更改的value,它被传递下来。没有v-modelvalue 不会发生任何变化,因此没有新的东西可以重新发射。

将该输入更改为:

<input
  :value="value"
  @input="$emit('update:value', $event.target.value)"
  type="text"
  step="1"
  placeholder="Child Input1 (value)"
/>

这样,当输入事件发生时,您会从输入框中发出一个新值。

【讨论】:

【参考方案2】:

为了完整起见,我想在 Dan 的回答中添加一个通用替代方案:允许将 v-model 与任何无法直接变异的内容一起使用的 Vue 模式:computed getter + setter。

概念证明:

Vue.component('child', 
  template: `
  <input v-model="local" type="text" />
  `,
  props: ['value'],
  computed: 
    local: 
      get() 
        return this.value;
      ,
      set(value) 
        this.$emit('update:value', value);
      
    
  
)

new Vue(
  el: '#app',
  data: () => (
    foo: 
      bar: 'baz'
    
  )
)
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>

<div id="app">
  <div>
    <child :value.sync="foo.bar" />
  </div>
  <pre v-html="foo" />
</div>

我特意使用了一个嵌套属性,它通常不是反应式的。

虽然在这个特定示例中使用它实际上只是有点冗长(因此它可能不如 Dan 提出的语法有用)它在与 Vuex 状态属性一起使用时会派上用场(在 getter 中获取存储值并提交setter 中的突变 - 特别是因为您可以将本地计算命名为与 state 属性相同)。

值得注意的是,它不需要额外的侦听器(性能提升可以忽略不计)(例如:@input@change@keydown 等... - 为了完整起见,在生产代码中您可能想要添加粘贴事件侦听器,可能还有其他边缘情况 - 自动完成!? - 虽然大多数情况都被 @input 覆盖)。

正如您所料,每当v-model 属性的值发生变化时,setter 中的代码就会运行一次。简而言之,这是一个适当的双向绑定。

【讨论】:

以上是关于Vue .sync 仅适用于 v-model,但会出现突变错误的主要内容,如果未能解决你的问题,请参考以下文章

vue 中 v-model 和 .sync修饰符

CSS 表格样式仅适用于特定单元格,但会覆盖其他单元格

vue中 .sync 和 v-model 的区别

前端vue中的v-model与.sync修饰符的区别

前端vue中的v-model与.sync修饰符的区别

vue组件之间通信 (ref v-model 与.sync修饰符) 之三