vue实现左侧固定菜单栏锚点及滚动高亮(组件封装)

vue实现左侧固定菜单栏锚点及滚动高亮

先上总代码:

子组件:

<!-- LeftSidebar.vue -->
<template><div class="left-sidebar"><a v-for="(item, index) in sidebarItems" :key="index" @click="scrollToAnchor(item.anchor)"><!-- 竖线 --><div :class="isSelected(item.anchor) ? 'activeLine' : 'line'" /><!-- 图标 --><img :src="isSelected(item.anchor) ? item.activeIcon : item.icon" :alt="item.label"><span>{{ item.label }}</span></a></div>
</template><script>
export default {name: 'LeftSidebar',props: ['selectedAnchor'],data() {return {sidebarItems: [{ anchor: 'sidebar1', icon: require('@/assets/image/main/sidebarIcon/sidebar1.png'), activeIcon: require('@/assets/image/main/sidebarIcon/sidebarActive1.png'), label: '菜单1' },{ anchor: 'sidebar2', icon: require('@/assets/image/main/sidebarIcon/sidebar2.png'), activeIcon: require('@/assets/image/main/sidebarIcon/sidebarActive2.png'), label: '菜单2' },{ anchor: 'sidebar3', icon: require('@/assets/image/main/sidebarIcon/sidebar3.png'), activeIcon: require('@/assets/image/main/sidebarIcon/sidebarActive3.png'), label: '菜单3' },{ anchor: 'sidebar4', icon: require('@/assets/image/main/sidebarIcon/sidebar4.png'), activeIcon: require('@/assets/image/main/sidebarIcon/sidebarActive4.png'), label: '菜单4  ' }}},methods: {scrollToAnchor(anchor) {// 通过方法通知父组件修改 selectedAnchorthis.$emit('scroll-to-anchor', anchor);},isSelected(anchor) {// 检查当前项是否被选中return this.selectedAnchor === anchor;},}
}
</script><style lang="scss" scoped>
//根据自己需要编写样式
.left-sidebar {z-index: 999;position: fixed;left: 0;top: 50%;transform: translateY(-50%);height: 450px;width: 153px;padding: 20px 30px 20px 20px;gap: 10px;border-radius: 0 20px 20px 0;border: 1px solid var(--systNaNpx-text-icon-color-text-light-solid, #FFF);background: linear-gradient(180deg, #f0f2f6d9 0%, #fffeffd9 100%);box-shadow: 0 0 20px 0 #0000001a;display: flex;flex-direction: column;align-items: center;justify-content: center;a {width: 102px;display: flex;justify-content: flex-start;align-items: center;flex: 1;text-align: left;white-space: nowrap; // 防止文字换行.line {width: 1px;height: 60px;background: linear-gradient(180deg, #d9d9d900 0%, #D9D9D9 55.21%, #d9d9d900 100%);}.activeLine {width: 1px;height: 60px;background: linear-gradient(180deg, #1a76ff00 0%, #0D6EFF 55.21%, #2c80ff00 100%);}span {color: #131f31;font-family: "PingFang SC";font-size: 14px;font-style: normal;font-weight: 600;line-height: 24px;margin-left: 4px;}}
}img {width: 26px;height: 26px;margin-left: 12px;
}
</style>

父组件:

<!-- index.vue -->
<template>
<div class="sidebar" ref="sidebar1"></div>
<div class="sidebar" ref="sidebar2"></div>
<div class="sidebar" ref="sidebar3"></div>
<div class="sidebar" ref="sidebar4"></div>
<LeftSidebar :selectedAnchor="selectedAnchor" @scroll-to-anchor="scrollToAnchor" />
</template>
<script>
import LeftSidebar from '@/components/homeCops/sidebar/LeftSidebar .vue'export default {components: {LeftSidebar},data () {return {selectedAnchor:'sidebar1'//默认高亮显示第一个}},mounted() {//经测试不同电脑监听使用的可能不成功,这里可以自行选择一个监听//监听当滚动条发生变化时调用handleScroll设置selectedAnchor的值并传给子组件window.addEventListener('scroll', this.handleScroll, true)window.addEventListener('onscroll', this.handleScroll, true)window.addEventListener('scroll', this.handleScroll.bind(this), true)this.$el.addEventListener('scroll', this.handleScroll.bind(this))},methods: {scrollToAnchor(anchor) {// 获取对应锚点的DOM元素const targetElement = this.$refs[`${anchor}`].$el// 如果找到目标元素,则执行滚动if (targetElement) {// smooth不生效targetElement.scrollIntoView({ behavior: 'auto' })}},handleScroll() {// 获取所有需要需要锚点定位的DOM元素const navContents = document.querySelectorAll('.sidebar') const offsetTopArr = []navContents.forEach(item => {// 获取上面DOM元素距离顶部的距离offsetTopArr.push(item.offsetTop)   })// 获取页面滚动了距离const scrollTop  = document.getElementById('app').scrollToplet navIndex = 0//需要高亮显示的元素for (let n = 0; n < offsetTopArr.length; n++) {if (scrollTop >= offsetTopArr[n]) { navIndex = n       }        }// 设置高亮显示this.selectedAnchor = `sidebar${navIndex + 1}`;}}
}
</script>

解析:

1、实现滚动时让左侧相应的菜单高亮显示:

①首先让元素默认选中第一个,在父组件中设置一个字段表示选中第几个

data () {return {selectedAnchor:'sidebar1'}},

②将该值传递给子组件

:selectedAnchor="selectedAnchor"

③在子组件中接收并使用

<div :class="isSelected(item.anchor) ? 'activeLine' : 'line'" />props: ['selectedAnchor'],isSelected(anchor) {// 检查当前项是否被选中return this.selectedAnchor === anchor;},

④在父组件编写功能代码

mounted() {
//经测试不同电脑监听使用的可能不成功,这里可以自行选择一个监听window.addEventListener('scroll', this.handleScroll, true)window.addEventListener('onscroll', this.handleScroll, true)window.addEventListener('scroll', this.handleScroll.bind(this), true)this.$el.addEventListener('scroll', this.handleScroll.bind(this))},methods: {handleScroll() {// 获取所有需要需要锚点定位的DOM元素const navContents = document.querySelectorAll('.sidebar') const offsetTopArr = []navContents.forEach(item => {// 获取上面DOM元素距离顶部的距离offsetTopArr.push(item.offsetTop)   })// 获取页面滚动了距离const scrollTop  = document.getElementById('app').scrollToplet navIndex = 0//需要高亮显示的元素for (let n = 0; n < offsetTopArr.length; n++) {if (scrollTop >= offsetTopArr[n]) { navIndex = n       }        }// 设置高亮显示this.selectedAnchor = `sidebar${navIndex + 1}`;}}

到此为止以上代码实现了滚动自动选择菜单的功能


2、当点击左侧菜单时实现锚点跳转

①在子组件中添加点击事件,通过$emit将参数传给父组件

@click="scrollToAnchor(item.anchor)"scrollToAnchor(anchor) {// 通过方法通知父组件this.$emit('scroll-to-anchor', anchor);
},

②在父组件中接收子组件传递的参数,并使用scrollIntoView实现锚点功能

@scroll-to-anchor="scrollToAnchor"scrollToAnchor(anchor) {// 获取对应锚点的DOM元素const targetElement = this.$refs[`${anchor}`].$el// 如果找到目标元素,则执行滚动if (targetElement) {// smooth不生效targetElement.scrollIntoView({ behavior: 'auto' })}},

以上两个功能代码要结合使用,如果只使用点击功能则需要在父组件中修改selectedAnchor 的值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/183320.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WordPress(9)宝塔配置Redis

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、宝塔安装Redis2、安装好先关闭Redis1、Redis密码默认是没有的二、安装php、Redis扩展1.启动Redis三.WordPress 安装Redis1.安装Redis插件2.启动Redis前言 提示:这里可以添加本文要记录的…

Linux ubuntu20.04 安装使用 Intel sgx

文章目录 前言一、简介二、安装Intel SGX Software Stack2.1 安装Intel SGX driver2.2 Build the Intel SGX SDK and Inte SGX PSW Package2.3 Build the Intel SGX SDK and Intel SGX SDK Installer2.4 Install the Intel(R) SGX SDK2.5 Build the Intel SGX PSW and Intel SG…

5 面试题--redis

伪客户端&#xff1a; 伪客户端的 fd 属性值为 -1&#xff1b;伪客户端处理的命令请求来源于 AOF ⽂件或者 Lua 脚本&#xff0c;⽽不是⽹络&#xff0c;所以这种客户端不需要套接字连接&#xff0c;⾃然也不需要记录套接字描述符。⽬前 Redis 服务器会在两个地⽅ ⽤到伪客户端…

ThermalLabel SDK for .NET 13.0.23.1113 Crack

ThermalLabel SDK for .NET 是一个 .NET 典型类库&#xff0c;它允许用户和开发人员创建非常创新的条码标签并将其发布在 zebra ZPL、EPL、EPSON ESC、POS 以及 Honeywell intermec 指纹中通过在 VB.NET 或 C# 上编写 .NET 纯代码来实现热敏打印机&#xff0c;以实现项目框架的…

BiLSTM-CRF的中文命名实体识别

项目地址&#xff1a;NLP-Application-and-Practice/11_BiLSTM-ner-bilstm-crf/11.3-BiLSTM-CRF的中文命名实体识别/ner_bilstm_crf at master zz-zik/NLP-Application-and-Practice (github.com) 读取renmindata.pkl文件 read_file_pkl.py # encoding:utf-8import pickle# …

分享一些基于php商城案例

案例1&#xff1a; ​​​​​​http://www.9520.xin/ 案例2&#xff1a; http://ptll.hasbuy.com/ 案例3&#xff1a; http://likeshop.9520.xin/mobile 案例4&#xff1a; http://www.hasbuy.com/

Ubuntu Linux玩童年小霸王插卡游戏

1.下载安装模拟器 在Windows平台模拟器非常多&#xff0c;而且效果也很优秀&#xff0c;Linux平台的用户常常很羡慕&#xff0c;却因为系统的缘故&#xff0c;无法使用这样的模拟器&#xff0c;但是随着时代的发展&#xff0c;Linux平台也出现了许多优秀的模拟器&#xff0c;现…

CTF ssrf+pin

什么是pin码 pin码是flask在开启debug模式下&#xff0c;进行代码调试模式所需的进入密码&#xff0c;需要正确的PIN码才能进入调试模式,可以理解为自带的webshell pin码如何生成 pin码生成要六要素 1.username 在可以任意文件读的条件下读 /etc/passwd进行猜测 2.modname 默…

navigator.clipboard is undefined in JavaScript issue [Fixed]

navigator.clipboard 在不安全的网站是无法访问的。 在本地开发使用localhost或127.0.0.1没有这个问题。因为它不是不安全网站。 在现实开发中&#xff0c;可能遇到测试环境为不安全网站。 遇到这个问题&#xff0c;就需要将不安全网站标记为非不安全网站即可。 外网提供了3…

【HTML】VScode不打开浏览器实时预览html

1. 问题描述 预览HTML时&#xff0c;不想打开浏览器&#xff0c;想在VScode中直接实时预览 2. 解决方案 下载Microsoft官方的Live Preview 点击预览按钮即可预览

Unity中Shader优化通用规则

文章目录 前言一、精度优化1、三种精度 fixed / half / float2、位置坐标、物理坐标类使用float3、HDR颜色、方向向量类使用half4、普通纹理、颜色类使用 fixed5、实际上&#xff0c;使用的精度取决于 平台 和 GPU6、现在桌面级GPU都是直接采用 float , Shader中的 fixed / hal…

J2EE征程——第一个纯servletCURD

第一个纯servletCURD 前言在此之前 一&#xff0c;概述二、CURD1介绍2查询并列表显示准备实体类country编写 CountryListServlet配置web.xml为web应用导入mysql-jdbc的jar包 3增加准备增加的页面addc.html编写 CAddServlet配置web.xml测试 4删除修改CountryListServlet&#xf…

RabbitMQ消息模型之Routing-Topic

Routing Topic Topic类型的Exchange与Direct相比&#xff0c;都是可以根据RoutingKey把消息路由到不同的队列。只不过Topic类型Exchange可以让队列在绑定Routing key的时候使用通配符&#xff01;这种模型Routingkey一般都是由一个或多个单词组成&#xff0c;多个单词之间以”…

ESP32-Web-Server编程- WebSocket 编程

ESP32-Web-Server编程- WebSocket 编程 概述 在前述 ESP32-Web-Server 实战编程-通过网页控制设备的 GPIO 中&#xff0c;我们创建了一个基于 HTTP 协议的 ESP32 Web 服务器&#xff0c;每当浏览器向 Web 服务器发送请求&#xff0c;我们将 HTML/CSS 文件提供给浏览器。 使用…

智能手表上的音频(四):语音通话

上篇讲了智能手表上音频文件播放。本篇开始讲语音通话。同音频播放一样有两种case&#xff1a;内置codec和BT。先看这两种case下audio data path&#xff0c;分别如下图&#xff1a; 内置codec下的语音通话audio data path 蓝牙下的语音通话audio data path 从上面两张图可以看…

享元模式 (Flyweight Pattern)

定义&#xff1a; 享元模式&#xff08;Flyweight Pattern&#xff09;是一种结构型设计模式&#xff0c;用于优化性能和内存使用。它通过共享尽可能多的相似对象来减少内存占用&#xff0c;特别是在有大量对象时。这种模式通常用于减少应用程序中对象的数量&#xff0c;并在多…

Redis 实战缓存

本篇概要&#xff1a; 1. 设置、查询、获取过期时间&#xff1b;2. 缓存穿透&#xff1a;设置空键&#xff1b;3. 封杀单ip&#xff1b;4. 封杀ip段&#xff1b;5. 缓存预热&#xff1b;6. 使用 hash 数据类型保存新闻的缓存&#xff0c;增加点击量&#xff1b;7. Sorted set&a…

纯js实现录屏并保存视频到本地的尝试

前言&#xff1a;先了解下&#xff1a;navigator.mediaDevices&#xff0c;mediaDevices 是 Navigator 只读属性&#xff0c;返回一个 MediaDevices 对象&#xff0c;该对象可提供对相机和麦克风等媒体输入设备的连接访问&#xff0c;也包括屏幕共享。 const media navigator…

【刷题】DFS

DFS 递归&#xff1a; 1.判断是否失败终止 2.判断是否成功终止&#xff0c;如果成功的&#xff0c;记录一个成果 3.遍历各种选择&#xff0c;在这部分可以进行剪枝 4.在每种情况下进行DFS&#xff0c;并进行回退。 199. 二叉树的右视图 给定一个二叉树的 根节点 root&#x…

深度学习之十二(图像翻译AI算法--UNIT(Unified Neural Translation))

概念 UNIT(Unified Neural Translation)是一种用于图像翻译的 AI 模型。它是一种基于生成对抗网络(GAN)的框架,用于将图像从一个域转换到另一个域。在图像翻译中,这意味着将一个风格或内容的图像转换为另一个风格或内容的图像,而不改变图像的内容或语义。 UNIT 的核心…