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

目录
  • 前言
  • 1、递归组件
  • 2、右键菜单组件
  • 总结

前言

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

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递归组件封装内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

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

    目录 前言 1.递归组件 2.右键菜单组件 总结 前言 今天在写项目时,遇到一个自定义右键菜单的需求.在菜单中还有子菜单,所以这个时候就要用到递归组件了.所以写下这篇文章来记录一下自己编写递归组件的过程. 1.递归组件    递归组件,顾名思义就是在组件本身内部调用自身.所以我们先构建一个组件,并在自身内部调用自身.常见的递归组件就是我们项目中经常会用到的树组件了.下面就是我自己实现的一个能够满足项目需求的递归组件的源码. <template> <ul class="list-

  • 10分钟了解Vue3递归组件的用法

    目录 前言 用法讲解 什么是递归? 什么是递归组件? 递归组件在哪会用到? 上手实操 1.创建组件 2.全局注册组件 3.获取导航数据 4.设置递归边界,并渲染数据 完整代码 总结 前言 在日常 Vue 项目中,大概率会用组件库辅助开发,所以 递归组件 的出镜率可能不会非常高.但这并不代表 递归组件 不重要. 本文用10分钟左右的时间让你掌握 递归组件 的用法. 在此之前,你必须掌握:html + css + js + Vue3 基础用法,至少需要知道 Vue 组件 是什么. 用法讲解 在讲解

  • vue3+vite自定义封装vue组件发布到npm包的全过程

    目录 创建项目 创建组件 导出组件 使用vite构建 打包 注册->登录npm 发布前准备 发布到npm 参考: 总结 创建项目 “vue”: “^3.2.8” “vite”: “^2.5.2” 习惯用HB的直接用创建vue3项目即可 或 npm init vite@latest 创建组件 打开项目 在src/components文件夹下新增文件,我这里叫TestBtn.vue <template> <button>我是测试要发布的按钮组件</button> &l

  • Vue结合Element-Plus封装递归组件实现目录示例

    目录 前言 用正则匹配出所有的h标签并且保存在数组中 封装函数,将数组中的内容变成父子结构 封装递归组件fold-item(在使用之前不要忘了导入自己哦) 在foldMenu中使用递归组件 使用效果 前言 在写我的个人博客网站,用MarkDownIt将md解析成html时,我一直在想,怎么才能实现官方文档他们那些可折叠的目录结构呢?我有那么多标题(h1...h5),而且有的文章是只有h2或者h3的,难道我要在目录组件里面一个个v-if来渲染这些标题达到目录的效果嘛?这个问题在我某一天看vue文档

  • vue3+Element采用递归调用封装导航栏实现

    目录 效果预览 模拟数据 父组件aside.vue 子组件subAside.vue 配置 效果预览 模拟数据 数据来源有很多,可以是自己写死的,也可以是后端调用得到的,也可以从别的组件中拿到 这里采用从路由中拿 定义数据源src/router/module.js/ const Login = () => import('../views/Login/Login.vue'); const Layout = () => import('../layout/layout.vue'); const H

  • 利用vue3自己实现计数功能组件封装实例

    目录 前言 一.封装的意义 二.如何封装? 1. 思路 2. 准备 2. 使用 三. 效果演示 总结 前言 本文将带你用vue3自己封装一个实现计数功能的全局组件,其应用场景相信各位一看便知,那就是购物网站中常见的数量选择模块,一起来看看如何实现哇 一.封装的意义 项目中需要用到的地方较多 模块化开发,降低了代码冗余,是开发更加高效 一次封装,到处使用 二.如何封装? 1. 思路 使用vue3中v-model来完成父子组件之间的相互传值,本文章使用vueuse/core中封装好的useVMode

  • vue3.0手动封装分页组件的方法

    本文实例为大家分享了vue3.0手动封装分页组件的具体代码,供大家参考,具体内容如下 1.父组件引入 src/views/goods/components/goods-comment.vue <!-- page表示初始化分页时,默认显示第几页 --> <XtxPagination @change-page='changePage' :pagesize='reqParams.pageSize' :total='total' :page='1' /> //调接口 import {fin

  • vue3与ts组件封装提高代码复用性

    目录 引言 轮播图组件的封装 在pinia中发请求拿到数据 父组件中 在子组件中 引言 对于一名前端程序员来说封装组件是一个必备技能.当我们在日常的工作中总有所用的组件库满足不了需求的情况,这就需要我们有封装组件的基本功了. 封装组件,可以提高我们代码的复用性,提高工作效率,提高代码的可阅读性. 组件我自己的理解的话,分为两种吧,一种是工具类的组件,一种是页面级别的组件,工具类的组件就是说封装后,在以后的项目中如果用相同的应用场景时,可复用.页面类组件的话就是将一个大的页面分成很多的小组件,然后

  • vue封装TabBar组件的完整步骤记录

    目录 实现思路: 步骤一:TabBar和TabBarItem的组件封装 步骤二:给TabBarItem传入active图片 步骤三:TabBarItem和路由的结合效果 步骤四:TabBarItem的颜色控制 用字体图标实现 引入字体图标 运用 总结 实现思路: 步骤一:TabBar和TabBarItem的组件封装 做到这,可以发现页面的基本布局已经实现了,但是item的点击活跃状态还没实现 步骤二:给TabBarItem传入active图片 为了防止替换的内容直接整个替换掉插槽,从而插槽上定义

  • Vue组件封装之input输入框实战记录

    目录 实战目的 实战效果 核心思想 一 格式规范 二 给父组件传递value值 三 错误提示 四 格式检验 五 多个input框的检验 写在最后 实战目的 封装一个自定义的input组件,只适用于 input元素type属性为text或password. 实战效果 核心思想 准备: 需要两个文件,分别为 register.vue(父组件), input.vue(子组件) register.vue 引入 input.vue import inputstyle from '@/components/

随机推荐