js 自定义滚动条
效果图
需求分析
- 滚轮滚动带动内容滚动
- 滚轮拖动带动内容拖动
页面结构
<div class="wrap">
<div class="bar">
</div>
<div class="show">
<img src="https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2529206747.webp" alt="">
<img src="https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2561305376.webp" alt="">
<img src=" https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2315672647.webp" alt="">
<img src=" https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2563780504.webp" alt="">
<img src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p480747492.webp" alt="">
<img src="https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2557573348.webp" alt="">
<img src=" https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2457983084.webp" alt="">
<img src=" https://img1.doubanio.com/view/photo/s_ratio_poster/public/p501177648.webp" alt="">
<img src="https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2498971355.webp" alt="">
<img src="https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2551995207.webp" alt="">
<img src=" https://img1.doubanio.com/view/photo/s_ratio_poster/public/p1832875827.webp" alt="">
<img src=" https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2549648344.webp" alt="">
<img src="https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2516578307.webp" alt="">
<img src="https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2552058346.webp" alt="">
<img src=" https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2537158013.webp" alt="">
<img src=" https://img9.doubanio.com/view/photo/s_ratio_poster/public/p513344864.webp" alt="">
</div>
</div>
调用方式
new Scroll({
bar: '.bar',
wrap: '.wrap',
show: '.show'
})
js代码
class Scroll {
constructor(option) {
this.init(option)
}
init(option) {
this.bar = document.querySelector(option.bar);
this.wrap = document.querySelector(option.wrap);
this.show = document.querySelector(option.show);
this.exchange = this.show.clientHeight / (this.wrap.offsetHeight);
this.scroll = 0
this.initBar(); //初始化滚动条
this.bindEvent(); //绑定事件
}
initBar() {
if (this.wrap.offsetHeight >= this.show.offsetHeight) { //判断显示内容是否超出父元素,如果没有则隐藏滚动条
this.bar.style.display = 'none';
} else {
this.bar.style.height = this.wrap.offsetHeight * this.wrap.offsetHeight / this.show
.clientHeight + 'px'; //如果超出滚动条的高度
}
}
bindEvent() {
this.wrap.onmousewheel = (ev) => {
if (this.wrap.offsetHeight >= this.show.offsetHeight) { //如果没有超出,取消滚轮事件
return;
}
let e = ev || event;
e.preventDefault();
if (e.wheelDelta < 0) {
this.scroll += 10;//滚轮每次滚动,滚动条增加
if (this.scroll > this.wrap.offsetHeight - this.bar.offsetHeight) {
this.scroll = this.wrap.offsetHeight - this.bar.offsetHeight;
}
this.show.style.top = -this.scroll * this.exchange + 'px';
this.bar.style.top = this.scroll + 'px';
} else {
this.scroll -= 10;
if (this.scroll < 0) {
this.scroll = 0;
}
this.show.style.top = -this.scroll * this.exchange + 'px';
this.bar.style.top = this.scroll + 'px';
}
}
this.bar.onmousedown = (ev) => {
let e = ev || event;
e.preventDefault();
e.stopPropagation();
let to_t = e.clientY - this.bar.offsetTop;
this.bar.style.background = 'maroon'
document.onmousemove = (ev) => {
let e = ev || event;
let t = e.clientY - to_t;
if (e.clientX < this.wrap.offsetLeft || e.clientX > this.wrap.offsetLeft + this.wrap
.offsetWidth +
100) {
return;
}
if (t < 0) {
t = 0;
} else if (t > this.wrap.offsetHeight - this.bar.offsetHeight) {
t = this.wrap.offsetHeight - this.bar.offsetHeight;
}
this.show.style.top = -t * this.exchange + 'px';
this.bar.style.top = t + 'px';
this.scroll = t;
}
document.onmouseup = () => {
this.bar.style.background = 'lightgrey'
document.onmousemove = null;
}
this.wrap.onmouseup = (ev) => {
this.bar.style.background = 'lightgrey'
document.onmousemove = null;
}
}
}
}
主要利用滚轮滚动的方向计算自定义滚动条的top值,然后根据置换比例算出内容的top值,拖拽原理类似。