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

Vue3 + TypeScript 实现 PC 端鼠标横向拖动滚动

功能说明

​​拖动功能​​:

  • 鼠标按下时记录初始位置和滚动位置
  • 拖动过程中计算移动距离并更新滚动位置
  • 松开鼠标后根据速度实现惯性滚动

​​滚动控制​​:

  • 支持鼠标滚轮横向滚动(通过 wheel 事件)
  • 自动边界检测防止滚动超出内容范围

实现代码

<template><div ref="scrollContainer" class="horizontal-scroll-container"@mousedown="startDrag"@mousemove="onDrag"@mouseup="stopDrag"@mouseleave="stopDrag"><div class="scroll-content"><div v-for="(item, index) in items" :key="index" class="item">{{ item }}</div></div></div>
</template><script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'// 定义滚动容器引用
const scrollContainer = ref<HTMLElement | null>(null)// 定义滚动内容数据
const items = ref<string[]>(Array.from({ length: 20 }, (_, i) => `Item ${i + 1}`))// 拖动状态变量
let isDragging = false
let startX = 0
let scrollLeft = 0
let lastTime = 0
let velocity = 0// 开始拖动
const startDrag = (e: MouseEvent): void => {if (!scrollContainer.value) returnisDragging = truestartX = e.pageX - scrollContainer.value.getBoundingClientRect().leftscrollLeft = scrollContainer.value.scrollLeftlastTime = performance.now()scrollContainer.value.style.cursor = 'grabbing'
}// 拖动中
const onDrag = (e: MouseEvent): void => {if (!isDragging || !scrollContainer.value) returnconst x = e.pageX - scrollContainer.value.getBoundingClientRect().leftconst walk = (x - startX) * 1.5 // 调整滚动速度系数scrollContainer.value.scrollLeft = scrollLeft - walk// 计算速度(用于惯性滚动)const now = performance.now()velocity = (x - startX) / (now - lastTime)lastTime = now
}// 停止拖动
const stopDrag = (): void => {if (!isDragging || !scrollContainer.value) returnisDragging = falseif (Math.abs(velocity) > 0.1) {requestAnimationFrame(inertiaScroll)}scrollContainer.value.style.cursor = 'grab'
}// 惯性滚动
const inertiaScroll = (): void => {if (!scrollContainer.value || Math.abs(velocity) < 0.01) returnscrollContainer.value.scrollLeft += velocity * 10velocity *= 0.95 // 摩擦系数requestAnimationFrame(inertiaScroll)
}// 边界检测
const checkBounds = (): void => {if (!scrollContainer.value) returnconst containerWidth = scrollContainer.value.clientWidthconst contentWidth = scrollContainer.value.scrollWidthif (scrollContainer.value.scrollLeft < 0) {scrollContainer.value.scrollLeft = 0} else if (scrollContainer.value.scrollLeft > contentWidth - containerWidth) {scrollContainer.value.scrollLeft = contentWidth - containerWidth}
}// 鼠标滚轮横向滚动
const handleWheel = (e: WheelEvent): void => {if (!scrollContainer.value) returne.preventDefault()scrollContainer.value.scrollLeft += e.deltaYcheckBounds()
}// 生命周期钩子
onMounted(() => {if (scrollContainer.value) {scrollContainer.value.addEventListener('wheel', handleWheel, { passive: false })}
})onUnmounted(() => {if (scrollContainer.value) {scrollContainer.value.removeEventListener('wheel', handleWheel)}
})
</script><style scoped>
.horizontal-scroll-container {width: 100%;overflow-x: auto;white-space: nowrap;cursor: grab;height: 220px; /* 确保容器有固定高度 */border: 1px solid #eee;border-radius: 8px;padding: 10px;box-sizing: border-box;
}.horizontal-scroll-container:active {cursor: grabbing;
}.scroll-content {display: inline-block;
}.item {display: inline-block;width: 200px;height: 200px;margin-right: 10px;background: #f0f0f0;display: flex;align-items: center;justify-content: center;font-size: 20px;border: 1px solid #ddd;box-sizing: border-box;border-radius: 4px;transition: transform 0.2s ease, box-shadow 0.2s ease;
}.item:hover {transform: scale(1.02);box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
</style>
http://www.xdnf.cn/news/3313.html

相关文章:

  • 【蓝桥杯】第十六届蓝桥杯C/C++大学B组个人反思总结
  • 高性能架构设计-数据库(读写分离)
  • OpenHarmony - 小型系统内核(LiteOS-A)(十七)标准库
  • 加速LLM大模型推理,KV缓存技术详解与PyTorch实现
  • java: 警告: 源发行版 21 需要目标发行版 21
  • PostgreSQL的COALESCE 函数用法
  • 慧星云支持 Qwen3:开启智算新生态,共筑高效 AI 未来
  • WebGL图形编程实战【5】:层次构建 × Shader初始化深度剖析
  • 基于ssm的校园旧书交易交换平台(源码+文档)
  • Microsoft Entra ID 详解:现代身份与访问管理的核心
  • 三分钟了解自动拆箱封箱操作
  • Pillow 移除或更改了 FreeTypeFont.getsize() 方法
  • mac下载homebrew 安装和使用git
  • SimFlow: 基于OpenFOAM的CFD求解器
  • 积木报表的 API 数据集 (附Demo图文)
  • JavaAPI — 日期与集合
  • Spring MVC @RequestParam 注解怎么用?如何处理可选参数和默认值?
  • 温补晶振(TCXO)稳定性优化:从实验室到量产的关键技术
  • 【爬虫】deepseek谈爬虫工具
  • Java 多线程进阶:什么是线程安全?
  • 如何在 Linux 环境下使用 Certbot 自动生成 SSL 证书并部署到 Nginx 服务中
  • 【论文阅读】APMSA: Adversarial Perturbation Against Model Stealing Attacks
  • 7.软考高项(信息系统项目管理师)-资源管理
  • C++初阶-string类2
  • [PRO_A7] SZ501 FPGA开发板简介
  • Roboflow标注数据集
  • crashpad 编译
  • 时态--00--总述
  • 1254. 【动态规划】单词的划分
  • KUKA机器人不同的用户权限详细介绍