滑块(通用)
<template>
<div class="mint-range" :style="{ height: height + 'rem'}" :class="{ 'mint-range--disabled': disabled }">
<slot name="start"></slot>
<div class="mint-range-content" ref="content" :style="{ 'margin-right': btnWidth + 'rem' }">
<div class="mint-range-runway" :style="{ 'height': height + 'rem', right: -btnWidth + 'rem' }"></div>
<div class="mint-range-progress" :style="{ width: progress + '%', height: height + 'rem'}"></div>
<div class="mint-range-thumb" ref="thumb"
:style="{ left: progress + '%' , width: btnWidth + 'rem', height: btnHeight + 'rem', top: -(btnHeight-height)/2 + 'rem'}"
:class="{'thumb-round': btnRound}"
></div>
</div>
<slot name="end"></slot>
<div class="mint-range-progress-real" :style="{ width: progress + '%', height: height + 'rem'}"></div>
</div>
</template>
<script type="text/babel">
import draggable from 'common/js/draggable';
export default {
name: 'mint-range',
props: {
min: { // 区间最小值
type: Number,
default: 0
},
max: {
type: Number,
default: 100
},
height: { // range高度
type: Number,
default: 0.1
},
step: { // 滑动步数
type: Number,
default: 1
},
disabled: { // 禁止滑动
type: Boolean,
default: false
},
value: { // 预设值
type: Number
},
btnWidth: { // 滑块的宽
type: Number,
default: 0.3
},
btnHeight: { // 滑块的高
type: Number,
default: 0.3
},
btnRound: { // 滑块默认为圆形
type: Boolean,
default: true
}
},
computed: {
progress () {
const value = this.value;
if (typeof value === 'undefined' || value === null) return 0;
return Math.floor((value - this.min) / (this.max - this.min) * 100);
}
},
mounted () {
const thumb = this.$refs.thumb;
const content = this.$refs.content;
const getThumbPosition = () => {
const contentBox = content.getBoundingClientRect();
const thumbBox = thumb.getBoundingClientRect();
return {
left: thumbBox.left - contentBox.left,
top: thumbBox.top - contentBox.top,
thumbBoxLeft: thumbBox.left
};
};
let dragState = {};
draggable(thumb, {
start: (event) => {
if (this.disabled) return;
const position = getThumbPosition();
const thumbClickDetalX = event.clientX - position.thumbBoxLeft;
dragState = {
thumbStartLeft: position.left,
thumbStartTop: position.top,
thumbClickDetalX: thumbClickDetalX
};
},
drag: (event) => {
if (this.disabled) return;
const contentBox = content.getBoundingClientRect();
const deltaX = event.pageX - contentBox.left - dragState.thumbStartLeft - dragState.thumbClickDetalX;
const stepCount = Math.ceil((this.max - this.min) / this.step);
const newPosition = (dragState.thumbStartLeft + deltaX) - (dragState.thumbStartLeft + deltaX) % (contentBox.width / stepCount);
let newProgress = newPosition / contentBox.width;
if (newProgress < 0) {
newProgress = 0;
} else if (newProgress > 1) {
newProgress = 1;
}
this.$emit('input', Math.round(this.min + newProgress * (this.max - this.min)));
},
end: () => {
if (this.disabled) return;
this.$emit('change', this.value);
dragState = {};
}
});
}
};
</script>
<style>
.mint-range {
width: 100%;
position: relative;
display: -webkit-box;
display: -ms-flexbox;
box-sizing: border-box;
}
.mint-range-content {
position: relative;
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
}
.mint-range-runway {
position: absolute;
top: 0;
left: 0;
background-color: #a9acb1;
}
.mint-range-progress,
.mint-range-progress-real {
position: absolute;
display: block;
background-color: #26a2ff;
top: 0;
width: 0;
}
.mint-range-progress {
opacity: 0;
}
.mint-range-thumb {
background-color: #a9ccf2;
position: absolute;
left: 0;
cursor: move;
z-index: 2;
}
.thumb-round {
border-radius: 100%;
box-shadow: 0 1px .03rem rgba(0, 0, 0, .4);
}
.mt-range--disabled {
opacity: .5;
}
</style>
引用的js文件
let isDragging = false;
import Vue from 'vue';
const supportTouch = !Vue.prototype.$isServer && 'ontouchstart' in window;
export default function (element, options) {
const moveFn = function (event) {
if (options.drag) {
options.drag(supportTouch ? event.changedTouches[0] || event.touches[0] : event);
}
};
const endFn = function (event) {
if (!supportTouch) {
document.removeEventListener('mousemove', moveFn);
document.removeEventListener('mouseup', endFn);
}
document.onselectstart = null;
document.ondragstart = null;
isDragging = false;
if (options.end) {
options.end(supportTouch ? event.changedTouches[0] || event.touches[0] : event);
}
};
element.addEventListener(supportTouch ? 'touchstart' : 'mousedown', function (event) {
if (isDragging) return;
event.preventDefault();
document.onselectstart = function () {
return false;
};
document.ondragstart = function () {
return false;
};
if (!supportTouch) {
document.addEventListener('mousemove', moveFn);
document.addEventListener('mouseup', endFn);
}
isDragging = true;
if (options.start) {
options.start(supportTouch ? event.changedTouches[0] || event.touches[0] : event);
}
});
if (supportTouch) {
element.addEventListener('touchmove', moveFn);
element.addEventListener('touchend', endFn);
element.addEventListener('touchcancel', endFn);
}
};
在项目中使用,封装成自己的range组件
<template>
<div class="range-wrapper">
<mint-range
v-model="rangeValue"
:min="0"
:max="300"
:height="0.2"
:step="1"
:btn-round="false"
:btn-width=".15"
@input=handleDrag // 获取drag过程中 的value
>
</mint-range>
<div class="range-status">
<span class="status" :class="{general: generalStatus}">一般</span>
<span class="status" :class="{more: moreStatus}">较紧急</span>
<span class="status" :class="{very: veryStatus}">很紧急</span>
</div>
</div>
</template>
<script type="text/ecmascript-6">
import jsBridge from 'common/js/jsbridge';
import mintRange from 'common/components/range';
export default {
props: {
element: {
type: Object
}
},
components: {
mintRange
},
data () {
return {
rangeValue: 0
};
},
watch: {
urgencyLevel (newLevel) {
console.log(newLevel, 'get-level----------');
this.$emit('setLevel', newLevel);
}
},
methods: {
handleDrag (value) {
this.$emit('onchange', value);
}
},
computed: {
generalStatus () {
return this.rangeValue < 100;
},
moreStatus () {
return 100 <= this.rangeValue && this.rangeValue < 200;
},
veryStatus () {
return 200 <= this.rangeValue;
},
urgencyLevel () {
if (this.rangeValue < 100) {
return 0;
} else if (100 <= this.rangeValue && this.rangeValue < 200) {
return 1;
} else if (200 <= this.rangeValue) {
return 2;
}
}
}
}
</script>
<style lang="scss" type="text/css" rel="stylesheet/scss" scoped>
@import "../../../common/css/mixin";
.range-wrapper {
width: 100%;
height: .64rem;
box-sizing: border-box;
@include border-1px(#EBEBEB);
.mint-range {
margin-top: .1rem;
}
.range-status {
margin-top: .1rem;
.status {
display: inline-block;
float: left;
width: 33.33%;
color: #cccccc;
}
.general {
color: #71e350;
}
.more {
color: #ff6200;
}
.very {
color: #ff0000;
}
}
}
</style>
引入到页面中
注册后使用:
<!--测试range demo-->
<range @setLevel="setLevel" @onchange=''onchange''></range>
// 取到level的值
methods:
setLevel (level) {
this.formData.approves.urgencyLevel = level;
console.log(level, 'set-level----------');
}
// 获取滑块的进度值
onchange(value) {
console.log(value, 'get-range-value----------');
}