<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JavaScript 原生实现进度条组件</title>
<style>
* {
margin: 0;
padding: 0;
}
.container {
width: 500px;
height: 400px;
position: absolute;
top: 50%;
left: 50%;
margin-top: -200px;
margin-left: -250px;
background-color: rgba(0, 0, 0, 0.5);
}
.container .slider {
width: 100%;
border-radius: 10px;
height: 20px;
border: 2px #eeeeee solid;
background-color: white;
position: absolute;
bottom: 20px;
box-sizing: border-box;
}
.container .slider .point {
width: 20px;
height: 20px;
background-color: #6ac2f5;
position: absolute;
top: 50%;
left: 0;
margin-top: -10px;
border-radius: 50%;
border: 2px #000000 solid;
box-sizing: border-box;
pointer-events: none;
}
.container .slider .progress {
width: 10px;
height: 100%;
background-color: #07c160;
border-radius: 10px;
pointer-events: none;
}
</style>
</head>
<body>
<div class="container">
<div class="slider" id="slider"></div>
</div>
<script>
function Slider(options) {
if (typeof options !== "object") {
return false;
}
this.id = options.el || "slider";
this.onchange = options.onchange;
this.state = {
isPress: false
};
this.init();
}
Slider.prototype.init = function() {
this.el = document.querySelector(this.id);
if (!this.el || this.el.nodeType !== 1) {
return false;
}
this.point = this.createElement("point");
this.progress = this.createElement("progress");
this.el.append(this.progress, this.point);
this.sliderWidth = this.el.clientWidth;
this.pointWidth = this.point.clientWidth;
this.addEvents(this.el);
};
Slider.prototype.createElement = function(tag) {
var el = document.createElement("div");
el.setAttribute("id", tag);
el.setAttribute("class", tag);
return el;
};
// 监听事件
Slider.prototype.addEvents = function(target) {
var _this = this;
target.addEventListener("mousedown", this.mousedown.bind(_this), false);
document.addEventListener("mousemove", this.mousemove.bind(_this), false);
document.addEventListener("mouseup", this.mouseup.bind(_this), false);
// 当窗口改变重新计算
window.addEventListener("resize", this.debounce(function() {
_this.sliderWidth = _this.el.clientWidth;
_this.pointWidth = _this.point.clientWidth;
}, 500));
this.callThrottle = this.throttle(function(x) {
_this.moveTo(x);
}, 100);
this.callDebounce = this.debounce(function(x) {
_this.moveTo(x);
}, 200);
};
Slider.prototype.mousedown = function(e) {
this.callDebounce(e.offsetX);
this.state.isPress = true;
};
Slider.prototype.mousemove = function(e) {
if (this.state.isPress) {
var offsetX = e.offsetX;
var sliderWidth = this.sliderWidth;
if (offsetX >= 0 && offsetX <= sliderWidth) {
this.callThrottle(offsetX);
}
}
};
// 封装节流方法
Slider.prototype.throttle = function(callback, interval) {
var timestamp = Date.now();
return function(e) {
var currentTime = Date.now();
if (currentTime - timestamp >= interval) {
callback && callback(e);
timestamp = Date.now();
}
};
};
// 封装防抖方法
Slider.prototype.debounce = function(callback, delay) {
var timer = 0;
return function(e) {
timer && clearTimeout(timer);
timer = setTimeout(function() {
callback && callback(e);
timer = 0;
}, delay);
};
};
/*
* 移动滑块和进度条
* 计算移动限制
* 返回onchange回调进度percent
* */
Slider.prototype.moveTo = function(x) {
var sliderWidth = this.sliderWidth;
var pointWidth = this.pointWidth;
var half = pointWidth / 2;
var percent = x / sliderWidth;
if (x <= sliderWidth - pointWidth) {
this.point.style.left = x + "px";
} else {
this.point.style.left = sliderWidth - pointWidth + "px";
percent = 1;
}
if (x >= half && x <= sliderWidth - half) {
this.progress.style.width = x + half + "px";
} else if (x <= half) {
this.progress.style.width = half + "px";
percent = 0;
} else if (x >= sliderWidth - half) {
this.progress.style.width = sliderWidth - half + "px";
percent = 1;
}
this.onchange && this.onchange(percent);
};
Slider.prototype.mouseup = function(e) {
if (this.state.isPress) {
this.state.isPress = false;
}
};
// 初始化Slider插件
var slider = new Slider({
el: "#slider",
// 进度变化回调函数
onchange: function(e) {
console.log("change", e);
}
});
</script>
</body>
</html>
网友评论