vue3.0实现下拉菜单的封装

 更新时间:2021年09月22日 16:37:23   作者:风清云淡_A  
这篇文章主要为大家详细介绍了vue3.0实现下拉菜单的封装代码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

vue3.0出来已经有段时间的了,也与必要开始研究它了!

先看下我们要实现的效果

很常见的展开显示菜单项的内容,在vue3.0里面怎么开发,这里样式我们用的是bootstrap的默认样式

思路一:

<DropDown :title="'退出'" :list="menuLists" />

思路二:

<drop-down :title="'退出'">
   <drop-dowm-item>新建文章</drop-down-item>
   <drop-dowm-item>编辑文章</drop-down-item>
   <drop-dowm-item>个人信息</drop-down-item>
</drop-down>

两种思路都行,相比较而言,第二种思路比较清晰,使用的时候知道具体的层次,也是elementUI组件开发的模式.
现在就第二种组件开发思路进行分析

DropDown.ts

<template>
  <div class="dropdown" ref="dropDownRef">
    <a
      @click.prevent="toggleOpen"
      class="btn btn-secondary dropdown-toggle"
      href="#" rel="external nofollow" 
    >
      {{ title }}
    </a>
    <div class="dropdown-menu" :style="{ display: 'block' }" v-show="isOpen">
      <slot></slot>
    </div>
  </div>
</template>

js部分

<script lang="ts">
import { defineComponent, ref, onMounted, onUnmounted, watch } from "vue";
import useClickOutside from "../hooks/useClickOutside";
export default defineComponent({
  name: "DropDown",
  props: {
    title: {
      type: String,
      required: true,
    },
  },

  setup(context) {
    const isOpen = ref(false);
    //vue3.0获取dom对象的引用
    const dropDownRef = ref<null | HTMLElement>(null);
    const toggleOpen = () => {
      isOpen.value = !isOpen.value;
    };
    const handleClick = (e: MouseEvent) => {
      console.log(e.target, "e");
      if (dropDownRef.value) {
        console.log(dropDownRef.value);
        if (
        //contains判断节点是否包含节点
          !dropDownRef.value.contains(e.target as HTMLElement) &&
          isOpen.value
        ) {
          isOpen.value = false;
        }
      }
    };
    onMounted(() => {
    //注册全局的点击事件
      document.addEventListener("click", handleClick);
    });
    onUnmounted(() => {
    //解绑
      document.removeEventListener("click", handleClick);
    }); 
    return {
      isOpen,
      toggleOpen,
      dropDownRef,
    };
  },
});
</script>

DropDownItem.ts

<template>
  <li class="dropdowm-option" :class="{ 'is-disabled': disabled }">
    <slot></slot>
  </li>
</template>
<style scoped>

/* 此处是插槽需要穿透 */
.dropdowm-option.is-disabled >>> * {
  color: #6c757d;
  pointer-events: none;
  background-color: transparent;
}
</style>
<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  props: {
    disabled: {
      type: Boolean,
      default: false,
    },
  },
  setup() {
    return {};
  },
});
</script>

到这里这个组件就完成了。但是…我们可以看到点击整个document隐藏这个事件与整个组件的关联不大,因此我们可以抽取成一个hooks

useClickOutside.ts

import { ref, onMounted, onUnmounted,Ref } from 'vue'
const useClickOutside = (elementRef:Ref<null | HTMLElement>) => {
    const isClickOutside = ref(false)
    const handler = (e: MouseEvent) => {
        console.log(elementRef.value);
        if (elementRef.value) {
            if (elementRef.value.contains(e.target as HTMLElement)) {
                isClickOutside.value = false
            } else {
                isClickOutside.value = true
            }
        }
    }
    onMounted(() => {
      document.addEventListener("click", handler);
    });
    onUnmounted(() => {
      document.removeEventListener("click", handler);
    });
    return isClickOutside
}

export default useClickOutside

然后再改写我们的DropDown.ts组件

//删掉之前已有的事件逻辑
<script lang="ts">
... 
 const isClickOutside = useClickOutside(dropDownRef);
    /* console.log(isClickOutside.value, "isClickOutside"); */
    //引入监听方法,数据变化时我们改变isOpen的值为false
    watch(isClickOutside, (newValue) => {
      if (isOpen.value && isClickOutside.value) {
        isOpen.value = false;
      }
    });
 ...
</script>

实现了同样的效果,整个组件的代码也精简了不少!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • vuex的辅助函数该如何使用

    vuex的辅助函数该如何使用

    vue通过辅助函数mapState、mapActions、mapMutations,把vuex.store中的属性映射到vue实例身上,这样在vue实例中就能访问vuex.store中的属性了,对于操作vuex.store就很方便了,本文具体的介绍下这些辅助函数的使用方法
    2021-06-06
  • vue3使用Pinia修改state的三种方法(直接修改,$patch,actions)

    vue3使用Pinia修改state的三种方法(直接修改,$patch,actions)

    Vue3 Pinia是一个状态管理库,专门为Vue3设计优化,它提供了一种简单而强大的方式来管理应用程序的状态,并且与Vue3的响应式系统紧密集成,本文给大家介绍了vue3使用Pinia修改state的三种方法,需要的朋友可以参考下
    2024-03-03
  • Vue最新防抖方案(必看篇)

    Vue最新防抖方案(必看篇)

    今天小编就为大家分享一篇Vue最新防抖方案(必看篇),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-10-10
  • vue-cli脚手架初始化项目各个文件夹用途

    vue-cli脚手架初始化项目各个文件夹用途

    这篇文章主要介绍了vue-cli脚手架初始化项目各个文件夹用途,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-01-01
  • 详解基于webpack和vue.js搭建开发环境

    详解基于webpack和vue.js搭建开发环境

    本篇文章主要介绍了详解基于webpack和vue.js搭建开发环境 ,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-04-04
  • vue input输入框关键字筛选检索列表数据展示

    vue input输入框关键字筛选检索列表数据展示

    这篇文章主要为大家详细介绍了vue input输入框关键字筛选检索列表数据展示,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-05-05
  • vue3.0和vue2.0的区别详细讲解

    vue3.0和vue2.0的区别详细讲解

    vue经历从2.0到3.0更新之后,简⽽⾔之就是变得更轻更快,使⽤起来更加⽅便,下面这篇文章主要给大家介绍了关于vue3.0和vue2.0区别的相关资料,需要的朋友可以参考下
    2023-10-10
  • vue基于Vue2.0和高德地图的地图组件实例

    vue基于Vue2.0和高德地图的地图组件实例

    本篇文章主要介绍了vue基于Vue2.0和高德地图的地图组件实例,非常具有实用价值,需要的朋友可以参考下
    2017-04-04
  • vue动态添加路由addRoutes之不能将动态路由存入缓存的解决

    vue动态添加路由addRoutes之不能将动态路由存入缓存的解决

    这篇文章主要介绍了vue动态添加路由addRoutes之不能将动态路由存入缓存的解决方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-02-02
  • vue实现虚拟滚动的示例详解

    vue实现虚拟滚动的示例详解

    虚拟滚动或者移动是指禁止原生滚动,之后通过监听浏览器的相关事件实现模拟滚动,下面小编就来和大家详细介绍一下vue实现虚拟滚动的示例代码,需要的可以参考下
    2023-10-10

最新评论