手写锚点,且随着滚动屏幕自动高亮

news2025/1/11 22:47:50

入上图效果 

通过判断几个id对应的dom离滚动区域上方的高度跟滚动区域高度对比高亮锚点

<template>
  <div v-loading="totalLoading" class="define-target-container">
    <el-radio-group v-model="ucatsType" class="ucats-setting-content-group" size="medium" @change="changeRadio">
      <el-radio-button :label="item.val" :key="i" v-for="(item, i) in radioOpts">{{ item.label }}</el-radio-button>
    </el-radio-group>
    <div class="define-target-middle-content">
      <div class="left">
        <template v-for="(item, i) in ucatsSetTabs[ucatsType]">
          <DefineTargetComponents
            :key="`${item.id}_${i}`"
            :opt-config="item"
            :ucast-data="ucastJson[item.id]"
            v-loading="ucastLoading[`${item.id}Loading`]"
            @refreshScroll="getTabsAnchor"
            @refreshList="getApi"
          />
        </template>
      </div>
      <ul class="right-anchor">
        <li :key="i" v-for="(item, i) in ucatsSetTabs[ucatsType]">
          <span :id="`${item.id}Link`" @click="jumpLink(item.id, `${item.id}Link`)">{{ item.title }}</span>
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
    export default {
        name: "Maodian.vue",
        data() {

        },
        mounted() {
          const dom = document.querySelector('.ucats-set-content')
          dom && dom.addEventListener('scroll', this.mouseScroll, true)
        },
        beforeDestroy () {
          const dom = document.querySelector('.ucats-set-content')
          dom && dom.removeEventListener('scroll', this.mouseScroll, true)
        },
       updated() {
         // 页面滚动锚点
         this.getTabsAnchor()
         const { jumpId } = this.$route.params
         if (jumpId) {
           this.jumpLink(jumpId, `${jumpId}Link`)
         } else {
           // 默认第一个锚点选中
           const spans = document.querySelectorAll('.right-anchor span')
           spans[0].style.color = '#296AFD'
           spans[0].parentNode.style.borderLeft = '1px solid #296AFD'
         }
       },

    methods: {
      // 锚点跳转
      jumpLink(id, linkId) {
        const spans = document.querySelectorAll('.right-anchor span')
        spans.forEach((item, index) => {
          spans[index].style.color = item.id === linkId ? '#296AFD' : '#111217'
          spans[index].parentNode.style.borderLeft = item.id === linkId ? '1px solid #296AFD' : '1px solid #DEE1E7'
        })
        this.$nextTick(() => {
          document.querySelector('#' + id).scrollIntoView(true)
        })
      },
      mouseScroll () {
        const spans = document.querySelectorAll('.right-anchor span')
          // 锚点link
        const spanArr = Array.prototype.slice.call(spans)
        const scroll = document.querySelector('.ucats-set-content').scrollTop
          // 滚动的高度
        const [top1, top2, top3] = this.offsetTops
          // 滚动的高度在第一个与下一个高度时,就显示对应的锚点link
        const conditionFirst = (scroll < top2)
        const conditionSecond = scroll >= top2 && (this.offsetTops.length === 3 ? (scroll < top3) : true)
        const conditionThird = scroll >= top3
        if (conditionFirst) {
          this.scrollUp(spans, spanArr, 0)
        } else if (conditionSecond) {
          this.scrollUp(spans, spanArr, 1)
        } else if (conditionThird) {
          this.scrollUp(spans, spanArr, 2)
        }
      },

      scrollUp (spans, arr, i) {
        arr.forEach((item, index) => {
          if (index !== i) {
            spans[index].style.color = '#111217'
            spans[index].parentNode.style.borderLeft = '1px solid #DEE1E7'
          }
        })
        spans[i].style.color = '#296AFD'
        spans[i].parentNode.style.borderLeft = '1px solid #296AFD'
      }// 滚动监听end

        }
    }
</script>

<style scoped>
  .define-target-middle-content{
    display: flex;
    padding-right: 16px;
    .left{
      width: calc(100% - 160px);
      font-family: MicrosoftYaHei;
      font-size: 14px;
      line-height: 22px;
      /*height: 22px;*/
    }
    .right-anchor{
      width:160px;
      border-left: 1px solid #DEE1E7;
      position: fixed;
      right: 30px;
      li{
        height: 32px;
        line-height: 32px;
        color: #111217;
        padding-left: 15px;
        cursor: pointer;
      }
    }
  }
</style>

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

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

相关文章

AUTOSAR Gateway介绍

概述 熟悉整车电子架构的朋友们都知道,Gateway(网关)在整车网络架构中协调不同物理链路数据的交换,发挥着数据中枢作用。本文为大家介绍AUTOSAR架构中Gateway的应用方式。 在AUTOSAR架构中,Signal、Signal Group或者PDU从一个源总线接收可以发送到一个或相同或不同协议的总…

ChatGPT可以做WebRTC音视频质量性能优化,惊艳到我了

摘要 随着GPT-4的发布&#xff0c;AI的风越吹越旺。GPT-4可以回答问题&#xff0c;可以写作&#xff0c;甚至可以基于一张草图生成html代码搭建一个网站。即构社区的一位开发者倪同学就基于目前在研究的WebRTC QoS技术点对GPT-3.5跟GPT-4进行一场实验&#xff0c;ChatGPT会取代…

HTTP与HTTPS的区别;TLS握手过程

一、HTTP协议与HTTPS 我们都知道当客户端与服务端需要进行通信时&#xff0c;需要根据一套协议来进行通信。 HTTP全程是超文本传输协议&#xff08;Hyper Text Transfer Protocol&#xff0c;HTTP&#xff09;是一个简单的请求-响应协议&#xff0c;它通常运行在TCP之上。它指…

Redis应用问题及解决

目录 一.缓存穿透 1.1 问题描述 1.2 解决方案 二.缓存击穿 2.1 问题描述 2.2 解决方案 三.缓存雪崩 3.1 问题描述 3.2 解决方案 当数据库压力变大&#xff0c;导致服务访问数据库响应变慢&#xff0c;导致服务的压力变大&#xff0c;最终可能导致服务宕机。 一.缓存穿透 1.1 …

Linux编译器——gcc/g++使用

前言&#xff1a; 在上一篇&#xff0c;我们学习了关于文本编辑器 vim 的全部知识&#xff0c;今天给大家带来的是关于Linux编译器—gcc/使用的详细介绍。 本文目录 &#xff08;一&#xff09;温习程序的产生的过程 1、前言 2、程序的产生过程 3、&#x1f31c;初步认识 gc…

深度学习中的算法学习与记忆,利用故事联想帮助大家记忆,每个人都会

大家好&#xff0c;我是微学AI&#xff0c;大家看过我的文章&#xff0c;想必是对深度学习有了一定的了解了&#xff0c;但是对于初学者来说&#xff0c;深度学习中有很多名词和数学知识、原理还是不太清楚&#xff0c;记忆的不牢固&#xff0c;用起来不熟练&#xff0c;今天就…

网络安全 - Web应用防护墙(WAF)

什么WAF Web应用防护墙&#xff08;Web Application Firewall&#xff09;简称WAF。是一种特定形式的应用程序防火墙&#xff0c;用于过滤、监控和阻断通过网页服务的HTTP流量。通过监察HTTP流量&#xff0c;它可以防止利用网页应用程序已知漏洞的攻击&#xff0c;例如SQL 注入…

适配器模式C++用法示例

五.适配器模式一.适配器模式1.原理2.适用场景3.代理、桥接、装饰器、适配器区别4.分类&#xff08;类适配器模式、对象适配器模式&#xff09;二.C程序示例1.类适配器2.对象适配器一.适配器模式 1.原理 适配器模式的原理是将一个类的接口转换成客户希望的另一个接口。适配器模…

权威认证!腾讯云数据安全中台入选工信部商用密码典型应用方案

近日&#xff0c;工业和信息化部、国家密码管理局发布了《关于公布工业和信息化领域商用密码典型应用方案名单的通知》&#xff0c;腾讯云“基于商用密码的数据安全中台”在众多方案中脱颖而出&#xff0c;成功入选工业和信息化领域商用密码典型应用方案名单。 密码可以实现信息…

在springboot项目中使用rocketmq消息队列实战

rocketmq环境搭建 在docket环境下安装部署rocketmq的方法记录在上一篇文章中。 (31条消息) docker环境下搭建rocketmq集群_haohulala的博客-CSDN博客 这种方式不一定是最好的&#xff0c;但是我用这种方式可以成功搭建rocketmq开发环境。 项目架构 我们需要在springboot中…

CSDN 周赛填空题,充满恶意的嘲讽

CSDN 周赛填空题&#xff0c;充满恶意的嘲讽41期的填空题44期的填空题45期的填空题再说题型老顾最近一直在玩 csdn 周赛&#xff0c;没啥想法&#xff0c;就是想票点小玩意&#xff0c;之前从第四十一期开始&#xff0c;题型进行了扩展&#xff0c;增加了填空、判断、单选。扩展…

C#调试与测试 | Assert(断言)

Assert(断言) 文章目录Assert(断言)前言什么是Assert适用场景使用示例检查传入的参数是否为空检查循环变量是否在规定范围内检查方法返回值是否为null结束语前言 今天我要和大家聊聊C#调试和测试中的一种神器——断言&#xff08;Assert&#xff09;。如果你还不知道什么是断言…

nvm-windows的安装使用及踩坑指南

nvm是node的一款版本管理工具&#xff0c;可以简单操作node版本的切换、安装、查看。常规来说&#xff0c;开发中安装一个node版本就够了&#xff0c;但是最近在开发中有的老项目或者一些特定的项目需要来回切换node的版本&#xff0c;不可能手动去卸载掉之前的node版本&#x…

轻松掌握微服务治理的注册中心Eureka到Nacos知识点

1、SpringCloud 1、介绍 2、消费者与服务者 3、服务拆分 1、介绍 2、服务之间调用 例如有两个微服务&#xff0c;分别提供用户信息和订单信息。两个服务都有自己的数据库&#xff0c;所以如下查订单信息是不能直接去查用户信息的数据库的&#xff0c;只能从订单服务发起远程…

Seata 将参展 SOFA 五周年开源集市~

SOFA 五周年开源集市4 月 15 日&#xff08;本周六&#xff09;&#xff0c;SOFAStack 社区将在北京市朝阳区恒通国际创新园 C work 举办开源五周年活动&#xff0c;现场将于 12:00 正式开放开源集市&#xff0c;欢迎感兴趣的开发者们前来参与。今天让我们一起走近认识下开源的…

上海雷卯推出DFN1006超小体积网口保护ESD ULC0342P26LV 带回扫

什么是静电放电&#xff1f; 静电放电是指由于两种不同材料之间的摩擦或分离而产生的电荷累积所引起的电荷释放现象。 为什么需要防静电保护&#xff1f; 静电放电会对电子设备造成损害&#xff0c;特别是对于灵敏的网络设备来说&#xff0c;静电放电可能导致设备损坏或失效。…

图卷积网络GCN---底层逻辑最简单直白的理解

一 、GNN是怎么被提出来的&#xff1f; 比较常见的有CNN、RNN等。CNN的核心在于它的kernel&#xff0c;kernel在图片上平移&#xff0c;通过卷积的方式来提取特征。这里的关键在于图片结构上的平移不变性&#xff1a;一个小窗口无论移动到图片的哪一个位置&#xff0c;其内部的…

Elk运维-elastic7.6.1集群安装部署

wei集群安装结果说明 实例配置安装软件安装账号hadoop1 2C4G 磁盘&#xff1a;50G 云服务器 elasticsearch kibana rdhadoop2 2C4G 磁盘&#xff1a;50G 云服务器 elasticsearchrdhadoop3 2C4G 磁盘&#xff1a;50G 云服务器 elasticsearchrd整个安装过程使用的账号&…

linux(docker)下使用VuePress从零开始搭建自己的博客(一):VuePress环境搭建

目标&#xff1a;在linux centos下使用VuePress搭建博客系统&#xff0c;最好能利用docker进行备份和迁移。 本节内容&#xff1a;本节主要讲述VuePress的环境搭建过程&#xff0c;VuePress的基本配置以及备份和迁移。详细记录了从零开始搭建的过程&#xff0c;以及搭建过程中遇…

Apache配置与应用

1.基于域名的虚拟主机 为虚拟主机提供域名解析 基于域名&#xff1a;为每个虚拟主机使用不同的域名&#xff0c;但是其对应的 IP 地址是相同的。例如&#xff0c;www.benet.com 和 www.accp.com 站点的 IP 地址都是 192.168.80.10。这是使用最为普遍的虚拟 Web 主机类型。 方法…