JavaScript 原生实现进度条组件

<!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>
 跨浏览器,可兼容IE7--IE10, FireFox, Chrome, Opera等几大内核的浏览器,且不需要浏览器再加装任何控件。  多系统兼容性、可移植性:由于只包括前台UI,因此二次开发者可很方便将本插件用在任何一种需要流程图的B/S系统应用上,流程图的详细实现逻辑完全交于后台程序开发者自己实现;对于后台,只要能返回/接收能被本插件解析的JSON格式数据即可.所以本插件可用于不同的服务器语言建立的后台上.  跨领域:流程图设计器不止用在电信领域,在其它需要IT进行技术支持的领域中都有重大作用.  以下从纯技术实现层面具体描述:  页面顶部栏、左边侧边栏均可自定义;  当左边的侧边栏设为不显示时,为只读状态,此时的视图区可当作是一个查看器而非编辑器。  侧边工具栏除了基本和一些流程节点按钮外,还自定义新的节点按钮,自定义节点都可以有自有的图标、类型名称,定义后在使用可可在工作区内增加这些自定义节点。  顶部栏可显示流程图数据组的标题,也可提供一些常用操作按钮。  顶部栏的按钮,除了撤销、重做按钮外,其余按钮均可自定义点击事件。  可画直线、折线;折线还可以左右/上下移动其中段。  具有区域划分功能,能让用户更直观地了解哪些节点及其相互间的转换,是属于何种自定义区域内的。  具有标注功能,用橙红色标注某个结点或者转换线,一般用在展示流程进度时。  能直接双击结点、连线、分组区域中的文字进行编辑  在对结点、连线、分组区域的各种编辑操作,如新增/删除/修改名称/重设样式或大小/移动/标注时,均可捕捉到事件,并触发自定义事件,如果自定义事件执行的方法返回FALSE,则会阻止操作。  具有操作事务序列控制功能,在工作区内的各种有效操作都能记录到一个栈中,然后可以进行撤销(undo())或重做(redo()),像典型的C/S软件一样。  0.4版中,加入了只导出在初始载入后被编辑的流程图中,只作了增删改等变更的元素,这样可用于用户快速存储,只保存本次变更过的内容,不用重新保存整个流程。  0.5版中,结点的样式不再受到原有程序的限制,所有样式均默认为淡蓝色长方形;如果要指定为圆形,可在初始化时定义结点类型为”原有类型”+” round”;如果要指定为复合结点,则可在初始化时定义结点类型为”原有类型”+” mix”。”原有类型”+” myType”:myType可为自己写的一种特殊样式类.  0.6版中,修正了一些BUG,改善了用户操作体验,并增加在可编辑状态下时,能用键盘上DELETE按键对元素进行删除功能。  0.7版中,修正了一些BUG,增加了连线变更要连的起始结点或结束结点的功能。  0.8版,取消原来的拟物化页面,变成如今的扁平化页面,并且支持主要位置的颜色自定义功能(如果想沿用原来老版本中的拟物化页面,只需保留原来的GooFlow.css文件即可);修正0.7版中的画线BUG。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值