前言
vue3增加了一个emits选项,而且之前都是调用全局钩子函数$emit来出发事件,我们使用composition API 之后,setup里也可以通过上下文暴露出来的ctx.emit来触发事件,可谓玩法姿势又增多了,我们来总结一下吧。
ps: 如果懒得看文章 可以直接点击这里查看例子
进入主题
首先,之前的方法也是可以用的,区别就是 在vue2中,我们是把$emit绑定到了全局实例上,这里就是当前组件的实例上
比如
const Foo = defineComponent({
render() {},
created() {
// the `emit` function is bound on component instances
this.$emit('foo')
this.$emit('bar')
this.$emit('!baz')
}
})
这些都是可以触发事件的,这里我发现了一个并不常见的写法**!baz**,在事件触发内部会先把事件名转化成小驼峰,
// convert handler name to camelCase. See issue #2249
let handlerName = toHandlerKey(camelize(event)) // toHandlerKey把首字母大写然后加on前缀
let handler = props[handlerName]
const camelize = (str)=>str.replace(/-(\w)/g,(_, c) => (c ? c.toUpperCase() : ''))
//比如event 是!baz handlerName = on!baz
//这个camelize主要处理了 -x => X
所以调用的时候我们需要传入对应的'onXXX'事件 所以了解了等价写法,下面这些都是等价的
// 触发
emit('foo-bar')
emit('fooBar')
// 属性
onFooBar
// v-model相关
emit(update:fooProp)
'onUpdate:fooProp' === 'onUpdate:foo-prop'
emits选项
emits用于声明当前组件实例上可以触发的事件 声明的好处 可以让我们在emit()的时候有更好的代码补全,而且如果你触发了一个没有在emits中声明的事件,会有警告,当然ts的话也会有报错,比如下面的
emits: ["welcome"],
setup(props, ctx) {
ctx.emit("hh"); // Argument of type '"hh"' is not assignable to parameter of type '"welcome"'
~~~~
},
但是 当我们不在emits声明任何事件的时候,我们是自由的,可以自由触发任意事件,所以这个选项的使用见仁见智
props
我们注意到我们声明的事件名, 父组件在传入的时候都会在前面加上一个on, 所以onXXX (必须小驼峰) 的prop就是XXX事件的等价写法
props: ['onFoo'],
emits: [],
render() {},
created() {
this.$emit('foo')
}
所以我们定义了一个等价的onFoo,上面的代码也是不会报错的,但是在jsx/tsx中,我们必须显式的在组件中定义props才能传入对应的自定义组件 所以当你这么使用的时候 ,通过属性和方法都可以调用
// 子组件
const child = defineComponent({
props: ['onFoo'],// 用['on-foo'] 也可
emits: [],
render() {},
created() {
this.$emit('foo')
}
})
// parent.vue
<Child :onFoo="foo" > // 1
function foo(){alert('1')}
//jsx
<Child onFoo={foo} >
! 必须是小驼峰式,这里和:on-foo不等价