vue实现根据点击或滑动展示对应高亮

news2025/2/27 13:26:29

页面需求:

  • 点击左侧版本号,右侧展示对应版本内容并置于顶部
  • 右侧某一内容滚动到顶部时,左侧需要展示高亮

实现效果:

请添加图片描述

实现代码:

<template>
  <div>
    <div class="historyBox pd-20 bg-white">
      <div class="w100 flex h100" v-if="versionList.length > 0">
        <div class="left size-14">
          <div
            v-for="(item, index) in versionList"
            :key="index"
            class="leftItem pd-10 pointer"
            :class="index == activeIndex ? 'isActive' : ''"
            @click="gotoTarget(index)"
          >
            <div>{{ item.versionNumber }}</div>
            <div>{{ item.releaseTime }}</div>
          </div>
        </div>
        <div class="right">
          <div
            v-for="(item, index) in versionList"
            :key="index"
            class="rightItem pd-20 center"
            :class="index == activeIndex ? 'isActive' : ''"
          >
            <div v-html="item.versionDescription" class="ql-editor w60"></div>
          </div>
        </div>
      </div>
      <div class="w100 h100 center size-16 gray-2" v-else>暂无版本记录</div>
    </div>
  </div>
</template>

<script>
import { listAllVersion } from "./components/api";

export default {
  name: "VersionHistory",
  data() {
    return {
      versionList: [], // 表格数据
      activeIndex: 0, // 高亮下标
      clickIndex: 0, // 点击下标
      scrollIndex: 0, // 滚动下标
      scrollStopTimer: null,
    };
  },
  created() {
    this.getList();
  },
  mounted() {},
  methods: {
    // 监听鼠标移入元素 、右侧父元素滚动
    checkItemsHover() {
      const rightBox = document.querySelector(".right");

      // 监听父容器的滚动事件
      rightBox.addEventListener("scroll", this.checkItemsAtTop);

      // 页面加载时也检查一次
      window.addEventListener("load", this.checkItemsAtTop);
    },
    // 监听元素 rightItem 触顶
    checkItemsAtTop() {
      const rightBox = document.querySelector(".right");
      const rightItems = Array.from(rightBox.querySelectorAll(".rightItem"));
      rightItems.forEach((item, index) => {
        // 使用 getBoundingClientRect 来获取元素相对于视口的位置
        const rect = item.getBoundingClientRect();
        const containerRect = rightBox.getBoundingClientRect();

        // 判断元素是否触顶父容器
        if (
          rect.top - containerRect.top <= 0 &&
          rect.bottom - containerRect.top >= 0
        ) {
          this.scrollIndex = index;
          // this.activeIndex = index;
        }

        // 清除之前的定时器,防止重复触发
        if (this.scrollStopTimer) {
          clearTimeout(this.scrollStopTimer);
        }
        // 设置新的定时器,在滚动停止后延迟指定时间触发
        this.scrollStopTimer = setTimeout(this.onScrollStopped, 150); // 150ms 的延迟可以根据需要调整
      });
    },
    // 滚动停止后的回调函数
    onScrollStopped() {
      // console.log("滚动停止了", this.scrollIndex, this.clickIndex);
      // 在这里放置你希望在滚动停止后执行的代码
      if (this.scrollIndex < this.clickIndex) {
        this.activeIndex = this.clickIndex;
        this.clickIndex = 0;
      } else {
        this.activeIndex = this.scrollIndex;
      }
      const leftItems = document.querySelectorAll(".leftItem");
      const leftBox = document.querySelector(".left");
      const targetLeftItem = leftItems[this.activeIndex];
      // 计算目标元素距离父容器顶部的距离
      const offsetTop = targetLeftItem.offsetTop - leftBox.offsetTop;

      // 使用 scrollTo 方法让父容器滚动到目标元素的位置
      leftBox.scrollTo({
        top: offsetTop,
        behavior: "smooth", // 如果需要平滑滚动,请确保父容器设置了 scroll-behavior: smooth;
      });
    },
    // 定义当鼠标移入时触发的函数
    gotoTarget(index) {
      // this.scrollIndex = index;
      this.clickIndex = index;
      this.activeIndex = index;

      const rightItems = document.querySelectorAll(".rightItem");
      const rightBox = document.querySelector(".right");
      const targetRightItem = rightItems[index];
      /* // 使用 scrollIntoView 方法让目标元素滚动到视图顶部
      targetRightItem.scrollIntoView({ behavior: "smooth", block: "start" }); */

      // 计算目标元素距离父容器顶部的距离
      const offsetTop = targetRightItem.offsetTop - rightBox.offsetTop + 1;

      // 使用 scrollTo 方法让父容器滚动到目标元素的位置
      rightBox.scrollTo({
        top: offsetTop,
        behavior: "smooth", // 如果需要平滑滚动,请确保父容器设置了 scroll-behavior: smooth;
      });
    },
    /** 查询列表 */
    getList() {
      listAllVersion().then((response) => {
        this.versionList = response.data;
        // .concat(response.data)
        // .concat(response.data)
        // .concat(response.data)
        // .concat(response.data);
        this.$nextTick(() => {
          this.checkItemsHover();
        });
      });
    },
  },
};
</script>
<style lang="scss" scoped>
@import "./components/quill.snow.css";
.historyBox {
  height: calc(100vh - 90px);
  ::-webkit-scrollbar {
    width: 6px;
    // height: 24px;
  }

  /* 滚动槽的样式设置 */
  ::-webkit-scrollbar-track {
    background: #eee;
  }

  /* 滚动条滑块的样式设置 */
  ::-webkit-scrollbar-thumb {
    background: rgba(0, 0, 0, 0.1);
    background: rgb(158, 203, 255);
    border-radius: 12px;

    &:hover {
      background: rgb(95, 169, 253);
    }
  }
  .left {
    width: 260px;
    min-width: 260px;
    height: 100%;
    // height: calc(100vh - 117px);
    overflow-y: auto;

    .leftItem {
      display: flex;
      justify-content: space-evenly;
      align-items: center;
      border: 1px solid #eee;
    }
    .isActive {
      border: 1px solid #3f8cff;
      border-left: 4px solid #3f8cff;
      color: #3f8cff;
      background: rgba(63, 140, 255, 0.1);
      font-weight: bold;
    }
  }
  .right {
    box-sizing: border-box;
    width: calc(100% - 260px);
    height: 100%;
    // height: calc(100vh - 117px);
    overflow-y: auto;
    background: #eef6ff;

    .rightItem {
      border: 1px dotted #eef6ff;
      &:hover {
        border: 1px dotted #ddd;
      }
      .w60 {
        width: 60%;
      }
    }
    .isActive {
      // border: 1px dotted #ddd;
      border: 1px dotted #3f8cff;
      // box-shadow: 0px 0px 20px #3f8cff;
      // box-shadow: 0px 5.04px 10.08px rgba(55, 114, 233, 0.22),
      //   inset 0px 5.04px 10.08px rgba(211, 221, 242, 1);
    }
  }
}
</style>

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

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

相关文章

Magma:多模态 AI 智体的基础模型

25年2月来自微软研究、马里兰大学、Wisconsin大学、韩国 KAIST 和西雅图华盛顿大学的论文“Magma: A Foundation Model for Multimodal AI Agents”。 Magma 是一个基础模型&#xff0c;可在数字和物理世界中服务于多模态 AI 智体任务。Magma 是视觉-语言 (VL) 模型的重要扩展…

02_linux系统命令

一、绝对路径与相对路径 1.以 ./ 开始的路径名是相对路径 2.以 / 开始的路径是绝对路径. 相对路径:会随着用户当前所在的目录发生改变. 绝对路径:不会根据用户所在的路径而改变. 3.gcc 编译器 编译器把高级语言(C语言/JAVA语言/C语言)生成二进制代码的一种工具.gcc 是专用…

【leetcode hot 100 11】移动零

一、暴力解法&#xff1a;两个 for 循环&#xff0c;外层循环遍历所有可能的左边界&#xff0c;内层循环遍历所有可能的右边界 class Solution {public int maxArea(int[] height) {int max_area0;for(int i0; i<height.length; i){for(int ji1; j<height.length; j){in…

AI绘画软件Stable Diffusion详解教程(2):Windows系统本地化部署操作方法(专业版)

一、事前准备 1、一台配置不错的电脑&#xff0c;英伟达显卡&#xff0c;20系列起步&#xff0c;建议显存6G起步&#xff0c;安装win10或以上版本&#xff0c;我的显卡是40系列&#xff0c;16G显存&#xff0c;所以跑大部分的模型都比较快&#xff1b; 2、科学上网&#xff0…

轨迹控制--odrive的位置控制---负载设置

轨迹控制 此模式使您可以平滑地使电机旋转&#xff0c;从一个位置加速&#xff0c;匀速和减速到另一位置。 使用位置控制时&#xff0c;控制器只是试图尽可能快地到达设定点。 使用轨迹控制模式可以使您更灵活地调整反馈增益&#xff0c;以消除干扰&#xff0c;同时保持平稳的运…

【安卓逆向】逆向APP界面UI修改再安装

1.背景 有一客户找到我&#xff0c;说能不能把APP首页的底部多余界面去掉。 逆向实战 想要去除安卓应用软件中的内容&#xff0c;需要对APP逆向进行修改再打包。 通过工具 MIT管理器工具 提取APK包&#xff0c;点击apk文件&#xff0c;点击查看反编译apk。 搜索关键字。这里关键…

SAP Webide系列(7)- 优化FreeStyle新建项目预设模板

目录 一、背景 二、优化目标 三、定位调整点 四、调整步骤 五、效果展示 六、附言 一、背景 在每次通过Webide进行FreeStyle方式自开发SAP UI5应用的时候&#xff0c;新建项目&#xff0c;得到的模板文件都是只有很少的内容&#xff08;没有路由配置、没有设置默认全屏等…

python读取sqlite温度数据,并画出折线图

需求&#xff1a; 在Windows下请用python画出折线图&#xff0c;x轴是时间&#xff0c;y轴是温度temperature 和体感温度feels_like_temperature 。可以选择县市近1小时&#xff0c;近1天&#xff0c;近1个月的。sqlite文件weather_data.db当前目录下&#xff0c;建表结构如下…

【Linux网络编程】高效I/O--select/poll服务器

目录 多路转接之select select服务器实现 获取连接 handlerEvent select服务器代码链接 select的优缺点 多路转接之poll poll服务器实现(select服务器改写) poll的优缺点 多路转接之select select的作用 I/O的本质 等 拷贝 多路转接就是通过同时等待多个文件描述…

C语言实战项目(1)---------->猜数字游戏

在学习完循环和选择结构之后&#xff0c;我们可以做一个猜数字游戏。在此项目之前&#xff0c;如果还不会C语言的if语句、switch语句等组成选择结构的语句&#xff0c;while循环、for循环、do-while循环等组成循环结构的语句。可以参考我之前的博客&#xff1a; C语言&#xf…

Failed to start The PHP FastCGI Process Manager.

报错如下&#xff1a; Job for php-fpm.service failed because the control process exited with error code. See "systemctl status php-fpm.service" and "journalctl -xe" for details. 2月 25 21:49:00 nginx systemd[1]: Starting The PHP FastC…

【REST2SQL】15银河麒麟系统下达梦数据库部署REST2SQL

【REST2SQL】01RDB关系型数据库REST初设计 【REST2SQL】02 GO连接Oracle数据库 【REST2SQL】03 GO读取JSON文件 【REST2SQL】04 REST2SQL第一版Oracle版实现 【REST2SQL】05 GO 操作 达梦 数据库 【REST2SQL】06 GO 跨包接口重构代码 【REST2SQL】07 GO 操作 Mysql 数据库 【RE…

晶体管输出光耦和逻辑输出光耦

晶体管输出光耦&#xff08;非线性&#xff09;和逻辑输出光耦&#xff08;线性&#xff09;的区别&#xff1a; 逻辑输出光耦的电流传输特性曲线是非线性的&#xff0c;适合于开关信号的传输&#xff0c;不适合于传输模拟量&#xff1b; 光电晶体管输出光耦的电流传输特性是线…

绕过过滤order by

一、常见绕过技术 1、注释符截断 利用注释符&#xff08;如 --、#&#xff09;截断后续查询&#xff0c;消除过滤逻辑的影响。 ORDER BY 1-- 若原查询为 SELECT * FROM table ORDER BY 用户输入&#xff0c;注入后可能忽略后续过滤逻辑。 2、大小写混淆/编码绕过 若过滤是大…

面试八股文--数据库基础知识总结(1)

1、数据库的定义 数据库&#xff08;DataBase&#xff0c;DB&#xff09;简单来说就是数据的集合数据库管理系统&#xff08;Database Management System&#xff0c;DBMS&#xff09;是一种操纵和管理数据库的大型软件&#xff0c;通常用于建立、使用和维护数据库。数据库系统…

机试刷题_1614. 括号的最大嵌套深度【python】

1614. 括号的最大嵌套深度 class Solution:def maxDepth(self, s: str) -> int:maxD 0if not s:return maxDstack []for char in s:if char(:stack.append(char)maxD max(maxD,len(stack))elif char) :stack.pop()return maxD

VM虚拟机安装与配置Ubuntu Linux操作系统详细教程~

一、下载VM虚拟机 VMware16.0.zip百度网盘下载链接:https://pan.baidu.com/s/1-l-CcAVNINqhRLSiQ26R7w?pwd=tznn 提取码: tznn 二、软件介绍 VMware(虚拟机)是指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统,通过它可在一台电脑上同…

免费PDF工具

Smallpdf.com - A Free Solution to all your PDF Problems Smallpdf - the platform that makes it super easy to convert and edit all your PDF files. Solving all your PDF problems in one place - and yes, free. https://smallpdf.com/#rappSmallpdf.com-解决您所有PD…

组件注册方式、传递数据

组件注册 一个vue组件要先被注册&#xff0c;这样vue才能在渲染模版时找到其对应的实现。有两种注册方式&#xff1a;全局注册和局部注册。&#xff08;组件的引入方式&#xff09; 以下这种属于局部引用。 组件传递数据 注意&#xff1a;props传递数据&#xff0c;只能从父…

异步fifo学习

FIFO 本质是由 RAM 加上读写逻辑构成的先入先出的数据缓冲器。与 RAM 的区别是 FIFO 没有外部读写地址线&#xff0c;顺序写入顺序读出数据&#xff0c;其数据地址是由内部读写指针自增完成&#xff0c;因此 FIFO 在读写时不需要考虑读写冲突的问题。 根据 FIFO 工作的时钟域&a…