这篇文章希望从整体上认识Vue的几种通信方式,希望做到快速全面掌握。
一、父子组件-props/$emit
这种通信方式很常用,也很基础,大家都很熟悉。不展示代码,仅总结用法:
父组件->子组件: 父组件 v-bind:绑定变量传给子组件。子组件通过props接收数据。
子组件->父组件: 子组件通过emit提交,向父组件传值,父组件通过v-on绑定事件接收数据。
this.$emit("titleChanged","子向父组件传值");//自定义事件 传递值“子向父组件传值”
父组件通过props向下传递数据给子组件。(Vue的单向数据流)
注:组件中的数据共有三种形式:data、props、computed
二、父子组件-通过获取组件实例的方式— parent / $children 和 ref(ref更常用)
(标题写法:parent 前面也有$。编辑器的问题。下面也都有。)
$root :当前组件树的根 Vue 实例。如果当前实例没有父实例,此实例将会是其自己。
$parent:父实例,如果当前实例有的话。
$children:
当前实例的直接子组件。需要注意 children并不保证顺序,也不是响应式的。如果你发现自己正在尝试使用children 来进行数据绑定,考虑使用一个数组配合 v-for 来生成子组件,并且使用 Array 作为真正的来源。
子实例可以用 this.parent访问父实例,子实例被推入父实例的children 数组中。
需要注意的是:这两种都是直接得到组件实例,使用后可以直接调用组件的方法或访问数据。
this.$parent.message //在子组件中访问父组件中的数据
this.$children[0].num //因为父组件可能有很多子组件
注意:
节制地使用 $parent 和 $children - 它们的主要目的是作为访问组件的应急方法。更推荐用 props 和 events 实现父子组件通信
ref: 如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例。
注意:ref 也是很重要的一种方式,且实际工作中很常用。 除了可以使用它获取数据,还可以通过ref调用子组件中的方法,使其执行。
三、EventBus中央事件总线-emit/ on
这种方法通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。当我们的项目比较大时,可以选择更好的状态管理解决方案vuex。
var bus = new Vue()
// 组件A
bus.$emit('id-selected', 1)
// 组件B
bus.$on('id-selected', function (id) {
console.log(id)
})
$on 监听了自定义事件,因为有时不确定何时会触发事件,一般会在 mounted 或 created 钩子中来监听。
四、Vuex
详见本人文章: Vuex的使用和原理
五、localstorage /sessionstorage使用
这种通信比较简单,缺点是数据和状态比较混乱,不太容易维护。
localStorage / sessionStorage可以结合vuex, 实现数据的持久保存,同时使用vuex解决数据和状态混乱问题.
六、attrs/listeners (前面都有$符)
多级组件嵌套需要传递数据时,通常使用的方法是通过vuex。但如果仅仅是传递数据,而不做中间处理,也可使用Vue2.4 版本提供的另一种方法----attrs/listeners。
vm.$attrs
包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。
$listeners:
包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件。
// 父组件 index.vue
<list class="list-box" desc="描述" :list="list"></list>
// 子组件 list.vue
props: {
list: [],
},
mounted() {
console.log(this.$attrs) // {title: "标题", desc: "描述"}
// 子组件 list.vue
<detail v-bind="$attrs"></detial>
// 孙子组件 detail.vue
// 不定义props,直接打印 $attrs
mounted() {
console.log(this.$attrs) // {title: "标题", desc: "描述"}
同样的,通过 listeners用类似的操作方式可以进行跨级的事件传递,实现子到父的通信。listeners 包含了父作用域中不含 .native 修饰的 v-on 事件监听器,通过 v-on="$listeners" 传递到子组件内部。
// 父组件 index.vue
<list @change="change" @update.native="update"></list>
// 子组件 list.vue
<detail v-on="$listeners"></detail>
// 孙子组件 detail.vue
mounted() {
this.$listeners.change()
this.$listeners.update() // TypeError: this.$listeners.update is not a function
}
七、provide / inject API (一般开发不用)
在根组件中,传入变量,然后在后代组件中使用即可。
// 父级组件提供 'foo'
var Provider = {
provide: {
foo: 'bar'
},
// ...
}
// 子组件注入 'foo'
var Child = {
inject: ['foo'],
created () {
console.log(this.foo) // => "bar"
}
// ...
}
利用 ES2015 Symbols、函数 provide 和对象 inject:
const s = Symbol()
const Provider = {
provide () {
return {
[s]: 'foo'
}
}
}
const Child = {
inject: { s },
// ...
}
慎用 provide/inject
Vuex 和 provide/inject 最大的区别在于,Vuex 中的全局状态的每次修改是可以追踪回溯的,而 provide/inject 中变量的修改是无法控制的,换句话说,你不知道是哪个组件修改了这个全局状态。
了解参考
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!