文章目录
一、前言
在华为快应用中官方提供了<slider>
控件,但是这个控件的限制比较多,比如滑块无法自定义,所以这里进行下自定义,自己修改样式。
二、实现代码
整体效果如下:
源码如下:
custom_slider.ux
html
<template>
<div id="container">
<div id="progress-background"></div>
<div id="progress-second" style="width: {{progressSecondWidth}}px"></div>
<div id="slider" style="left: {{left}}px" ontouchmove="handleTouchMove"></div>
</div>
</template>
<script>
import prompt from '@system.prompt'
export default {
props: [
'progress',
'min',
'max',
'step'
],
public: {
progressSecondWidth: 0,
left: 0,
right: 0,//右侧可以滑动到的位置
containerLeft: 0,
containerRight: 0,
stepWidth: 1, // 每一步滑动的距离,这个根据step值进行计算
minDuration: 5, //滑动最小间距,小于这个间距不算滑动
},
onInit: function () {
this.$on('onShow', this.onShow)
this.$watch('progress', 'progressChange')
},
progressChange(newValue, oldValue) {
console.log('progressChange:' + JSON.stringify(newValue))
if(newValue === oldValue){
return
}
this.sliderOtherProgress(newValue)
},
handleTouchMove(e) {
let touchX = e.touches[0].clientX - this.containerLeft; // 获取触摸点的全局X坐标
if (touchX - this.progressSecondWidth < -this.minDuration) {
this.leftSlide()
}
if (touchX - this.progressSecondWidth > this.minDuration) {
this.rightSlide()
}
this.emitChange()
},
onShow(e) {// 或者使用onReady()的生命周期的函数调用这个,但是记得外部不要再传递onShow的广播
let that = this
this.$element('container').getBoundingClientRect({
success: function (data) {
const { top, bottom, left, right, width, height } = data;
prompt.showToast({
message: `getBoundingClientRect结果: width:${width}, height:${height},
top:${top}, bottom:${bottom}, left:${left}, right:${right}`
})
that.containerLeft = left
that.containerRight = right
that.right = right - left - 40 //40是滑块的宽度
that.computerStepWidth()
},
fail: (errorData, errorCode) => {
prompt.showToast({
message: `错误原因:${JSON.stringify(errorData)}, 错误代码:${errorCode}`
})
},
complete: function () {
console.info('complete')
}
})
},
//向左滑动
leftSlide() {
let nextWidth = this.progressSecondWidth - this.stepWidth
if (nextWidth <= 0) {
nextWidth = 0
}
this.progressSecondWidth = nextWidth
this.left = nextWidth;
},
//向右滑动
rightSlide() {
let nextWidth = this.progressSecondWidth + this.stepWidth
if (nextWidth >= this.right) {
nextWidth = this.right
}
this.progressSecondWidth = nextWidth
this.left = nextWidth;
},
computerStepWidth() {
let progressMax = 100;
let progressMin = 0;
let progressStep = 1;
let currentProgress = 0;
if (this.max) {
progressMax = this.max
}
if (this.min) {
progressMin = this.min
}
if (this.step) {
progressStep = this.step
}
if (this.progress) {
currentProgress = this.progress
}
this.stepWidth = this.right / (progressMax - progressMin) * progressStep //获取每一步滑动的距离
let currentProgressWidth = this.stepWidth * currentProgress
this.progressSecondWidth = currentProgressWidth
},
sliderOtherProgress(progress){
let nextWidth = progress + this.stepWidth
if (nextWidth >= this.right) {
nextWidth = this.right
}
if (nextWidth <= 0) {
nextWidth = 0
}
this.progressSecondWidth = nextWidth
this.left = nextWidth;
this.emitChange()
},
emitChange() {
let progress = Math.ceil(this.progressSecondWidth / this.stepWidth)
this.$emit('change', {
progress
})
}
}
</script>
<style lang="less">
#container {
flex-grow: 1;
height: 24px;
display: flex;
}
#progress-background {
flex-grow: 1;
height: 4px;
background-color: red;
margin-top: 10px;
border-radius: 4px;
}
#progress-second {
height: 4px;
background-color: pink;
margin-top: 10px;
border-radius: 4px;
left: 0px;
position: absolute;
}
#slider {
width: 40px;
height: 24px;
background-color: #3b2204;
position: absolute;
border-radius: 12px;
}
</style>
使用如下:
html
<import name="custom-slider" src="./custom_slider"></import>
...
<custom-slider onchange="progressChange" progress="{{customSliderProgress}}"></custom-slider>
<script>
import prompt from '@system.prompt'
export default {
public: {
customSliderProgress: 30,
},
progressChange(evt){
console.log("--->当前进度",evt.detail.progress);
},
},
onShow(){
//这里需要注意的是slider是作为组件嵌入的,所以这里需要在显示的时候调用该函数让slider去刷新UI
//如果子组件里面使用onReady()的生命周期的函数初始化计算逻辑,那么这里就不需要延迟发送消息了
setTimeout(() => {//延迟发送广播,否则控件可能没有渲染完成
console.log("YM--->延迟发送广播")
this.$broadcast('onShow', {})
}, 100)
}
</script>
...