JavaScript通用进度条
这是一个结构简单、功能齐全的进度条
进度条效果图
进度条的基本功能
- 进度条的宽度、高度、颜色等基本属性都可以自行调整,怎么好看怎么来
- 监听点击事件和拖拽事件:事件监听会要求传入回调函数,你可以选择往回调函数中传入合适的参数,因此在回调函数中就可以控制其他元素
创建实例示范
let progress = new Progress({
selector: '#progress',
fill: 20, // 初始内部进度为 20%
click: function (scale){ // 进度条点击事件的回调函数
console.log(scale);
},
drag: {
dragging: function (scale){ // 进度条正在被拖拽的回调函数
console.log(scale);
},
dragend: function (scale){ // 进度条拖拽完成时的回调函数
console.log(scale);
}
}
});
创建实例的配置项说明
- 除了
selector
项必填,其他全部可选 - 如果在创建实例时不填
click
项与drag
项,初始化进度条将没有点击事件和拖拽事件 - 当然,也可以后期在合适的地方再添加事件监听,调用实例
progress.progressClick([function])
和progress.progressDrag([function],[function])
函数,可为进度条添加点击事件和拖拽事件监听
config = {
selector: string, // 进度条元素选择器 (必填)
length: string | number, // 进度条总长度
fill: number, // 初始进度,为百分数,值的区间是:0 - 100
click: function, // 监听进度条的点击事件,callback:传入:已经过长度变化后的比例
drag: { // 监听进度条的拖拽事件
dragging: function, // 正在拖动进度条的回调函数, callback: 传入:拖动时进度的 时刻变化比例
dragend: function // 结束拖动进度条的回调函数, callback: 传入:拖动完成后进度的 最终比例
}
};
HTML结构
<div id="progress"> <!-- 进度条整体 -->
<div class="progress-fill"></div> <!-- 进度条内部可移动的部分 -->
</div>
CSS代码
/* 进度条外层 */
#progress{
display: inline-block;
width: 600px; /* 进度条总长度 */
height: 4px;
background-color: rgba(255, 255, 255, 0.4);
position: relative;
top: 0;
left: 0;
}
/* 进度条内部走动的部分 */
.progress-fill{
display: inline-block;
width: 300px; /* 进度条已经过的长度 */
height: 4px;
background-color:rgba(255, 255, 255, 0.9);
position: absolute;
top: 0;
left: 0;
}
/* 伪元素充当小圆点 */
.progress-fill::after{
content: "";
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
background-color:rgba(255, 255, 255, 0.9);
position: absolute;
top: -4px;
right: -6px;
}
进度条JS源码
- 注意:此js文件依赖 jQuery ,此处使用的是 jQuery 1.11.0 版本
- 可直接添加jQuery的cdn引用:
<script src="https://cdn.bootcss.com/jquery/1.11.0/jquery.min.js" type="text/javascript" charset="utf-8"></script>
;(function($, win){
/**
* @description 进度条构造函数
* @param {object} config - 进度条配置项
* @return {object} new Progress()
* @example
* let progress = new Progress({
* selector: '#progress',
* fill: 50,
* click: function (scale){},
* drag: {
* dragging: function (scale){},
* dragend: function (scale){}
* }
* });
*/
function Progress(config) {
return new Progress.prototype.init(config);
}
Progress.prototype = {
constructor: Progress,
/**
* @description 初始化进度条
* @param {object} config - 进度条配置项
* @return {void}
*/
init: function (config){
this.$progress = $(config.selector).eq(0);
this.progress = this.$progress.get(0); // 进度条
this.progressFill = this.progress.children[0]; // 走动的进度条
this.$progressFill = $(this.progressFill);
this.isDragging = false; // 标记进度条是否正在被拖动
this._configure(config); // 对进度条进行配置
},
/**
* @description 根据 config 配置项对进度条进行设置
* @param {object} config - 配置项
* @return {void}
*/
_configure: function _configure(config){
// config: selector,length,fill,click,drag
let value = null;
for (const key of Object.keys(config)) {
value = config[key];
switch (key.toLowerCase()) {
case 'length': this.progressWidth(value); break;
case 'fill': this.progressFillWidth(value); break;
case 'click': this.progressClick(value); break;
case 'drag': this.progressDrag(value.dragging, value.dragend); break;
default: break;
}
}
},
/**
* @description 设置或者返回属性 isDragging ,进度条是否正在被拖动
* @param {[boolean]} drag - true:表示进度条正在被拖拽,false:表示进度条没有被拖拽
* @return {boolean} 当不传入参数时,返回属性 isDragging
*/
isDrag: function (drag){
if(drag === undefined) {
return this.isDragging;
}
this.isDragging = drag;
},
/**
* @description 设置或者返回进度条总长度
* @param {[string | number]} width - 新的长度值 ,如 "50px" 和 50 表示同样的长度
* @return {number} 当不传入参数时,返回进度条的总长度
*/
progressWidth: function (width){
if(width === undefined) {
return this.$progress.width();
}
width = parseFloat(width);
if(typeof width !== 'number') {
return;
}
let oldWidth = this.$progress.width();
let fillWidth = parseFloat(width / oldWidth * this.progressFillWidth()); // 走动进度条在进度条总长度变化后的长度
this.$progress.css('width',width+'px'); // 设置进度条总长度
this.setProgressFillPixel(fillWidth); // 设置走动进度条随比例变化
return width;
},
/**
* @description 设置或者返回走动进度条的长度
* @param {[string | number]} value - 走动进度条新的长度值,如字符 "150px" 表示指定像素长度, 数字 20 表示比例 20%
* @return {number} 当不传入参数时,返回走动进度条的长度
*/
progressFillWidth: function (value){
if(value === undefined) {
return this.$progressFill.width();
}
// 通过像素设置走动进度条的进度
if(typeof value === 'string') {
this.setProgressFillPixel(value);
}
// 通过百分数设置走动进度条的进度
else if(typeof value === 'number') {
if(value > 100) {
this.setProgressFillPixel(value); // 如果 value > 100,就不当做比例了,当做像素值
return;
}
this.setProgressFillPercentage(value);
}
},
/**
* 通过像素设置走动进度条的进度
* @param {number} width - 指定进度条已走过的长度
* @return {number} 走动进度条变化后的长度值
*/
setProgressFillPixel: function(width){
width = parseFloat(width);
if(typeof width !== 'number') {
return;
}
let proWidth = this.$progress.width(); // 进度条总长度
width = width<0 ? 0 : (width>proWidth ? proWidth : width);
this.$progressFill.css('width',width+'px');
return width;
},
/**
* 通过百分数设置走动进度条的进度
* @param {number} percentage - 表示 已经过长度 与 进度条总长度 比例的百分数: 0 - 100
* @return {number} 走动进度条变化后的长度值
*/
setProgressFillPercentage: function(percentage){
percentage = parseFloat(percentage);
if(typeof percentage !== 'number') {
return;
}
percentage = percentage<0 ? 0 : (percentage>100 ? 100 : percentage);
this.$progressFill.css('width',percentage+'%');
return this.progressFillWidth();
},
/**
* @description 监听进度条的点击事件
* @param {function} clickCallback - 点击进度条的回调函数,传入:点击后 已经过长度 与 进度条总长度 的比例
* @return {void}
*/
progressClick: function(clickCallback){
let _this = this;
let offsetLeft = 0; //进度条距离窗口左边的距离
let clickX = 0; //鼠标点击的横坐标位置
let clickLength = 0;//进度条点击后的的长度
let scale = 0; //点击后的长度与进度条总长度的比例
// 监听进度条的点击事件
this.$progress.on('click',function(e){
e = e || window.event;
offsetLeft = $(this).offset().left; // 获取进度条距离窗口左边的距离
clickX = e.pageX; // 获取鼠标点击的横坐标
clickLength = clickX - offsetLeft; // 进度条点击的长度
// 设置走动进度条的长度
_this. setProgressFillPixel(clickLength);
// 计算点击长度与总长度的比例;注意 toFixed方法的返回值为 string 类型
scale = clickLength / _this.progressWidth();
scale = parseFloat(scale.toFixed(4));
// 将比例返回给外界调用者
if(typeof clickCallback === 'function') {
clickCallback(scale);
}
});
},
/**
* @description 监听进度条的拖动事件
* @param {function} draggingCallback - 正在拖动进度条的回调函数,传入:拖动长度的 时刻变化比例
* @param {function} dragEndCallback - 结束拖动进度条的回调函数, 传入:拖动长度的最终比例
* @return {void}
*/
progressDrag: function (draggingCallback, dragEndCallback){
let _this = this;
let progressWidth = 0; // 进度条总长度
let offsetLeft = 0; // 获取进度条距离窗口左边的距离
let clickX = 0; // 鼠标点击的位置
let moveLength = 0; // 拖拽的长度
let scale = 0; // 拖动的长度与进度条总长度的比例
// 监听进度条的鼠标按下事件
this.$progress.on('mousedown',function(){
progressWidth = _this.progressWidth();
offsetLeft = _this.$progress.offset().left;
// 监听文档的鼠标移动事件
$(document).on('mousemove',function(ev){
ev = ev || window.event;
clickX = ev.pageX; // 获取鼠标点击的距离
moveLength = clickX - offsetLeft;// 获取拖拽的长度
// 是否超出进度条左边界 0 ,是否超出进度条右边界 progressWidth
moveLength = moveLength<0 ? 0 : (moveLength>progressWidth ? progressWidth : moveLength);
// 计算拖拽后的长度与总长度的比例,保留四位小数;
scale = parseInt((moveLength / progressWidth)*10000) / 10000;
// 将 拖动进度条时刻变化的比例 返回给外界调用者
if(typeof draggingCallback === 'function'){
draggingCallback(scale);
}
// 进度条是否正在被拖拽,正在拖拽
_this.isDrag(true);
// 更新进度
_this.setProgressFillPixel(moveLength);
});
// 监听文档的鼠标抬起事件
$(document).on('mouseup',function(){
// document 一定要移除 mousemove事件 和 mouseup 事件
$(document).off('mousemove');
$(document).off('mouseup');
// 进度条是否正在被拖拽,已结束拖拽
_this.isDrag(false);
// 将 拖动进度条的最终比例 返回给外界调用者
if(typeof dragEndCallback === 'function'){
dragEndCallback(scale);
}
});
return false;
});
}
};
Progress.prototype.init.prototype = Progress.prototype;
win.Progress = Progress;
}(window.jQuery,window));