1 简介

  组件自定义事件是一种组件间的通信方式,方向是 子组件====>父组件。

  使用场景:A是父组件,B是子组件,如果要把B的数据传给A,可以使用props加回调函数实现或者自定义事件实现。

 

2 自定义组件

  主要分为两个步骤:1绑定事件回调函数  2触发事件

 

2.1 绑定事件回调函数

  它有两种写法

1)在组件标签上直接绑定

<StudentComp v-on:student="getStudentName" ></StudentComp>

简写

<StudentComp @student="getStudentName" ></StudentComp> 
 methods: {
            getStudentName(stname){
                console.log(this) //SchoolComp的vc对象
                console.log('在SchoolComp中事件student的回调函数getStudentName被调用:','@',stname)
            }
        }

  

2)ref属性加上$on('事件名',回调方法)

<StudentComp ref="stud" ></StudentComp>

手动去绑定事件(这里选择挂载后去绑定),这种方式更加灵活,可以选择在什么时候去绑定

mounted() {
            this.$refs.stud.$on('student',this.getStudentName)
        },

 

2.2 触发事件$emit('事件名','参数1','参数2',...)

<button v-on:click="showName">点击</button>
methods: {
            showName(){
                console.log('在StudentComp中触发student事件')
                this.$emit('student',this.stname)
            }
        },

 

3 示例

  SchoolComp是StudentComp的父组件,现在StudentComp向SchoolComp传一个值stname

 

3.1 第一种绑定方式

1)main.js

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

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

 

2) App.vue

<template>
<div>
    <SchoolComp></SchoolComp>
    
</div>
</template>

<script>

import SchoolComp from './components/SchoolComp'


export default {
    name:'App',
    components:{
        SchoolComp
    }
}

</script>

 

3)SchoolComp.vue

<template>
    <div>
        <h1 >{{schoolname}}</h1>
        <StudentComp v-on:student="getStudentName" ></StudentComp>
    </div>
</template>

<script>
import StudentComp from './StudentComp'

    export default {
        name:'SchoolComp',
        data(){
            return {
                schoolname:'实验小学1',
                age:18   
            }
        },
        components:{
            StudentComp
        },
        methods: {
            getStudentName(stname){
                console.log(this) //SchoolComp的vc对象
                console.log('在SchoolComp中事件student的回调函数getStudentName被调用:','@',stname)
            }
        },
    }
</script>

<style>

</style>

 

4)StudentComp.vue

<template>
    <div>
        <h1>{{stname}}</h1>
        <button v-on:click="showName">点击</button>
        
    </div>
    
</template>

<script>



    export default {
        name:'StudentComp',
        data(){
            return {
               stname:'小新'
            }
        },
        methods: {
            showName(){
                console.log('在StudentComp中触发student事件')
                this.$emit('student',this.stname)
            }
        },
    }
</script>

 

5) 效果

点击按钮,事件触发,SchoolComp中的回调被调用,且接收到了stname

 

3.2 第二种绑定方式

  修改下SchoolComp.vue

<template>
    <div>
        <h1 >{{schoolname}}</h1>
        <StudentComp ref="stud" ></StudentComp>
    </div>
</template>

<script>
import StudentComp from './StudentComp'

    export default {
        name:'SchoolComp',
        data(){
            return {
                schoolname:'实验小学1',
                age:18   
            }
        },
        components:{
            StudentComp
        },
        methods: {
            getStudentName(stname){
                console.log(this) //SchoolComp的vc对象
                console.log('在SchoolComp中事件student的回调函数getStudentName被调用:','@',stname)
            }
        },
        mounted() {
            this.$refs.stud.$on('student',this.getStudentName)
        },
    }
</script>

<style>

</style>

 

4 解绑

4.1 语法

1)解除单个事件绑定

$off('事件名')

 

2)解除多个事件绑定

$off(['事件名1','事件名2'])

 

3) 解除所有事件绑定

$off()

 

4.2 示例

  在StudentComp.vue中解绑,解除绑定后,事件不会被触发,回调函数不会被调用

<template>
    <div>
        <h1>{{stname}}</h1>
        <button v-on:click="showName">点击</button>
        <button v-on:click="cancelBind">解除绑定</button>
        
    </div>
    
</template>

<script>



    export default {
        name:'StudentComp',
        data(){
            return {
               stname:'小新'
            }
        },
        methods: {
            showName(){
                console.log('在StudentComp中去触发student事件')
                this.$emit('student',this.stname)
            },
            cancelBind(){
                this.$off('student')
            }
        },
    }
</script>

 

5 组件标签上使用原生事件

@原生事件名.native='方法'

  如

<StudentComp @click.native="cli" ></StudentComp>

 

6 自定义事件注意事项

  通过this.$refs.stud.$on('student',this.getStudentName)这种方式绑定时,回调函数写在methods里面,回调函数里面的this就是当前组件实例对象,也就是SchoolComp实例

  如果把回调函数直接写在on里面,this就是触发事件的组件实例,也就是StudentComp实例

mounted() {
            this.$refs.stud.$on('student',function getStudentName(stname){
                console.log(this) //Student的vc对象
                console.log(stname) 
                
            })
        }

  要想获得当前组件实例,需要写成箭头函数

mounted() {
            this.$refs.stud.$on('student', (stname)=>{
                console.log(this) //SchoolComp的vc对象
                console.log(stname) 
                
            })
        },

 

7 自定义事件小结

  自定义事件实际上就是在一个组件中为另一个组件绑定一个事件并定义回调函数,在绑定事件的那个组件中触发事件

 

8 事件总线

8.1 简介

  在上面,我们实现了子传数据到父,而通过props可以实现父传数据到子。

  那么兄弟之间如何通信呢,爷爷和孙子的通信呢?

  可以利用事件总线来实现任意两个组件之间的通信,它就是利用自定义事件来实现的,使用一种非常巧妙的用法。

  eventBus 又称为事件总线。在 Vue 中可使用 eventBus 来作为沟通桥梁的概念,就像是所有组件共用相同的事件中心,可向该中心注册发送事件或接收事件,所以组件都可以上下平行地通知其他组件。

8.2 图示

  事件总线就是通过一个处处可见的第三者组件,来实现任意两个组件之间的通信

 

9 事件总线的使用

1) 定义事件总线组件

  在创建Vue实例时,在生命周期函数beforeCreate里面,为Vue原型对象加上一个属性,属性名为$bus,值为当前的Vue实例

new Vue({
       ...
       beforeCreate() {
           Vue.prototype.$bus = this // 安装全局事件总线,$bus 就是当前应用的 vm
       },
    ...
})

 

2)在接收数据的组件里面为$bus绑定事件并定义回调函数

 

3)在发送数据的组件中触发事件

 

10 事件总线示例

1)main.js

  在Vue原型对象上加上$bus

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  beforeCreate() {
    Vue.prototype.$bus = this // 安装全局事件总线,$bus 就是当前应用的 vm
},
}).$mount('#app')

 

2) SchoolComp.vue

  接收数据的组件,为$bus绑定事件student,并定义回调函数

<template>
    <div>
        <h1 >{{schoolname}}</h1>
        <StudentComp  ></StudentComp>
        
    </div>
</template>

<script>
import StudentComp from './StudentComp'

    export default {
        name:'SchoolComp',
        data(){
            return {
                schoolname:'实验小学1',
                age:18   
            }
        },
        components:{
            StudentComp
        },
        methods: {
            
        },
        mounted() {

            this.$bus.$on('student', (stname)=>{
                console.log(this) //Student的vc对象
                console.log(stname) //Student的vc对象
                
            })

        },
        
    }
</script>

<style>

</style>

 

3)StudentComp.vue

  发送数据的组件,触发事件

<template>
    <div>
        <h1>{{stname}}</h1>
        <button v-on:click="showName">点击</button>
    </div>
    
</template>

<script>



    export default {
        name:'StudentComp',
        data(){
            return {
               stname:'小新'
            }
        },
        methods: {
            showName(){
                console.log('在StudentComp中触发student事件')
                this.$bus.$emit('student',this.stname)
            }
        },
    }
</script>

 

4)效果

 

11 事件总线注意事项

  由于所有的事件都是绑定在$bus上面的,当事件多的时候,注意事件名称的管理