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

 更新时间:2021年09月26日 11:51:12   作者:慕斯不想说话  
组件是可以在自己的模板中调用自身的,不过他们只能通过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递归组件封装内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Vue3中导航守卫的使用教程

    Vue3中导航守卫的使用教程

    在Vue3中,导航守卫(Navigation Guards)用于在路由切换前后执行一些操作,例如验证用户权限、取消路由导航等,本文主要为大家介绍了vue3中导航守卫的使用方法,需要的可以参考下
    2023-08-08
  • vue如何实现Toast轻提示

    vue如何实现Toast轻提示

    这篇文章主要介绍了vue如何实现Toast轻提示,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04
  • vue中自定义右键菜单插件

    vue中自定义右键菜单插件

    这篇文章主要为大家详细介绍了vue中自定义右键菜单插件,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • vue3的reactive赋值问题解决

    vue3的reactive赋值问题解决

    vue3中直接对reactive声明的变量本身进行赋值是无效的,本文主要介绍了vue3的reactive赋值问题解决,具有一定的参考价值,感兴趣的可以了解一下
    2024-03-03
  • Vue图片裁剪组件实例代码

    Vue图片裁剪组件实例代码

    这篇文章主要给大家介绍了关于Vue图片裁剪组件的相关资料,本文介绍的组件是基于vue-cropper二次封装,vue-cropper大家应该都很熟悉了吧,需要的朋友可以参考下
    2021-07-07
  • 基于Vue SEO的四种方案(小结)

    基于Vue SEO的四种方案(小结)

    这篇文章主要介绍了基于Vue SEO的四种方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-07-07
  • vue3.0公共组件自动导入的方法实例

    vue3.0公共组件自动导入的方法实例

    这篇文章主要给大家介绍了关于vue3.0公共组件自动导入的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • Vue Router中router.resolve方法使用实例

    Vue Router中router.resolve方法使用实例

    这篇文章主要给大家介绍了关于Vue Router中router.resolve方法使用的相关资料,router.resolve方法在前端路由库中用于解析路由信息,接受路径或路由对象,返回解析后的 URL、路由和位置对象,需要的朋友可以参考下
    2024-11-11
  • 图文详解Vue3没有代码提示问题的解决办法

    图文详解Vue3没有代码提示问题的解决办法

    最近在使用Vue.js时候没有自动提示,就很难受,下面这篇文章主要给大家介绍了关于Vue3没有代码提示问题的解决办法,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2023-01-01
  • Vue defineProperty使用教程

    Vue defineProperty使用教程

    Vue通过Object.defineProperty来实现监听数据的改变和读取(属性中的getter和setter方法) 实现数据劫持。下面简单记录一下,vue监听数据变化的原理
    2023-01-01

最新评论