|
|
|
@ -10,6 +10,7 @@ |
|
|
|
icon="el-icon-arrow-left" |
|
|
|
:disabled="isLeftDisabled" |
|
|
|
></el-button> |
|
|
|
<el-button icon="el-icon-delete" size="medium" :disabled="tags.length==0" @click="clearControlLabel"></el-button> |
|
|
|
</div> |
|
|
|
<div class="tag-style" ref="tagBox"> |
|
|
|
<div class="scrollWrapper" ref="scrollWrapper" id="nav"> |
|
|
|
@ -69,27 +70,43 @@ export default { |
|
|
|
mounted() { |
|
|
|
this.scrollWrapper = this.$refs.scrollWrapper; |
|
|
|
this.$nextTick(() => { |
|
|
|
this.updateButtonStates(); |
|
|
|
// 使用防抖版本以避免重复调用 |
|
|
|
this.debouncedUpdateButtonStates(); |
|
|
|
}); |
|
|
|
this.scrollWrapper.addEventListener("scroll", this.handleScroll); |
|
|
|
window.addEventListener("resize", this.updateButtonStates); |
|
|
|
// 记录引用,便于移除 |
|
|
|
this._resizeHandler = this.debouncedUpdateButtonStates; |
|
|
|
window.addEventListener("resize", this._resizeHandler); |
|
|
|
}, |
|
|
|
beforeDestroy() { |
|
|
|
// 移除事件监听器 |
|
|
|
if (this.scrollWrapper) { |
|
|
|
this.scrollWrapper.removeEventListener("scroll", this.handleScroll); |
|
|
|
} |
|
|
|
window.removeEventListener("resize", this.updateButtonStates); |
|
|
|
if (this._resizeHandler) { |
|
|
|
window.removeEventListener("resize", this._resizeHandler); |
|
|
|
} |
|
|
|
}, |
|
|
|
methods: { |
|
|
|
// 简单防抖实现 |
|
|
|
debounce(func, wait = 100) { |
|
|
|
let timeout = null; |
|
|
|
const self = this; |
|
|
|
return function () { |
|
|
|
const args = arguments; |
|
|
|
if (timeout) clearTimeout(timeout); |
|
|
|
timeout = setTimeout(() => { |
|
|
|
timeout = null; |
|
|
|
func.apply(self, args); |
|
|
|
}, wait); |
|
|
|
}; |
|
|
|
}, |
|
|
|
...mapMutations({ |
|
|
|
close: "closeTab", |
|
|
|
}), |
|
|
|
handleScroll() { |
|
|
|
// 使用 setTimeout 确保获取到最新的滚动位置 |
|
|
|
setTimeout(() => { |
|
|
|
this.updateButtonStates(); |
|
|
|
}, 50); |
|
|
|
// 使用防抖版本避免高频触发 |
|
|
|
this.debouncedUpdateButtonStates(); |
|
|
|
}, |
|
|
|
// 标签向左切换 |
|
|
|
arrowBack() { |
|
|
|
@ -100,9 +117,21 @@ export default { |
|
|
|
this.$refs.scrollWrapper.scrollBy({ left: 300, behavior: "smooth" }); |
|
|
|
}, |
|
|
|
updateButtonStates() { |
|
|
|
const { scrollLeft, scrollWidth, clientWidth } = this.scrollWrapper; |
|
|
|
// 如果没有滚动容器或没有标签,直接禁用左右箭头 |
|
|
|
if (!this.scrollWrapper || !this.tags || this.tags.length === 0) { |
|
|
|
this.isLeftDisabled = true; |
|
|
|
this.isRightDisabled = true; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 防御性读取尺寸,部分浏览器/布局下可能为 0 或 undefined,使用 Number() 保证数值计算 |
|
|
|
const scrollLeft = Number(this.scrollWrapper.scrollLeft || 0); |
|
|
|
const scrollWidth = Number(this.scrollWrapper.scrollWidth || 0); |
|
|
|
const clientWidth = Number(this.scrollWrapper.clientWidth || 0); |
|
|
|
|
|
|
|
this.isLeftDisabled = scrollLeft <= 0; |
|
|
|
this.isRightDisabled = scrollLeft + clientWidth >= scrollWidth - 1; |
|
|
|
// 当内容宽度小于等于可视宽度时,右箭头应禁用 |
|
|
|
this.isRightDisabled = scrollWidth <= clientWidth || scrollLeft + clientWidth >= scrollWidth - 1; |
|
|
|
}, |
|
|
|
scrollToActiveTag() { |
|
|
|
this.$nextTick(() => { |
|
|
|
@ -134,9 +163,9 @@ export default { |
|
|
|
behavior: 'smooth' |
|
|
|
}); |
|
|
|
|
|
|
|
// 滚动后更新按钮状态 |
|
|
|
// 滚动后更新按钮状态(防抖) |
|
|
|
setTimeout(() => { |
|
|
|
this.updateButtonStates(); |
|
|
|
this.debouncedUpdateButtonStates(); |
|
|
|
}, 150); |
|
|
|
} |
|
|
|
}); |
|
|
|
@ -149,37 +178,61 @@ export default { |
|
|
|
this.handleScroll(); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 关闭的标签是最右边的话,往左边跳转一个 |
|
|
|
if (index === length) { |
|
|
|
if (this.tags[index - 1]) { |
|
|
|
try { |
|
|
|
this.$router.push(this.tags[index - 1].routeUrl); |
|
|
|
} catch (e) { |
|
|
|
this.$router.push({ path: this.tags[index - 1].routeUrl }); |
|
|
|
} |
|
|
|
} else { |
|
|
|
this.$router.push({ path: "/home" }); |
|
|
|
} |
|
|
|
} else { |
|
|
|
// 否则往右边跳转 |
|
|
|
try { |
|
|
|
this.$router.push(this.tags[index].routeUrl); |
|
|
|
} catch (e) { |
|
|
|
this.$router.push({ path: this.tags[index].routeUrl }); |
|
|
|
} |
|
|
|
} |
|
|
|
this.handleScroll(); |
|
|
|
}, |
|
|
|
changeMenu(item) { |
|
|
|
if (item.displayName !== this.$route.name) { |
|
|
|
// 点击标签页时,该标签页一定存在于tabsList中 |
|
|
|
// 使用 tabsList 中保存的完整 routeUrl(可能包含时间戳),以保持与创建时的 key 一致,避免刷新 |
|
|
|
try { |
|
|
|
this.$router.push(item.routeUrl); |
|
|
|
} catch (e) { |
|
|
|
this.$router.push({ path: item.routeUrl }); |
|
|
|
} else { |
|
|
|
// this.$message({ |
|
|
|
// message: '请不要重复选择', |
|
|
|
// type: 'error' |
|
|
|
// }); |
|
|
|
} |
|
|
|
} |
|
|
|
this.$nextTick(() => { |
|
|
|
this.scrollToActiveTag(); |
|
|
|
}); |
|
|
|
}, |
|
|
|
async clearControlLabel() { |
|
|
|
await this.$store.commit("clearMenuTab"); |
|
|
|
clearControlLabel() { |
|
|
|
this.$store.commit("clearMenuTab"); |
|
|
|
// 等待 DOM 更新后重置滚动位置并刷新按钮状态 |
|
|
|
this.$nextTick(() => { |
|
|
|
if (this.$refs.scrollWrapper) { |
|
|
|
this.$refs.scrollWrapper.scrollLeft = 0; |
|
|
|
} |
|
|
|
// // 保证左右箭头状态正确 |
|
|
|
// this.debouncedUpdateButtonStates(); |
|
|
|
this.$router.push({ path: "/home" }); |
|
|
|
}); |
|
|
|
}, |
|
|
|
}, |
|
|
|
created() { |
|
|
|
// 在实例生命周期早期创建防抖函数引用 |
|
|
|
this.debouncedUpdateButtonStates = this.debounce(function () { |
|
|
|
this.updateButtonStates(); |
|
|
|
}, 100); |
|
|
|
}, |
|
|
|
}; |
|
|
|
</script> |
|
|
|
|
|
|
|
@ -204,7 +257,7 @@ export default { |
|
|
|
pointer-events: all; |
|
|
|
cursor: pointer; |
|
|
|
position: relative; |
|
|
|
margin: 0 64px; |
|
|
|
margin: 0 64px 0 138px; |
|
|
|
} |
|
|
|
.scrollWrapper { |
|
|
|
display: flex; |
|
|
|
@ -216,7 +269,7 @@ export default { |
|
|
|
height: 0; |
|
|
|
} |
|
|
|
.el-tag { |
|
|
|
margin: 0 5px; |
|
|
|
margin: 0 60px; |
|
|
|
cursor: pointer; |
|
|
|
padding: 0 0px 0 10px; |
|
|
|
} |
|
|
|
|