组件通信
ViewModel 在 View 层内进行流动的时候,遵循函数调用的规律,根据函数的纯洁性可以进行分类。数据从根部通过属性或者 provide 传递向叶子的时候,数据应当尽量保持单向传递,如果是基本类型数据的话,那么无话可说,直接传入,数据只能在父组件中改变,并且只能 props 再传入。“再传入”指的是,子组件是否需要使用额外操作来监听父组件传入的 props 的变化从而再次初始化组件的数据和初始状态,由于 vue 的组件顶层逻辑只执行一次,所以,props 变化时,需要使用额外的监听操作来处理子组件中的数据。如果引用类型或者说对象,由于其数据结构的复杂性,需要分为几种解决方案的级别:
脏函数方案
数据由父组件创建后,传入子组件,子组件可以对复杂数据的内部进行直接修改。 特点:实现和操作简单,但是 props 不可再传入,性能较高,可复用性较差。 使用建议:该对象最好只由父组件和一个子组件所共同持有,不要在多个组件中持有,这样可以减少数据的不确定性,同时,甚至可以移交所有权,父组件将数据的所有权移交给子组件,父组件不得修改,但是可以读取。
local store 方案
由子组件定义一个 local store 类型,所有调用子组件的父组件应当实例化一个 local store 对象,并传入其子组件中,对于数据的修改应当由 local store 提供,父组件和子组件均可调用。 特点:该方案可以形成一个局部的 store,使得 store 在多个组件中进行分享,使用方便灵活,性能较高,可复用性中等,其可复用性依赖于该 local store。props 不可再传入。 使用建议:可以结合 EventBus,让 store 继承 EventBus,从而直接通过 store 进行数据的订阅而无需使用组件事件。
纯函数方案
数据由父组件创建,并规定修改的方法,父组件传入子组件后,子组件不得再修改,子组件通过定义事件,描述数据可能发生的变化,由父组件监听事件然后更新数据。 特点:该方法满足单向数据流,提供规范的组件交互,props 可再传入,但是操作繁琐,性能较差,可复用性较高。 使用建议:推荐在子组件中通过递归声明对象的代理来进行 emit,这样可以让代理对象来自动 emit,并且使用手感可以像脏组件一样,比较直接方便,但是如此 props 不可再传入。另外,如果父组件不处理事件,那么数据也将无法更新。
总结:引用类型的 props 统一不要再传入。根据不同的情况酌情选取方案。 备注:数据派生,computed/computedObject 或者 ref+watch,