Vue .sync 仅适用于 v-model,但会出现变异错误 // 注意:问题是由 VueFormulate 的 FormulaInput自定义输入引起的在孩子在父级

问题描述

// 注意:问题是由 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"
/>

解决方法

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

将该输入更改为:

<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/[email protected]"></script>

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

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

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

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

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