IT码农库

您当前所在位置:首页 > 网络编程 > JavaScript

JavaScript

vue3递归组件封装的全过程记录

网络 慕斯不想说话2021-09-26JavaScript4201
组件是可以在自己的模板中调用自身的,不过他们只能通过name选项来做这件事,下面这篇文章主要给大家介绍了关于vue3递归组件封装的相关资料,需要的朋友可以参考下

前言

今天在写项目时,遇到一个自定义右键菜单的需求。在菜单中还有子菜单,所以这个时候就要用到递归组件了。所以写下这篇文章来记录一下自己编写递归组件的过程。

1、递归组件

   递归组件,顾名思义就是在组件本身内部调用自身。所以我们先构建一个组件,并在自身内部调用自身。常见的递归组件就是我们项目中经常会用到的树组件了。下面就是我自己实现的一个能够满足项目需求的递归组件的源码。

<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"  />
           <!-- 判断是否需要调用自身 -->
           <div v-if="item.children&&childrenMenuIndex===index"
            class="context-menu context-menu_children"
           >
            <!-- 在组件自身内部调用自身 -->
            <list-comp :list-data='item.children' @hideContextMenu='hideContextMenuEvent' />
           </div>
       </li>
   </ul>
</template>
<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}){
    	//点击事件
        const handleClick=(event,{text,callBack})=>{
            emit('hideContextMenu');
            //callBack是你自己传进来的回调函数,如果传入了,则调用自定义回调函数
            if(callBack){
                callBack();
                return;
            }
        }
        const hideContextMenuEvent=()=>{
            emit('hideContextMenu');    
        }
        //用于标识当前选中的菜单项
        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>

注意事项

  • 在递归组件本身内部,调用自身时,需要将在递归组件上接收自己通过emit发出的自定义事件,接收后,在组件内部再次通过emit触发自定义事件。
  • 通过监听click事件,可以通过emit触发自定义事件,在组件外部监听;也可以直接在通过 props传递数据到组件内部时,就自己先构建好回调,这样就可以不用通过emit触发自定义事件了。
  • 在点击递归组件中的菜单项时,需要让递归组件销毁。所有我们需要在 递归组件内通过事件冒泡 监听click,contextmenu等事件来让组件销毁,然后通过emit触发自定义事件,让外界接收,从而达到销毁组件的目的。
  • 在递归组件内部调用click事件时,需要阻止事件冒泡以及默认事件。可以在click事件后面添加click.prevent.stop来阻止事件冒泡和默认事件。

2、右键菜单组件

  我项目中使用的是组件的形式来实现右键菜单菜单的。当然也可以通过插件的形式来实现。我这里的右键菜单本质上就是对递归组件 的二次封装,其实不用二次封装也可以,可以直接使用递归组件作为右键菜单。

<template>
    <teleport to='body' >
        <div class="content-menu_container" :style="styleObj">
            <list-comp 
                :list-data='menuData'
                @hideContextMenu='windowClickHandler'
             />
        </div>
    </teleport>
</template>
<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>

注意事项

在项目中调用右键菜单时,需要先禁用掉window自身的右键菜单事件。然后实现自己的自定义菜单事件。实现代码如下所示。

const showContextMenu=(event)=>{
    //禁用默认事件和阻止冒泡
    event.stopPropagation();
    event.preventDefault();
    state.showContextMenu=true;
    state.styleObj={
      left:event.clientX+ "px",
      top:event.clientY+'px'
    }
  }
  //监听window自身的右键菜单事件
  onMounted(()=>{
    window.addEventListener('contextmenu',showContextMenu)
  })
  onBeforeUnmount(()=>{
    window.removeEventListener('contextmenu',showContextMenu)
  })

总结

到此这篇关于vue3递归组件封装的文章就介绍到这了,更多相关vue3递归组件封装内容请搜索 以前的文章或继续浏览下面的相关文章希望大家以后多多支持 !

大图广告(830*140)