el-tabs点击跳锚定转到对应内容区域,滚动跟随

需求:

  1. el-tabs列表项,点击标题自动锚定到对应的内容区域
  2. 内容滚动到对应区域时,自动定位到对应标题,并高亮

实现:

		<!-- tab标题 -->
		<el-tabs v-model="tabName" class="home-tabs" @tab-click="jump">
			<template v-for="(tab, index) of tabs">
				<el-tab-pane :key="index" :label="tab.title" :name="tab.refName"></el-tab-pane>
			</template>
		</el-tabs>
		<!-- 滚动内容 -->
		<div
			class="content scroll-content"
			@scroll="onScroll"
			:style="'overflow-x: hidden; overflow-y: auto;height:' + contentStyleObj.height"
		>
			<!-- 基本信息 -->
			<div :ref="tabs[0].refName" class="scroll-item">
				<p>基本信息</p>
				......
			</div>
			<!-- 客户信息 -->
			<div :ref="tabs[1].refName" class="scroll-item">
				<p>客户信息</p>
				......
			</div>
			<!-- 企业信息 -->
			<div :ref="tabs[2].refName" class="scroll-item">
				<p>企业信息</p>
				......
			</div>
			<!-- 联系人信息 -->
			<div :ref="tabs[3].refName" class="scroll-item">
				<p>联系人信息</p>
				......
			</div>
			......
	</div>
// 滚动区域的跳转和锚定
export default {
	data() {
		return {
			activeTab: "1",
			tabIndex: "0",
			tabName: "basic",
			//tab切换表头
			tabs: [
				{ title: "基本信息", refName: "basic" },
				{ title: "客户信息", refName: "customer" },
				{ title: "企业信息", refName: "business" },
				{ title: "联系人信息", refName: "contact" },
			],
			contentStyleObj: {
				height: "100px"
			},
			scrollItems: [], //滚动项
			isScroll: true //是否处于滚轮手动滚动中
		};
	},
	created() {
		this.getHight();
		window.addEventListener("resize", this.getHight);
	},
	mounted() {
		this.scrollItems = document.querySelectorAll(".scroll-item");
	},
	destroyed() {
		window.removeEventListener("resize", this.getHight);
	},
	methods: {
		// tab锚定
		jump(tab, event) {
			this.isScroll = false;
			let target = document.querySelector(".scroll-content"); //滚动容器

			// 判断滚动条是否滚动到底部
			if (target.scrollHeight <= target.scrollTop + target.clientHeight) {
				this.tabIndex = tab.index.toString();
			}
			let totalY = this.scrollItems[tab.index].offsetTop - this.scrollItems[0].offsetTop; // 锚点元素距离其offsetParent(这里是body)顶部的距离(待滚动的距离)
			let distance = document.querySelector(".scroll-content").scrollTop; // 滚动条距离滚动区域顶部的距离
			// let distance = document.body.scrollTop || document.documentElement.scrollTop || window.pageYOffset // 滚动条距离滚动区域顶部的距离(滚动区域为窗口)
			// 滚动动画实现, 使用setTimeout的递归实现平滑滚动,将距离细分为50小段,10ms滚动一次
			// 计算每一小段的距离
			let step = totalY / 50;
			if (totalY > distance) {
				smoothDown(document.querySelector(".scroll-content"));
			} else {
				let newTotal = distance - totalY;
				step = newTotal / 50;
				smoothUp(document.querySelector(".scroll-content"));
			}

			// 参数element为滚动区域
			function smoothDown(element) {
				if (distance < totalY) {
					distance += step;
					element.scrollTop = distance;
					setTimeout(smoothDown.bind(this, element), 10);
				} else {
					element.scrollTop = totalY;
				}
			}

			// 参数element为滚动区域
			function smoothUp(element) {
				if (distance > totalY) {
					distance -= step;
					element.scrollTop = distance;
					setTimeout(smoothUp.bind(this, element), 10);
				} else {
					element.scrollTop = totalY;
				}
			}
			setTimeout(() => {
				this.isScroll = true; //跳转完成,滚动状态恢复
			}, 500);
		},
		// 滚动监听
		onScroll(e) {
			if (!this.isScroll) return;
			// this.scrollItems = document.querySelectorAll(".scroll-item");
			// for (let i = this.scrollItems.length - 1; i >= 0; i--) {
			// 	// 判断滚动条滚动距离是否大于当前滚动项可滚动距离
			// 	let judge = e.target.scrollTop >= this.scrollItems[i].offsetTop - this.scrollItems[0].offsetTop - 400;
			// 	if (judge) {
			// 		this.tabIndex = i.toString();
			// 		// 找对应的tab-name值
			// 		this.tabName = this.tabs[this.tabIndex].refName;
			// 		break;
			// 	}
			// }
			// return;
			const scrollTop = e.target.scrollTop;
			let foundIndex = -1;

			for (let i = 0; i < this.scrollItems.length; i++) {
				const item = this.scrollItems[i];
				const threshold = item.offsetTop - this.scrollItems[0].offsetTop - 100;

				if (scrollTop >= threshold) {
					foundIndex = i;
				} else {
					break;
				}
			}

			if (foundIndex !== -1) {
				this.tabIndex = foundIndex.toString();
				this.tabName = this.tabs[this.tabIndex].refName;
			}
		},
		getHight() {
			this.contentStyleObj.height = window.innerHeight - 175 + "px";
		}
	}
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值