超详细的vue组件间通信总结

前言

组件通信在我们平时开发过程中,特别是在vue和在react中,有着举足轻重的地位。本篇将总结在vue中,组件之间通信的几种方式:

props、$emit

$parent、$children

$attrs、$listeners

provide、inject

eventBus

vuex

本地存储

一、props、$emit单向数据流

超详细的vue组件间通信总结

father.vue:

<template> <div> <div>我是父亲:<input type="button" value="父亲" /> 数字为: {{num}}</div> <son :num="num" @change="change"></son> </div> </template> <script> import son from "./son.vue"; export default { name: "Father", components: { son, }, data() { return { num: 1, }; }, methods:{ change(val){ this.num = val } } }; </script>

son.vue:

<template> <div>我是儿子:<input type="button" value="儿子" @click="change"/>数字为:{{num}}</div> </template> <script> export default { name: "App", components: {}, props: { num: { default: 0, }, }, created() {}, methods: { change(){ // this.num = 2 props通信是单向数据流,在这直接修改父组件传过来的num将会报错    // 可以用$emit触发change事件,father组件绑定change事件    this.$emit('change', 2) } }, }; </script>

对于上面的场景:子组件的change事件只是为了修改父组件中某一个值,还可以有以下几种写法:

1.父组件绑定给子组件的事件使用箭头函数

father: <son :num="num" @change="val => num = val"></son> son: this.$emit('change', 2)

2.update:num和.sync

father: <son :num.sync="num"></son> son: this.$emit('update:num', 2)//update是规定的写法,不可更换

3.v-model

先修改props和绑定的事件:

father:<son :value="num" @input="val => num = val"></son>son:this.$emit('input', 2) 可用v-model简写:<son v-model="num"></son>

二、$parent、$children

$parent、$children可直接在父子组件中调用各自的方法以及修改数据

子组件中直接:this.$parent.num = 2

父组件中$children是个数组,因此具体是哪个子组件不太直观,可以用$refs来操作子组件

vue官方并不推荐使用这种通信方式:节制地使用$parent和$children- 它们的主要目的是作为访问组件的应急方法,更推荐用 props 和 events 实现父子组件通信

三、$attrs、$listeners

$attrs可以拿到父组件传过来的属性:

<div>我是儿子:<input type="button" value="儿子" @click="change"/>数字为:{{$attrs}}</div>

dom节点:

超详细的vue组件间通信总结

$attrs会直接将传过来的属性放到对应的标签上,反观props就不会。如果想去掉标签中的这些属性,可以用inheritAttrs:

超详细的vue组件间通信总结

值得注意的是:props的优先级大于$attrs,即当props存在的时候,$attrs为空对象:

$attrs常用于跨多级组件传递属性,比如祖孙组件,用父组件做中转:

father:

<son v-bind="$attrs"></son>

$attrs用于属性跨级传递,方法跨级传递则用$listeners。

grandFather.vue:

<template> <div> <div>我是祖父: 数字为:{{nums}}</div> <father :nums="nums" @up="up" @down="down"></father> </div> </template> <script> import father from "./father.vue"; export default { name: "App", components: { father, }, data(){ return { nums:0 } }, methods: { up() { alert('up') },  down() {   alert('down')  }, }, }; </script>

father.vue:

<son v-bind="$attrs" v-on="$listeners"></son>

son.vue:

<div>我是儿子:<input type="button" value="儿子" @click="$listeners.up"/></div>

超详细的vue组件间通信总结

四、provide、inject

这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在其上下游关系成立的时间里始终生效

provide选项应该是一个对象或返回一个对象的函数。

inject选项应该是一个字符串数组或一个对象。

App:

... export default { provide(){ return {vm: this} }, ...

son:

... export default { inject: ['vm'], data(){}, mounted(){  console.log(this.vm) } ...

超详细的vue组件间通信总结

注意:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。

   inject注入中的值会沿着组件向上查找,遵从"就近原则"。

   provide 和 inject中的数据流是双向的。

五、eventBus(事件总线)

eventBus通过发布订阅全局事件,供其他组件使用。

在main.js中:

Vue.prototype.$bus = new Vue();

parent.vue:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyfjdj.html