在实际场景中,我们通过props可从父组件向子组件传递数据来达到数据共享的目的。但是在某一些场景中,我们需要从子组件向父组件传递消息,此时,我们就可以使用vue提供的自定义事件。
其语法很简单,在子组件中我们可以使用: emit()来触发一个来自子组件的事件,在父组件中使用: e m i t ( ) 来 触 发 一 个 来 自 子 组 件 的 事 件 , 在 父 组 件 中 使 用 : on()来监听子组件的事件。
下面我们看一个例子:
<template>
<div>
<p style="margin: 50px;">totals:{{total}}</p>
<child-component ref="child">
</child-component>
</div>
</template>
<script>
export default {
name: "VCustomEvent",
// 数据
data() {
return {
total: 0
}
},
mounted() {
this.$on('increase', this.handleIncrease)
this.$on('reduce', this.handleReduce)
},
methods: {
handleIncrease(counter) {
this.total = counter
console.log("parent total:" + this.total.toString() + " child:" + counter.toString())
},
handleReduce(counter) {
this.total = counter
console.log("parent total:" + this.total.toString() + " child:" + counter.toString())
}
},
// 组件注册
components: {
'child-component': {
template: '\
<div style="margin: 0 50px;">\
<button @click="increase" style="margin-right: 20px;">increase</button>\
<button @click="reduce">reduce</button>\
</div>',
data() {
return {
counter: 0,
}
},
methods: {
increase() {
this.counter++
console.log("child counter:" + this.counter.toString())
this.$emit('increase', this.counter)
},
reduce() {
this.counter--
console.log("child counter:" + this.counter.toString())
this.$emit('reduce', this.counter)
},
},
},
// add somethings
}
}
</script>
<style scoped>
</style>
运行效果图:
这里我们借助chrome的一款插件来看下当我们点击按钮的时候,到底有没有触发该事件:
这里大家可以看到,子组件没有任何问题,确实发出了我们期望的事件,但是父组件并没有响应。
这里我们简单的分析一下,使用this.$emit发出事件消息,那么它会发送到哪里?这个由于本人水平有限,也不知道怎么给大家来个实际的图来的清楚,所以只能猜猜了。
this代表的是当前的对象,对于子组件来说,使用this. emit发出的事件,自然是子组件能够监听到的,而我们在父组件中使用this. e m i t 发 出 的 事 件 , 自 然 是 子 组 件 能 够 监 听 到 的 , 而 我 们 在 父 组 件 中 使 用 t h i s . on来监听,这两个this代表的对象是截然不同的,所以在父组件中不能够正常的接收到来自子组件的事件也就可以理解了。让我们验证一下,在子组件中我们重新监听这两个事件。
我们在子组件的mouted方法中进行事件的监听:
mounted(){
this.$on('increase',function () {
console.log("我监听到了事件increase")
})
this.$on('reduce',function () {
console.log("我监听到了事件reduce")
})
},
运行程序:
可以发现确实如我们所猜测的,事件消息是在子组件内部传递的。那么知道了原因,我们就可以有办法来实现我们的目的,我们可以在子组件中通过:this. parent. p a r e n t . emit的方式发送事件消息。
当然了,我们也可以在父组件中,得到我们的自定义组件,然后监听:
this.$refs.child.$on('increase', this.handleIncrease)
this.$refs.child.$on('reduce', this.handleReduce)
这里我们可以给我们的子组件申明一个别名,方便我们引用:
<child-component ref="child">
</child-component>
这些操作还是比较麻烦的,在vue中我们可以直接在子组件的标签上使用v-on来监听子组件触发的自定义事件:
<child-component ref="child"
@increase="handleIncrease"
@reduce="handleReduce">
</child-component>
我个人还是比价喜欢这种方式,毕竟是vue官方推荐的,使用起来还是挺方便的。
效果图:
我们也可以通过v-on监听dom原生事件,这里需要使用修饰符native:
child-component ref="child"
@increase="handleIncrease"
@reduce="handleReduce"
@click.native="handleClick">
</child-component>
handleClick(){
console.log("子组件被我点击了。")
}
修改子组件的样式,让我们能够直观的看到效果:
<div style="margin: 0 50px;width: 200px;background: beige;">
运行效果: