vue3.0实现下拉菜单的封装
程序员文章站
2022-03-09 08:21:30
vue3.0出来已经有段时间的了,也与必要开始研究它了!先看下我们要实现的效果很常见的展开显示菜单项的内容,在vue3.0里面怎么开发,这里样式我们用的是bootstrap的默认样式思路一:
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>
实现了同样的效果,整个组件的代码也精简了不少!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。