为什么我无法在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: ""
}
});
答案 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>
模板可能如下所示。它只为id
,id
和name
属性使用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数组:contactNum
,a
,b
和c
:
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: ""
}