原生js实现滑块区间组件


Posted in Javascript onJanuary 20, 2021

本文实例为大家分享了js实现滑块区间组件的具体代码,供大家参考,具体内容如下

功能需求:

1、最小值为0,按照给定的最大值,生成区间范围;
2、拖动滑块移动时,显示相应的范围区间,滑块条显示对应的状态;
3、点击时,使最近的滑块移动到鼠标点击的位置。

默认效果:

原生js实现滑块区间组件

当拖动滑块时,显示如下:

原生js实现滑块区间组件

分析:

  • 首先布局要写好,一共有4个元素,两个滑块和两个滑块条。布局时要考虑到后期对滑块和滑块条进行事件监听,尽可能少地出现事件冒泡;
  • 拖动滑块时,要区分是左边的滑块还是右边的滑块;
  • 鼠标的click事件和mousedown事件要兼容好,这里统一使用的是mousedown事件;
  • 要确定好左右滑块的最大最小 left 值;
  • 滑块条的显示就很简单了,宽度是左、右滑块的定位差值,left值是左滑块的left值;
  • 因为使用了事件委托机制,而在mousemove和mouseup事件中,无法判断当前操作的是哪一个滑块,所以要在鼠标按下时,将当前操作的对象传到mousemove事件中;

下面附上代码:

html结构,实例化滑块,可以设置当前滑块的区间范围:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>slide</title>
</head>
<body>
 <script type="module">
 import Slide from "./js/Slide.js";

 init();
 function init(){
  //参数为最大范围,不传的话默认是4000
  let slide=new Slide(4200);
  slide.appendTo("body");
 }

 </script>
</body>
</html>

Slide.js文件:完成创建滑块,拖动滑块,点击滑块的功能。

import Utils from "./Utils.js";
export default class Slide{
 static styleCss=false;
 //最小范围
 minNum=0;
 //最大范围
 maxNum;
 //左边按钮的left值
 leftBtnLeft=0;
 //右边按钮的left值
 rightBtnLeft=238;
 constructor(_max=4000){
 //最大值默认为4000
 this.maxNum=_max;
 this.elem=this.createElem();
 }
 createElem(){
 if(this.elem) return this.elem;
 //创建最外层容器
 let div=Utils.createE("div");
 div.className="slideContainer";
 div.innerHTML=`<p class="priceTxt">价格<span id="rangeText">¥${this.minNum}-${this.maxNum}</span></p>
 <div class="rangeContainer" id="rangeContainer">
  <div class="bgRange" id="bgRange"></div>
  <div class="priceRange" id="priceRange"></div>
  <span id="leftBtn" class="leftBtn"></span>
  <span id="rightBtn" class="rightBtn"></span>
 </div>`;
 Utils.getIdElem(div,this);
 //设置样式
 Slide.setStyles();
 //给父元素监听mousedown事件
 this.rangeContainer.addEventListener("mousedown",e=>this.mouseHandler(e))
 return div;
 }
 appendTo(parent){
 Utils.appendTo(this.elem,parent);
 }
 mouseHandler(e){
 //注意:getBoundingClientRect()返回的结果中,width height 都是包含border的
 let rect=this.rangeContainer.getBoundingClientRect();
 switch (e.type) {
  case "mousedown":
  //取消鼠标快速拖动的默认事件
  e.preventDefault();
  this.x = e.offsetX;
  this.btnType=e.target.id;
  //如果点击的是背景条,执行rangeClick函数
  if(/Range/.test(this.btnType)){
   e.stopPropagation();
   //点击函数
   this.rangeClick(e);
   return;
  }
  //如果点击的是按钮,监听document鼠标移动事件
  this.mouseHandlers=e=>this.mouseHandler(e);
  document.addEventListener("mousemove", this.mouseHandlers);
  document.addEventListener("mouseup", this.mouseHandlers);
  break;
  case "mousemove":
  let x = e.clientX - rect.x - this.x;
  //获取左右按钮的left值
  this.leftBtnLeft=parseInt(getComputedStyle(this.leftBtn).left);
  this.rightBtnLeft=parseInt(getComputedStyle(this.rightBtn).left);
  if (this.btnType === "leftBtn") {
   //确定左边按钮的取值范围
   if (x < 0) x = 0;
   if (x > this.rightBtnLeft) x = this.rightBtnLeft;
   this.leftBtn.style.left = x + "px";
  } else if (this.btnType === "rightBtn") {
   //确定右边按钮的取值范围,减去1px边框
   if (x < this.leftBtnLeft) x = this.leftBtnLeft;
   if (x > this.bgRange.offsetWidth - 2) x = this.bgRange.offsetWidth - 2;
   this.rightBtn.style.left = x + "px";
  }
  //文字范围显示
  this.changeRangeText();
  break;
  case "mouseup":
  //移动事件监听
  document.removeEventListener("mousemove", this.mouseHandlers);
  document.removeEventListener("mouseup", this.mouseHandlers);
  break;
 }
 }
 rangeClick(e){
 //计算出鼠标点击位置的值
 let click_X=e.clientX-this.rangeContainer.getBoundingClientRect().x-this.leftBtn.offsetWidth/2;
 //判断,如果当前点击的位置是在左边按钮的左侧、或者当左右按钮重叠时,点击的位置在按钮左侧,让左边按钮移动到鼠标点击的位置
 if(Math.abs(click_X-this.leftBtnLeft)<Math.abs(click_X-this.rightBtnLeft) || 
 (this.leftBtnLeft===this.rightBtnLeft && click_X<this.leftBtnLeft)) this.leftBtn.style.left=click_X+"px";
 //否则,让右边按钮移动到鼠标点击的位置
 else this.rightBtn.style.left=click_X+"px";
 //获取移动后的左右按钮的left值
 this.leftBtnLeft=parseInt(getComputedStyle(this.leftBtn).left);
 this.rightBtnLeft=parseInt(getComputedStyle(this.rightBtn).left);
 //文字范围显示
 this.changeRangeText();
 }
 changeRangeText(){
 //计算出最小范围与最大范围的值,四舍五入
 let minTxt=Math.round(this.leftBtnLeft/(this.bgRange.clientWidth-2)*this.maxNum);
 let maxTxt=Math.round(this.rightBtnLeft/(this.bgRange.clientWidth-2)*this.maxNum);
 this.rangeText.innerText=`¥${minTxt}-${maxTxt}`;
 //滑块颜色的改变
 this.changeRangeSlide();
 }
 changeRangeSlide(){
 //滑块宽度等于左右按钮间的距离
 this.priceRange.style.width=this.rightBtnLeft-this.leftBtnLeft+"px";
 //滑块的left值等于左边按钮的left值
 this.priceRange.style.left=this.leftBtnLeft+"px";
 }
 static setStyles(){
 if(Slide.styleCss) return;
 Slide.styleCss=true;
 Utils.insertCss(".slideContainer",{
  width:"260px",
  height:"70px",
  margin:"50px"
 })
 Utils.insertCss(".priceTxt",{
  fontSize:"14px",
  color:"#666",
  marginBottom:"20px"
 })
 Utils.insertCss(".priceTxt span",{
  float:"right"
 })
 Utils.insertCss(".rangeContainer",{
  width:"260px",
  height:"20px",
  position:"relative",
 })
 Utils.insertCss(".bgRange",{
  width:"240px",
  height:"3px",
  backgroundColor:"#dedede",
  position:"absolute",
  left:"10px",
  top:"9px"
 })
 Utils.insertCss(".priceRange",{
  width:"240px",
  height:"3px",
  background:"#ffa800",
  position:"absolute",
  left:"10px",
  top:"9px"
 })
 Utils.insertCss(".rangeContainer span",{
  width: "20px",
  height: "20px",
  borderRadius:"50%",
  border:"1px solid #ccc",
  background:"#fff",
  position:"absolute",
  top:"0px",
  boxShadow:"2px 2px 2px #333"
 })
 Utils.insertCss(".leftBtn",{
  left:"0px"
 })
 Utils.insertCss(".rightBtn",{
  left:"238px"
 })
 }
}

Utils.js文件:是一个工具包文件。

export default class Utils{
 static createE(elem,style,prep){
 elem=document.createElement(elem);
 if(style) for(let prop in style) elem.style[prop]=style[prop];
 if(prep) for(let prop in prep) elem[prop]=prep[prop];
 return elem;
 }
 static appendTo(elem,parent){
 if (parent.constructor === String) parent = document.querySelector(parent);
 parent.appendChild(elem);
 }
 static randomNum(min,max){
 return Math.floor(Math.random*(max-min)+min);
 }
 static randomColor(alpha){
 alpha=alpha||Math.random().toFixed(1);
 if(isNaN(alpha)) alpha=1;
 if(alpha>1) alpha=1;
 if(alpha<0) alpha=0;
 let col="rgba(";
 for(let i=0;i<3;i++){
  col+=Utils.randomNum(0,256)+",";
 }
 col+=alpha+")";
 return col;
 }
 static insertCss(select,styles){
 if(document.styleSheets.length===0){
  let styleS=Utils.createE("style");
  Utils.appendTo(styleS,document.head);
 }
 let styleSheet=document.styleSheets[document.styleSheets.length-1];
 let str=select+"{";
 for(var prop in styles){
  str+=prop.replace(/[A-Z]/g,function(item){
  return "-"+item.toLocaleLowerCase();
  })+":"+styles[prop]+";";
 }
 str+="}"
 styleSheet.insertRule(str,styleSheet.cssRules.length);
 }
 static getIdElem(elem,obj){
 if(elem.id) obj[elem.id]=elem;
 if(elem.children.length===0) return obj;
 for(let i=0;i<elem.children.length;i++){
  Utils.getIdElem(elem.children[i],obj);
 }
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
利用javascript中的call实现继承
Jan 22 Javascript
Use Word to Search for Files
Jun 15 Javascript
Extjs学习笔记之三 extjs form更多的表单项
Jan 07 Javascript
改变javascript函数内部this指针指向的三种方法
Apr 23 Javascript
使用apply方法处理数组的三个技巧[译]
Sep 20 Javascript
Jquery遍历Json数据的方法
Apr 20 Javascript
Angular中使用ui router实现系统权限控制及开发遇到问题
Sep 23 Javascript
react 实现页面代码分割、按需加载的方法
Apr 03 Javascript
jquery ajaxfileuplod 上传文件 essyui laoding 效果【防止重复上传文件】
May 26 jQuery
基于canvasJS在PHP中制作动态图表
May 30 Javascript
解决vue动态路由异步加载import组件,加载不到module的问题
Jul 26 Javascript
React列表栏及购物车组件使用详解
Jun 28 Javascript
原生js实现下拉框选择组件
Jan 20 #Javascript
原生js实现自定义滚动条组件
Jan 20 #Javascript
原生js实现自定义滚动条
Jan 20 #Javascript
uniapp微信小程序:key失效的解决方法
Jan 20 #Javascript
JavaScript实现下拉列表
Jan 20 #Javascript
浅谈Vue开发人员的7个最好的VSCode扩展
Jan 20 #Vue.js
详解实现vue的数据响应式原理
Jan 20 #Vue.js
You might like
解析阿里云ubuntu12.04环境下配置Apache+PHP+PHPmyadmin+MYsql
2013/06/26 PHP
PHP用星号隐藏部份用户名、身份证、IP、手机号等实例
2014/04/08 PHP
php+mysql数据库实现无限分类的方法
2014/12/12 PHP
PHP中检索字符串的方法分析【strstr与substr_count方法】
2017/02/17 PHP
关于 Laravel Redis 多个进程同时取队列问题详解
2017/12/25 PHP
Laravel5.0+框架邮件发送功能实现方法图文与实例详解
2019/04/23 PHP
Yii 框架使用数据库(databases)的方法示例
2020/05/19 PHP
JavaScript学习笔记(十七)js 优化
2010/02/04 Javascript
JQuery对id中含有特殊字符的转义处理示例
2013/09/06 Javascript
JavaScript对Cookie进行读写操作实例
2015/07/25 Javascript
动态设置form表单的action属性的值的简单方法
2016/05/25 Javascript
AngularJS使用ng-repeat指令实现下拉框
2016/08/23 Javascript
AngularJs $parse、$eval和$observe、$watch详解
2016/09/21 Javascript
vue如何实现observer和watcher源码解析
2017/03/09 Javascript
简单谈谈React中的路由系统
2017/07/25 Javascript
vue中使用sessionStorage记住密码功能
2018/07/24 Javascript
es6中class类静态方法,静态属性,实例属性,实例方法的理解与应用分析
2020/02/15 Javascript
JavaScript动态生成表格的示例
2020/11/02 Javascript
[49:28]VP vs Optic 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
Python科学计算之NumPy入门教程
2017/01/15 Python
Python3删除排序数组中重复项的方法分析
2019/01/31 Python
Python列表切片操作实例总结
2019/02/19 Python
Python实现的微信支付方式总结【三种方式】
2019/04/13 Python
Python爬虫学习之获取指定网页源码
2019/07/30 Python
Python基本类型的连接组合和互相转换方式(13种)
2019/12/16 Python
python3利用Axes3D库画3D模型图
2020/03/25 Python
浅谈keras保存模型中的save()和save_weights()区别
2020/05/21 Python
Python创建临时文件和文件夹
2020/08/05 Python
Python调用jar包方法实现过程解析
2020/08/11 Python
基于HTML5 Canvas 实现弹出框效果
2017/06/05 HTML / CSS
Belle Maison倍美丛官网:日本千趣会旗下邮购网站
2016/07/22 全球购物
全球最大的服务市场:Fiverr
2017/01/03 全球购物
预订全球最佳旅行体验:Viator
2018/03/30 全球购物
美国地毯购买网站:Rugs USA
2019/02/23 全球购物
关于运动会的口号
2014/06/07 职场文书
读群众路线的心得体会
2014/09/03 职场文书