vue3.0實(shí)現(xiàn)下拉菜單的封裝
vue3.0出來已經(jīng)有段時間的了,也與必要開始研究它了!
先看下我們要實(shí)現(xiàn)的效果
很常見的展開顯示菜單項(xiàng)的內(nèi)容,在vue3.0里面怎么開發(fā),這里樣式我們用的是bootstrap的默認(rèn)樣式
思路一:
<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組件開發(fā)的模式.
現(xiàn)在就第二種組件開發(fā)思路進(jìn)行分析
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判斷節(jié)點(diǎn)是否包含節(jié)點(diǎn) !dropDownRef.value.contains(e.target as HTMLElement) && isOpen.value ) { isOpen.value = false; } } }; onMounted(() => { //注冊全局的點(diǎn)擊事件 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>
到這里這個組件就完成了。但是…我們可以看到點(diǎn)擊整個document隱藏這個事件與整個組件的關(guān)聯(lián)不大,因此我們可以抽取成一個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"); */ //引入監(jiān)聽方法,數(shù)據(jù)變化時我們改變isOpen的值為false watch(isClickOutside, (newValue) => { if (isOpen.value && isClickOutside.value) { isOpen.value = false; } }); ... </script>
實(shí)現(xiàn)了同樣的效果,整個組件的代碼也精簡了不少!
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
element ui的el-input-number修改數(shù)值失效的問題及解決
這篇文章主要介紹了element ui的el-input-number修改數(shù)值失效的問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05如何通過Vue自定義指令實(shí)現(xiàn)前端埋點(diǎn)詳析
埋點(diǎn)分析是網(wǎng)站分析的一種常用的數(shù)據(jù)采集方法,下面這篇文章主要給大家介紹了關(guān)于如何通過Vue自定義指令實(shí)現(xiàn)前端埋點(diǎn)的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07在?Vite項(xiàng)目中使用插件?@rollup/plugin-inject?注入全局?jQuery的過程詳解
在一次項(xiàng)目腳手架升級的過程中,將之前基于?webpack?搭建的項(xiàng)目移植到?Vite?構(gòu)建,這篇文章主要介紹了在?Vite項(xiàng)目中,使用插件?@rollup/plugin-inject?注入全局?jQuery,需要的朋友可以參考下2022-12-12vue實(shí)現(xiàn)websocket客服聊天功能
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)websocket客服聊天功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-10-10