华为快应用中自定义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
相关推荐
方也_arkling12 小时前
别名路径联想提示。@/统一文件路径的配置
前端·javascript
卢锡荣12 小时前
Type-c OTG数据与充电如何进行交互使用应用讲解
c语言·开发语言·计算机外设·电脑·音视频
毕设源码-朱学姐12 小时前
【开题答辩全过程】以 基于web教师继续教育系统的设计与实现为例,包含答辩的问题和答案
前端
qq_1777673712 小时前
React Native鸿蒙跨平台剧集管理应用实现,包含主应用组件、剧集列表、分类筛选、搜索排序等功能模块
javascript·react native·react.js·交互·harmonyos
qq_1777673712 小时前
React Native鸿蒙跨平台自定义复选框组件,通过样式数组实现选中/未选中状态的样式切换,使用链式调用替代样式数组,实现状态驱动的样式变化
javascript·react native·react.js·架构·ecmascript·harmonyos·媒体
A懿轩A12 小时前
【Java 基础编程】Java 变量与八大基本数据类型详解:从声明到类型转换,零基础也能看懂
java·开发语言·python
2301_8112329812 小时前
低延迟系统C++优化
开发语言·c++·算法
web打印社区12 小时前
web-print-pdf:突破浏览器限制,实现专业级Web静默打印
前端·javascript·vue.js·electron·html
我能坚持多久12 小时前
D20—C语言文件操作详解:从基础到高级应用
c语言·开发语言
橘子师兄13 小时前
C++AI大模型接入SDK—ChatSDK封装
开发语言·c++·人工智能·后端