一般这样的功能在一个项目中很多地方需要用到
vue3可以将功能代码单独提出来
import { ref, onMounted, onUnmounted, Ref } from 'vue'
const useClickOutside = (elementRef: Ref<null | HTMLElement>) => {
const isClickOutside = ref(false)
const handler = (e: MouseEvent) => {
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
在组件中使用
<div class="dropdown" ref="dropdownRef">
<a href="#" class="btn btn-outline-light my-2 dropdown-toggle" @click.prevent="toggleOpen">
点击title展示下拉
</a>
<ul class="dropdown-menu" :style="{display: 'block'}" v-if="isOpen">
<li>下拉列表1</li>
<li>下拉列表2</li>
<li>下拉列表3</li>
<li>下拉列表4</li>
</ul>
</div>
<script lang="ts">
import { defineComponent, ref, watch } from 'vue'
import useClickOutside from '../hooks/useClickOutside'
export default defineComponent({
name: 'Dropdown',
props: {
title: {
type: String,
required: true
}
},
setup() {
const isOpen = ref(false)
const dropdownRef = ref<null | HTMLElement>(null)
const toggleOpen = () => {
isOpen.value = !isOpen.value
}
const isClickOutside = useClickOutside(dropdownRef)
watch(isClickOutside, () => {
if (isOpen.value && isClickOutside.value) { //下拉展开且点击位置为组件外的区域隐藏
isOpen.value = false
}
})
return {
isOpen,
toggleOpen,
dropdownRef
}
}
})
</script>
使用vue2实现,
采用自定义指令的方式:
全局定义指令:
// 自定义指令clickoutside绑定了一个函数handleClose用来关闭菜单
Vue.directives:{
clickoutside:{
bind:function(el,binding,vnode){
function documentHandler(e){
if(el.contains(e.target)){
return false;
}
if(binding.expression){
binding.value(e)
}
}
el._vueClickOutside_ = documentHandler;
document.addEventListener('click',documentHandler);
},
unbind:function(el,binding){
document.removeEventListener('click',el._vueClickOutside_);
delete el._vueClickOutside_;
}
}
}
在组件中使用
<div class="mobile-menu" v-clickoutside="menuHandleClose">
<img src="../assets/image/home/nav_logo.svg" >
<div class="user-info flex" >
<img src="../assets/image/home/nav_down.png" @click="clickLogin">
<a-icon type="menu" @click="menuListVisible = !menuListVisible" />
</div>
</div>
<div v-if="menuListVisible">
<li>下拉列表1</li>
<li>下拉列表2</li>
<li>下拉列表3</li>
<li>下拉列表4</li>
</div>
//....
methods:{
menuHandleClose(){
this.menuListVisible=false
}
}