目的:
1. 练习手写滚动条
2. 市面上多是竖向滚动条,横向滚动条较少
3. 横向滚动条,需要滑动到容器底部才能使用,不方便,因此想自己写一个横向滚动条放置在容器内部的视口高度的最低处
3. 问题复现:
如果容器的内容超过了容器的宽度,就会出现横向滚动条(暂不考虑换行),但是如果该容器的高度过高,用户需要滑到容器的底部才能操作横向滚动条(横向滚动条默认在容器的底部,当然我们不考虑使用shift+鼠标左键的方式横向移动)
问题演示视频:
<iframe allowfullscreen="true" data-mediaembed="csdn" frameborder="0" id="gkPmxp3y-1723084633429" src="https://live.csdn.net/v/embed/415892"></iframe>横向滚动条-问题演示
制作横向滚动条
样式:
滚动条包含两个方面:track(滚动轨道) + thumb(滚动块)
最开始是只有content容器的,然后我们在content下面添加横向滚动条容器,并且在最外层添加box容器。
最外层的box是相对定位(没有宽高),滚动条是绝对定位
.box {
position: relative;
}
.content {
width: 100px;
height: 1000px;
background-color: pink;
overflow: auto;
}
.content::-webkit-scrollbar {
display: none;
}
.track {
position: absolute;
left: 0;
bottom: 0; /*0<=bottom<=1000-10px*/
width: 100px;
height: 10px;
background-color: red;
}
.thumb {
cursor: grab;
position: absolute;
left: 0;
top: 0;
width: 10px;
height: 100%;
background-color: blue;
}
<div class="box">
<div class="content">
asdawdkjaslkdjalkwjdlkasjdlawkldakslldjawlkdjlkasjdkawdasdawes
asdawdkjaslkdjalkwjdlkasjdlawkldakslldjawlkdjlkasjdkawdasdawes
asdawdkjaslkdjalkwjdlkasjdlawkldakslldjawlkdjlkasjdkawdasdawes
</div>
<div class="track" id="scrollbar">
<div class="thumb" id="scrollbar-thumb"></div>
</div>
</div>
逻辑:
监听容器横向滚动,同步滑块位置
监听content容器的滚动动作,同步到滑块的位置
const content = document.querySelector(".content")
const track = document.querySelector(".track")
const thumb = document.querySelector(".thumb")
function updateScrollbar() {
const scrollPercentage =
content.scrollLeft / (content.scrollWidth - content.clientWidth)
const thumbPosition =
scrollPercentage * (track.clientWidth - thumb.clientWidth)
thumb.style.left = thumbPosition + "px"
}
// content(这样还包括了shift+鼠标左键)
content.addEventListener("scroll", updateScrollbar)
拖动滑块
然后,我们再来制作拖动滑块同时横向移动容器的功能,主要用到三个动作,mousedown,mousemove,mouseup
// 监听滑块拖动事件
let isDragging = false
let startX
let startScrollLeft
thumb.addEventListener("mousedown", function (e) {
isDragging = true
startX = e.clientX
startScrollLeft = content.scrollLeft
// 拖动开始时改变鼠标样式为正在抓取
thumb.style.cursor = "grabbing"
// 防止在拖动时选择文本
e.preventDefault()
})
document.addEventListener("mousemove", function (e) {
if (isDragging) {
const deltaX = e.clientX - startX
const scrollDelta =
(deltaX / track.clientWidth) *
(content.scrollWidth - content.clientWidth)
content.scrollLeft = startScrollLeft + scrollDelta
}
})
document.addEventListener("mouseup", function () {
isDragging = false
})
规定横向滚动条的位置的界限
(横向滚动条的位置最低不低于容器的边界底部,最高不高于容器的边界顶部)
let contentRec = content.getBoundingClientRect()//得到content容器的边界
track.style.bottom =
content.clientHeight - (window.innerHeight - contentRec.top) + "px"
let trackBottom = parseInt(track.style.bottom) // 获取轨道的底部位置
if (
trackBottom <= 0 ||
trackBottom >= content.clientHeight - track.clientHeight
) {
track.style.bottom = "0px" // 设置时加上单位
}
// 更新 track.style.bottom 的逻辑
document.addEventListener("scroll", function () {
let viewHeight = window.innerHeight + scrollY
contentRec = content.getBoundingClientRect()
// 计算新的 bottom 值
let newBottom =
content.clientHeight - (window.innerHeight - contentRec.top)
// 确保 newBottom 不小于 0 且不大于 content.clientHeight - track.clientHeight
newBottom = Math.max(
0,
Math.min(newBottom, content.clientHeight - track.clientHeight)
)
// 更新 track 的 bottom 样式
track.style.bottom = `${newBottom}px`
})
成品
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.header {
width: 100px;
height: 1000px;
background-color: skyblue;
}
.footer {
width: 100px;
height: 300px;
background-color: green;
}
.box {
position: relative;
}
.content {
width: 100px;
height: 1000px;
background-color: pink;
overflow: auto;
}
.content::-webkit-scrollbar {
display: none;
}
.track {
position: absolute;
left: 0;
bottom: 0; /*0<=bottom<=1000-10px*/
width: 100px;
height: 10px;
background-color: red;
}
.thumb {
cursor: grab;
position: absolute;
left: 0;
top: 0;
width: 10px;
height: 100%;
background-color: blue;
}
</style>
</head>
<body>
<div class="header"></div>
<div class="box">
<div class="content">
asdawdkjaslkdjalkwjdlkasjdlawkldakslldjawlkdjlkasjdkawdasdawes
asdawdkjaslkdjalkwjdlkasjdlawkldakslldjawlkdjlkasjdkawdasdawes
asdawdkjaslkdjalkwjdlkasjdlawkldakslldjawlkdjlkasjdkawdasdawes
asdawdkjaslkdjalkwjdlkasjdlawkldakslldjawlkdjlkasjdkawdasdawes
asdawdkjaslkdjalkwjdlkasjdlawkldakslldjawlkdjlkasjdkawdasdawes
asdawdkjaslkdjalkwjdlkasjdlawkldakslldjawlkdjlkasjdkawdasdawes
</div>
<!-- 我觉得这个滚动条应该是不能在内容容器内部的 -->
<div class="track" id="scrollbar">
<div class="thumb" id="scrollbar-thumb"></div>
</div>
</div>
<div class="footer"></div>
<script>
const content = document.querySelector(".content")
const track = document.querySelector(".track")
const thumb = document.querySelector(".thumb")
// console.log("window.innerHeight", window.innerHeight)
// track.style.bottom = window.innerHeight + "px"
let contentRec = content.getBoundingClientRect()
track.style.bottom =
content.clientHeight - (window.innerHeight - contentRec.top) + "px"
function updateScrollbar() {
const scrollPercentage =
content.scrollLeft / (content.scrollWidth - content.clientWidth)
const thumbPosition =
scrollPercentage * (track.clientWidth - thumb.clientWidth)
thumb.style.left = thumbPosition + "px"
}
// content(这样还包括了shift+鼠标左键)
content.addEventListener("scroll", updateScrollbar)
// 提取数值进行比较
let trackBottom = parseInt(track.style.bottom) // 将字符串转换为整数
if (
trackBottom <= 0 ||
trackBottom >= content.clientHeight - track.clientHeight
) {
track.style.bottom = "0px" // 设置时加上单位
}
// 更新 track.style.bottom 的逻辑
document.addEventListener("scroll", function () {
let viewHeight = window.innerHeight + scrollY
contentRec = content.getBoundingClientRect()
// 计算新的 bottom 值
let newBottom =
content.clientHeight - (window.innerHeight - contentRec.top)
// 确保 newBottom 不小于 0 且不大于 content.clientHeight - track.clientHeight
newBottom = Math.max(
0,
Math.min(newBottom, content.clientHeight - track.clientHeight)
)
// 更新 track 的 bottom 样式
track.style.bottom = `${newBottom}px`
console.log(track.style.bottom)
})
// 监听滑块拖动事件
let isDragging = false
let startX
let startScrollLeft
thumb.addEventListener("mousedown", function (e) {
isDragging = true
startX = e.clientX
startScrollLeft = content.scrollLeft
// 拖动开始时改变鼠标样式为正在抓取
thumb.style.cursor = "grabbing"
// 防止在拖动时选择文本
e.preventDefault()
})
document.addEventListener("mousemove", function (e) {
if (isDragging) {
const deltaX = e.clientX - startX
const scrollDelta =
(deltaX / track.clientWidth) *
(content.scrollWidth - content.clientWidth)
content.scrollLeft = startScrollLeft + scrollDelta
}
})
document.addEventListener("mouseup", function () {
isDragging = false
})
</script>
</body>
</html>
演示视频:
<iframe allowfullscreen="true" data-mediaembed="csdn" frameborder="0" id="pVXaJowX-1723080648922" src="https://live.csdn.net/v/embed/415737"></iframe>横向滚动条
标签:content,style,bottom,track,clientHeight,滚动条,html,css From: https://blog.csdn.net/Java_Coder2021/article/details/140945223