Vue组件中的自定义事件

  • Vue组件当中的自定义事件的一种组件间通信的方式,适用于:子组件 ===> 父组件
  • 使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。

实现子组件给父组件传递数据有两种方法

  • 1.使用props,但是前提是实现父组件要先传给子组件一个函数用于接收数据
  • 2.使用自定义组件

方法一:使用props

  • 实现步骤:
    • 1.使用props先接受父组件传过来的函数,
    • 2.再自己定义一个发送函数将自己的数据通过该发送函数传给从父组件中接收过来的接收函数实现数据传递

1.App组件代码展示:

<template>
<div class="app">
<h1>{{msg}},学生姓名是:{{studentName}}</h1>

<!-- 通过父组件给子组件传递函数类型的props实现:子给父传递数据 -->
<School :getSchoolName="getSchoolName"/>

<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一种写法,使用@或v-on) -->
<!-- <Student @wyu="getStudentName" @demo="m1"/> -->

<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref) -->
<!-- 这种方法更为灵活:可以嵌套异步任务 -->
<Student ref="student" @click.native="show"/>
</div>
</template>

<script>
import Student from './components/Student'
import School from './components/School'

export default {
name:'App',
components:{School,Student},
data() {
return {
msg:'Hello Vue!!',
studentName:''
}
},
methods: {
getSchoolName(name){
console.log('App收到了学校名:',name)
},
getStudentName(name,...params){
console.log('App收到了学生名:',name,params)
this.studentName = name
},
m1(){
console.log('demo事件被触发了!')
},
show(){
console.log(123);
}
},
mounted() {
this.$refs.student.$on('wyu',this.getStudentName) //绑定自定义事件
// this.$refs.student.$once('wyu',this.getStudentName) //绑定自定义事件(一次性)

// 嵌套异步任务(ref方法更为灵活的体现)
// setTimeout(()=>{
// this.$refs.student.$on('wyu',this.getStudentName) //绑定自定义事件
// },3000)

// 注意点1:将挂在函数mounted()和getStudentName写在了一起
// this.$refs.student.$on('wyu', (name,...params)=>{
// console.log("App收到了学生的名字:", name , params)
// this.studentName = name
// console.log(this);//这时这里的this指向并不是指向vm,而是指向了Student的vc
// })
},
}
</script>

<style scoped>
.app{
background-color: skyblue;
padding: 5px;
}
</style>

2.School组件代码展示:

<template>
    <div class="school">
        <h2>学校名称:{{name}}</h2>
        <h2>学校地址:{{address}}</h2>
        <button @click="sendSchoolName">把学校名给App</button>
    </div>
</template>

<script>
    export default {
        name:'School',
        // 使用props先接受父组件传过来的函数,
        // 再自己定义一个发送函数将自己的数据
        // 通过该发送函数传给从父组件中接收过
        // 来的接收函数实现数据传递
        props:['getSchoolName'],
        data() {
            return {
                name:'五邑大学',
                address:'江门',
            }
        },
        methods: {
            // 自己定义的发送函数
            sendSchoolName(){
                this.getSchoolName(this.name)
            }
        },
    }
</script>

<style scoped>
    .school{
        background-color: peru;
        padding: 5px;
    }
</style>

运行结果展示:

image

方法二:使用自定义事件

  • 自定义事件的常用指令(方法)[后面有详细代码]

    • 1、父组件可以使用 props 把数据传给子组件。
      • vc.$emit( event, arg ) //触发当前实例上的事件
    • 2、子组件可以使用 $emit 触发父组件的自定义事件。
      • vc.$on( event, fn );//监听event事件后运行 fn
    • 3、解绑自定义事件 $off()
      • vc.$off(‘事件名’);//解绑自定义事件
    • 4、销毁自定义事件 $destroy()
      • vc.$destroy(‘事件名’);//销毁自定义事件,不填默认销毁该组件的全部自定义事件
  • 绑定自定义事件有两种方法:

    • 第一种:直接使用 v-on 或者 @绑定即可
    • 第二种:使用ref(使用这种方法需要注意:它不认识原生的js事件,需要使用.native来配合使用),这种方法更为灵活,可以嵌套异步任务
 <!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一种写法,使用@或v-on) -->
<Student @wyu="getStudentName" @demo="m1"/>

<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref) -->
<Student ref="student" @click.native="show"/>

这里就展示Student组件的代码(App组件[父组件]在上面已经显示了)

<template>
    <div class="student">
        <h2>学生姓名:{{name}}</h2>
        <h2>学生性别:{{sex}}</h2>
        <h2>当前求和为:{{number}}</h2>
        <button @click="add">点我number++</button>
        <button @click="sendStudentlName">把学生名给App</button>
        <button @click="unbind">解绑自定义事件(wyu)</button>
        <button @click="death">销毁当前Student组件的实例(vc)</button>
    </div>
</template>

<script>
    export default {
        name:'Student',
        data() {
            return {
                name:'张三',
                sex:'男',
                number:0
            }
        },
        methods: {
            add(){
                console.log('add回调被调用了')
                this.number++
            },
            sendStudentlName(){
                //触发Student组件实例身上的wyu事件
                this.$emit('wyu',this.name,666,888,900)
                // this.$emit('demo')
                // this.$emit('click')
            },
            unbind(){
                this.$off('wyu') //解绑一个自定义事件
                // this.$off(['wyu','demo']) //解绑多个自定义事件
                // this.$off() //解绑所有的自定义事件
            },
            death(){
                this.$destroy() //销毁了当前Student组件的实例,销毁后所有Student实例的自定义事件全都不奏效。
            }
        },
    }
</script>

<style lang="less" scoped>
    .student{
        background-color: yellowgreen;
        padding: 5px;
        margin-top: 30px;
    }
</style>

结果展示:

  • 方法一:(使用v-on:或者@)
    image
  • 方法二(使用ref,这表现为更加灵活,可以嵌套异步任务[添加一个定时器])
    image

解绑自定义事件(在谁身上绑定,就在谁(组件)身上解绑)

  • Student组件
    unbind(){
        this.$off('wyu') //解绑一个自定义事件
        // this.$off(['wyu','demo']) //解绑多个自定义事件
        // this.$off() //解绑所有的自定义事件
    },

结果展示:

image

回顾一下生命周期的销毁流程:

  • 在销毁组件的时候会销毁该组件当中的自定义事件,但是不会销毁原生的js内置事件
  • 如:设置一个按钮,没点击一次,num++

结果展示:

image

两个注意点:

1.注意点1:在使用ref方式绑定自定义组件的时候,

  • (1)正常的挂载mounted()和发送名字分开写:
    // App组件代码片段(<script></script>)
    methods:{
        getStudentName(name,...params){
            console.log('App收到了学生名:',name,params)
            this.studentName = name
        }
    },

    mounted(){
        this.$refs.student.$on('wyu',this.getStudentName) //绑定自定义事件
    },

结果展示:(正常接收和展示)

image

  • (2)为求方便,将挂在函数mounted()和getStudentName一起写:
    mounted() {
        // 注意点1:将挂在函数mounted()和getStudentName写在了一起
        this.$refs.student.$on('wyu', function (name,...params){
            console.log("App收到了学生的名字:", name , params)
            this.studentName = name
            console.log(this);//这时这里的this指向并不是指向vm,而是指向了Student的vc
        })
    }
  • 这时就会产生一个问题:页面上的姓名就会不会展示了

结果展示:

image

解决办法:

  • 可以将getStudentName写成箭头函数,因为我们知道,箭头函数是没有this指向的,它会向外找到mounted()的this指向,因为mounted()是写在App身上的生命周期钩子函数,它的this是指向App的实例对象的,因此能解决问题
    mounted() {
        // 注意点1:将挂在函数mounted()和getStudentName写在了一起
        this.$refs.student.$on('wyu', (name,...params)=>{
            console.log("App收到了学生的名字:", name , params)
            this.studentName = name
            console.log(this);//这时这里的this指向并不是指向vm,而是指向了Student的vc
        })
    },

结果展示:

image

2.注意点2:组件上使用原生的js内置事件

  • 组件上绑定js原生事件,因为组件是不认识原生的js内置事件的,因此组件会认为该事件是自定义的事件。
  • 可以使用.native修饰符指明是原生的js事件
<Student ref="student" @click.native="show"/>

结果展示:

  • 1.不使用 .native
    image
  • 2.使用 .native
    image