先看效果图:
说明:两端值300,750 是可选范围的最大值;两个按钮上的值是已经选择的范围 ;
目前灰色背景条的宽度单位是px,
上面代码中,背景条宽度是写死的;下面是优化后的代码:
<template>
<div
:style="{
display: 'flex',
'justify-content': 'center',
width: '100%',
}"
>
<div
class="slider-box"
id="slider-box"
:style="{
width: '100%',
background: outBg,
}"
@mousedown="handleClickZong"
>
<div
:class="['slider-nei', isClick ? 'transtion' : '']"
:style="{
width: Math.abs(moveDistanceOne - moveDistanceTwo) + 20 + 'px',
transform:
moveDistanceTwo > moveDistanceOne
? `translateX(${moveDistanceOne}px)`
: `translateX(${moveDistanceTwo}px)`,
background: neiBg,
}"
></div>
<div
:style="{
transform: `translateX(${moveDistance}px)`,
}"
:class="{
'point-box': true,
zhua: isMove,
transtion: isClick,
}"
v-if="!range"
@mousedown.stop.prevent="handleMousedown"
></div>
<div
:style="{
transform: `translateX(${moveDistanceOne}px)`,
background: btnBg,position:'absolute','z-index': leftIndex
}"
:class="{
'point-box': true,
zhua: isMove,
transtion: isClick,
}"
v-if="range"
@mousedown.stop.prevent="handleMousedownOne"
@touchstart="handleMousedownOne1"
@mouseup="handleUp"
@touchend="handleUp"
>
{{ Math.trunc(moveDistanceOne * rate) + min }}
</div>
<div
:style="{
transform: `translateX(${moveDistanceTwo}px)`,
background: btnBg,position:'absolute','z-index': rightIndex
}"
:class="{
'point-box': true,
point: true,
zhua: isMove,
transtion: isClick,
}"
@mousedown.stop.prevent="handleMousedownTwo"
@touchstart="handleMousedownTwo1"
@mouseup="handleUp"
@touchend="handleUp"
>
{{ Math.trunc(moveDistanceTwo * rate + min) }}
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from "vuex";
export default {
data() {
return {
range: true, //是否开启双滑块
isClick: false, //是否直接点击
isMove: false, //是否处于滑动状态
flag: false, //
moveDistance: 0,
initX: 0, //记录鼠标点下时的坐标,用于移动中求差值
moveStart: 0, //进度条的开始位置
moveEnd: 0, //进度条的结束位置
moveDistanceOne: 0, //滑块一的位置
moveDistanceTwo: 50, //滑块二的位置
rate: 1, // 比率
outerWidth: 100,
rate1: 1, // 比率
outerWidth1: 100,
valueRange: [],
leftIndex: 0,
rightIndex: 0.5,
};
},
computed: {
// 使用对象展开运算符将 getter 混入 computed 对象中
...mapGetters("common", [
"userType"
]),
},
props: {
// 可选择范围的较大值
max: {
type: Number,
default: 750,
},
// 外层背景色
outBg: {
type: String,
default: "#F0F0F0",
},
// 滑块背景色
btnBg: {
type: String,
default: "#497cfe",
},
// 内层背景色
neiBg: {
type: String,
default: "#E5EDFF",
},
// 可选择范围的较小值
min: {
type: Number,
default: 150,
},
// 已经选择的范围
valuesRange: {
type: Array,
default: [350, 550],
},
},
watch: {
valuesRange: {
handler(val1) {
this.valueRange = val1;
this.init();
},
deep: true,
immediate: true,
},
},
mounted() {
window.addEventListener("resize", this.init);
window.addEventListener("mouseup", () => {
if(this.flag) {
this.handleUp2();
this.flag = false;
}
});
// this.init();
},
methods: {
init() {
this.$nextTick(() => {
/* this.valueRange [1, 750] */
if (this.valueRange && this.valueRange.length > 0) {
let max_min = this.max - this.min;
var slide_width = document.querySelector("#slider-box").clientWidth;
var point_width = document.querySelector(".point").clientWidth;
this.outerWidth = slide_width - point_width;
this.outerWidth1 = slide_width - point_width - point_width;
this.rate = max_min / this.outerWidth;
this.rate1 = max_min / this.outerWidth1;
let vr = JSON.parse(JSON.stringify(this.valueRange));
if(vr[0] > vr[1]) {
this.valueRange = [vr[1],vr[0]];
}
this.moveDistanceOne = (this.valueRange[0] - this.min) / this.rate;
this.moveDistanceTwo = (this.valueRange[1] - this.min) / this.rate;
this.$forceUpdate();
}
});
},
//移动端 touchstart 点击监听 ontouchmove 移动监听 ontouchend 松开监听,e.changedTouches[0] 元素偏移的一些数据
//PC端 mousedown 点击监听 onmousemove 移动监听 onmouseup 松开监听
/**
* 初始坐标就是鼠标点下时的clientX坐标,这样就可以做到将slider放在页面任何位置,拖动原点偏移的量也是正确的,
* 因为原点移动距离是用鼠标移动的位置和鼠标点下的位置做差值计算,所以不用担心这里的clientX会因为slider放在
* 别的地方而导致距离计算错误
* @param e
*/
//鼠标点击
handleMousedown(e) {
this.isMove = true;
this.initX = e.clientX;
const sliderDomWidth = this.outerWidth;
// const sliderDomWidth = document.getElementsByClassName("slider-box")[0].clientWidth;
document.onmousemove = (e) => {
if (this.isMove) {
this.moveDistance += e.clientX - this.initX;
this.initX = e.clientX;
if ((this.moveDistance / sliderDomWidth) * 100 > 100) {
this.moveDistance = sliderDomWidth;
return;
}
if ((this.moveDistance / sliderDomWidth) * 100 < 0) {
this.moveDistance = 0;
return;
}
}
};
document.onmouseup = (e) => {
this.isMove = false;
document.onmousemove = null;
};
},
handleUp(){
// console.log('this.valueRange', this.valueRange);
// this.$emit("recommendRange", this.valueRange);
},
handleUp2(){
this.$emit("recommendRange", this.valueRange);
},
handleUp3(){
this.$emit("recommendRange", this.valueRange);
},
handleUp4(){
this.$emit("recommendRange", this.valueRange);
},
/**
* 当点击进度条某一个位置时,快捷设置进度条的位置,这里就需要用offsetX而不是clientX了。这里需要设置的便宜距离是鼠标距离目标元素的距离而不是鼠标在整个页面上的坐标
* @param e
*/
handleClickZong(e) {
this.isClick = true;
setTimeout(() => {
this.isClick = false;
}, 300);
this.moveDistance = e.offsetX - 10;
},
//滑动滑块1
handleMousedownOne1(e) {
if (this.userType != 'VIP') {
this.$store.commit('common/SET_SHOWEXCHANGEVIP', true);
return;
}
this.flag = true;
this.isMove = true;
this.leftIndex = 0.5;
this.rightIndex = 0;
let currentDistance = e.changedTouches[0].clientX;
document.ontouchmove = (e) => {
let item = e.changedTouches[0];
if (this.isMove) {
const moveX = item.clientX - currentDistance;
currentDistance = item.clientX;
this.moveDistanceOne += moveX;
if (this.moveDistanceOne < 0) {
this.moveDistanceOne = 0;
return;
}
if (this.moveDistanceOne > this.moveDistanceTwo) {
this.moveDistanceOne = this.moveDistanceTwo;
return;
}
this.valueRange = [this.moveDistanceOne, this.moveDistanceTwo];
}
};
document.ontouchend = (e) => {
this.isMove = false;
// this.flag = false;
document.onmousemove = null;
};
},
handleMousedownOne(e) {
console.log(e);
if (this.userType != 'VIP') {
this.$store.commit('common/SET_SHOWEXCHANGEVIP', true);
return;
}
this.flag = true;
this.isMove = true;
this.leftIndex = 0.5;
this.rightIndex = 0;
let currentDistance = e.clientX;
document.onmousemove = (e) => {
if (this.isMove) {
/* moveX 滑块横向移动的距离 */
const moveX = e.clientX - currentDistance;
currentDistance = e.clientX;
this.moveDistanceOne += moveX;
if (this.moveDistanceOne < 0) {
this.moveDistanceOne = 0;
return;
}
if (this.moveDistanceOne > this.moveDistanceTwo) {
this.moveDistanceOne = this.moveDistanceTwo;
return;
}
let arr_one = Math.trunc(this.moveDistanceOne * this.rate) + this.min;
let arr_two = Math.trunc(this.moveDistanceTwo * this.rate) + this.min;
this.valueRange = [arr_one, arr_two];
}
};
document.onmouseup = (e) => {
this.isMove = false;
// this.flag = false;
document.onmousemove = null;
};
},
//滑动滑块2
handleMousedownTwo1(e) {
if (this.userType != 'VIP') {
this.$store.commit('common/SET_SHOWEXCHANGEVIP', true);
return;
}
this.isMove = true;
this.flag = true;
this.leftIndex = 0;
this.rightIndex = 0.5;
let currentDistance = e.changedTouches[0].clientX;
document.ontouchmove = (e) => {
if (this.isMove) {
let item = e.changedTouches[0];
const moveX = item.clientX - currentDistance;
currentDistance = item.clientX;
this.moveDistanceTwo += moveX;
if (this.moveDistanceTwo > this.outerWidth) {
this.moveDistanceTwo = this.outerWidth;
return;
}
if (this.moveDistanceTwo < this.moveDistanceOne) {
this.moveDistanceTwo = this.moveDistanceOne;
return;
}
if (this.moveDistanceTwo < 0) {
this.moveDistanceTwo = 0;
return;
}
this.valueRange = [this.moveDistanceOne, this.moveDistanceTwo];
}
};
document.ontouchend = (e) => {
this.isMove = false;
// this.flag = false;
document.onmousemove = null;
};
},
//滑动滑块2
handleMousedownTwo(e) {
if (this.userType != 'VIP') {
this.$store.commit('common/SET_SHOWEXCHANGEVIP', true);
return;
}
this.flag = true;
this.isMove = true;
this.leftIndex = 0;
this.rightIndex = 0.5;
let currentDistance = e.clientX;
document.onmousemove = (e) => {
if (this.isMove) {
const moveX = e.clientX - currentDistance;
currentDistance = e.clientX;
this.moveDistanceTwo += moveX;
if (this.moveDistanceTwo > this.outerWidth) {
this.moveDistanceTwo = this.outerWidth;
return;
}
if (this.moveDistanceTwo < this.moveDistanceOne) {
this.moveDistanceTwo = this.moveDistanceOne;
return;
}
if (this.moveDistanceTwo < 0) {
this.moveDistanceTwo = 0;
return;
}
let arr_one = Math.trunc(this.moveDistanceOne * this.rate) + this.min;
let arr_two = Math.trunc(this.moveDistanceTwo * this.rate) + this.min;
this.valueRange = [arr_one, arr_two];
}
};
document.onmouseup = (e) => {
this.isMove = false;
// this.flag = false;
document.onmousemove = null;
};
},
},
};
</script>
<style lang="scss" scoped>
@function autoPx($num) {
@return (($num / 1200) * 24rem);
}
.slider-box {
height: autoPx(10);
border-radius: autoPx(20);
position: relative;
}
.slider-nei {
position: absolute;
left: 0;
top: 0;
width: 0;
height: autoPx(10);
border-radius: autoPx(20);
}
.point-box {
width: autoPx(43);
height: autoPx(20);
border-radius: autoPx(20);
position: absolute;
top: -(autoPx(5));
color: #fff;
font-size: autoPx(12);
line-height: autoPx(20);
text-align: center;
user-select: none;
cursor: pointer;
}
.point-box:hover {
cursor: grab;
}
.zhua:active {
cursor: grabbing;
}
.transtion {
transition: all 0.3s;
}
</style>