欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-03-09 08:21:30
vue3.0出来已经有段时间的了,也与必要开始研究它了!先看下我们要实现的效果很常见的展开显示菜单项的内容,在vue3.0里面怎么开发,这里样式我们用的是bootstrap的默认样式思路一:

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>

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

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

相关标签: vue3.0 下拉菜单