Vue.js绑定对象属性

GMs*_*soF 8 html javascript 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>
Run Code Online (Sandbox Code Playgroud)

使用Javascript

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

的jsfiddle

Aer*_*er0 13

在初始化期间,Vue为每个已知属性设置getter和setter.由于contactNum最初没有设置,Vue不知道该属性,也无法正确更新.这可以通过添加contactNum到您的addr对象轻松修复.

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

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

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

<input type="text" id="contactNum" @input="update(addr, 'contactNum', $event)" name="contactNum">
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 哦不,有更好的方法吗?我有很多`addr` 对象的属性,我不想一一初始化它们。 (2认同)

Ter*_*rry 8

根据我的评论,您需要考虑以下几点:

  • 你的代码不工作的原因是由于JS 固有的无法观察对象属性的变化。这意味着即使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);
  }
}
Run Code Online (Sandbox Code Playgroud)

我们仍然可以将您的表单数据存储在addr对象中,该对象将updateFormData根据使用.$set(). 现在,我们可以为您的输入元素创建一个自定义的 Vue 组件。

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

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

模板可能如下所示。它只是将idprop 用于其id,nameplaceholder属性(后者在演示中易于识别)。我们绑定@change@input事件,强制它触发updated回调:

<script type="text/template" id="my-input">
    <input
    type="text"
    :id="id"
    :name="id"
    :placeholder="id"
    @input="updated"
    @change="updated">
</script>
Run Code Online (Sandbox Code Playgroud)

在组件逻辑中,你让它知道它将id作为一个 prop接收,并且它应该inputUpdated使用$.emit(). 我们将 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);
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

使用上面的代码,我们有一个工作示例。在这种情况下,我已经创建的输入字段的arbirary数组:contactNumab,和c

data: {
  addrFields: ['contactNum', ...],
  addr: {},
  test: ""
},
methods: {
  updateFormData: function(id, value) {
    this.$set(this.addr, id, value);
  }
}
Run Code Online (Sandbox Code Playgroud)
<my-input
     v-for="(addrField, i) in addrFields"
     :key="i"
     :id="addrField"
     v-on:inputUpdated="updateFormData"></my-input>
Run Code Online (Sandbox Code Playgroud)