vue父子关系组件间的双向数据绑定

6,446 阅读2分钟

vue组件间通信(1-父子)

props

父传子时,我们通常使用自定义属性,props接收。

但是大家都知道,这种数据传递是单向的,只能父传子,而子组件也不能直接去操作这个数据;

# Prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,
但是反过来不会。这是为了防止子组件无意间修改了父组件的状态,来避免应用的数据流变得难以理解。

# 另外,每次父组件更新时,子组件的所有 prop,都会更新为最新值。这意味着你不应该在子组件内部改变 prop。

在两种情况下,我们很容易忍不住想去修改 prop 中数据:

#1 Prop 作为初始值传入后,子组件想把它当作局部数据来用;
#2 Prop 作为原始数据传入,由子组件处理成其它数据输出。

对这两种情况,正确的应对方式是:

定义一个局部变量,并用 prop 的值初始化它:

props: ['initialCounter'],
data: function () {
  return { counter: this.initialCounter }
}

定义一个计算属性,处理 prop 的值并返回:

props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

$emit

子传父时,我们通常使用自定义方法,子组件调用$emit( event, […args] )执行函数,并传递参数,这样就实现了子传父


父组件
<pageHeader v-on:isBack="fun" title="个人信息"></pageHeader>

子组件中
<div @click="clickDiv">点我触发事件</div>


----------
methods: {
clickDiv () {
    this.$emit('update:isBack', '参数')
    }
}

.sync 修饰符

但是这样如果只是想实现传递参数,那就有点麻烦了,因为我们还需要在父组件定义函数去接收,我们希望实现一种双向数据绑定;
    #在我们修改了子组件的数据时能够同步更新父组件,于是我就找到了这个方法
    # Vue 1.x 中的 .sync 修饰符实现了对一个 prop 进行“双向绑定”,当一个子组件改变了一个带 .sync 的 prop 的值时,这个变化也会同步到父组件中所绑定的值。这很方便,但也会导致问题。(官网给出了较为详细的说明,因为它破坏了单向数据流,debug 复杂结构的应用时会带来很高的维护成本。
    # 在 2.0 中移除 .sync ;但是在 2.0 发布之后的实际应用中,我们发现 .sync 还是有其适用之处,比如在开发可复用的组件库时。我们需要做的只是让子组件改变父组件状态的代码更容易被区分。
    # 从 2.3.0 起我们重新引入了 .sync 修饰符)
下面的代码
<pageHeader :isBack.sync="parameter" title="个人信息"</pageHeader>` 
会被扩展为
<pageHeader :isBack.sync="parameter" @update:isBack="val => parameter = val title="个人信息"</pageHeader>

子组件中
<div @click="clickDiv">点我触发事件</div>
methods: {
clickDiv () {
    this.$emit('update:isBack', '参数')
    }
}

当使用一个对象一次性设置多个属性的时候,这个 .sync 修饰符也可以和 v-bind 一起使用:

<comp v-bind.sync="{ foo: 1, bar: 2 }"></comp>

这个例子会为 foo 和 bar 同时添加用于更新的 v-on 监听器。


js数据存储原理

以上为比较正统的写法,也是比较推荐的,有的时候我们想要更加巧妙地方法实现,那么我们可以利用js中对象和数组是引用类型,指向同一个内存空间的原理。

如果 prop 是一个对象或数组,在子组件内部改变它会影响父组件的状态。
即,将需要传递的参数放到一个对象或者数组里传递,在子组件中修改对象的属性,就会联动触发父组件的视图更新了。
# 因为,他们操作的是同一个内存地址引用的对象