在开发的时候发现公司封装的树组件的右键菜单是预先在页面中放置一个DOM,通过修改绝对定位top,left的方式来将菜单定位到鼠标点击的位置,但是又引发了一些样式和布局的问题。所以想用Vue的$createElementAPI去优化一下。同时也希望能更深入了解Vue的VNode实现原理。目前的设计思路是声明一个局部组件,在点击菜单项时通过$emit传递状态, 最后统一在父组件中处理点击事件。
代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no"/>
<title>Title</title>
<script src="./dependency/vue.js"></script>
</head>
<body>
<div id="app">
<context-menu :test-render="testRender" @click-li="collectClick"></context-menu>
</div>
<script>
let contextMenu = Vue.component('contextMenu', {
props: ['testRender'],
render: function (h) {
return h('div', {
class: 'contextMenuBox'
},
[h('ul', this.testRender.map(item => h('li', {
on: {
click: (...args) => {
this.$emit('click-li', args)
}
}
}, item)))]);
}
});
const vm = new Vue({
data: {
testRender: ['Item 1', 'Item 2', 'Item 3'],
},
components: {
'context-menu': contextMenu
},
methods: {
collectClick(e) {
console.log(e)
}
}
}).$mount('#app');
</script>
</body>
</html>
目前遇到的问题是:这种实现方式与在页面中预先放置一个DOM的实现方式是一致的,只是代码的复用性会稍强一些(也可能更优雅)包括在createElementAPI中传递的参数,只能是固定的某些内容,那能否在一个场景下,譬如问题中的右键菜单,也许会加入权限来控制可选项的数量。这些更抽象的设计思路,有没有更优雅的设计思路呢?希望路过的大佬不吝赐教。谢谢各位大佬。
用
Teleport
和 https://floating-ui.com/docs/vueteleport 可以将 dom 挂载在 body 的其他位置,
floating-ui/vue
用来计算位置参数,位置这一块自己写定位的话 有太多边界情况要处理。