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](https://i-blog.csdnimg.cn/blog_migrate/49e157e2a1e3a5a4040443bfcb86cbbe.jpeg)
将这个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
打印出父组件的数据吗??
解决办法
我们只能通过props
对mybutton
进行操作,但是也只限于操作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)
很可惜,打印出的randomNumber
是undefined
但是我也不知道为什么
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](https://i-blog.csdnimg.cn/blog_migrate/38aeddadf2e335dae37a8a9f227485c8.png)
看来$event
只能保存第一个参数,不过还有办法,把传递的参数整成Object
不就好了吗? 调用$emit
$emit('Iam-clicked', ['hello world', 'holy shit'])
handler
运行的结果
![8646feb4c4ce90200869820a6df2d6c0.png](https://i-blog.csdnimg.cn/blog_migrate/016d6493fff10084d394074329709768.png)