web浏览器拖拽橡皮筋效果+同步进度条

问了 ChatGPT,实现了拖拽橡皮筋效果。

但再让它增加一个同步进度条的时候,怎么问也给不出代码了,给的都是错的。于是我一怒之下怒了一下,决定手动修改。

这个是完整的 html 文件,直接复制粘贴自己看效果吧。说明文字也在代码里了。

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>拖拽橡皮筋+同步进度条</title>
		<style>
			#container {
				position: relative;
				width: 300px;
				height: 200px;
				overflow: hidden;
				border: 1px solid #ccc;
			}
			#draggable {
				position: absolute;
				width: 100%;
				background-color: white;
				border: 1px solid blue;
				top: 0;
				transition: top 0.5s ease; /* 仅在回弹时使用动画 */
			}
			.list-item {
				padding: 10px;
				border-bottom: 1px solid #ddd;
			}

			#scroll-container {
				position: absolute;
				left: 330px;
				height: 200px;
				width: 10px;
				background-color: #fff;
				border: 1px solid black;
				top: 8px;
				overflow: hidden;
			}

			#scrollbar {
				position: absolute;
				background-color: grey;
				width: 100%;
			}
		</style>
	</head>
	<body>
		<div id="container">
			<div id="draggable">
				<div class="list-item">Item 1</div>
				<div class="list-item">Item 2</div>
				<div class="list-item">Item 3</div>
				<div class="list-item">Item 4</div>
				<div class="list-item">Item 5</div>
				<div class="list-item">Item 6</div>
				<div class="list-item">Item 7</div>
				<div class="list-item">Item 8</div>
				<div class="list-item">Item 9</div>
				<div class="list-item">Item 10</div>
				<div class="list-item">Item 11</div>
				<div class="list-item">Item 12</div>
				<div class="list-item">Item 13</div>
				<div class="list-item">Item 14</div>
				<div class="list-item">Item 15</div>
			</div>
		</div>
		<div id="scroll-container">
			<div id="scrollbar"></div>
		</div>

		<div>1. 拖拽列表可以滑动,滑块位置也会同步。拖拽滑块也会同步列表位置。</div>
		<div>2. 拖拽到顶部和底部且继续拖拽,然后再松手时,会出现橡皮筋效果。</div>
		<div>3. 无法通过鼠标滑轮来实现滑动,这里的拖拽滑动本质上只是在操作 top 值。</div>

		<script>
			document.addEventListener('DOMContentLoaded', function () {
				const container = document.getElementById('container')
				const containerHeight = container.clientHeight
				const draggable = document.getElementById('draggable')
				const draggableHeight = draggable.offsetHeight
				const draggableMinTop = containerHeight - draggableHeight // 拖拽容器的最小 top 值(负数)

				const lists = document.querySelectorAll('.list-item') // 列表项
				const listCount = lists.length // 列表项个数
				const listItemHeight = lists[0].clientHeight // 列表项的单个高度

				const scrollContainer = document.getElementById('scroll-container') // 滑槽
				const scrollContainerHeight = scrollContainer.clientHeight
				const scrollbar = document.getElementById('scrollbar') // 滑槽上的滑块
				const scrollbarPercentageHeight = (containerHeight / (listCount * listItemHeight)) * 100 // 滑块高度所占滑槽的百分比
				scrollbar.style.height = `${scrollbarPercentageHeight}%`
				const scrollbarHeight = scrollbar.clientHeight // 滑块的 px 高度
				const scrollbarMaxTop = scrollContainerHeight - scrollbarHeight // 滑块的最大 top 值

				const scrollbarRestPercent = 100 - scrollbarPercentageHeight // 滑槽高度减去滑块高度后,剩余区域所占的百分比
				const scrollbarRestPX = (container.clientHeight * scrollbarRestPercent) / 100 // 滑槽高度减去滑块高度后,剩余区域所占的 px

				let isDragging = false // 是否正在拖拽 #draggable 元素
				let initialY // 临时变量, 记录 #draggable 元素的下次初始位置

				draggable.addEventListener('mousedown', function (e) {
					isDragging = true
					initialY = e.clientY - draggable.offsetTop
					container.style.cursor = 'grabbing'

					// 禁用动画效果以便拖动时立即响应
					draggable.style.transition = 'none'
					scrollbar.style.transition = `none`
				})

				document.addEventListener('mousemove', function (e) {
					if (isDragging) {
						const offsetY = e.clientY - initialY // 得到拖拽元素的 Y 偏移值

						// 修改滑块的 top 值以实现同步效果
						if (offsetY < 0) {
							const scrolled = Math.abs(offsetY) / Math.abs(draggableMinTop)
							const scrollbarTop = scrolled * scrollbarRestPX
							scrollbar.style.top = `${scrollbarTop}px`
						} else if (offsetY > 0) {
							const scrolled = offsetY / Math.abs(draggableMinTop)
							const scrollbarTop = scrolled * scrollbarRestPX
							scrollbar.style.top = `${-scrollbarTop}px`
						}

						draggable.style.top = `${offsetY}px`
					}
				})

				document.addEventListener('mouseup', function () {
					if (isDragging) {
						isDragging = false
						container.style.cursor = 'default'
						const topValue = parseInt(draggable.style.top, 10)

						// 给回弹启用动画效果, 防止瞬间回弹
						draggable.style.transition = 'top 0.5s ease'
						scrollbar.style.transition = `top 0.5s ease`

						if (topValue > 0) {
							// 如果 `top` 大于0,恢复到容器顶部
							draggable.style.top = '0px'
							scrollbar.style.top = '0px'
						} else if (topValue < draggableMinTop) {
							// 如果 `top` 值小到使底边超出容器底部,恢复底边贴到容器底边
							draggable.style.top = `${draggableMinTop}px`

							// 同样地,对滚动条的滑块做出恢复的操作
							scrollbar.style.top = `${scrollbarMaxTop}px`
						}
					}
				})

				document.addEventListener('mouseleave', function () {
					if (isDragging) {
						isDragging = false
						container.style.cursor = 'default'
						draggable.style.transition = 'top 0.5s ease' // 重新启用动画效果
						const topValue = parseInt(draggable.style.top, 10)

						if (topValue > 0) {
							draggable.style.top = '0px' // 如果 `top` 大于0,恢复到容器顶部
						} else if (topValue < draggableMinTop) {
							// 如果 `top` 值小到使底边超出容器底部,恢复底边贴到容器底边
							draggable.style.top = `${draggableMinTop}px`
						}
					}
				})

				let isDraggingScrollbar = false // 是否正在拖拽滑块
				let initialScrollbarY = 0 // 临时变量, 记录滑块元素的下次初始位置
				scrollbar.addEventListener('mousedown', function (e) {
					isDraggingScrollbar = true

					draggable.style.transition = 'none'
					scrollbar.style.transition = 'none'
					initialScrollbarY = e.clientY - scrollbar.offsetTop
				})

				scrollbar.addEventListener('mousemove', function (e) {
					if (isDraggingScrollbar) {
						const scrollbarOffsetY = e.clientY - initialScrollbarY

						// 滑块拖拽到顶部或底部后, 不再移动
						if (scrollbarOffsetY < 0 || scrollbarOffsetY > scrollbarMaxTop) return

						// 否则移动滑块
						scrollbar.style.top = `${scrollbarOffsetY}px`
						// 并同步列表容器的偏移量
						const offsetYPercentage = scrollbarOffsetY / scrollbarMaxTop // 滑块偏移的百分比
						const neededDraggableOffsetY = offsetYPercentage * Math.abs(draggableMinTop)
						draggable.style.top = `${-neededDraggableOffsetY}px`
					}
				})

				scrollbar.addEventListener('mouseleave', function () {
					isDraggingScrollbar = false
				})
			})
		</script>
	</body>
</html>
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值