类似于滑块拖动很多组件都有,需求不复杂的可以直接用第三方组件的。但是如果碰到渐变拖动相信一大部分组件都没有,所以就要想办法自己封装了,其实原理还是很简单的。›
知识点:
- background: linear-gradient 背景渐变属性
- clip-path: polygon 背景裁切属性
- 移动端ontouchstart,ontouchmove,ontouchend和Pc 端onmousedown,onmousemove,onmouseup
组件使用:
代码语言:javascript复制<template>
<div class="body">
<slider :planNum.sync="plan" :color="['#D6FF7F','#00B3CC']"></slider>
<slider :planNum.sync="plan1" :color="['#ED7B84','#9055FF']"></slider>
<slider :planNum.sync="plan2" :color="['#2F80ED']"></slider>
<slider :planNum.sync="plan3"></slider>
</div>
</template>
<script>
import slider from '../common/slider'
export default {
components: {
slider
},
data() {
return {
plan: 75,
plan1: 45,
plan2: 100,
plan3: 88
}
},
methods: {
}
}
</script>
<style lang="scss" scoped>
.body {
display: inline-block;
margin: 50px auto;
}
</style>
组件封装:slider.vue
代码语言:javascript复制<template>
<div class="plan_box" ref="wrapper">
<div
class="plan"
:style="`clip-path: polygon(0 0,${plan}% 0,${plan}% 100%,0 100%);background: linear-gradient(to left, ${this.gradient});`"
></div>
<div class="slider" ref="slider">
<span class="text">{{planNum}}%</span>
</div>
</div>
</template>
<script>
export default {
props: {
planNum: Number, //进度数值
color: { //背景颜色,['#e233ff'] 为单色 ,['#e233ff', '#ff6b00']为渐变色
type: Array,
default: function() {
return ['#e233ff', '#ff6b00']
}
}
},
computed: {
plan: {
get() {
return this.planNum
},
set(val) {
this.$emit('update:planNum', Number(val))
}
},
gradient() {
if (this.color.length > 1) {
return this.color.join(',')
} else {
return `${this.color[0]},${this.color[0]}`
}
}
},
data() {
return {
// plan: 55
}
},
mounted() {
this.init(this.$refs.wrapper)
},
methods: {
//pc端鼠标拖动
mouseDown(el) {
var _this = this
var $el = el
var slider = _this.$refs.slider
var rect = $el.getBoundingClientRect()
if (_this.plan) {
let plan = _this.plan
slider.style.left = (plan / 100) * rect.width 'px'
}
slider.onmousedown = function(event) {
event.preventDefault()
document.onmousemove = function(e) {
var sliderX = e.clientX - rect.left
if (sliderX < 0) {
sliderX = 0
} else if (sliderX > rect.width) {
sliderX = rect.width
}
// console.log(sliderX)
//滑块的位置
slider.style.left = sliderX 'px'
//进度条的长度
_this.plan = ((sliderX / rect.width) * 100).toFixed(0)
}
document.onmouseup = function() {
document.onmousemove = null
document.onmousedown = null
}
}
},
touchStart(el) {
var _this = this
var $el = el
var slider = _this.$refs.slider
var rect = $el.getBoundingClientRect()
if (_this.plan) {
let plan = _this.plan
slider.style.left = (plan / 100) * rect.width 'px'
}
slider.ontouchstart = function(event) {
event.preventDefault()
document.ontouchmove = function(e) {
var oEvent = e.touches[0]
var sliderX = oEvent.clientX - rect.left
if (sliderX < 0) {
sliderX = 0
} else if (sliderX > rect.width) {
sliderX = rect.width
}
// console.log(sliderX)
//滑块的位置
slider.style.left = sliderX 'px'
//进度条的长度
_this.plan = ((sliderX / rect.width) * 100).toFixed(0)
}
document.ontouchend = function() {
document.ontouchmove = null
document.ontouchstart = null
}
}
},
init(el) {
// 判断是否为移动设备
if (/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)) {
this.touchStart(el)
} else {
this.mouseDown(el)
}
}
}
}
</script>
<style lang="scss" scoped>
.plan_box {
margin: 50px 0;
height: 11px;
width: 300px;
// border: 1px solid black;
background: #f1f1f1;
box-sizing: border-box;
position: relative;
display: flex;
justify-content: center;
align-items: center;
border-radius: 5px;
.plan {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
// background: black;
border-radius: 5px;
}
.slider {
cursor: grab;
position: absolute;
left: 0px;
&::before {
content: '';
display: block;
width: 20px;
height: 20px;
border-radius: 50%;
background: white;
box-shadow: 2px 2px 4px #919191;
position: absolute;
left: -10px;
top: -10px;
}
.text {
font-size: 12px;
position: absolute;
display: inline-block;
padding: 5px;
border-radius: 3px;
background: white;
top: -45px;
left: -20px;
box-shadow: 2px 2px 4px #d3d3d3;
}
}
}
</style>