Vue.js绑定对象属性

时间:2017-10-25 06:38:07

标签: javascript html html5 vue.js vuejs2

为什么我无法在Vue中绑定对象属性?对象addr不会立即被动,但是test是被动的,为什么会这样?在这种情况下,我应该如何绑定它?

HTML

<div id="app">

   <input type="text" id="contactNum" v-model="addr.contactNum" name="contactNum">

   <input type="text" id="test" v-model="test" name="test">
   <br/>
   {{addr}}<br/>
   {{addr.contactNum}}<br/>
   {{test}}
</div>

的Javascript

var vm = new Vue({
    el: '#app',
    data: {
      addr: {},
      test: ""
    }
});

Jsfiddle

3 个答案:

答案 0 :(得分:8)

在初始化期间,Vue为每个已知属性设置getter和setter。由于contactNum最初未设置,因此Vue不了解该属性,无法正确更新。通过将contactNum添加到addr对象,可以轻松解决此问题。

var vm = new Vue({
  el: '#app',
  data: {
    addr: {
      contactNum: "" // <-- this one
    },
    test: ""
  }
});

以上在Vue中称为 reactivity 。由于Vue不支持动态地向其反应系统添加属性,因此我们可能需要某种解决方法。 API提供了可能的solution。如果是动态添加的属性,我们可以使用Vue.set(vm.someObject, 'b', 2)

这样做标记需要进行一些更新。而不是使用v-model,最好使用像@input这样的事件监听器。在这种情况下,我们的标记可能如下所示。

<input type="text" id="contactNum" @input="update(addr, 'contactNum', $event)" name="contactNum">

所以基本上每次输入元素值改变时都会触发该函数。显然这样做也需要对JS部分进行一些调整。

var vm = new Vue({
  el: '#app',
  data: {
    addr: {},
    test: ""
  },
  methods: {
    update: function(obj, prop, event) {
      Vue.set(obj, prop, event.target.value);
    }
  }
});

由于Vue在任何被动元素上触发Vue.set(),我们只是自己调用它,因为Vue没有将动态添加的属性识别为被动属性。当然,这只是一种可能的解决方案,可能还有很多其他的解决方法。可以看到一个完整的工作示例here

答案 1 :(得分:3)

根据我的评论,您需要考虑几件事情:

  • 您的代码无法正常工作的原因是由于内部无法监视对象属性的变化。这意味着即使addr具有反应性,添加到addr的任何属性在声明时都不会执行,这将使其成为非反应性的。有关详细信息,请参阅VueJS文档:https://vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats
  • 如果您将拥有任意数量的输入字段,则可能更好地编写自定义输入组件,并且只需使用v-for迭代注入输入字段您拥有的输入字段数。

现在回到第二点,如果您知道addr将包含哪些字段,您只需在应用中声明它即可。我们创建了一个新的updateFormData方法,该方法由组件调用:

data: {
  addrFields: ['contactNum', ...],
  addr: {},
  test: ""
},
methods: {
  updateFormData: function(id, value) {
    this.$set(this.addr, id, value);
  }
}

我们仍然可以将您的表单数据存储在addr对象中,该对象将根据使用.$set()收到的有效内容通过updateFormData方法进行更新。现在,我们可以为您的input元素创建一个自定义Vue组件。

在下面的示例中,组件将遍历您的所有addrFields,并使用addrField向下传递:id="addrField"作为道具。我们还希望确保捕获从组件中发出的自定义命名的updated事件。

<my-input
     v-for="(addrField, i) in addrFields"
     :key="i"
     :id="addrField"
     v-on:inputUpdated="updateFormData"></my-input>

模板可能如下所示。它只为ididname属性使用placeholder道具(后者可在演示中轻松识别)。我们绑定@change@input事件,强制它触发updated回调:

<script type="text/template" id="my-input">
    <input
    type="text"
    :id="id"
    :name="id"
    :placeholder="id"
    @input="updated"
    @change="updated">
</script>

在组件逻辑中,您让它知道它将作为道具接收id,并且它应该使用$.emit()发出inputUpdated事件。我们将ID和值附加为有效负载,以便我们可以通知父级已更新的内容:

var myInput = Vue.component('my-input', {
    template: '#my-input',
  props: {
    id: {
        type: String
    }
  },
  methods: {
    updated: function() {
        this.$emit('inputUpdated', this.id, this.$el.value);
    }
  }
});

通过上面的代码,我们有一个工作示例。在这种情况下,我创建了一个输入字段的arbirary数组:contactNumabc

var myInput = Vue.component('my-input', {
	template: '#my-input',
  props: {
  	id: {
    	type: String
    }
  },
  methods: {
  	updated: function() {
    	this.$emit('updated', this.id, this.$el.value);
    }
  }
});

var vm = new Vue({
    el: '#app',
    data: {
      addrFields: ['contactNum', 'a', 'b', 'c'],
      addr: {},
      test: ""
    },
    methods: {
    	updateFormData: function(id, value) {
      	this.$set(this.addr, id, value);
      }
    }
});
<script src="https://unpkg.com/vue@2.1.3/dist/vue.js"></script>
<div id="app">
   
   <my-input
     v-for="(addrField, i) in addrFields"
     :key="i"
     :id="addrField"
     v-on:updated="updateFormData"></my-input>
   
   <input type="text" id="test" v-model="test" name="test" placeholder="test">
   <br/>
   <strong>addr:</strong> {{addr}}<br/>
   <strong>addr.contactNum:</strong> {{addr.contactNum}}<br />
   <strong>test:</strong> {{test}}
</div>

<script type="text/template" id="my-input">
	<input
  	type="text"
    :id="id"
    :name="id"
    :placeholder="id"
    @input="updated"
    @change="updated">
</script>

答案 2 :(得分:0)

使用此编辑您的 Vue data,因为它没有设置getter和setter方法。另外,请在Vue文档here上查看声明性反复渲染

data: {
    addr: {
      contactNum: "" // <-- this one
    },
    test: ""
  }