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)文章
vue.js引用背景圖background無效的3種解決方案
這篇文章主要介紹了vue.js引用背景圖background無效的3種解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08
elementPlus中的Autocomplete彈出層錯位問題解決分析
這篇文章主要介紹了elementPlus中的Autocomplete彈出層錯位問題解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
前端vue?uni-app?cc-countdown倒計(jì)時組件使用詳解
cc-countdown是一個倒計(jì)時組件,它可以顯示剩余時間、天數(shù)、小時數(shù)、分鐘數(shù)和秒數(shù),在本文中,我們將介紹如何在uni-app中使用cc-countdown組件,需要的朋友可以參考下2023-08-08
Vue keep-alive實(shí)踐總結(jié)(推薦)
本篇文章主要介紹了Vue keep-alive實(shí)踐總結(jié)(推薦),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-08-08
詳解vue-cli 本地開發(fā)mock數(shù)據(jù)使用方法
這篇文章主要介紹了詳解vue-cli 本地開發(fā)mock數(shù)據(jù)使用方法,如果后端接口尚未開發(fā)完成,前端開發(fā)一般使用mock數(shù)據(jù)。小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05

