Files
2026-09-20 15:46:34 +08:00

232 lines
5.2 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
*Desc:
*Create by: jug
*Create time:2023/5/8/14:52
*/
<template>
<div>
<el-tabs class="customer-tab" type="card" @tab-click="jump" v-model="tabName">
<el-tab-pane v-for="(tab, index) in tabs" :name="tab.refName" :key="index" :label="tab.name"></el-tab-pane>
</el-tabs>
<div class="scroll-content" @scroll="onScroll" :style="{height:h+'px'}">
<div v-for="(item,index) in tabs" :key="item.refName" class="scroll-item">
<div class="line-name">
<h5>{{ item.name }}</h5>
</div>
<div>
<slot :name="item.refName"></slot>
</div>
</div>
</div>
</div>
</template>
<script>
module.exports = {
name: "ELTabPlus",
props: {
tabs: {
type: Array,
default: []
},
h: {
type: Number,
default: 700
}
},
data() {
return {
tabName: null
}
},
methods: {
jump(tab, event) {
const container = this.$el.querySelector('.scroll-content')
const scrollItems = this.$el.querySelectorAll('.scroll-item')
if (!container || !scrollItems.length) return
const targetIndex = Number(tab.index)
const targetTop = scrollItems[targetIndex].offsetTop - scrollItems[0].offsetTop
// ✅ 设置标志位,锁定 tab 不被 onScroll 覆盖
this.isJumping = true
this.tabName = this.tabs[targetIndex]?.refName
container.scrollTo({
top: targetTop,
behavior: 'smooth'
})
// ✅ 滚动动画结束后解锁(smooth 滚动大约 300~500ms)
clearTimeout(this._jumpTimer)
this._jumpTimer = setTimeout(() => {
this.isJumping = false
}, 500)
},
onScroll(e) {
// ✅ jump 期间不处理滚动联动
if (this.isJumping) return
const container = e.target
const { scrollTop, scrollHeight, clientHeight } = container
// 1. 滚动到底部
if (scrollTop + clientHeight >= scrollHeight - 1) {
const lastIndex = this.tabs.length - 1
if (this.tabIndex !== lastIndex) {
this.tabIndex = lastIndex
this.tabName = this.tabs[lastIndex]?.refName
}
return
}
// 2. 顶部
if (scrollTop === 0) {
if (this.tabIndex !== 0) {
this.tabIndex = 0
this.tabName = this.tabs[0]?.refName
}
return
}
// 3. 中间区域
const scrollItems = this.$el.querySelectorAll('.scroll-item')
const threshold = 100
for (let i = scrollItems.length - 1; i >= 0; i--) {
const itemTop = scrollItems[i].offsetTop - scrollItems[0].offsetTop
if (scrollTop + threshold >= itemTop) {
if (this.tabIndex !== i) {
this.tabIndex = i
this.tabName = this.tabs[i]?.refName
}
break
}
}
},
scrollEnd() {
this.$nextTick(() => {
setTimeout(() => {
$('#app > div.guava-main-content > span > div.el-card').each((idx, item) => {
if ($(item).is(':visible')) {
const scrollContent = $(item).find('.scroll-content')[0]
scrollContent.scrollTop = scrollContent.scrollHeight
}
})
// document.querySelector('.scroll-content').scrollTop = document.querySelector('.scroll-content').scrollHeight
this.tabName = 'audit'
}, 250)
})
},
scrollToTop() {
const tryScroll = () => {
const scrollEl = this.$el.querySelector('.scroll-content')
if (!scrollEl) return
// 检查内容是否已渲染(scrollHeight > clientHeight 说明有滚动空间)
if (scrollEl.scrollHeight <= scrollEl.clientHeight) {
// 内容还没加载完,100ms 后重试
setTimeout(tryScroll, 100)
return
}
// ✅ 内容就绪,执行滚动
scrollEl.scrollTo({top: 0, behavior: 'auto'})
this.tabIndex = 0
this.tabName = this.tabs[0]?.refName
}
this.$nextTick(() => {
setTimeout(tryScroll, 200)
})
},
},
created() {
}
}
</script>
<style scoped>
::-webkit-scrollbar {
display: none;
}
.scrollbar {
height: 10px;
background-color: #f1f1f1;
}
.scrollbar-thumb {
border-radius: 10px;
background-color: #888;
}
.scrollbar-thumb:hover {
background-color: #555;
}
.scroll-content {
overflow-x: hidden;
overflow-y: auto;
position: relative;
margin-top: 10px;
}
.customer-tab {
/*width: 100%;*/
background-color: #f5f7fa;
padding: 5px;
height: 50px;
/*display: flex;*/
/*overflow-x: scroll;*/
}
.line-name {
padding-left: 10px;
position: relative;
}
.line-name::before {
content: "";
width: 5px;
background: #11879f;
display: inline-block;
position: absolute;
left: 0;
top: 0;
bottom: 0;
}
.el-tabs--card > .el-tabs__header {
border-bottom: none;
margin: 0;
}
.el-tabs--card > .el-tabs__header .el-tabs__nav {
/*width: 100%;*/
/*display: flex;*/
/*justify-content: space-around;*/
border: none;
}
.el-tabs--card > .el-tabs__header .el-tabs__nav .el-tabs__item {
text-align: center;
border: none;
}
.el-tabs--card > .el-tabs__header .el-tabs__nav .is-active {
border-radius: 4px;
background-color: #1867b0;
color: #fff;
}
</style>