文章目录
- 一、前言
- 二、实现代码
- 三、参考链接
一、前言
在华为快应用中官方提供了<slider>
控件,但是这个控件的限制比较多,比如滑块无法自定义,所以这里进行下自定义,自己修改样式。
二、实现代码
整体效果如下:
源码如下:
custom_slider.ux
<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 = thisthis.$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 = leftthat.containerRight = rightthat.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.stepWidthif (nextWidth <= 0) {nextWidth = 0}this.progressSecondWidth = nextWidththis.left = nextWidth;},//向右滑动rightSlide() {let nextWidth = this.progressSecondWidth + this.stepWidthif (nextWidth >= this.right) {nextWidth = this.right}this.progressSecondWidth = nextWidththis.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 * currentProgressthis.progressSecondWidth = currentProgressWidth},sliderOtherProgress(progress){let nextWidth = progress + this.stepWidthif (nextWidth >= this.right) {nextWidth = this.right}if (nextWidth <= 0) {nextWidth = 0}this.progressSecondWidth = nextWidththis.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>
使用如下:
<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> ...
三、参考链接
- touch