25
例子是在 jsrun.net 平台编写,不支持移动端平台,所以本文建议在 PC 端进行阅读。

Vue 是数据驱动的视图框架,那么组件间的数据通信是必然的事情,那么组件间如何进行数据传递呢?

首先组件间通信有父子组件、兄弟组件、堂兄弟组件、叔侄组件等,分类太多可能不好理解,我们暂且分为:

  • 父子组件通信
  • 子父组件通信
  • 非父子组件通信

    • 兄弟组件通信
    • 非兄弟组件通信(不是直属关系,如堂兄组件、叔侄组件等)

后续的组件间通信方式的例子就会根据这些分类进行说明。

Vue 本身提供哪几种通信方式?

首先 Vue 灵感源于 angular,支持双向绑定,Vue 本质还是单向数据流。跟 React 一样,组件间最基本的数据流是通过 prop 向子组件传递数据。

props 数据流多层示例图

这里列举一下 Vue 本身支持的通信方式:

  • prop
  • $emit

    这个其实类似 React 的 props 回调。

  • provide / inject

    如果你熟悉 React,这与 React 的 context 特性很相似。

那么有人说 $attrs$listener 呢?这些严格意义上不能归纳为数据流的通信方式,这些只是辅助属性,本人也不建议过多的使用这些 $ 属性,除了一些有必要的场景。

prop

prop 是 Vue 三大核心概念之一,prop 在组件中无处不在。prop 只可以从上一级组件传递到下一级组件(父子组件),即所谓的单向数据流。而且 prop 只读,不可被修改,所有修改都会失效并警告。

可以先阅读官网的 通过 Prop 向子组件传递数据 的教程。

父子组件通信

这里也编写了一个简单的例子 http://jsrun.net/wXyKp/edit

子父组件通信

不是说是单向数据流吗,怎么还可以使用 prop 进行子父组件通信?这样想是对的,prop 是无法向上传递数据,但是我们可以使用回调啊。数据流的确向上走了,但是这并不违反单向数据流的思想,这个并不会使得数据流混乱,还是比较清晰。

这个 prop 回调方式,在 React 会经常使用。但是在 Vue 却很少使用,因为组件可以自定义事件,即后面的 $emit 组件间通信方式(其实就是订阅发布模式)。

例子可以看这个 http://jsrun.net/aXyKp/edit

兄弟组件的通信

如果你了解上面提到的父子组件通信子父组件通信,那么你就很容易理解兄弟组件通信的方式。

可以看下这个例子 http://jsrun.net/QyyKp/edit

兄弟组件的通信就是父子组件通信子父组件通信的结合,需要父组件作为中间组件进行数据传递。

那么这样岂不是很麻烦?的确是多了一步,所以我们基本不会使用这种方式进行数据传递。

但是单向数据流思想是不存在交叉的数据流,即使 vuex 也无法避免这一步,但是 vuex 用法上你感觉不到这一步。所以请不要随意引入第三方订阅发布的类库来解决这个问题,兄弟组件不可以直接通信的问题,这会造成数据流混乱,这就完全违反了单向数据流的思想。

可以看下这个强烈不建议的使用例子 http://jsrun.net/PyyKp/edit,这种使用方式完全违背了单向数据流的思想,当程序复杂起来,数据流会特别混乱,项目不好维护。

$emit

官网教程可以看监听子组件事件

$on$emit 是 Vue 自带的订阅发布模式,可以自定义事件。在子父组件通信中可以使用这种模式代替 prop 回调模式,相对便捷一点。

每个组件的 $on$emit 都是独立的,$emit 只会触发当前组件的 $on 事件。

对比例子可以看这个 http://jsrun.net/cXyKp/edit

子父组件通信可以看上面提到的例子可以看这个 http://jsrun.net/aXyKp/edit

provide / inject

首先你需要看官网教程 https://cn.vuejs.org/v2/api/#...prviode / inject 在 vue@2.2.0 才新增的。这个也是作者参考 react context ,新加的用法,如果你熟悉 react,那么这个很好理解。

在组件嵌套比较深的情况下,我们再使用 prop 层层传递数据将是个噩梦。 孙辈组件想直接获取到祖辈的数据,而不用经过父辈组件,该怎么处理呢?provide / inject 可以解决这个问题。

可看这个使用例子 http://jsrun.net/nXyKp/edit

从上面的例子运行可知,provide 执行与 beforeCreatecreated 之间,也可以访问 datainject 的数据。

其他的通信方式

除了 vue 本身支持的通信方式,还有其他的吗?当然有 vuex 就是 vue 官方的数据流管理类库。

上面提到的 vue 本身支持的通信方式,涉及到的都是父子或者子父组件的通信,那么非父子组件通信呢?通过 vuex 我们就可以很简单的进行非父子组件的通信了,使用了 vue 支持各种方式的通信(包括父子组件、子父组件的通信)。

结合单向数据流的思想,我们难道不可以统一一个地方集中管理数据(我们简称 store),然后每个组件可以直接和 store 通信吗?答案当然可以,这就是我们 vuex 所做的事情,这个跟 react 的 redux、mobx 等类库的思想是一致的。

props 的通信方式是这样的,component -> component

而 vuex 的通信方式是这样的,component(传递数据) -> store -> (数据变化更新组件)component,可以简单理解为 component -> store -> component。我们在中间搭建了数据管理层,那么这样我们就可以更好的管理数据了,而且数据流符合单向数据流的思想,数据都是从 store 流向 componentcomponent 可以是任何嵌套层次的组件。

理论上我们也可以在 vue 上使用 redux,但是没人会这样做,不合适,vuex 才是量身定制的。

参考文章


学习和总结文章同步发布于 https://github.com/xianshanna...,有兴趣可以关注一下,一起学习和进步。

Samon
1.3k 声望92 粉丝