Javascript Vue.js 绑定对象属性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/46925527/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 03:40:11  来源:igfitidea点击:

Vue.js bind object properties

javascripthtmlvue.jsvuejs2

提问by GMsoF

Why I can't bind the object properties in Vue? The object addris not reactive immediately, but testis reactive, how come? In this case, how should I bind it?

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

HTML

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

Javascript

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

Jsfiddle

提琴手

回答by Aer0

During initialisation Vue sets up getters and setters for every known property. Since contactNumisn't initially set up, Vue doesn't know about that property and can not update it properly. This can be easly fixed by adding contactNumto your addrobject.

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

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

The above is called reactivityin Vue. Since Vue doesn't support adding properties dynamically to its reactivity system, we may need some kind of workaround. A possible solutionis provided by the API. In case of dynamically added properties we can use Vue.set(vm.someObject, 'b', 2).

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

Doing so the markup would need to get some update. Instead of using v-modelit'd be better to use an event listener like @input. In this case our markup could look like this.

这样做标记需要得到一些更新。而不是使用v-model它会更好地使用像@input. 在这种情况下,我们的标记可能如下所示。

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

So basically the function will get triggered every time the input elements value changes. Obviously doing so will also require some adjustments on the JS part.

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

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

Since Vue triggers Vue.set()on any reactive element, we simply call it on our own because Vue doesn't recognizes a dynamically added property as a reactive one. Of course, this is only one possible solution and there may be lots of other workarounds. A fully working example can be seen here.

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

回答by Terry

As per my comments, there are several things that you want to consider:

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

  • The reason why your code is not working is due to the inherent inability of JS to watch for changes in object properties. This means that even though addris reactive, any properties added to addrthat is not done when it is declared will make it non-reactive. Refer to the VueJS docs for more details: https://vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats
  • If you are going to have an arbitrary number of input fields, you are probably better of composing a custom input component, and simply use v-forto iteratively inject input fields based on the number of input fields you have.
  • 你的代码不工作的原因是由于JS 固有的无法观察对象属性的变化。这意味着即使addr是响应式的,任何添加到addr它的属性在声明时未完成都会使其成为非响应式。有关更多详细信息,请参阅 VueJS 文档:https://vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats
  • 如果您打算拥有任意数量的输入字段,那么您可能最好编写一个自定义输入组件,并v-for根据您拥有的输入字段的数量简单地使用迭代注入输入字段。


Now back to the second point, if you know what fields addrwill have, you can simply declare it in your app. We create a new updateFormDatamethod, which is called by the component:

现在回到第二点,如果你知道有哪些字段addr,你可以简单地在你的应用程序中声明它。我们创建一个新updateFormData方法,由组件调用:

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

We can still store your form data in the addrobject, which will be updated by the updateFormDatamethod based on the received payload using .$set(). Now, we can then create a custom Vue component for your input element.

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

In the example below, the component will iterate through all your addrFields, and pass down the addrFieldas a prop using :id="addrField". We also want to make sure that we capture the custom-named updatedevent emitted from within the component.

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

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

The template can look something like the following. It simply uses the idprop for both its id, name, and placeholderattribute (the latter for easy identification in the demo). We bind the @changeand @inputevents, forcing it to trigger the updatedcallback:

模板可能如下所示。它只是将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>

In the component logic, you let it know that it will receive idas a prop, and that it should emit an inputUpdatedevent using $.emit(). We attach the ID and value as payloads, so that we can inform the parent what has updated:

在组件逻辑中,您让它知道它将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);
    }
  }
});


With the code above, we have a working example. In this case, I have created an arbirary array of input fields: contactNum, a, b, and c:

使用上面的代码,我们有一个工作示例。在这种情况下,我已经创建的输入字段的arbirary数组:contactNumab,和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/[email protected]/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>

回答by hamzox

Edit your Vuedatawith this since it's getter and setter methods are not set up. Also, check out Declarative Reactive Renderingon Vue docs here:

用这个编辑你的Vuedata,因为它没有设置 getter 和 setter 方法。另外,请在此处查看Vue 文档上的声明式反应式渲染

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