文章目录
- 1、mounted 和 beforeDestroy
- 1.1、mounted
- 1.2、beforeDestroy
- 2、父组件向子组件传递参数 props
- 2.1、子组件定义
- 2.2、父组件调用子组件并传参
- 3、完整例子
- 3.1、父组件 Tags.vue
- 3.2、子组件 TagsMenu.vue
- 3.3、效果图
1、mounted 和 beforeDestroy
1.1、mounted
mounted() 钩子函数在组件被挂载到 DOM 后调用。代码 document.addEventListener(“click”, this.closeMenu) 在组件挂载后,为整个文档添加了一个点击事件监听器,当用户在文档任何地方点击时,都会触发 this.closeMenu 方法。
<script>
export default {
mounted() {
//动作
},
1.2、beforeDestroy
beforeDestroy() 钩子函数在组件被销毁之前调用。代码 document.removeEventListener(“click”, this.closeMenu) 在组件销毁之前,移除之前添加的点击事件监听器,避免组件销毁后仍然存在监听器,导致潜在的错误或内存泄漏。
<script>
export default {
beforeDestroy() {
//动作
},
2、父组件向子组件传递参数 props
2.1、子组件定义
<script>
export default {
props: ["clientX", "clientY", "clickIndex","tagsLength"],
//其余内容略
}
2.2、父组件调用子组件并传参
<template>
//其余略
<TagsMenu v-show="isShowTagsMenu" :clientX="clientX" :clientY="clientY" :clickIndex="clickIndex"
:tagsLength="tags.length" />
//其余略
</template>
<script>
import TagsMenu from './TagsMenu.vue';
//其余略
3、完整例子
3.1、父组件 Tags.vue
<template>
<div class="tags">
<!-- .native 用法:在 Vue.js 中,.native 修饰符用于监听原生 DOM 事件,而不是 Vue 组件的自定义事件。
例如,@contextmenu.native="rightClick($event)"
.prevent 阻止浏览器默认行为
表示你希望监听原生的 contextmenu 事件(通常是右键点击),
而不是 Vue 组件中可能定义的 contextmenu 事件。这在你想要直接处理 DOM 事件时非常有用,
尤其是当组件内部没有提供相应的事件时。 -->
<el-tag size="medium" :closable="index>0" v-for="item,index in tags" :key="item.path"
:effect="item.title==$route.name?'dark':'plain'" @click="goTo(item.path)" @close="close(index)"
:disable-transitions="true" @contextmenu.native.prevent="rightClick($event,index)">
<i class="cir" v-show="item.title==$route.name"></i>
{{item.title}}</el-tag>
<TagsMenu v-show="isShowTagsMenu" :clientX="clientX" :clientY="clientY" :clickIndex="clickIndex"
:tagsLength="tags.length" />
</div>
</template>
<script>
import TagsMenu from './TagsMenu.vue';
export default {
components: {
TagsMenu
},
data() {
return {
tags: [{
title: "layout",
path: "/layout",
isActive: true,
}],
isShowTagsMenu: false,
clientX: 0,
clientY: 0,
clickIndex: 0,
}
},
mounted() {
document.addEventListener("click", this.closeMenu)
},
beforeDestroy() {
document.removeEventListener("click", this.closeMenu)
},
methods: {
closeMenu() {
this.isShowTagsMenu = false
},
rightClick(e, i) {
console.log("右键点击了", e.clientX, e.clientY, i);
this.clientX = e.clientX;
this.clientY = e.clientY;
this.isShowTagsMenu = true;
this.clickIndex = i;
//关闭浏览器的默认行为
window.event.returnValue = false;
return false;
},
goTo(path) {
this.$router.replace({
path: (path == '/' || path == undefined ? '/Index' : path)
});
},
close(index) {
const name = this.tags[index].title;
this.tags.splice(index, 1);
if (this.tags.length == 0) return;
//如果关闭当前页,则激活最后一个标签页
const path = this.tags[this.tags.length - 1].path;
if (name === this.$route.name && this.tags.length != 0) {
this.$router.replace({
path: (path == '/' || path == undefined ? '/Index' : path)
});
}
}
},
watch: {
$route: {
immediate: true,
handler(val, oldVal) {
console.log(val);
const bool = this.tags.find(item => {
return item.path == val.path;
});
if (!bool) {
this.tags.push({
title: val.name,
path: val.path
});
}
}
}
}
}
</script>
<style scoped>
.tags {
margin-top: 3px;
/* 添加距离上边缘的距离 */
}
.tags .el-tag {
padding-left: 10px;
padding-top: 0px;
margin-right: 5px;
.cir {
width: 8px;
height: 8px;
margin-right: 4px;
background-color: #fff;
border-radius: 50%;
display: inline-block;
}
}
</style>
3.2、子组件 TagsMenu.vue
<template>
<div class="tags-menu" :style="{left:clientX+'px',top:clientY+'px'}">
<ul>
<li v-for="item,index in tmenu" :key="index" v-show="isShowLi(index)">
<i :class="item.icon"></i>
{{item.text}}
</li>
<li>{{clientX+","+clickIndex}}</li>
</ul>
</div>
</template>
<script>
export default {
props: ["clientX", "clientY", "clickIndex","tagsLength"],
methods: {
isShowLi(i) {
if(this.tagsLength===1){
//只有首页
return i===0;
}
if (this.clickIndex == 0) {
return ![1, 3].includes(i)
}
if(this.clickIndex == 1 && this.clickIndex==this.tagsLength-1){
return ![3,4].includes(i)
}else if(this.clickIndex == 1 && this.clickIndex!=this.tagsLength-1){
return ![3].includes(i)
}else if(this.clickIndex==this.tagsLength-1){
return ![4].includes(i)
}
return true;
}
},
data() {
return {
tmenu: [{
icon: "el-icon-refresh-right",
text: "刷新页面"
},
{
icon: "el-icon-close",
text: "关闭当前"
},
{
icon: "el-icon-circle-close",
text: "关闭其他"
},
{
icon: "el-icon-back",
text: "关闭左侧"
},
{
icon: "el-icon-right",
text: "关闭右侧"
},
{
icon: "el-icon-circle-close",
text: "关闭全部"
}
]
}
}
}
</script>
<style>
.tags-menu {
position: absolute;
z-index: 1000;
/* 确保菜单在最上层 */
background-color: white;
/* 设置背景颜色为白色 */
border: 1px solid #ddd;
/* 添加边框 */
border-radius: 4px;
/* 圆角效果 */
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
/* 添加阴影 */
padding: 10px;
/* 内边距 */
min-width: 120px;
/* 最小宽度 */
/* 可选:添加过渡效果 */
transition: opacity 0.2s ease;
}
.tags-menu ul {
list-style: none;
/* 去掉列表样式 */
margin: 0;
/* 去掉外边距 */
padding: 0;
/* 去掉内边距 */
}
.tags-menu li {
padding: 8px 12px;
/* 单个菜单项的内边距 */
cursor: pointer;
/* 鼠标悬停变成手指 */
transition: background-color 0.2s;
/* 添加过渡效果 */
}
.tags-menu li:hover {
background-color: #f5f5f5;
/* 悬停时的背景颜色 */
}
</style>