华为快应用中自定义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
相关推荐
无咎.lsy8 分钟前
vue之vuex的使用及举例
前端·javascript·vue.js
fishmemory7sec15 分钟前
Electron 主进程与渲染进程、预加载preload.js
前端·javascript·electron
小叶学C++16 分钟前
【C++】类与对象(下)
java·开发语言·c++
ac-er888817 分钟前
PHP“===”的意义
开发语言·php
fishmemory7sec18 分钟前
Electron 使⽤ electron-builder 打包应用
前端·javascript·electron
jk_10136 分钟前
MATLAB中decomposition函数用法
开发语言·算法·matlab
weixin_4640780736 分钟前
C#串口温度读取
开发语言·c#
无敌の星仔39 分钟前
一个月学会Java 第2天 认识类与对象
java·开发语言
豆豆1 小时前
为什么用PageAdmin CMS建设网站?
服务器·开发语言·前端·php·软件构建
JUNAI_Strive_ving2 小时前
番茄小说逆向爬取
javascript·python