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

Vue .sync only works with v-model, but gives mutation error

// 注意:问题是由于 VueFormulate 的 FormulaInput(自定义输入)造成的。

检查代码沙箱以获得 .sync

的 3 个工作示例

用例

我的应用程序将多个动态组件注入一个视图,然后将每个组件内的多个输入绑定到 parent 中的数据。

由于 v-model 仅适用于单个值,我发现 .sync(在 Vue 2.3 之后再次添加)是 two-way 在每个输入中绑定多个输入的唯一方法child 我的 parent 数据的组成部分。

问题

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

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

预期结果

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

我想我需要某种观察者来检查引用我的 prop 的值,但这看起来有点混乱,而且我必须为大约 30 个组件实现它...我更喜欢一些东西尽可能清洁。

Code Sandbox Example of issue

在Child

// 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
  }
}

在Parent

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

value 不起作用的原因只是因为您发出相同的未更改 value,它被传递下来。没有 v-model,什么都没有改变 value,所以没有新的东西可以发射回来。

将该输入更改为:

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

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

为了完整起见,我想在 Dan 的回答中添加一个通用的替代方案:一个 Vue 模式,允许将 v-model 用于任何不能直接改变的东西: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 中提交突变 - 特别是因为您可以将本地计算命名为与状态相同 属性).

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

如您所料,每当 v-model 属性 的值发生变化时,setter 中的代码都会得到一次 运行。总之,就是妥妥的双向绑定。