前言:
组件之间通信的方式有很多种,比如props
、自定义事件
、全局事件总线
、消息订阅与发布
、父链与子组件索引
、插槽
、Vuex
等都可以实现组件之间的通信。在这里我将介绍以下三种通信方式。
或
this.$emit('dome',数据)
代码示例:
app组件
<template>
<div>
<h1 class="title">你好啊h1>
<Student @dome="test" />
div>
template>
<script>
import Student from "./components/Student";
export default {
name: "App",
components: { Student },
methods: {
test() {
console.log("我被触发了");
},
},
};
script>
<style scoped>
style>
子组件student
<template>
<div class="demo">
<button @click="domes">点我触发button>
div>
template>
<script>
export default {
name: "Student",
methods: {
domes() {
this.$emit("dome");
},
},
};
script>
<style scoped>
style>
在父组件中:
<Demo ref="xxx"/>
......
mounted(){
this.$refs.xxx.$on('demo',this.test)
}
代码示例:
app组件
<template>
<div>
<h1 class="title">你好啊</h1>
<!-- <Student @dome.once="test" /> -->
<Student ref="student" />
</div>
</template>
<script>
import Student from "./components/Student";
export default {
name: "App",
components: { Student },
methods: {
test() {
console.log("我被调用了");
},
},
mounted() {
this.$refs.student.$on("dome", this.test);
},
};
</script>
<style scoped>
</style>
子组件student
<template>
<div class="demo">
<button @click="domes">点我触发button>
div>
template>
<script>
export default {
name: "Student",
methods: {
domes() {
this.$emit("dome");
},
},
};
script>
<style scoped>
style>
注意:通过
this.$refs.xxx.$on('dome',回调)
绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!
代码示例:
mounted() {
this.$refs.student.$on("dome", function() {
console.log(this);
this指向子组件student
将普通函数换成箭头函数,this指向就还是原来的app组件
});
},
若想让自定义事件只能触发一次,可以使用once
修饰符,或$once
方法。
代码示例:
代码示例:
app组件
<template>
<div>
<h1 class="title">你好啊h1>
<Student @dome.once="test" />
div>
template>
<script>
import Student from "./components/Student";
export default {
name: "App",
components: { Student },
methods: {
test() {
console.log("我被调用了");
},
},
/* mounted() {
this.$refs.student.$on("dome", this.test);
}, */
};
script>
<style scoped>
style>
代码示例:
app组件
<template>
<div>
<h1 class="title">你好啊h1>
<Student ref="student" />
div>
template>
<script>
import Student from "./components/Student";
export default {
name: "App",
components: { Student },
methods: {
test() {
console.log("我被调用了");
},
},
mounted() {
this.$refs.student.$once("dome", this.test);//绑定自定义事件(一次性)
},
};
script>
<style scoped>
style>
this.$off('atguigu')
代码示例:
app
组件
<template>
<div>
<h1 class="title">你好啊h1>
<Student @dome="test" @dome2="test2"/>
div>
template>
<script>
import Student from "./components/Student";
export default {
name: "App",
components: { Student },
methods: {
test() {
console.log("我被调用了");
},
test2() {
console.log("我是第二个事件");
},
},
/* mounted() {
this.$refs.student.$on("dome", this.test);
}, */
};
script>
<style scoped>
style>
子student
组件
<template>
<div class="demo">
<button @click="domes">点我触发button>
<button @click="unbind">点我解绑事件button>
div>
template>
<script>
export default {
name: "Student",
methods: {
domes() {
this.$emit("dome");
this.$emit("dome2");//绑定多个自定义事件
},
unbind() {
// this.$off("dome")//解绑一个自定义事件
// this.$off(['dome','dome2'])//解绑多个自定义事件
this.$off()//解绑所有的自定义事
}
},
};
script>
<style scoped>
style>
native
修饰符。如果不加上native
修饰符,Vue会默认将此事件当作自定义事件。代码示例:
<Student @click.native="xxx"/>
一种组件间通信的方式,适用于:子组件 ===> 父组件
使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。
绑定自定义事件:
第一种方式,在父组件中:
或
第二种方式,在父组件中:
<Demo ref="demo"/>
......
mounted(){
this.$refs.xxx.$on('atguigu',this.test)
}
若想让自定义事件只能触发一次,可以使用once
修饰符,或$once
方法。
触发自定义事件:this.$emit('atguigu',数据)
解绑自定义事件this.$off('atguigu')
组件上也可以绑定原生DOM事件,需要使用native
修饰符。
注意:通过this.$refs.xxx.$on('atguigu',回调)
绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!
一种组件间通信的方式,适用于任意组件间通信。
安装全局事件总线:
new Vue({
......
beforeCreate() {
Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
},
......
})
使用事件总线:
接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。
methods(){
demo(data){......}
}
......
mounted() {
this.$bus.$on('xxxx',this.demo)
}
提供数据:this.$bus.$emit('xxxx',数据)
最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件。
代码示例:
在main文件
里面安装全局事件总线
//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false
//创建vm
new Vue({
el:'#app',
render: h => h(App),
beforeCreate() {
Vue.prototype.$bus = this //安装全局事件总线
},
})
没有涉及到和app组件通信,所以app组件正常编写即可
<template>
<div class="app">
<h1>{{msg}}h1>
<School/>
<Student/>
div>
template>
<script>
import Student from './components/Student'
import School from './components/School'
export default {
name:'App',
components:{School,Student},
data() {
return {
msg:'你好啊!',
}
}
}
script>
<style scoped>
.app{
background-color: gray;
padding: 5px;
}
style>
由于我们将school组件
作为接受数据方,所以我们要给school组件
种的$bus绑定自定义事件,事件的回调留在school组件自身。
<template>
<div class="school">
<h2>学校名称:{{name}}h2>
<h2>学校地址:{{address}}h2>
div>
template>
<script>
export default {
name:'School',
data() {
return {
name:'东方',
address:'北京',
}
},
mounted() {
// console.log('School',this)
this.$bus.$on('hello',(data)=>{
console.log('我是School组件,收到了数据',data)
})
},
beforeDestroy() {
this.$bus.$off('hello')
},
}
script>
<style scoped>
.school{
background-color: skyblue;
padding: 5px;
}
style>
由于我们将student组件
作为提供数据方,所以我们要在student组件
中调用自定义事件
<template>
<div class="student">
<h2>学生姓名:{{name}}h2>
<h2>学生性别:{{sex}}h2>
<button @click="sendStudentName">把学生名给School组件button>
div>
template>
<script>
export default {
name:'Student',
data() {
return {
name:'张三',
sex:'男',
}
},
mounted() {
// console.log('Student',this.x)
},
methods: {
sendStudentName(){
this.$bus.$emit('hello',this.name)
}
},
}
script>
<style lang="less" scoped>
.student{
background-color: pink;
padding: 5px;
margin-top: 30px;
}
style>
一种组件间通信的方式,适用于任意组件间通信。
使用步骤:
安装pubsub:npm i pubsub-js
引入: import pubsub from 'pubsub-js'
接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。
methods(){
demo(data){......}
}
......
mounted() {
this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息
}
提供数据:pubsub.publish('xxx',数据)
最好在beforeDestroy钩子中,用PubSub.unsubscribe(pid)
去取消订阅。
全局事件总线案例
应用消息订阅与发布
的方法实现一下,整体思路是一样的。目录结构图:
首先我们先要安装pubsub:npm i pubsub-js
,然后在需要通信的组件中引入import pubsub from 'pubsub-js'
这个包。
代码示例:
main文件
//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false
//创建vm
new Vue({
el:'#app',
render: h => h(App),
})
app组件
<template>
<div class="app">
<h1>{{msg}}h1>
<School/>
<Student/>
div>
template>
<script>
import Student from './components/Student'
import School from './components/School'
export default {
name:'App',
components:{School,Student},
data() {
return {
msg:'你好啊!',
}
}
}
script>
<style scoped>
.app{
background-color: gray;
padding: 5px;
}
style>
school组件
作为接受信息订阅方
<template>
<div class="school">
<h2>学校名称:{{name}}h2>
<h2>学校地址:{{address}}h2>
div>
template>
<script>
import pubsub from 'pubsub-js'
export default {
name:'School',
data() {
return {
name:'东方',
address:'北京',
}
},
mounted() {
this.pubId = pubsub.subscribe('hello',(msgName,data)=>{
console.log(this)
// console.log('有人发布了hello消息,hello消息的回调执行了',msgName,data)
})
},
beforeDestroy() {
pubsub.unsubscribe(this.pubId)
},
}
script>
<style scoped>
.school{
background-color: skyblue;
padding: 5px;
}
style>
student组件
作为发布信息方
<template>
<div class="student">
<h2>学生姓名:{{name}}h2>
<h2>学生性别:{{sex}}h2>
<button @click="sendStudentName">把学生名给School组件button>
div>
template>
<script>
import pubsub from 'pubsub-js'
export default {
name:'Student',
data() {
return {
name:'张三',
sex:'男',
}
},
mounted() {
},
methods: {
sendStudentName(){
pubsub.publish('hello',666)
}
},
}
script>
<style lang="less" scoped>
.student{
background-color: pink;
padding: 5px;
margin-top: 30px;
}
style>