当前位置: 首页 > news >正文

vue实现目录锚点且滚动到指定区域时锚点自动回显——双向锚点

最近在用vue写官网,别问我为什么用vue写官网,问就是不会jq。。。。vue都出现11年了。。。

左侧目录:点击时,右侧区域可以自动滚动到指定的位置。
在这里插入图片描述
右侧区域手动滚动时,左侧锚点可以自动切换到对应的目录上
在这里插入图片描述

从而实现双向锚点的功能:

直接上代码:

解决步骤1:左侧锚点部分

<div class="leftFixed">
			<div @click="goId('shouyeId')" :class="[currentId == 'shouyeId' ? 'activeCls' : '']">我的首页</div>
			<div @click="goId('gongchangId')" :class="[currentId == 'gongchangId' ? 'activeCls' : '']">工厂展示&档案</div>
			<div @click="goId('chanxianId')" :class="[currentId == 'chanxianId' ? 'activeCls' : '']">产线展示</div>
			<div @click="goId('gongyiId')" :class="[currentId == 'gongyiId' ? 'activeCls' : '']">工艺能力&制程</div>
			<div @click="goId('chanpinId')" :class="[currentId == 'chanpinId' ? 'activeCls' : '']">产品展示</div>
			<div @click="goId('tixiId')" :class="[currentId == 'tixiId' ? 'activeCls' : '']">体系认证</div>
			<div @click="goId('pingjiaId')" :class="[currentId == 'pingjiaId' ? 'activeCls' : '']">用户评价</div>
		</div>

对应的css代码:

<style lang="less" scoped>
.leftFixed {
	position: fixed;
	top: 100px;
	left: 110px;
	background: #fff;
	padding: 16px;
	display: flex;
	flex-direction: column;

	div {
		padding: 5px 0;
		padding-left: 20px;
		cursor: pointer;

		&.activeCls {
			color: #1f833b;
			font-weight: bold;
			position: relative;

			&:before {
				content: "";
				/* 使用空内容 */
				position: absolute;
				top: 50%;
				transform: translateY(-50%);
				left: 0;
				width: 0;
				height: 0;
				border-top: 5px solid transparent;
				/* 控制箭头的上半部分 */
				border-bottom: 5px solid transparent;
				/* 控制箭头的下半部分 */
				border-left: 10px solid #1f833b;
				/* 控制箭头的右侧,创建箭头效果 */
			}
		}
	}
}
</style>

对应的js代码:

goId(id) {
	document.getElementById(id).scrollIntoView();
	this.currentId = id;//用于显示当前指定的目录
},

解决步骤2:右侧区域滚动后左侧自动回显

mounted方法中写以下代码:

if(document.getElementById("content_wrap")){
	window.addEventListener(
	"scroll",
	() => {
		let elements = document.getElementById("content_wrap").querySelectorAll("[id]"); // 获取所有有ID的元素
		let scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
		let closestElement = null;
		let closestDistance = Infinity;

		elements.forEach((element) => {
			let distance = Math.abs(element.getBoundingClientRect().top - scrollPosition);
			if (distance < closestDistance) {
				closestDistance = distance;
				closestElement = element;
			}
		});

		if (closestElement && closestElement.id && typeof closestElement.id == "string") {
			this.currentId = closestElement.id;
			console.log("Closest element to the top of the viewport is:", closestElement.id);
		}
	},
	{ passive: true, capture: true }
); // 使用捕获阶段和标记为 passive 以提高性能
}

注意一定要写{ passive: true, capture: true },否则可能会出现监听不到scroll的情况

通过上面的两个步骤,就可以实现双向锚点的效果了!!!

多多积累,多多收获!!!

当我把上面的代码发给cursor帮我进行解析时,它给我了可以添加【防抖/节流】的优化建议:

让我帮你分析这段代码。这是一个用于监听滚动事件并确定最接近视口顶部元素的代码段。让我逐步分析:

1.初始条件判断:
if(document.getElementById(“content_wrap”))
首先检查页面中是否存在 ID 为 content_wrap 的元素,这是一个安全检查。

2.事件监听器设置:
window.addEventListener(“scroll”, callback, { passive: true, capture: true })
在窗口上添加滚动事件监听器
passive: true - 告诉浏览器这个监听器不会调用 preventDefault(),这可以提高滚动性能
capture: true - 使用事件捕获而不是冒泡,确保这个监听器最先执行

3.元素获取:
let elements = document.getElementById(“content_wrap”).querySelectorAll(“[id]”)
在 content_wrap 容器内查找所有带有 ID 属性的元素
使用属性选择器 [id] 来选择这些元素

4.滚动位置获取:
let scrollPosition = window.pageYOffset || document.documentElement.scrollTop
获取当前页面的垂直滚动位置
使用降级方案确保兼容性

5.查找最近元素的逻辑:
let closestElement = null;
let closestDistance = Infinity;
elements.forEach((element) => {
let distance = Math.abs(element.getBoundingClientRect().top - scrollPosition);
if (distance < closestDistance) {
closestDistance = distance;
closestElement = element;
}
});
初始化变量来跟踪最近的元素
遍历所有带 ID 的元素
计算每个元素到视口顶部的距离
更新距离最近的元素

6.结果处理:
if (closestElement && closestElement.id && typeof closestElement.id == “string”) {
this.currentId = closestElement.id;
console.log(“Closest element to the top of the viewport is:”, closestElement.id);
}
进行安全检查确保找到了元素且有有效的 ID
更新 currentId 属性
在控制台输出最近元素的 ID

主要用途:
这段代码通常用于实现滚动监听功能,比如文档导航或目录高亮
可以用来实现类似于"目录跟随阅读位置"的功能
对于长文档或教程类网站特别有用

性能考虑:
使用了 passive: true 提高滚动性能
但是每次滚动都会触发 DOM 查询和计算,如果元素很多可能会影响性能
可以考虑添加节流(throttle)来优化性能

改进建议:
可以添加防抖或节流来减少计算频率
考虑缓存 elements 查询结果,避免每次滚动都查询 DOM
可以添加一个最小距离阈值,只在距离大于某个值时才更新
考虑使用 Intersection Observer API 作为替代方案,可能更高效

根据上面提供的改进建议,我让cursor帮我实现了一下防抖/节流的效果

我来帮你添加防抖函数来优化这段代码。下面是添加防抖后的代码:

// 首先定义一个防抖函数
function debounce(func, wait) {
    let timeout;
    return function executedFunction(...args) {
        const later = () => {
            clearTimeout(timeout);
            func(...args);
        };
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
    };
}

// 使用防抖优化后的滚动监听代码
if(document.getElementById("content_wrap")){
    // 将滚动处理函数单独提取出来
    const handleScroll = () => {
        let elements = document.getElementById("content_wrap").querySelectorAll("[id]");
        let scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
        let closestElement = null;
        let closestDistance = Infinity;

        elements.forEach((element) => {
            let distance = Math.abs(element.getBoundingClientRect().top - scrollPosition);
            if (distance < closestDistance) {
                closestDistance = distance;
                closestElement = element;
            }
        });

        if (closestElement && closestElement.id && typeof closestElement.id == "string") {
            this.currentId = closestElement.id;
            console.log("Closest element to the top of the viewport is:", closestElement.id);
        }
    };

    // 创建防抖后的处理函数,设置 200ms 的延迟
    const debouncedHandleScroll = debounce(handleScroll, 200);

    // 添加事件监听器,使用防抖后的函数
    window.addEventListener(
        "scroll",
        debouncedHandleScroll,
        { passive: true, capture: true }
    );
}

这个优化版本的主要改进点:

添加防抖函数:
通过 debounce 函数实现防抖
防抖函数会等待用户停止滚动 200ms 后才执行计算
这样可以显著减少函数执行次数

函数结构优化:
将滚动处理逻辑提取为单独的 handleScroll 函数
使用 debounce 包装处理函数
保持了原有的功能,但大大提升了性能

防抖时间设置:
设置了 200ms 的防抖延迟时间
这个时间可以根据实际需求调整
时间设置太短可能效果不明显,太长可能影响用户体验

上面的代码还可以二次优化,因为这个页面全是静态数据,也就是可以通过下面的方法来处理

额外的优化建议:
1.缓存 DOM 查询:

if(document.getElementById("content_wrap")){
    // 缓存 content_wrap 元素
    const contentWrap = document.getElementById("content_wrap");
    // 缓存所有带 ID 的元素(如果元素列表不会动态变化)
    const elements = contentWrap.querySelectorAll("[id]");
    
    const handleScroll = () => {
        let scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
        let closestElement = null;
        let closestDistance = Infinity;

        elements.forEach((element) => {
            // ... 其余代码不变
        });
    };
    
    const debouncedHandleScroll = debounce(handleScroll, 200);
    window.addEventListener("scroll", debouncedHandleScroll, { passive: true, capture: true });
}

2.添加清理函数

if(document.getElementById("content_wrap")){
    // ... 其他代码

    // 在组件卸载时清理事件监听
    const cleanup = () => {
        window.removeEventListener("scroll", debouncedHandleScroll);
    };

    // 如果在 Vue 或 React 组件中使用,可以在组件卸载时调用 cleanup
    return cleanup; // 返回清理函数
}

这些优化可以显著提高代码的性能,特别是在长页面或频繁滚动的情况下。防抖可以有效减少不必要的计算,同时保持功能的响应性。根据具体使用场景,你可以调整防抖的时间间隔来平衡性能和用户体验。

相关文章:

  • [特殊字符] 企业级Docker私有仓库实战:3步搭建Harbor安全仓库,镜像管理从此高效无忧
  • 【Vue 3 + Element Plus 实现产品标签的动态添加、删除与回显】
  • 【AI提示词】竞品分析专家
  • 解决IDEA中自动生成返回值带final修饰的问题
  • 揭秘大数据 | 19、软件定义的世界
  • 基于 C语言 的信号量实现与应用
  • C# 状态模式深度解析:构建灵活的状态驱动系统
  • linux中CosyVoice声音克隆安装教程——TTS文本转语音(数字人组件)
  • React首页加载速度优化
  • Android PowerManager功能接口详解
  • Linux 字符串截取#与%
  • xtrabackup备份
  • SpringQuartz集群支持:JDBC存储与分布式执行
  • Blender 转 STL 文件全攻略:从基础到进阶
  • 大语言模型:在共识与创造之间的技术困局与破局探索
  • Python 实现的运筹优化系统数学建模详解(最大最小化模型)
  • 如何使用 qrcode.react生成二维码
  • VBA知识学习
  • Stable Diffusion 四重调参优化——项目学习记录
  • 人工智能应用工程师:开启智能时代的金钥匙
  • 开发公司清除地上树木侵犯了谁的权利/网站及搜索引擎优化建议
  • 开发板是干什么用的/广州做seo整站优化公司
  • 漯河网站建设漯河/自制网站 免费
  • 合肥做公司网站一般多少钱/福清网络营销
  • 苏州网站建设公司哪家好/网络营销和传统营销的区别有哪些
  • 通过模板做网站/小升初最好的补课机构排行榜