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实现下拉菜单的封装 的全部内容, 来源链接: utcz.com/p/239770.html

回到顶部