vue.js - 点击时触发命名组件并管理点击关闭元素
问题描述
我正在创建一个Dropdown.vue
组件。它有一个名为的道具name
,以便我可以使用我想要的任何 div 通过点击事件触发它。
例如,我有一个元素<button @click="openDropdown('notifications-dropdown')">test</test>
然后我有组件:<dropdown name="notifications-dropdown"><div>content</div></dropdown>
click 事件是从全局 Vue 对象的方法中处理的:
methods: {
openDropdown( name) {
EventBus.$emit('dropdown-opened', name);
}
}
在实际的 Dropdown 组件上,我使用了 Mounted 方法:
EventBus.$on('dropdown-opened', (name) => {
if (this.name == name) {
this.active = true;
}
});
这一切都很好,但是,我需要处理单击关闭元素的功能,以便当没有单击下拉菜单时,active
布尔值更改为 false。
在下拉列表中,我有:
methods: {
closeDropdown(e) {
if ( !this.$el.contains(e.target) ) {
this.active = false;
}
}
}
在mounted
and中beforeDestroy
,我有:
document.removeEventListener('click', this.closeDropdown)
然后问题就变成了,在触发下拉菜单的初始按钮单击时,也会触发事件单击关闭元素。所以下拉菜单打开并立即关闭
如何在触发下拉菜单的初始按钮单击时做到这一点也不会触发 off e.target
click closeDropdown()
。
但是,如果您再次单击触发器,我希望下拉菜单会关闭。
以下是完整代码:
Dropdown.vue
<template>
<Transition name="fade-in-scale">
<div @click.stop ref="thedropdown" v-if="active" class="dropdown-menu absolute bg-white border-l border-b border-r border-gray-200 top-100 w-72 right-0 md:w-84">
<slot></slot>
</div>
</Transition>
</template>
<script>
// @ is an alias to /src
export default {
name: 'Dropdown',
data() {
return {
active: false
}
},
props: {
name: String
},
computed: {
},
mounted() {
document.addEventListener('click', this.closeDropdown);
EventBus.$on('dropdown-opened', (name) => {
if (this.name == name) {
this.active = !this.active;
}
});
},
beforeDestroy () {
document.removeEventListener('click', this.closeDropdown)
},
watch: {
},
methods: {
closeDropdown(e) {
if ( !this.$el.contains(e.target) ) {
this.active = false;
}
}
}
}
</script>
<style lang="scss" scoped>
.dropdown-menu {
top:calc(100% + 5px);
}
.fade-in-scale-enter-active,
.fade-in-scale-leave-active {
transition: all 0.12s;
transform:scale(1) ;
opacity:1;
}
.fade-in-scale-enter,
.fade-in-scale-leave-to {
transform: scale(0.90);
opacity: 0;
}
</style>
app.blade.php
<button @click="openDropdown('notifications-dropdown')" type="button" class="p-2 outline-none focus:outline-none"></button>
<dropdown name="notifications-dropdown"></dropdown>
app.js
require('./bootstrap');
/**
* UI
*/
import Btn from './components/ui/Button.vue';
import Dropdown from './components/ui/Dropdown.vue';
const app = new Vue({
el: '#app',
components: {
Btn,
Dropdown
},
methods: {
openDropdown( name) {
EventBus.$emit('dropdown-opened', name);
}
}
});
解决方案
在打开按钮上使用.stop
事件修饰符@click
,以便事件的传播停止并且不会到达文档的click
处理程序:
<button @click.stop="openDropdown(...)">
还要注意 中的内存泄漏Dropdown.vue
,因为它不会从事件总线中删除事件侦听器。这很容易通过声明一个组件方法来解决openDropdown
,并使用它来添加事件侦听器mounted
并在其中删除它beforeDestroy
:
export default {
mounted() {
EventBus.$on('dropdown-opened', this.openDropdown);
},
beforeDestroy () {
EventBus.$off('dropdown-opened', this.openDropdown)
},
methods: {
openDropdown(name) {/*...*/}
}
}
推荐阅读
- azure-maps - 历史 Azure Map 数据
- java - 如何将两个数字的和放在“=”旁边
- c++ - clang-format -style=文件在 Ubuntu 18.04 中不起作用
- python - 如何在海龟中独立移动 2 个对象?
- c# - 如何在 Unity with Vuforia 中使用我自己的 AI 模型进行图像识别?
- wso2 - WSO2 APIM 为 API 的后端服务器添加序列
- amazon-web-services - 如何在部署时将值传递给 AWS CDK?
- solr - 计算涵盖的查询词数除以 solr 中的查询词数
- r - 创建 Tibble 表时出现未使用的参数错误
- python - A Level Space 入侵者项目问题