Vue双向道具绑定

时间:2018-02-25 23:35:01

标签: vue.js vuejs2 vue-component

以下是我目前的结构(不起作用)。

父组件:

<template>
<field-input ref="title" :field.sync="title" />
</template>

<script>
import Field from './input/Field'
export default {
  components: {
    'field-input': Field
  },
  data() {
    return {
      title: {
        value: '',
        warn: false
      }
    }
  }
}
</script>

子组件:

<template>
<div>
  <input type="text" v-model="field.value">
  <p v-bind:class="{ 'is-invisible' : !field.warn }">Some text</p>
</div>
</template>

<script>
export default {
  props: ['field']
}
</script>

要求是:

  • 如果父级的数据title.warn值在父级中发生更改,则应更新子级class绑定(field.warn)。
  • 如果孩子的<input>已更新(field.value),则应更新家长的title.value

实现这一目标的最干净的工作解决方案是什么?

2 个答案:

答案 0 :(得分:7)

Don't bind the child component's <input> to the parent's title.value (like <input type="text" v-model="field.value">). This is a known bad practice,能够让您的应用数据流更难理解。

  

要求是:

     
      
  • 如果父级的数据title.warn值在父级中发生更改,则应更新子级class绑定(field.warn)。
  •   

这很简单,只需创建一个warn道具并将其从父传递给孩子。

父母(将道具传给孩子):

<field-input ref="title" :warn="title.warn" />

儿童/模板(仅使用道具阅读):

<p v-bind:class="{ 'is-invisible' : !warn }">Some text</p>

Child / JavaScript(声明道具及其预期类型):

export default {
  props: {warn: Boolean}
}

请注意,在模板中,它是!warn,而不是!title.warn。此外,您应该将warn声明为Boolean道具,因为如果您不这样做,则父级可能会使用会产生意外结果的字符串(例如<field-input warn="false" />)(!"false"是实际上是false,而不是true)。

  
      
  • 如果孩子的<input>已更新(field.value),则应更新家长的title.value
  •   

这里有几个可能的选项(like using .sync in a prop),但我认为在这种情况下最干净的解决方案是在父级上创建value prop and use v-model

父(使用v-model绑定道具):

<field-input ref="title" v-model="title.value" />

子/模板(使用prop作为初始值并在发生更改时发出input个事件):

<input type="text" :value="value" @input="$emit('input', $event.target.value)">

Child / JavaScript(声明道具及其预期类型):

export default {
  props: {value: String}
}

Click here for a working DEMO这两个解决方案在一起。

答案 1 :(得分:1)

有两种方法可以实现双向数据绑定:

  1. 使用props on components
  2. 使用v-model attribute
  3. 使用sync modifier
  4. 使用Vuex

请记住,对于双向绑定,它可能导致一系列难以维持的突变, 引用自文档:

  

不幸的是,真正的双向绑定会造成维护问题,因为子组件可以使父项发生变异,而在父项和子项中均不明显该变异的来源。

以下是可用方法的一些详细信息:

1。)在组件上使用道具

使用双向绑定的道具是not usually advised,但可以通过传递对象或数组来更改该对象的属性,并且在Vue中不会在子对象和父对象中观察到警告的情况下都可以观察到该对象的属性。控制台。

  

每次更新父组件时,子组件中的所有道具   组件将使用最新值刷新。这意味着你   不应该尝试在子组件内部修改道具

道具易于使用,是解决大多数常见问题的理想方法。
由于how Vue observes changes,所有属性都必须在对象上可用,否则它们将不起作用。 如果在Vue完成后添加了任何属性,则必须使用'set'

 //Normal usage
 Vue.set(aVariable, 'aNewProp', 42);
 //This is how to use it in Nuxt
 this.$set(this.historyEntry, 'date', new Date());

该对象对组件和父对象都是反应性的

  

我将对象/数组作为道具传递,它自动进行双向同步-在   子代,在父代中已更改。

     

如果您传递简单值(字符串,数字)   通过道具,您必须显式使用.sync modifier

引自-> https://stackoverflow.com/a/35723888/1087372

2。)使用v-model属性

v-model属性是语法糖,它可以在父子之间轻松进行双向绑定。它与sync修饰符的作用相同,只是它对绑定使用特定的道具和特定的事件

此:

 <input v-model="searchText">

与此相同:

 <input
   v-bind:value="searchText"
   v-on:input="searchText = $event.target.value"
 >

道具必须为 value 且事件必须为 input

3。)使用同步修改器

sync修饰符也是语法糖,并且与v-model相同,只是prop和event名称由正在使用的任何东西来设置。

在父级中,可以按以下方式使用:

 <text-document v-bind:title.sync="doc.title"></text-document>

可以从孩子发出事件,以将任何更改通知父母:

 this.$emit('update:title', newTitle)

4。)使用Vuex

Vuex是一个可以从每个组件访问的数据存储。 可以订阅更改。

通过使用Vuex存储,可以更轻松地查看数据突变的流,并明确定义了它们。通过使用vue developer tools,可以轻松调试和回滚所做的更改。

这种方法需要更多样板,但是如果在整个项目中使用,它将变得更加清晰,可以定义如何进行更改以及从何处进行更改。

请参见getting started guide