While writing a project today, I came across a need for a custom right-click menu. There are submenus within the menu, so this is where recursive components come in. So write this article to document the process of writing your own recursive components.
1. Recursive components
A recursive component, as its name implies, calls itself from within the component itself. So we start by building a component and calling itself within itself. The most common recursive component is the tree component that we often use in our projects. Below is my own implementation of a recursive component to meet the needs of the project source code.
<template>
<ul class="list-container">
<li v-for="(item,index) in listData"
:key="index" class="list-item"
@click.prevent.stop="handleClick($event,item)"
@mouseover="childrenMenuIndex=index"
>
<span class="list-item_span">
{{item.text}}
</span>
<CaretRightOutlined v-if="item.children" />
<! -- Determine if you need to call itself -->
<div v-if="item.children&&childrenMenuIndex===index"
class="context-menu context-menu_children"
>
<! Call itself inside the component itself -->
<list-comp :list-data='item.children' @hideContextMenu='hideContextMenuEvent' />
</div>
</li>
</ul>
</template>
Copy the code
<script>
import { defineComponent, ref } from "vue";
import {CaretRightOutlined} from '@ant-design/icons-vue';
export default defineComponent({
name:'list-comp'.props: {listData: {type:Array.default:() = >[]}},components:{
CaretRightOutlined
},
emits: ["hideContextMenu"].setup(props,{emit}){
// Click the event
const handleClick=(event,{text,callBack}) = >{
emit('hideContextMenu');
//callBack is the callBack you pass in, and if it is passed in, the custom callBack is called
if(callBack){
callBack();
return; }}const hideContextMenuEvent=() = >{
emit('hideContextMenu');
}
// Identifies the currently selected menu item
const childrenMenuIndex=ref(-1);
const eventNames=['click'.'contextmenu'];
onMounted(() = >{
eventNames.forEach(eventName= >window.addEventListener(eventName,hideContextMenuEvent))
})
onBeforeUnmount(() = >{
eventNames.forEach(eventName= >window.removeEventListener(eventName,hideContextMenuEvent))
})
return {
handleClick,
childrenMenuIndex,
hideContextMenuEvent
}
}
})
</script>
Copy the code
Matters needing attention
- Within the recursive component itself, when calling itself, it needs to receive itself through on the recursive component
emit
Emitted custom events that are received and passed again within the componentemit
Triggers a custom event. - By listening
click
Events can be passedemit
Trigger custom events that listen outside the component; It can also be directly throughprops
When passing data inside a component, you build your own callbacks so that you don’t have to passemit
The custom event is triggered. - When a menu item in a recursive component is clicked, the recursive component needs to be destroyed. All we need in theBubbling through events within recursive componentsListening to the
click,contextmenu
Wait for the event to destroy the component and then pass throughemit
Triggers a custom event that is received by the outside world to destroy the component. - Called within a recursive component
click
Event, you need to prevent event bubbling and default events. Can be found inclick
Add after the eventclick.prevent.stop
To prevent event bubbling and default events.
2. Right-click the menu component
My project is used in the form of components to achieve the right menu menu. Of course, it can also be implemented in the form of plug-ins. My right-click menu here is essentially a second wrapper for a recursive component. You can use the recursive component directly as the right-click menu without the second wrapper.
<template>
<teleport to='body' >
<div class="content-menu_container" :style="styleObj">
<list-comp
:list-data='menuData'
@hideContextMenu='windowClickHandler'
/>
</div>
</teleport>
</template>
Copy the code
<script>
import { defineComponent } from "vue";
import ListComp from "./list-comp.vue"
export default defineComponent({
name:"contextMenu".components:{
ListComp
},
props: {styleObj: {type:Object.default:() = >{}},menuData: {type:Array.default:() = >[]}},emits: ['closeContextMenu'].setup(props,{emit}){
const windowClickHandler=() = >{
emit('closeContextMenu')};return {
windowClickHandler,
}
}
})
</script>
Copy the code
Matters needing attention
- When calling the right-click menu in a project, you need to disable it first
window
Its own right-click menu event. Then implement your own custom menu events. The implementation code is shown below.
const showContextMenu=(event) = >{
// Disable default events and prevent bubbling
event.stopPropagation();
event.preventDefault();
state.showContextMenu=true;
state.styleObj={
left:event.clientX+ "px".top:event.clientY+'px'}}// Listen for the window's own right-click menu event
onMounted(() = >{
window.addEventListener('contextmenu',showContextMenu)
})
onBeforeUnmount(() = >{
window.removeEventListener('contextmenu',showContextMenu)
})
Copy the code
[Shanghai] Meituan – In-store platform Technology Department/in-store comprehensive front-end research and development
Resume should be sent to [email protected] (email format: name – position)
The project code address is as follows. If you find it helpful, welcome star.