难点:点击下拉框以外的地方关闭下拉框
思路总结:
1.获取下拉框的DOM元素。
2.写一个回调函数,获取当前点击的DOM元素。
3.通过 contains 方法,判断当前点击的DOM元素是否在下拉框DOM元素内来决定是否显示和隐藏下拉框。
<template>
<div class="dropdown" ref="dropdownRef">
<a
class="btn btn-outline-light my-2 dropdown-toggle"
href="#"
role="button"
@click.prevent="toggleOpen" // 点击按钮 改变是否显示下拉框状态
>
{{ title }}
</a>
<ul
class="dropdown-menu"
aria-labelledby="dropdownMenuLink"
:style="{ display: 'block' }"
v-if="isOpen" // 是否显示下拉框的标志
>
<slot></slot>
</ul>
</div>
</template>
<script lang='ts'>
import { defineComponent, ref, watch, onMounted, onUnmounted } from "vue";
import useClickOutside from "../hooks/useClickOutside";
export default defineComponent({
name: "Dropdown",
props: {
title: {
type: String,
required: true,
},
},
setup(props) {
// 通过给标签绑定的 ref 获取 DOM结点
const dropdownRef = ref<null | HTMLElement>(null);
const isOpen = ref(false);
// 点击按钮 显示和隐藏下拉框
const toggleOpen = () => {
isOpen.value = !isOpen.value;
};
// 点击边框外部隐藏下拉框的回调函数
const handler = (e: MouseEvent) => {
// 这层判断必须有,dropdownRef.value 可能是null 而null是没有contains方法的
// 没有此层 if 判断 if 内部 dropdownRef.value.contains 会报错
if (dropdownRef.value) {
console.log(dropdownRef.value);
// 判断 ref=dropdownRef 的DOM结点中是否包含 当前点击的DOM元素
if (!dropdownRef.value.contains(e.target as HTMLElement) && isOpen.value ) {
isOpen.value = false;
}
}
};
// 生命周期 挂载点击事件
onMounted(() => {
document.addEventListener("click", handler);
});
// 生命周期,卸载点击事件
onUnmounted(() => {
document.removeEventListener("click", handler);
});
return {
isOpen,
toggleOpen,
dropdownRef,
};
},
});
</script>
<style scoped>
</style>