适用于:父子组件间通信
父组件给子组件传递数据(非函数):本质其实是父组件----->子组件传递数据
//父组件App.vue
<template>
<div>
<Student name="李四" sex="女" :age="18"/>
</div>
</template>
<script>
import Student from './components/Student'
export default {
components:{Student}
}
</script>
//子组件
<template>
<div>
<h2>学生姓名:{{name}}</h2>
<h2>学生性别:{{sex}}</h2>
<h2>学生年龄:{{myAge+1}}</h2>
<button @click="updateAge">尝试修改收到的年龄</button>
</div>
</template>
<script>
export default {
data() {
return {
myAge:this.age
}
},
methods: {
updateAge(){
this.myAge++
}
},
//props的三种接收方式
//1、简单声明接收
// props:['name','age','sex']
//2、接收的同时对数据进行类型限制
/* props:{
name:String,
age:Number,
sex:String
} */
//3、接收的同时对数据:进行类型限制+默认值的指定+必要性的限制
props:{
name:{
type:String, //name的类型是字符串
required:true, //name是必要的
},
age:{
type:Number,
default:99 //默认值
},
sex:{
type:String,
required:true
}
}
}
父组件给子组件传递数据(函数类型):本质其实是子组件----->父组件传递数据
通过父组件给子组件传递函数类型的props实现:子给父传递数据
//父组件APP.vue中
<template>
//1、父给子传递一个函数
<School :getSchoolName="getSchoolName"/>
</template>
<script>
export default {
components:{School},
data() {
return {
schoolName:''
}
},
methods:{
//2、声明这个函数
getSchoolName(name){
console.log('App收到了学校名:',name)
this.schoolName = name
},
}
}
</script>
//子组件School.vue中
<template>
//4、写点击事件
<button @click="sendSchoolName">把学校名给App</button>
</template>
<script>
.......
export default {
//3、子组件声明接收函数
props:['getSchoolName'],
data(){
return {
name:'xxxxxx'
}
},
methods: {
//5、写点击事件的函数
sendSchoolName(){
//6、调用接收到的函数,传参数
this.getSchoolName(this.name)
}
},
}
</script>
适用于:子给父传递数据。通过父组件给子组件绑定一个自定义事件
在谁身上绑定的自定义事件就去谁身上触发(或解绑),下面代码中给子组件Student身上绑定(用@/v-on)了自定义事件demo,应该去Student身上触发(用$emit)
//父组件App.vue
<template>
//1、通过父组件给子组件绑定一个自定义事件demo实现:子给父传递数据(使用@或v-on)。这个事件demo对应一个回调函数getStudentName
<Student @demo="getStudentName" />
</template>
<script>
.........
export default {
components:{Student},
data() {
return {
studentName:''
}
},
methods: {
//2、声明回到调函数 当子组件用$emit触发这个自定义事件demo后会执行事件对应的回调函数,这个回调函数能接收到触发自定义事件的组件(即本例的子组件)传过来的参数
getStudentName(name,...params){
console.log('App收到了学生名:',name,params)
this.studentName = name
},
</script>
//子组件
<template>
<div class="student">
//3、给点击事件绑定回调函数
<button @click="sendStudentlName">把学生名给App</button>
<button @click="unbind">解绑demo事件</button>
<button @click="death">销毁当前Student组件的实例(vc)</button>
</div>
<script>
export default {
name:'Student',
data() {
return {
name:'张三',
}
},
methods: {
//4、写触发点击事件后调用的回调函数
sendStudentlName(){
//5、用$emit方法触发Student组件实例身上的demo事件,同时把子组件的数据传给了父组件
this.$emit('demo',this.name,666,888,900)
},
unbind(){
this.$off('demo') //解绑一个自定义事件
// this.$off(['demo','demo1']) //解绑多个自定义事件
// this.$off() //解绑所有的自定义事件
},
</script>
</template>
与写法1不同的是,用ref代替了v-on/@,同时增添了一个监听($on)的步骤
//父组件App.vue
<template>
//1、通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(使用@或v-on)
<Student ref="student"/>
</template>
<script>
.........
export default {
components:{Student},
data() {
return {
studentName:''
}
},
methods: {
//3、声明demo事件对应的回调函数
getStudentName(name,...params){
console.log('App收到了学生名:',name,params)
this.studentName = name
},
mounted() {
//2、
//this.$refs.student:拿到了组件的实例对象Student。然后用$on方法监听demo自定义事件,如果demo事件被触发,则调用demo事件对应的回调函数,同时这个回调能收到传过来的参数
this.$refs.student.$on('demo',this.getStudentName)
//绑定自定义事件(一次性)
// this.$refs.student.$once('atguigu',this.getStudentName)
},
}
</script>
//子组件与写法1中的相同
适用于:任意组件间通信(子给父、父给子、兄弟给兄弟)
用兄弟组件间通信来举例
//main.js
.............
new Vue({
el:'#app',
render: h => h(App),
beforeCreate() {
Vue.prototype.$bus = this //1、安装全局事件总线。让所有组件都能用$bus
},
})
student组件给school组件传数据
school组件作为想要接收数据的一方,需要先在全局事件总线上绑定自定义事件,由于在自己组件内给$bus绑定的事件,该事件对应的回调函数自然就留在了自己组件内。
//school组件
<template>
......
</template>
<script>
export default {
name: "School",
mounted() {
// console.log('School',this)
// 在这个组件内给全局事件总线$bus绑定了自定义事件hello,
// 但是这个自定义事件对应的回调是留在了这个组件内
// 如果别的组件触发$bus身上的自定义事件hello,该事件对应的回调就会执行
// 该回调在那个组件内,那个组件就能收到触发事件的组件传过来的数据
//2、
this.$bus.$on("hello", (data) => {
//6、执行自定义事件对应的回调,同时能接收到数据
console.log("我是School组件,收到了数据", data);
});
},
beforeDestroy() {
//解绑自定义事件
this.$bus.$off("hello");
},
};
</script>
如果student组件想给school组件传递数据,就可以触发school组件在$bus身上绑定的自定义事件,同时传递数据。由于自定义事件被触发,对应的回调函数(留在school组件内)也会执行,该回调函数能接收到传递过来的数据
//student组件
<template>
<div class="student">
<h2>学生姓名:{{name}}</h2>
<h2>学生性别:{{sex}}</h2>
//3、绑定点击事件
<button @click="sendStudentName">把学生名给School组件</button>
</div>
</template>
<script>
export default {
name:'Student',
data() {
return {
name:'张三',
sex:'男',
}
},
methods: {
//4、声明点击事件对应的回调
sendStudentName(){
//5、该回调触发自定义事件,同时传递数据
this.$bus.$emit('hello',this.name)
}
},
}
</script>
适用于:任意组件间通信(react中用的多,vue中用的少)
用兄弟组件间通信来举例
student组件给school组件传数据
//安装库
npm i pubsub-js
school组件拿到student组件的数据,即school组件是作为订阅消息的一方。
//school组件
<template>
..............
</template>
<script>
//引入库
import pubsub from 'pubsub-js'
export default {
name:'School',
mounted() {
//订阅消息hello,如果发布了消息hello,就执行该消息对应的回调函数,同时拿到传递的数据。msgName是消息名,data才是传递的数据。
//每次订阅都是不同的id
this.pubId = pubsub.subscribe('hello',(msgName,data)=>{
console.log(this)
// console.log('有人发布了hello消息,hello消息的回调执行了',msgName,data)
})
},
beforeDestroy() {
pubsub.unsubscribe(this.pubId)
},
}
</script>
而student组件是发布消息的一方
//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:'男',
}
},
methods: {
//点击事件对应的回调函数
sendStudentName(){
//执行该回调函数,则发布消息hello,同时传递数据
pubsub.publish('hello',666)
}
},
}
</script>
适用于:任意组件间通信
适用于:父子组件通信(一般结构)