最全Vue组件间通信方式总结,Vue组件化

Vue组件化, 组件间通信方式

1.0 父子组件之间通信

1.1 父传子

1.1.1 props 方式传参.

props 通信的方式是 父级组件和子级组件之间通信的一种方式, 具体使用方法如下

  1. 子组件接收数据时的方式有 props: [’’] 数组的方式**
  2. 或者通过 props:{} 对象的方式接收数据

🏴 注意: 子组件中的函数或方法如果要操作父组件的数据的时候,通常是在父组件定义一个方法, 把这个方法通过标签属性props传给子组件, 在子组件中调用该方法把参数传递过去,完成子组件对父组件数据的操作

案例代码如下:

Parent 父组件:

<template>
    <div>
        <h1 style="color: pink">我是parent组件, 下面是Son组件</h1>
        <Son msg="我是props 方式给子组件传参"/>
    </div>
</template>
<script>
    import Son from './Son'
    export default {
        name: "Parent",
        components: {
            Son,
        },
        methods: {
        },
    }
</script>
<style scoped>
</style>

children子组件:

<template>
    <div>
        <h3>我是son组件: {{msg}}</h3>
    </div>
</template>
<script>
    export default {
        name: "Son",
        props: ['msg'],
        mounted() {
            console.log(this.msg);
        }
    }
</script>
<style scoped>
</style>
1.1.2 自定义函数传参

自定义函数的方式, 可以实现父组件的函数在子组件中触发, 这种方式可以在子组件中, 再调用函数的是候, 给父组件传递数据

// 1. 在 Vue中也可以通过自定义函数的方式和子组件之间通信, 一般会在自定义函数的函数名字之前添加一个 @ 符号, 写法如下.
	<!-- 父组件自定义一个函数, 通过标签属性传递给子组件 -->
    <Son @selfDefineEvent="selfDefineEvent"/>
        
// 2. 这种方式, 在子组件中, 可以直接通过  this.$emit('自定义函数名', 参数) 方法分发事件. (相当于触发传递过来的事件)
        
/**
 * 自定义事件通信方式的方式
 * 1. 在父组件中定义一个事件函数, 通过标签属性的方式把该自定义事件传给子组件
 * 2. 在子组件中直接通过 this.$emit() 来触发事件.
 * 3. 其本质是在子组件调用该自定义事件的时候, 通过传递参数的方式, 把数据传递给父组件
*/

案例代码如下:

Parent父组件:

<template>
    <div>
        <h1 style="color: pink">我是parent组件, 下面是Son组件</h1>
        <!-- 父组件自定义一个函数 -->
        <Son @selfDefineEvent="selfDefineEvent"/>
    </div>
</template>
<script>
    import Son from './Son'
    export default {
        name: "Parent",
        components: {
            Son,
        },
        methods: {
            selfDefineEvent(...params) {
                console.log(...params);
            }
        },
    }
</script>
<style scoped>
</style>

Son 子组件代码:

<template>
    <div>
        <h3>我是son组件</h3>
        <button @click="handleClick">Son 组件内点击触发父组件 自定义函数</button>
    </div>
</template>
<script>
    export default {
        name: "Son",
        methods: {
            handleClick() {
                // 在子组件内, 直接通过 $emit 触发父组件自定义的函数
                this.$emit('selfDefineEvent', '我是自定义函数参数',123,'mm')
            }
        },
    }
</script>
<style scoped>
</style>

原理:

1. // 在vue中, 每一个组件, 包括 App 组件, 如果你在组件的声明周期函数中 打印 console.log(this), 会打印出是一个 VueComponent{} 对象, 代表当前的组件实例对象

2. // 而 在 vue 中, 所有的组件对象, 包括 App 等其他一些子组件的实例 都是 Vue 这个组件的实例对象的子对象, 他们之间存在继承的关系.

3. // 在 vue中, 通过 @事件名,  自定义的事件, 都会放在 Vue 这个组件的 prototype 中, 所以 Vue组件的实例 vm对象及其所有 子组件实例对象,都可以找到 这个自定义事件. 所以就可以在它的子组件中通过  原型链就可以找到   Vue 组件对象的 $emit 这个方法, 完成通信.
		this.$emit('自定义事件名字', 参数);

1.2 子传父

vue 组件之间通信之 - 子组件传递数据给父组件.

即: 父组件访问子组件的数据.

1.2.1 ref 实现: 父组件访问子组件数据

通过 ref 属性给子组件做个标识, 可以获取到子组件, 进而可以获取到子组件data 中的数据, 也可以获取到子组件当中的相关方法.

代码示例如下:

Parent组件

<template>
    <div>
        <h1 style="color: pink">我是parent组件, 下面是Son组件</h1>
        <Son ref="sonRef" msg="我是父组件传递给子组件的msg属性..."/>
    </div>
</template>
<script>
    import Son from './Son'

    export default {
        name: "Parent",
        components: {
            Son
        },
        mounted() {
            console.log('父组件想要获取子组件数据---->> ',this.$refs.sonRef.sonData); // 获取子组件 data内的数据
            console.log('父组件想要获取子组件数据---->> ',this.$refs.sonRef.msg); // 获取子组件 pros 内的数据
            this.$refs.sonRef.sayHi() // 调用子组件的方法
        }
    }
</script>
<style scoped>
</style>

Son 组件

<template>
    <h3>我是son组件</h3>
</template>
<script>
    export default {
        name: "Son",
        props:['msg'],
        data() {
            return {
                sonData: '我是子组件的数据'
            }
        },
        methods: {
            sayHi() {
                console.log('%c hello parents, I am your son ...', 'color:pink');
            }
        }
    }
</script>
<style scoped>
</style>
1.2.2 $children实现: 父组件访问子组件数据

Vue.js官网关于 $children 的介绍:

- 类型: Array<Vue instance>
- 只读
- 详细:
	当前实例的 "直接" 子组件. 需要注意的是, `$children`"并不保证顺序, 也不是响应式的.",如果你发现自己正在尝试使用 `$children` 来进行数据绑定, 考虑使用一个数组配合 `v-for` 来生成子组件, 并且使用 Array 作为真正的来源.

通过$children的方式获取到当前组件的所有子组件, 用索引获取指定子组件, 然后获取到对应子组件的 props,data 以及method 方法等

但是: 使用 $children 的这种方式, vue中不一定是按照顺序的, vue中通过$children获取到的子组件是不保证这里取到子组件的顺序的.

Parent组件代码如下

<template>
    <div>
        <h1 style="color: pink">我是parent组件, 下面是Son组件</h1>
        <Son ref="sonRef" msg="我是父组件传递给子组件的msg属性..."/>
    </div>
</template>
<script>
    import Son from './Son'

    export default {
        name: "Parent",
        components: {
            Son
        },
        mounted() {
            console.log(this.$children[0].msg); // 访问子组件 props 属性
            console.log(this.$children[0].sonData); // 访问子组件 data
            this.$children[0].sayHi() // 访问子组件 method 方法
        }
    }
</script>
<style scoped>
</style><template>
    <div>
        <h1 style="color: pink">我是parent组件, 下面是Son组件</h1>
        <Son ref="sonRef" msg="我是父组件传递给子组件的msg属性..."/>
    </div>
</template>
<script>
    import Son from './Son'

    export default {
        name: "Parent",
        components: {
            Son
        },
        mounted() {
            console.log(this.$children[0].msg); // 访问子组件 props 属性
            console.log(this.$children[0].sonData); // 访问子组件 data
            this.$children[0].sayHi() // 访问子组件 method 方法
        }
    }
</script>
<style scoped>
</style>

子组件代码同上面子组件的代码

1.2.3 $emit事件派发与监听

注意: 事件派发与监听, 虽然能在父组件中获取到子组件派发事件所传递的数据, 但是实际上, 还是在 子组件上监听的事件. 即: 谁派发事件, 谁来监听事件.

Parent 组件如下

<template>
    <div>
        <h1 style="color: pink">我是parent组件, 下面是Son组件</h1>
        <!-- 监听子组件派发的事件 -->
        <Son @eventEmit="handleEventEmit" ref="sonRef" msg="我是父组件传递给子组件的msg属性..."/>
    </div>
</template>
<script>
    import Son from './Son'

    export default {
        name: "Parent",
        components: {
            Son
        },
        mounted() {
        },
        methods: {
            handleEventEmit(params) {
                console.log('父组件监听到子组件派发的数据 -->', params);
            }
        }
    }
</script>
<style scoped>
</style>

Children组件如下

<template>
    <div>
        <!-- 子组件绑定派发事件 -->
        <h3 @click="$emit('eventEmit','我是事件派发想要传递的数据123.')">我是son组件</h3>
    </div>
</template>
<script>
    export default {
        name: "Son",
        props: ['msg'],
        data() {
            return {
                sonData: '我是子组件data 的数据...'
            }
        },
        methods: {
            sayHi() {
                console.log('%c hello parents, I am your son ...', 'color:pink');
            }
        }
    }
</script>
<style scoped>
</style>

2.0 兄弟组件之间的通信

2.1 $emit$on , 通过共同父组件实现兄弟组件通信

借助共有父组件的方式来实现.

用事件的派发与监听, 通过共同父组件来派发和监听事件, 实现兄弟组件之间通信

下面案例实现 Son组件与 Son1组件间通信, 共同父组件 Parent

Parent 组件如下

<template>
    <div>
        <h1 style="color: pink">我是parent组件, 下面是Son组件</h1>
        <!-- 监听子组件派发的事件 -->
        <Son @eventEmit="handleEventEmit" ref="sonRef" msg="我是父组件传递给子组件的msg属性..."/>
        <Son1/>
    </div>
</template>
<script>
    import Son from './Son'
    import Son1 from './Son1'

    export default {
        name: "Parent",
        components: {
            Son,
            Son1
        },
        mounted() {
        },
        methods: {
            handleEventEmit(params) {
                console.log('父组件监听到子组件派发的数据 -->', params);
            }
        }
    }
</script>
<style scoped>
</style>

Son组件

<template>
    <div>
        <!-- 子组件绑定派发事件 -->
        <h3 @click="$emit('eventEmit','我是事件派发想要传递的数据123.')">我是son组件</h3>
        <button @click="sendMsg">给兄弟Son1组件打招呼</button>
    </div>
</template>
<script>
    export default {
        name: "Son",
        props: ['msg'],
        data() {
            return {
                sonData: '我是子组件data 的数据...'
            }
        },
        methods: {
            sendMsg(){
                /* 通过中间组件, 共同父组件来派发事件 */
                this.$parent.$emit('sayHiToSiblings','大哥你好,我是你兄弟...')
            }
        }
    }
</script>
<style scoped>
</style>

Son1组件

<template>
    <div>
        <h2>我是Son1组件</h2>
    </div>
</template>

<script>
    export default {
        name: "Son1",
        mounted() {
            /* 通过中间组件 共同父组件 监听事件 */
            this.$parent.$on('sayHiToSiblings',(msg)=>{
                console.log('%c我是Son1组件, 我接收Son兄弟组件的数据--->','color:pink',msg);
            })
        }
    }
</script>
<style scoped>
</style>

2.2 $bus 事件总线的方式实现兄弟组件通信

其原理就是通过借助第三方组件的方式实现通信的.

如果两个组件之间没有共同的直接父组件, 我们还可以通过事件总线的方式, 实现跨组件之间的数据通信.

事件总线的方式可以完成任意组件之间的通信.

事件总线通信方式的使用:

1. // 在 main.js 中, 手动在 Vue 的原型上添加一个事件总线
	 Vue.prototype.$bus = new Vue()

	// 通过事件总线的 $on 方法,绑定一个方法
// 第一个参数: 事件名字
// 第二个参数: 需要处理的响应函数
this.$bus.$on('toggleTodo',(todo) => {
this.toggleTodo(todo)
})

2. // 在其他需要该方法的组件里通过 $emit() 触发该事件, 传入参数
	// 第一个参数: 对应事件名字
// 第二个参数: 传给回调函数的  实参
	this.$bus.$emit('toggleTodo',this.todoItem)

案例代码如下:

main.js

import Vue from "vue";
import App from "./App.vue";

Vue.config.productionTip = false;

// 创建一个第三方实例挂到Vue原型, 用来实现事件总线通信
Vue.prototype.$bus = new Vue();

new Vue({
    render: h => h(App)
}).$mount("#app");

Son组件:

<template>
    <div>
        <h3>我是son组件</h3>
        <p>{{msg}}</p>
    </div>
</template>
<script>
    export default {
        name: "Son",
        data() {
            return {
                msg: ''
            }
        },
        mounted() {
            /* 在组件挂载完的时候完成监听事件 */
            this.$bus.$on('siblingContact', (msg) => {
                console.log(msg);
                this.msg = msg
            })
        }
    }
</script>
<style scoped>
</style>

Son1 组件

<template>
    <div>
        <h2>我是Son1组件</h2>
        <button @click="handleClick">Son1组件点击, 触发Son组件传递过来的方法 </button>
    </div>
</template>

<script>
    export default {
        name: "Son1",
        methods:{
            handleClick(){
                // 触发点击事件的时候, 完成分发事件
                this.$bus.$emit('siblingContact','Hi,我是Son1, 我是你的兄弟啊...')
            }
        }
    }
</script>
<style scoped>
</style>

2.3 通过 PubSub.js 实现任意组件间通信

通过第三方的 Js库, 可以实现任意组件之间的数据通信.

PubSub的使用

消息的 订阅与发布 就好比 事件的绑定和 触发事件

**特点:**PubSub 消息订阅与发布这种方式实现通信可以实现任意组件之间的通信.

1. 安装pubsub-js
		npm install pubsub-js

2. 在需要 消息订阅与发布的文件中, 首先引入 pubsub-js
		import PubSub from 'pubsub-js'   // 注意 pubsub引入的时候, 完整的是 pubsub-js

	// 订阅消息, 传入一个 事件名字, 一个回调函数.  订阅事件就相当于定义的绑定事件
		PubSub.subscribe('MY TOPIC', ()=>{});

	//  发布消息, 传入一个与订阅消息相同的 事件名字, 和 数据
// 发布消息相当于 触发函数, (给定义的函数传递过去参数数据)
		PubSub.publish('MY TOPIC', 'hello world!');

对 pubsub 消息订阅机制的理解

#3. 对 pubsub 事件订阅与发布的理解
	// 事件的订阅与发布可以类比传统的  给元素绑定事件 和 添加响应函数来理解
/**
 * 1. 在传统的 添加绑定事件时有两步
 *    >1. 给元素添加绑定事件函数, 函数传入参数.
 *    >2. 给绑定的事件添加响应函数. (注意: 有函数)
 * 
 * 2. 在消息的订阅与发布中
 *    >1. 发布消息(传入参数)   ----> 相当于绑定事件
 *    >2. 订阅消息('',fn)   ----> 相当于添加响应函数
 *        因为订阅消息中需要两个参数, 第二个参数为回调函数, 
 *        回调函数 就相当于我们所说的 事件的响应函数,也就是具体处理逻辑的函数
*/

3.0 祖孙组件或嵌套组件之间通信

3.1 provide/inject 实现嵌套组件通信

注意: 通过provideinject 方式实现的嵌套组件之间传递的数据, 不是响应式的.

  • 类型:

    provide: Object | ()=> Object

    inject: Array<string> | {[key:string]:string | symbol | Object}

  • 详细

    provide 和 inject 主要在开发高阶插件/组件库时使用。并不推荐用于普通应用程序代码中。
    

    provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子孙的 property。在该对象中你可以使用 ES2015 Symbols 作为 key,但是只在原生支持 SymbolReflect.ownKeys 的环境下可工作。

    inject 选项应该是:

    • 一个字符串数组,或
    • 一个对象,对象的 key 是本地的绑定名,value 是:
      • 在可用的注入内容中搜索用的 key (字符串或 Symbol),或
      • 一个对象,该对象的:
        • from property 是在可用的注入内容中搜索用的 key (字符串或 Symbol)
        • default property 是降级情况下使用的 value

案例代码如下:

Parent组件:

<template>
    <div>
        <h1 style="color: pink">我是parent组件, 下面是Son组件</h1>
        <button @click="handleClick">点击修改注入的数据</button>
        <Son/>
    </div>
</template>
<script>
    import Son from './Son'

    export default {
        name: "Parent",
        data() {
            return {
                msg: '我是给后代组件注入的数据'
            }
        },
        provide() {
            return {
                msg: this.msg
            }
        },
        components: {
            Son,
        },
        methods: {
            handleClick() {
                console.log('修改前 的祖先组件 msg数据 --->> ', this.msg);
                this.msg = '我修改了祖先组件想要注入给后代组件的数据...'
                console.log('修改后的祖先组件 msg数据 --->> ', this.msg);
            }
        },
        mounted() {
        },
    }
</script>
<style scoped>
</style>

Son组件:

<template>
    <div>
        <h3>我是son组件</h3>
        <GrandSon/>
    </div>
</template>
<script>
    import GrandSon from './GrandSon'

    export default {
        name: "Son",
        props: ['msg'],
        components: {GrandSon},
        data() {
            return {
                sonData: '我是子组件data 的数据...'
            }
        },
        methods: {}
    }
</script>
<style scoped>
</style>

GrandSon组件:

<template>
    <div>
        <h2>我是GrandSon组件</h2>
        <p>{{msg}}</p>
    </div>
</template>

<script>
    export default {
        name: "Son1",
        inject:['msg'],
        mounted() {
            /* 通过中间组件 共同父组件 监听事件 */
            this.$parent.$on('sayHiToSiblings', (msg) => {
                // 由此可见,祖先组件点击按钮, 修改数据后, 此处数据并没有修改, 所以数据是非响应式的
                console.log('%c我是Son1组件, 我接收Son兄弟组件的数据--->', 'color:pink', msg);
            })
        }
    }
</script>
<style scoped>
</style>

4.0 插槽的方式实现通信

插槽常用语内容分发. 原理就是占位符的一个运用

插槽通信的方式后续会详细介绍.

4.1 普通插槽

4.2 具名插槽

4.3 作用域插槽

总结:

交流学习添加微信(备注技术交流学习): Gene199302
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值