1. $emit 是什么

$emit是子组件向父组件传递通信的方式,与之对应的是props

2. props 又是什么

// child.vue
<template>
    {{ title }} 
</template>

<script>
export default {
    props: {
        title: {
            type: String,
            default: "hello",
        }
    },
}
</script>

调用这个组件时

// father.vue
<template>
<child title="world"> </child>
</template>

<script>
import child from '@/components/child'
export default {
    components: {
        child: child,
    },
}
</script>

结果

world

3.为什么要用 $emit

3.1 背景

Vue中组件对复用html代码有很大帮助,Vue将这些html代码独立分割成一个文件

3.2 举例

在不用组件时,在需要用到同样html代码的文件中

1.html
<ul> 
    <li> 1 </li>
    <li> 2 </li>
    <li> 3 </li>
    <li> 4 </li>
    ....
    <li> 100 </li>
</ul>

2. html 
<ul> 
    <li> 1 </li>
    <li> 2 </li>
    <li> 3 </li>
    <li> 4 </li>
    ....
    <li> 100 </li>
</ul>

3. html
<ul> 
    <li> 1 </li>
    <li> 2 </li>
    <li> 3 </li>
    <li> 4 </li>
    ....
    <li> 100 </li>
</ul>

将相同代码封装成组件

// list.vue
<template>
<ul> 
    <li> 1 </li>
    <li> 2 </li>
    <li> 3 </li>
    <li> 4 </li>
    ....
    <li> 100 </li>
</ul>

</template>

导入需要的html文件中

1.html
<list> </list>

2.html
<list> </list>

3.html
<list> </list>
...

3.4 但这样做会遇到什么问题($event的引入)

以一个button为组件举例,不用组件时

<template
<div>
    <button @click="dosomething"> click me </button>
</div>
</template>

<script>
export default {
    data: function() {
        return {
            message: 'hello world',
        }
    },

    methods: {
        dosomething: function() {
            console.log(this.message)
        }
    },
}
</script>

279bd360b8526dc0f3a2b42bd02f61d3.png

将这个button包装成组件mybutton,

<template>
    <div>
        <button @click="dosomethind"> </button>
    </div>
</template>

<script> 
不着急写这里
</script>

调用这个组件

<template>
<mybutton> </mybutton>
</template>

<script>
import mybutton from '@/components/mybutton'
export default {
    components: {
        mybutton: mybutton,
    },

    data: function() {
        return {
            message: 'hello world',
        }
    },
}

</script>

问题来了

我可以为mybutton中为button设置click事件,但他可以像刚才那样 用console打印出父组件的数据吗??

解决办法

我们只能通过propsmybutton进行操作,但是也只限于操作mybutton的数据
如果mybutton中的button被点击之后, 能够告知调用<mybutton>的组件: 有事件发送,我被点击了,this.$emit('Iam-clicked')
父组件听见这句话,为这个呼叫绑定一个方法 <mybutton @Iam-clicked="handler"> </mybutton> 而这个方法是

handler: function() {
    console.log(this.message)
},

注意事项 $emit 可以传递参数,this.$emit('Iam-clicked', "hello")
父组件对应的handler中也必须要有一个参数

handler: function(arg) {
    ...
}

4. 补充

4.1 未解决的问题

看了简单的$emit介绍和处理$emit的用法后,让我们看看一个没有解决的问题 父组件

<div v-for="index in [1, 2, 3]">
    <mybutton @Iam-clicked="handler">
    </mybutton>
</div>

其中mybutton中,

<template>
    <div>
        <button @click="$emit('Iam-clicked', Math.random()"> </button>
    </div>
</template>

我们要求在button触发click事件后,mybutton传递Iam-clicked事件到父组件中,父组件的handler要打印出每个index所对应的random

handler: function(randomNumber) {
    console.log(randomNumber)
},

等等,你发现了没有,这里打印不了v-for中的index变量,handler不是要求只有一个参数吗??
那么我让他返回一个只有一个参数的闭包行不行??

handler: function(index) {
    return (randomNumber) => {
        console.log("index: ", randomNumber)
    }
}

调用handler时,写成handler(index) 很可惜,打印出的randomNumberundefined 但是我也不知道为什么

4.2 解决方法

刚开始时我们是这样处理$emit在子组件中传递事件和参数 $emit('event-name', arg1, arg2) 在父组件中处理子组件的通信 handler: function(arg1, arg2) { ... } 在上面我们想怎么做?v-for中的index与传递的参数一起处理,打印出 index: randomNumber 假设有一个全局的变量global_storage, 当调用$emit('Iam-clicked', Math.random()),将Math.random()赋值给global_storage, 此时handler定义为 handler: function(index, randomNumber) { ... } 调用handler @Iam-clicked="handler(index, global_storage)" 还好,Vue已经为我们提供了这种变量----$event

4.3 再进一步

如果$emit传递多个参数呢?,$event会自动把他们封装成数组吗?? 调用$emit $emit('Iam-clicked', 'hello world', 'holy shit') 定义handler

handler: function(index, event) {
    console.log("event: ", event)
    console.log("type of event", typeof event)
}

调用handler

handler(index, $event) 发现

b0246c5530e4fbddfda63a250e693f04.png

看来$event只能保存第一个参数,不过还有办法,把传递的参数整成Object不就好了吗? 调用$emit

$emit('Iam-clicked', ['hello world', 'holy shit']) handler运行的结果

8646feb4c4ce90200869820a6df2d6c0.png
Logo

前往低代码交流专区

更多推荐