前言
正在做右键菜单的组件,组件环境是vue3 tsx,但在使用事件修饰符withModifiers的时候遇到右键修饰符失效的情况,在这里记录下解决方法,并且通过分析源码来排查问题
什么是事件修饰符
vue提供了多个事件修饰符,可以查阅文档看详情,我们常用的@click.prevent中的.prevent就是其中一个修饰符
注意看,当使用.right的时候是可以控制鼠标右键的触发函数的,可以看以下demo
运行demo,右键红色方块,打开控制台,能看到正常输出内容,并且不会打开普通的右键菜单
TS(X)下使用事件修饰符
在TS环境下使用事件修饰符,这是官方文档的介绍,我们使用vue playground来实现
import { defineComponent, h, withModifiers } from 'vue'
export default defineComponent({
name: 'Comp',
setup() {
return () => h('div', {
style: {
width: '100px',
height: '100px',
background: 'green'
},
onClick: withModifiers(() => {
alert(1)
}, ['right', 'prevent']),
}, 'TSX组件')
}
})
会发现右键绿色方块,并不会执行传入的事件,而是打开了右键菜单,这表示我们的修饰符并没有生效
修复以上右键修饰符问题
起初我以为是vue出问题了(别问,问就不是我的问题),并且提了个issue,点击这里可查看issue内容
通过issue得知,想要控制右键方法,使用的是onContextmenu,而不是跟模板语法一样使用click,并且可以不用使用.right修饰符,这点跟react是一样的
import { defineComponent, h, withModifiers } from 'vue'
export default defineComponent({
name: 'Comp',
setup() {
return () => h('div', {
style: {
width: '100px',
height: '100px',
background: 'blue'
},
onContextmenu: withModifiers(() => {
alert(1)
}, ['prevent']),
}, 'TSX组件')
}
})
右键蓝色方块,就能正确执行事件,并且不打开右键菜单
同理,TSX模式需要这样写
import { defineComponent } from 'vue'
export default defineComponent({
name: 'TsxMode',
setup() {
return () => (
<div style={{width: '120px', height: '120px', backgroundColor: 'blue'}}>TsxMode</div>
)
}
})
浅谈原因
通过issue得知,@click在使用.right修饰符时,会被转化成onContextmenu
转化时机在vue模板的编译转换阶段,执行transform,并且遇到v-on的时候
export const transformOn: DirectiveTransform = (dir, node, context) => {
return baseTransform(dir, node, context, baseResult => {
const { modifiers } = dir
// ...
// normalize click.right and click.middle since they don't actually fire
if (nonKeyModifiers.includes('right')) {
key = transformClick(key, `onContextmenu`)
}
if (nonKeyModifiers.includes('middle')) {
key = transformClick(key, `onMouseup`)
}
// ...
return {
props: [createObjectProperty(key, handlerExp)]
}
})
}
可以看到,在使用.right修饰符的时候,onClick方法会被转化成onContextmenu
同理,在使用.middle修饰符的时候,onClick方法会被转化成onMouseup
总结
在vue模板语法中,可以使用@click.right.prevent来自定义鼠标右键方法
vue的ts(x)语法中,需要使用onContextmenu方法来自定义鼠标右键方法
很感谢在我issue中帮我解答问题的大兄弟 :),这里是大兄弟的github