原生js實現(xiàn)滑塊區(qū)間組件
本文實例為大家分享了js實現(xiàn)滑塊區(qū)間組件的具體代碼,供大家參考,具體內(nèi)容如下
功能需求:
1、最小值為0,按照給定的最大值,生成區(qū)間范圍;
2、拖動滑塊移動時,顯示相應(yīng)的范圍區(qū)間,滑塊條顯示對應(yīng)的狀態(tài);
3、點擊時,使最近的滑塊移動到鼠標(biāo)點擊的位置。
默認效果:

當(dāng)拖動滑塊時,顯示如下:

分析:
- 首先布局要寫好,一共有4個元素,兩個滑塊和兩個滑塊條。布局時要考慮到后期對滑塊和滑塊條進行事件監(jiān)聽,盡可能少地出現(xiàn)事件冒泡;
- 拖動滑塊時,要區(qū)分是左邊的滑塊還是右邊的滑塊;
- 鼠標(biāo)的click事件和mousedown事件要兼容好,這里統(tǒng)一使用的是mousedown事件;
- 要確定好左右滑塊的最大最小 left 值;
- 滑塊條的顯示就很簡單了,寬度是左、右滑塊的定位差值,left值是左滑塊的left值;
- 因為使用了事件委托機制,而在mousemove和mouseup事件中,無法判斷當(dāng)前操作的是哪一個滑塊,所以要在鼠標(biāo)按下時,將當(dāng)前操作的對象傳到mousemove事件中;
下面附上代碼:
html結(jié)構(gòu),實例化滑塊,可以設(shè)置當(dāng)前滑塊的區(qū)間范圍:
<!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(){
//參數(shù)為最大范圍,不傳的話默認是4000
let slide=new Slide(4200);
slide.appendTo("body");
}
</script>
</body>
</html>
Slide.js文件:完成創(chuàng)建滑塊,拖動滑塊,點擊滑塊的功能。
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;
//創(chuàng)建最外層容器
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);
//設(shè)置樣式
Slide.setStyles();
//給父元素監(jiān)聽mousedown事件
this.rangeContainer.addEventListener("mousedown",e=>this.mouseHandler(e))
return div;
}
appendTo(parent){
Utils.appendTo(this.elem,parent);
}
mouseHandler(e){
//注意:getBoundingClientRect()返回的結(jié)果中,width height 都是包含border的
let rect=this.rangeContainer.getBoundingClientRect();
switch (e.type) {
case "mousedown":
//取消鼠標(biāo)快速拖動的默認事件
e.preventDefault();
this.x = e.offsetX;
this.btnType=e.target.id;
//如果點擊的是背景條,執(zhí)行rangeClick函數(shù)
if(/Range/.test(this.btnType)){
e.stopPropagation();
//點擊函數(shù)
this.rangeClick(e);
return;
}
//如果點擊的是按鈕,監(jiān)聽document鼠標(biāo)移動事件
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":
//移動事件監(jiān)聽
document.removeEventListener("mousemove", this.mouseHandlers);
document.removeEventListener("mouseup", this.mouseHandlers);
break;
}
}
rangeClick(e){
//計算出鼠標(biāo)點擊位置的值
let click_X=e.clientX-this.rangeContainer.getBoundingClientRect().x-this.leftBtn.offsetWidth/2;
//判斷,如果當(dāng)前點擊的位置是在左邊按鈕的左側(cè)、或者當(dāng)左右按鈕重疊時,點擊的位置在按鈕左側(cè),讓左邊按鈕移動到鼠標(biāo)點擊的位置
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";
//否則,讓右邊按鈕移動到鼠標(biāo)點擊的位置
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);
}
}
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Vue 實現(xiàn)拖動滑塊驗證功能(只有css+js沒有后臺驗證步驟)
- 基于JS組件實現(xiàn)拖動滑塊驗證功能(代碼分享)
- 基于JavaScript實現(xiàn)拖動滑塊效果
- Javascript實現(xiàn)滑塊滑動改變值的實現(xiàn)代碼
- js實現(xiàn)兼容PC端和移動端滑塊拖動選擇數(shù)字效果
- JS響應(yīng)鼠標(biāo)點擊實現(xiàn)兩個滑塊區(qū)間拖動效果
- js用拖動滑塊來控制圖片大小的方法
- 基于Vue.js實現(xiàn)tab滑塊效果
- Javascript 鼠標(biāo)移動上去小三角形滑塊緩慢跟隨效果
- JS實現(xiàn)網(wǎng)頁游戲中滑塊響應(yīng)鼠標(biāo)點擊移動效果
相關(guān)文章
js實現(xiàn)省級聯(lián)動(數(shù)據(jù)結(jié)構(gòu)優(yōu)化)
這篇文章主要為大家詳細介紹了js實現(xiàn)省級聯(lián)動,數(shù)據(jù)結(jié)構(gòu)優(yōu)化,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-07-07
JavaScript/TypeScript 實現(xiàn)并發(fā)請求控制的示例代碼
這篇文章主要介紹了JavaScript/TypeScript 實現(xiàn)并發(fā)請求控制,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
JavaScript中判斷整數(shù)的多種方法總結(jié)
這篇文章主要介紹了JavaScript中判斷整數(shù)的多種方法總結(jié),本文總結(jié)了5種判斷整數(shù)的方法,如取余運算符判斷、Math.round、Math.ceil、Math.floor判斷等,需要的朋友可以參考下2014-11-11
如何在面試中手寫出javascript節(jié)流和防抖函數(shù)
這篇文章主要介紹了如何在面試中手寫出javascript節(jié)流和防抖函數(shù),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10

