vue滑动进度条组件,可点击、可拖拽
程序员文章站
2024-02-05 12:09:04
...
刚好碰到一个功能是做audio自定义播放样式的,但又没有相关的组件,因此自己封装一个,分享给大家。大家可根据自己的需求进行样式的修改,其中有bug和不足的,欢迎大家指出。
效果图
录屏有点边框,请忽略~
组件c-progress的使用
导入
import CProgress from './../components/c-progress'
使用
<c-progress class="c-progress" :percent="70" @percentChange="onPercentChange" />
<c-progress class="c-progress" :percent="70" :show-slider="true" :show-per-text="false"/>
<c-progress class="c-progress" :percent="70" :show-slider="true" :width="400"/>
<c-progress class="c-progress" :percent="70" :show-slider="true" :width="200" :slider-width="15"/>
<c-progress class="c-progress" :percent="80" :show-slider="false" progress-color="red"/>
<c-progress class="c-progress" :percent="80" :show-slider="false" type="warning"/>
<c-progress class="c-progress" :percent="80" :show-slider="false" type="fail"/>
<c-progress class="c-progress" :percent="90" :show-slider="true" type="success" />
组件的属性
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
percent | 百分比 | Number | 60 |
showSlider | 是否显示滑块 | Boolean | true |
showPerText | 是否显示百分比 | Boolean | true |
width | 进度条的宽度 | Number | 300 |
sliderWidth | 进度条的宽度 | Number | 300 |
bgColor | 背景颜色 | String | #ebeef5 |
progressColor | 进度的颜色 | String | #409EFF |
type | 进度的颜色类型(与progressColor只能填一个) | String | default |
组件的事件
事件名 | 说明 |
---|---|
percentChange | 百分比的变化在事件的第一个参数返回, percentChange(per) |
<c-progress class="c-progress" :percent="70" @percentChange="onPercentChange" />
onPercentChange (per) {
console.log(per)
}
组件源码
<template>
<div class="c-progress">
<div class="c-progress-outer" :style="setProgressBgStyle" ref="progress">
<div class="c-progress-inner" :style="setProgressStyle"></div>
<div v-if="showSlider" class="c-progress-slider" ref="slider" :style="setSliderStyle"></div>
</div>
<span v-if="showPerText">{{tempPercent}}%</span>
</div>
</template>
<script>
// 使用了element的颜色
const colorTable = {
success: '#13ce66',
fail: '#ff4949',
warning: '#e6a23c',
default: '#409EFF'
}
export default {
name: 'CProgress',
props: {
percent: {
type: Number,
default: 60
},
showSlider: {
type: Boolean,
default: true
},
showPerText: {
type: Boolean,
default: true
},
// 进度条的宽度
width: {
type: Number,
default: 300
},
bgColor: {
type: String,
default: '#ebeef5'
},
progressColor: {
type: String,
default: '#409EFF'
},
// 滑块的宽度
sliderWidth: {
type: Number,
default: 20
},
// 颜色的类型
type: {
type: String,
default: colorTable.default
}
},
data () {
return {
sliderLeft: 0, // 滑块相对父元素发x坐标
progressWidth: 0, // 进度条当前的的宽度
tempPercent: 0
}
},
computed: {
// 设置进度条的背景样式
setProgressBgStyle () {
return {
// 加上滑块的宽度
width: `${this.width + this.sliderWidth}px`
}
},
// 设置进度条的样式
setProgressStyle () {
const color = colorTable[this.type] || this.progressColor
return {
width: `${this.progressWidth}px`,
background: color
}
},
// 设置滑块的样式
setSliderStyle () {
const color = colorTable[this.type] || this.progressColor
return {
border: `1px solid ${color}`,
width: `${this.sliderWidth}px`,
height: `${this.sliderWidth}px`,
left: `${this.sliderLeft}px`
}
}
},
mounted () {
this.sliderLeft = this.width / 100 * this.percent
this.progressWidth = this.sliderLeft + this.sliderWidth // 滑块的x坐标加上滑块的宽度
this.tempPercent = this.percent
this.addListener()
},
methods: {
addListener () {
const slider = this.$refs.slider
const progress = this.$refs.progress
let isClickSlider = false
let distance = 0 // 滑块与点击坐标的绝对距离
progress.onclick = (e) => {
// 阻止事件冒泡
if (e.target == slider) {
return
}
let curX = progress.offsetLeft
this.sliderLeft = e.pageX - curX
if (this.sliderLeft <= 0) {
this.sliderLeft = 0
}
if (this.sliderLeft >= this.width) {
this.sliderLeft = this.width
}
this._countCurPercent()
}
slider.onmousedown = (e) => {
isClickSlider = true
let curX = slider.offsetLeft
distance = e.pageX - curX // 得出绝对距离
}
progress.onmousemove = (e) => {
if (isClickSlider) {
// 判断是否已经超出进度条的长度
if ((e.pageX - distance) >= 0 && (e.pageX - distance) <= (this.width - 0)) {
this.sliderLeft = e.pageX - distance
this._countCurPercent()
}
}
}
progress.onmouseup = () => {
isClickSlider = false
}
},
// 算出百分比
_countCurPercent () {
this.tempPercent = Math.ceil(parseInt(this.sliderLeft / this.width * 100))
this.progressWidth = this.sliderLeft + 20
// 取整的时候宽度可能不为0,所以在0和100的时候也将宽度取整
if (this.tempPercent <= 0) {
this.progressWidth = 0
this.sliderLeft = 0
}
if (this.tempPercent >= 100) {
this.progressWidth = this.width + 20
this.sliderLeft = this.width
}
this.$emit('percentChange', this.tempPercent)
}
}
}
</script>
<style scoped lang="scss">
.c-progress {
$width: 300px;
$radius: 5px;
display: flex;
align-items: center;
span {
margin-left: 5px;
font-size: 14px;
color: #666;
}
.c-progress-outer {
width: $width;
height: 10px;
border-radius: $radius;
background: #ebeef5;
position: relative;
display: flex;
align-items: center;
.c-progress-inner {
width: 100px;
height: 10px;
background: #409EFF;
border-radius: $radius;
}
.c-progress-slider {
width: 20px;
height: 20px;
border-radius: 50%;
background: #fff;
border: 1px solid #409EFF;
position: absolute;
z-index: 10;
left: 10px;
}
}
}
</style>