prop从父亲到儿子双向绑定

prop从父亲到儿子双向绑定(在vuejs2.0中反向回传是严正反对的!)

默认情况下prop是单向绑定:当父组件属性变化时,传递给子组件,但是反过来不会。你可以使用.sync或者.once绑定修饰符来显式地强制双向绑定或者单次绑定:

复制代码
<!-- 默认为单向绑定 -->
<child :msg="parentMsg"></child>

<!-- 双向绑定 -->
<child :msg.sync="parentMsg"></child>

<!-- 单次绑定 :注意单次绑定在数据传入后就不会同步后面的任何变化了,适合传入初始化数据的场景-->
<child :msg.once="parentMsg"></child>
复制代码

需要注意的是:如果prop本身是一个对象或者数组的话,由于javascript对象是引用方式,无论是什么绑定方式都会是双向绑定!!

父子组件通信:

子组件可硬用this.$parent访问父组件,this.$root访问祖根实例,每个父组件都有一个数组this.$children来包含所有子元素。

但是在vuejs2.0中,任何试图在组件内修改通过props传入的父组件数据都被认为是anti-pattern的,报以下错误:

Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders

我们必须重新思考如何架构我们的应用:

1. 不要在组件内试图修改props传进来的父组件数据,数据只应该由该数据的源头组件来负责app内的CRUD;

2. 数据永久性功能(就是和后台数据库交互保存)最好是由需要处理数据的子组件来和数据库交互,但是通过$emit一个事件通知该数据的源头组件来更新web app的数据;(在子组件tag引用处以@resource-deleted来引用父组件的事件函数) 这种模式带来的问题是数据来源和数据消费者有事件交互的强烈耦合。

还有一种小方案是将数据永久性功能以及web app内部的数据一致两个功能合为一处,即:子组件需要修改源数据时,$emit消息给父亲,由owner来同时完成数据永久性保存和内部app数据一致

3.对于大型web app可以使用vuex来实现解耦:父子之间通过vuex store state tree来保持联系,任何时候需要获取数据则getter,如果需要修改数据则setter,数据修改后的reactive则由vuejs处理,这种方式最大限度地实现了解耦

4. 但是有时也需要一些平衡:难道每一片小数据都得通过$emit事件给数据源头来做修改吗?由于如果传入的数据是Object类型或者array类型的,则本身由于是reference传参的,也就是说子组件prop传入供子组件读/写的object/array和“源头object/array”实际上是一个对象,因此只要我们不直接简单粗暴以

this.objFromParent = newObjectCreatedByChild  //这样会导致vuejs报错 Avoid mutating a prop directly ... 

但是如果我们这样操作,则是可以的,并且数据完全是同步的!

this.objFromParent.propertyChangedByChild = newObjectCreatedByChild.propertyChangedByChild  //这样数据就很轻松保持了一致性,而不用$emit消息到数据源来维护数据了!!!

5.第4点和vuex的机制比较类似。你可以在需要共享给儿子组件的数据(起源于hosted by本组件)存放在一个localStore对象的属性中,将localStore对象作为属性值传给儿子组件,比如:pstore="localStore",在儿子组件中,则可以直接操作pstore.parentData = somedatahandledbyson ,曲线救国,绕过了vuejs2.0不允许对属性赋值操作的限制。

6. 如果是需要共享给后代子孙的数据,则可以引入一种thisrootstore机制,所有这类数据作为thisrootstore的属性对象存在,后代以this.rootstore.xxx来引用它。

5和6的好处是剔除大部分不需要$emit事件来sync数据的冗余代码,更加易于实现组件功能的抽象和重用

7. 也可以考虑利用slot机制的特性: slot本身所在html js scope属于父组件,这样就可以以下面的形式来解决这个数据同步问题:

 

<!-- within parent template removeThisSon() resonsible for remove data which hosted by parent -->
<son v-for="son in sons"> 
  <div @click="removeThisSon(son)"> some operation affected parent data</div> 
</son>

 

心法:对整个属性对象替换(赋值),新增,或者删除操作必须由数据源来操作,但是对传入的属性对象的某些property修正,则可以在子组件内部直接操作,数据就同步反映到父组件中

心法:数据优先,你首先抽象驱动你的app的state,所有代码就围绕着这些个state的变迁,而让vuejs本身来执行构建和更新DOM的工作。

The whole idea is "data first". you define what the state of your application should look like, and let Vue build and update the DOM accordingly

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值