1. 程式人生 > 程式設計 >vue3.0實現下拉選單的封裝

vue3.0實現下拉選單的封裝

3.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="dropDownRefhttp://www.cppcns.com">
    <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>

部分

<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<nIjDulD
ull | 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>

/* 此www.cppcns.com處是插槽需要穿透 */
.dropdowm-option.is-disabled >>> * {
  color: #www.cppcns.com6c757d;
  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,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 &IjDulD& isClickOutside.value) {
        isOpen.value = false;
      }
    });
 ...
</script>

實現了同樣的效果,整個元件的程式碼也精簡了不少!

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。