6

HarmonyOS 实现一个悬浮球-51CTO.COM

 2 years ago
source link: https://os.51cto.com/article/715072.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

HarmonyOS 实现一个悬浮球-51CTO.COM

HarmonyOS 实现一个悬浮球
作者:lxj29 2022-07-28 14:20:44
很多手机都有悬浮球的功能,并且悬浮球可以有很多功能点,可以显示、隐藏与拖拽,这次我也来实现一个悬浮球的组件
89d4db031b3884797cb6061bced3e3e6e3bfcc.png

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

很多手机都有悬浮球的功能,并且悬浮球可以有很多功能点,可以显示、隐藏与拖拽,这次我也来实现一个悬浮球的组件

这是一个悬浮球,我们可以对这个悬浮球进行拖拽,当靠近左右两边时,会自动进行隐藏

#夏日挑战赛# HarmonyOS 实现一个悬浮球-开源基础软件社区

Number

Number

isShow

是否显示悬浮球

Boolean

1、拖拽原理

获取元素有两种方法:this.refs(“ball”),注意:获取元素不能在onInit()中获取,否则获取不到。

  • 在手指触摸事件中,将触摸时的坐标获取并存储,通过e.touches[0].localX获取。
  • 手指触摸屏幕移动的事件中,我们再获取移动后的坐标,通过移动后的坐标 - 移动前的坐标,就可以得到偏移量,最后再将当前坐标存储,依次循环。
  • 计算得到偏移量后,我们需要获取当前元素距离左边和顶部的距离,将该距离和偏移量相加,就能得到元素的最新位置。
  • 将最新的元素位置,通过动态样式赋值给元素,就能实现拖拽了。
// 手指刚触摸屏幕时触发该事件。
    mousedownHandler (e) {
        this.startPositionX = e.touches[0].localX;
        this.startPositionY = e.touches[0].localY;
        this.show()
    },
    // 手指触摸屏幕后移动时触发该事件
    mousemoveHandler (e) {
        const offsetX = e.touches[0].localX - this.startPositionX;
        const offsetY = e.touches[0].localY - this.startPositionY;
        const ball = this.$element("ball")
        this.left = ball.getBoundingClientRect().left + offsetX
        this.top = ball.getBoundingClientRect().top + offsetY
        this.startPositionX = e.touches[0].localX;
        this.startPositionY = e.touches[0].localY;
    },

2、显示与隐藏

显示与隐藏需要配合动画效果会更好!

  • 定义显示与隐藏两个事件,当我们触发手指触摸屏幕事件时,调用显示事件;当触发手指触摸结束离开事件时,调用隐藏事件。
  • 隐藏事件的触发条件:当元素贴近左侧或者右侧时,就将元素进行隐藏,隐藏就是将元素的一半位置移除屏幕外。

通过判断条件,当元素距离左侧位置left小于0时,就将元素的一半宽度,赋值给left,注意需要设置为负值!当元素贴近右侧,此时需要获取屏幕宽度和元素宽度,因为当元素的右侧贴近屏幕右侧时,即触发隐藏事件,所以需要通过屏幕宽度-元素宽度。

  • 显示事件的触发条件:我们只需要判断元素距离左侧位置left是否小于0即可,如果小于零,就让left=0;再判断元素距离右侧是否大于屏幕宽度-元素宽度,如果是,就让元素右侧距离 = 屏幕宽度-元素宽度。
hide(){
        const container = this.$element("container")
        const ball = this.$element("ball")
        const containerWidth = container.getBoundingClientRect().width
        const ballWidth = ball.getBoundingClientRect().width
        if(this.left<0){
            this.left = -ballWidth/2
        }else if(this.left > containerWidth-ballWidth){
            this.left = containerWidth-ballWidth/2
        }
    },
    show(){
        const container = this.$element("container")
        const ball = this.$element("ball")
        const containerWidth = container.getBoundingClientRect().width
        const ballWidth = ball.getBoundingClientRect().width
        if(this.left<0){
            this.left = 0
        }else if(this.left > containerWidth-ballWidth){
            this.left = containerWidth-ballWidth
        }
    }

index.js:

// @ts-nocheck
export default {
    data: {
        // 标记滑块是否显示
        isShow: true,
        startPositionX: 0,
        startPositionY: 0,
        top: null,
        left: null
    },
    onInit(){
        this.top = 0;
        this.left = 0;
    },
    // 手指刚触摸屏幕时触发该事件。
    mousedownHandler (e) {
        this.startPositionX = e.touches[0].localX;
        this.startPositionY = e.touches[0].localY;
        this.show()
    },
    // 手指触摸屏幕后移动时触发该事件
    mousemoveHandler (e) {
        const offsetX = e.touches[0].localX - this.startPositionX;
        const offsetY = e.touches[0].localY - this.startPositionY;
        const ball = this.$element("ball")
        this.left = ball.getBoundingClientRect().left + offsetX
        this.top = ball.getBoundingClientRect().top + offsetY
        this.startPositionX = e.touches[0].localX;
        this.startPositionY = e.touches[0].localY;
    },
    // 手指触摸结束离开屏幕时触发该事件。
    mouseupHandler (e) {
        this.hide();
    },
    hide(){
        const container = this.$element("container")
        const ball = this.$element("ball")
        const containerWidth = container.getBoundingClientRect().width
        const ballWidth = ball.getBoundingClientRect().width
        if(this.left<0){
            this.left = -ballWidth/2
        }else if(this.left > containerWidth-ballWidth){
            this.left = containerWidth-ballWidth/2
        }
    },
    show(){
        const container = this.$element("container")
        const ball = this.$element("ball")
        const containerWidth = container.getBoundingClientRect().width
        const ballWidth = ball.getBoundingClientRect().width
        if(this.left<0){
            this.left = 0
        }else if(this.left > containerWidth-ballWidth){
            this.left = containerWidth-ballWidth
        }
    }
}

index.hml:

<div class="container" id="container">
    <div
         id="ball"
         class="floatBall"
         style="left: {{left}}px;top: {{top}}px;"
         @touchstart="mousedownHandler"
         @touchmove="mousemoveHandler"
         @touchend="mouseupHandler">
        <slot></slot>
    </div>
</div>

index.css:

.container {
    width: 100%;
    height: 100%;
    position: relative;
    overflow: hidden;
}
.floatBall {
    position: absolute;
}

不足点:拖拽感觉不流畅,后续还需要优化

最后,通过自定义组件,加深对HarmonyOS的开发,共建鸿蒙生态!

文章相关附件可以点击下面的原文链接前往下载:

https://ost.51cto.com/resource/2218。

​想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com​​。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK