华为快应用中自定义Slider效果

文章目录

一、前言

在华为快应用中官方提供了<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> 

...

三、参考链接

  1. touch
相关推荐
花花鱼4 分钟前
vue3 基于element-plus进行的一个可拖动改变导航与内容区域大小的简单方法
前端·javascript·elementui
k09338 分钟前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
神奇夜光杯16 分钟前
Python酷库之旅-第三方库Pandas(202)
开发语言·人工智能·python·excel·pandas·标准库及第三方库·学习与成长
Themberfue18 分钟前
Java多线程详解⑤(全程干货!!!)线程安全问题 || 锁 || synchronized
java·开发语言·线程·多线程·synchronized·
plmm烟酒僧20 分钟前
Windows下QT调用MinGW编译的OpenCV
开发语言·windows·qt·opencv
EricWang135829 分钟前
[OS] 项目三-2-proc.c: exit(int status)
服务器·c语言·前端
September_ning29 分钟前
React.lazy() 懒加载
前端·react.js·前端框架
测试界的酸菜鱼31 分钟前
Python 大数据展示屏实例
大数据·开发语言·python
web行路人39 分钟前
React中类组件和函数组件的理解和区别
前端·javascript·react.js·前端框架
番茄小酱00140 分钟前
Expo|ReactNative 中实现扫描二维码功能
javascript·react native·react.js