Vue为什么要在不发出事件的情况下更改子项的父项值

时间:2019-06-01 02:25:23

标签: vue.js

我对Vue还是很陌生,但是这种行为不完全与道具设计,事件设计矛盾吗?

Object.assign({}, this.test_object );中初始化值时,我设法通过使用child-component来停止它,但这不是默认行为吗?

这里有一些背景。

我正在尝试在更大的应用程序中使用脏状态(例如,值已更改,因此用户必须先将数据保存回数据库,然后再继续操作)

我发出了一个事件,并被父级捕获,但是我必须测试该值并初始化脏状态的代码未运行,因为该值已在父级组件中更改。

Vue.component( 'parent-component', {
  template: '#parent-component',
  data: function() {
    return {
      testObject: {
        val: 'Test Value'
      }
    }
  }
});

Vue.component( 'child-component', {
  template: '#child-component',
  props: {
    test_object: Object
  },
  data: function() {
    return {
      child_object: this.test_object
    }
  }
});

Vue.config.productionTip = false;

new Vue({
  el: '#app',
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<script type="text/x-template" id="parent-component">
    <div>
        <child-component :test_object="testObject"></child-component>
        
        <p>This is in the parent component</p>
        <p><code>testObject.val = {{testObject.val}}</code></p>
        
    </div>
</script>
  
<script type="text/x-template" id="child-component">
    <div>
        <label for="html_input">HTML Input</label>
        <input style="border:1px solid #CCC; display:block;" type="text" name="html_input" v-model="child_object.val" />
    </div>
</script>

<div id="app">
  <parent-component></parent-component>
</div>

1 个答案:

答案 0 :(得分:2)

使用v-model是非常具有欺骗性的事情。如果您不小心,可能会导致突变不属于您组件的数据。在您的情况下,您无意间将只读道具直接传递给v-model。它不知道它是prop还是本地组件状态。

您正在做的是正确的解决方案,但考虑到单向/单向数据流,我们可以用更明确,更优雅的方式重写此示例:

您的组件定义为:

Vue.component( 'parent-component', {
  template: '#parent-component',
  data: function() {
    return {
      testObject: {
        val: 'Test Value'
      }
    }
  },

  methods: {
    // Added this method to listen for input event changes
    onChange(newValue) {
      this.testObject.val = newValue;

      // Or if you favor immutability
      // this.testObject = {
      //   ...this.testObject,
      //   val: newValue
      // };
    }
  }
});

您的模板应为:

<script type="text/x-template" id="parent-component">
  <div>
    <child-component :test_object="testObject"
      @inputChange="onChange"></child-component>

    <p>This is in the parent component</p>
    <p><code>testObject.val = {{testObject.val}}</code></p>

  </div>
</script>

<!-- Instead of v-model, you can use :value and @input binding. -->
<script type="text/x-template" id="child-component">
  <div>
    <label for="html_input">HTML Input</label>
    <input type="text" name="html_input"
      :value="test_object.val"
      @input="$emit('inputChange', $event.target.value)" />
  </div>
</script>

要注意的重要事项:

  • 使用v模型时,请确保您严格在处理组件的局部值/数据。绝不应该将其作为外部道具的副本。
  • 如果您接受v-model的当前值和:value的事件,则可以轻松地将自定义的类似于表单的组件转换为可以与@input一起使用的组件。 v-model只会work out of the box
  • 对值的任何修改都应在同一组件中进行。