组件的自定义事件

  1. 一种组件间通信的方式,适用于:子组件 ===> 父组件

  2. 使用场景:
    A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。

  3. 绑定自定义事件:
    3.1 第一种方式,在父组件中:<Demo @atguigu="test"/><Demo v-on:atguigu="test"/>
    3.2 第二种方式,在父组件中:

    <Demo ref="demo"/>
    ......
    mounted(){
        this.$refs.xxx.$on('atguigu',this.test)
    }
  1. 若想让自定义事件只能触发一次,可以使用once修饰符,或$once方法。

  2. 触发自定义事件:this.$emit('atguigu',数据)

  3. 解绑自定义事件this.$off('atguigu')

  4. 组件上也可以绑定原生DOM事件,需要使用native修饰符。

  5. 注意:通过this.$refs.xxx.$on('atguigu',回调)绑定自定义事件时,回调要么配置在methods中要么用箭头函数(否则this指向会出问题),!

源码

App.vue

<template>
    <div class="app">
        <h1>{{ msg }}, 学生姓名是:{{ studentName }}</h1>
        <!-- 通过父组件给子组件 传递函数类型的props 实现: 子给父传递数据 -->
        <School :getSchoolName="getSchoolName"/>

        <!-- 记住: v-on在谁身上,就是给谁在绑定事件。
        笼统说:给 Student组件,绑定了一个事件 atguigu。
        仔细说:由于 v-on 在 Student组件标签上,所以说是给student组件这个实例对象vc身上绑定了一个事件,事件名叫 atguigu 。
                如果以后有人触发atguigu事件,那么demo()函数就会被调用。
        -->
        <!-- 通过父组件给子组件 绑定一个自定义事件 实现: 子给父传递数据
        <Student v-on:atguigu="getStudentName"/> 
        <Student @atguigu="getStudentName" @demo="m1"/> -->

        <!-- 另外一种方法:  好处是比较灵活。 例如:想让App挂载之后,等5s再给Student组件实例,绑定自定义事件的话,上面一行的方法就无法实现,就需要下面一行的方法实现。
        通过 this.$refs.student 拿到 Student组件 的 实例对象 
        -->
        <!-- 注意: 此处写的 click ∈ 自定义事件 
        <Student ref="student" @click="show"/>

        //如果想 点Student组件就响应 click事件,需要加 .native 修饰符
        通过加 .native修饰符,表示当前写的 click是原生单击DOM事件,于是它就把click事件交给了 Student组件最外层元素div了。
        -->
        <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:'你好啊!',

                //082
                studentName:''
            }
        },

        methods:{
            getSchoolName(name){
                console.log('App收到了学校名:', name)
            },

            getStudentName(name, ...params){
                console.log('App收到了学生名:', name, params)

                this.studentName = name
            },

            //081
            m1(){
                console.log('demo事件被触发了')
            },

            show(){
                console.log('123')
            }
        },

        //配合 ref
        //App挂载完毕进入该函数
        mounted(){
            //.$on() 当 'atguigu' 事件被触发的时候,调用 getStudentName()函数
            this.$refs.student.$on('atguigu', this.getStudentName) //推荐写法
            //082 另外一种写法:  把上面的 getStudentName() 写到这里,需要 使用 => 箭头函数
            /*this.$refs.student.$on('atguigu', (name, ...params)=>{
                console.log('App收到了学生名:', name, params)
                console.log(this)
                this.studentName = name
            })*/

            //实验:让 App 挂载之后,等5s再绑定。 效果:刚打开页面,点击 学生 按钮,一开始就没有反应,等5s之后才能看到效果。
            /*setTimeout(()=>{
                this.$refs.student.$on('atguigu', this.getStudentName)
            }, 5000)*/

            //如果只想 触发一次,那么就使用.once():
            //this.$refs.student.$once('atguigu', this.getStudentName)

        }
    }
</script>

<style scoped>
    .app{
        background-color: gray;
    }
</style>

Student.vue

<template>
    <!-- 这里设计为只有一个根元素,本节的用到的原因之一: 给 Student组件 绑定 click.native 原生事件时, 会交给Student组件的最外层 div 。-->
    <div class="student">
        <h2 >学生姓名:{{name}}</h2>
        <h2 >学生性别:{{sex}}</h2>

        <h2> 当前求和为: {{ number }}</h2>
        <button @click="add">点我number++</button>

        <button @click="sndStudentName">把学生名给App</button>
        <button @click="unbind">解绑事件()</button>

        <button @click="dstry">销毁当前Student组件的实例(vc)</button>
    </div>
</template>

<script>
    export default {
        name:'StudentVue',
        data() {
            return {
                name:'张三',
                sex:'男',

                //081
                number:0

            }
        },

        methods:{
            //081
            add(){
                console.log('add回调被调用了')
                this.nubmer++
            },

            sndStudentName(){
                //借助 $emit 触发 student组件身上的 atguigu事件
                this.$emit('atguigu', this.name, 666,777,888)

                //注意: 在 Student.vue 组件中,事件名叫 demo
                //this.$emit('demo') 

                //082
                this.$emit('click')
            },
            unbind(){
                this.$off('atguigu') //解绑一个自定义事件:atguigu

                //同时解绑多个个自定义事件:传递数组
                //this.$off(['atguigu','demo']) //解绑多个自定义事件: atguigu 和 demo

                //
                //this.$off() //解绑所有的自定义事件
            },

            //081
            dstry(){
                this.$destroy() //销毁了 当前的 Student组件的实例,销毁后所有Student实例的自定义事件全都不奏效。
            }
        }
    }
</script>

 <style scoped>
    .student{
        background-color: pink;

        padding: 15px;

        margin-top: 30px;
    }
</style>