1、组件样式
2、使用
import cSlider from '@/components/c-slider/c-slider.vue'
<div class="range">
<cSlider v-model="cScale" @change="cScaleChange" :min="1" :max="10"/>
</div>
3、组件代码
<template>
<div
class="slider-box"
data-id="1"
ref="sliderBox"
@mousedown.stop.prevent="onMousedown($event)"
@mouseup.stop.prevent="onMouseup"
@mouseleave.stop.prevent="onMouseup"
@mousemove.stop.prevent="onMousemove($event)"
>
<div class="slider-wrap">
<div
class="slider-bar"
data-id="1"
:style="{
width: ((modelValue - min)*stepWidth)+'px'
}">
<span
class="slider-btn"
:class="{
active: sliderActive
}"
data-id="1"
@mousedown.stop.prevent="onMousedown($event, true)"
:style="{
left: ((modelValue - min)*stepWidth)+'px'
}">
<b>{{ modelValue }}</b>
</span>
</div>
</div>
</div>
</template>
<script>
export default {
model: {
prop: 'modelValue',
event: 'change'
},
props: {
modelValue: {
type: Number,
default: 0
},
min: {
type: Number,
default: 0
},
max: {
type: Number,
default: 10
},
step: {
type: Number,
default: 1
}
},
data() {
return {
rangeValue: 0,
stepWidth: 0,
sliderBox: null,
moveAbled: false,
mousePoint: null,
sliderActive: false
}
},
mounted() {
// document.addEventListener('mouseup', this.onMouseup)
// document.addEventListener('mouseleave', this.onMouseup)
// this.$nextTick(() => {
let _sliderBox = this.$refs['sliderBox'].getBoundingClientRect()
this.sliderBox = {
width: _sliderBox.width,
height: _sliderBox.height,
top: _sliderBox.top + document.documentElement.scrollTop,
left: _sliderBox.left + document.documentElement.scrollLeft
}
this.stepWidth = this.sliderBox.width/(this.max-this.min)
// console.log('xxx', _sliderBox, this.sliderBox)
// })
},
beforeMount() {
// document.removeEventListener('mouseup', this.onMouseup)
// document.removeEventListener('mouseleave', this.onMouseup)
},
methods: {
onMousemove(e) {
if(this.moveAbled) {
this.sliderActive = true
let d = e.pageX - this.mousePoint.pageX
let _val = Math.round(this.modelValue + d/this.stepWidth)
if(_val < this.min) {
_val = this.min
} else if(_val > this.max) {
_val = this.max
}
if(_val !== this.modelValue) {
this.mousePoint = e
}
this.$emit('update:modelValue', _val)
this.$emit('change')
console.log('onMousemove', _val)
}
},
onMouseup() {
// console.log('onMouseup')
this.moveAbled = false
this.sliderActive = false
},
onMousedown(e, moveAbled) {
console.log('onMousedown', this.stepWidth)
if(moveAbled) {
this.moveAbled = moveAbled
this.mousePoint = e
} else {
let d = e.pageX - this.sliderBox.left
let _val = Math.round(this.min + d/this.stepWidth)
if(_val < this.min) {
_val = this.min
} else if(_val > this.max) {
_val = this.max
}
this.$emit('update:modelValue', _val)
this.$emit('change')
}
},
}
}
</script>
<style lang="scss" scoped>
.slider-box {
width: 100%;
height: 100%;
display: flex;
align-items: center;
.range {
position: absolute;
top: 50%;
left: 50%;
width: 100%;
transform: translate(-50%, -50%);
opacity: 0.3;
}
.slider-wrap {
position: relative;
width: 100%;
height: 3px;
border-radius: 2px;
background: #D9D9D9;
cursor: pointer;
.slider-bar {
border-radius: 2px;
height: 100%;
background: #0256FF;
.slider-btn {
cursor: grab;
position: absolute;
top: 50%;
left: 0;
transform: translate(-50%, -50%);
width: 10px;
height: 10px;
background: white;
border-radius: 100%;
box-shadow: 0 0 2px 2px #D6D6D6;
&:hover, &.active {
width: 15px;
height: 15px;
b {
display: block;
}
}
&::after {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
content: '';
width: 4px;
height: 4px;
background: #0256FF;
border-radius: 100%;
}
b {
display: none;
position: absolute;
top: -10px;
left: 50%;
background: rgba(0, 0, 0, 0.3);
color: white;
font-size: 12px;
padding: 0 5px;
border-radius: 5px;
transform: translate(-50%, -100%);
&::after {
position: absolute;
bottom: 0px;
left: 50%;
transform: translate(-50%, 100%);
content: '';
width: 0;
height: 0;
border-top: 4px solid rgba(0, 0, 0, 0.3);
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-right: 4px solid transparent;
}
}
}
}
}
}
</style>