HarmonyOS - 基于ArkUI (JS) 实现图片旋转验证

Posted 开源基础软件社区官方

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HarmonyOS - 基于ArkUI (JS) 实现图片旋转验证相关的知识,希望对你有一定的参考价值。

作者:王少丽

前言

通过学习其他人的slider滑块组件衍生出的小组件, 本文主要结合HarmonyOS官网上的相关组件以及通用API,来实现一个图片的旋转验证 -- 需拖动滑块将图片旋转还原为正确,方可验证通过。

效果演示

实现原理

  1. 触发条件

    基于HarmonyOS通用事件touchstart和touchmove,touchend,通过手指刚触摸屏幕时触发、手指触摸屏幕后移动时触发事件,手指触摸屏幕后结束时触发事件;

  2. 实现slider滑块效果

    通过touches触摸事件的属性集合,返回屏幕触摸点的信息数组,拿到localX距离被触摸组件左上角横向距离,动态计算出子元素的宽度来实现slider滑块效果。

  3. 实现图片旋转效果

    初始化随机生成360°以内的角度,设置图片原点,360°除以100就得到圆的步长比上滑动距离除滑块总长度,最后加上图片原点就等于旋转后的角度。

使用到的官方API

通用方法

getBoundingClientRect()

获取元素的大小及其相对于窗口的位置。

属性 类型 描述
width number 该元素的宽度。
height number 该元素的高度。
left number 该元素左边界距离窗口的偏移。
top number 该元素上边界距离窗口的偏移。

通用事件

名称 参数 描述 是否支持冒泡
touchstart TouchEvent 手指刚触摸屏幕时触发该事件。 是5+
touchmove TouchEvent 手指触摸屏幕后移动时触发该事件。 是5+
touchend TouchEvent 手指触摸屏幕后结束时触发该事件。 是5+
属性 类型 说明
touches Array<TouchInfo> 触摸事件时的属性集合,包含屏幕触摸点的信息数组。
属性 类型 说明
globalX number 距离屏幕左上角(不包括状态栏)横向距离。屏幕的左上角为原点。
globalY number 距离屏幕左上角(不包括状态栏)纵向距离。屏幕的左上角为原点。
localX number 距离被触摸组件左上角横向距离。组件的左上角为原点。
localY number 距离被触摸组件左上角纵向距离。组件的左上角为原点。

实现过程

1. htm部分

<div class="slider-wrapper" style="flex-direction: column;">
    <div style="width: 100%;padding-top: 40px;">
        <text class="title" >
            <span>请</span>
            <span style="color: #F56A00;">
                拖动
            </span>
            <span>滑块旋转至正确位置</span>
        </text>
    </div>
    <div for=" item in imagesArr " tid="id" class="imagesArr">
        <div class="img">
            <image src=" item.src "></image>
       </div>
        <div class="pic">
            <image src="item.duan" style="transform: rotate(numdeg);"  id="rotatepic"></image>
        </div>
    </div>
    <div class="content" style="width: 300px;flex-direction: row;" >
        <div id="slider"  @touchstart="boxChoose" @touchmove="boxChoose" @touchend="Chooseend" style="width: 280px;background-color: #0fbda0;">
            <div class="slider-main" style="width:  width ;background-color: #73E9C5;" ></div>
            <text class="text" show=" done ">
                请拖动至正确位置
            </text>
            <text class="success text" show=" success ">
               验证通过
            </text>
            <text class="fail text" show=" fail ">
                验证失败,请重试
            </text>
        </div>
        <div class="dot" style ="left : dotLeft;background-color: #0fbda0;height: 60px;" show=" textblock "  >
            <text style="color: white;font-size: 20px;">
                >>>
            </text>
        </div>
        <div class="dot" style ="left : dotLeft;height: 60px;background-color: #10A68D;" show=" textblock2 ">
            <text style="color: white;font-size: 20px;">
                >>>
            </text>
        </div>
        <div show=" imageblock " class="imageblock" >
            <image src="../../common/images/succes.jpg"></image>
        </div>
    </div>

</div>

2. css部分

.slider-wrapper 
    width: 100%;
    display: flex;
    align-items: center;
    flex-direction: column;
    background-color: bisque;
    position: relative;

.title
    width: 100%;
    font-size: 20px;
    text-align: center;

.imagesArr
    width: 90%;


.img
    height: 200px;

.pic
    height: 200px;
    width: 200px;
    position: absolute;
    left: 62px;
    top: 0;

.content
    width: 360px;
    display: flex;
    align-items: center;
    flex-direction: row;
    position: relative;
    margin-top: 50px;
    position: relative;

#slider 
    width: 300px;
    height: 50px;
    background-color: #0fbda0;
    display: flex;
    justify-content: center;

.text
    font-size: 15px;

.fail
    color: red;

.success
    color: black;

.slider-main 
    background-color: #73E9C5;
    width: 0;
    height: 100%;
    position: absolute;
    left: 0;
    top: 0;
    border: 1px solid #d9f3ef;

.dot
    width: 50px;
    height: 50px;
    background-color: #0fbda0;
    position: absolute;
    bottom: -5px;
    border-radius: 5px;


.dot text
    text-align: center;
    padding-left: 5px;
    color:#A69E9E;

.imageblock
    height: 50px;
    width: 50px;
    position: absolute;
    right: 10px;

3. js部分

export default 
    data: 
        progress:0,
        width: 0,
        step1: 1,
        dotLeft:0,
        img:../../common/images/succes.jpg,
        imageblock:false,
        textblock:true,
        success:false,
        fail:false,
        done:true,
        numdeg:Math.round(Math.random()*360),// 初始化的随机角度
        startNumdeg: 0,
        textblock2:false,
        imagesArr:[
            src:common/images/ro.jpg,duan:common/images/ro.png,
        ],

    ,
    onInit()
        this.startNumdeg = this.numdeg;
    ,
    //控制点击结束后的样式
    Chooseend( )
        if(this.success && this.imageblock) 
            return
        
        if (!this.textblock ) 
            this.disable = true
        
        console.log(Chooseend==this.startNumdeg == + this.startNumdeg + ===this.numdeg=== + this.numdeg)
        if (this.width &&Math.abs(this.numdeg-360)<=5) 
            this.width = 240;
            this.progress = 100;
            this.textblock = false;
            this.fail = false;
            this.success =true;
            this.done =false;
            this.textblock2 =false;
            this.dotLeft = 0;
            this.numdeg = 0
            this.imageblock = true;
        else
            this.width = 0;
            this.progress = 0;
            this.fail = true;
            this.success =false;
            this.done =false;
            this.textblock2 = true;
            this.textblock = false
            this.dotLeft =0
            this.numdeg = this.startNumdeg + (360/100) * (this.width / 240)*100

        
    ,
    boxChoose(e) 
        if(this.success && this.imageblock) 
            return
        
        let slider = this.$element(slider)
        let width = e.touches[0].localX // 获取点击时距离容器左边位置
        this.dotLeft = width
        let elementWidth = slider.getBoundingClientRect().width //元素的宽度
        // 正方形的偏移量临界值
        if ( this.dotLeft >= elementWidth ) 
            this.dotLeft = 240
        
        let compare = elementWidth / (100 / this.step1) // 根据步长计算每一步宽度 2.4
        this.width = Math.ceil(width / compare) * compare   //滑动距离
        this.width = this.width < 0 ? 0 : (this.width > 240 ? 240 : this.width)
        this.numdeg = this.startNumdeg + 360 * (this.width / 240) //图像处理
        this.progress = Math.abs(this.width / elementWidth *100)   //slider滑块
        if (this.width>0) 
            this.fail = false;
            this.done = true
        
        if (this.width>=240) 
            this.width = 280
        
    ,

总结

这篇文章是我通过对slider滑块的一个延伸练习,也算是一个比较常用的组件,后续部分功能还需完善,比如在样式、功能及代码优化方面等等,还有很多不足之处,大家有想法的可以提出来,我们一起学习,共同进步!

更多原创内容请关注:中软国际 HarmonyOS 技术团队

入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。

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

51CTO 开源基础软件社区

https://ost.51cto.com/#bkwz

以上是关于HarmonyOS - 基于ArkUI (JS) 实现图片旋转验证的主要内容,如果未能解决你的问题,请参考以下文章

HarmonyOS - 基于ArkUI(JS)实现彩带飘动特效

#夏日挑战赛# HarmonyOS - 基于ArkUI(JS)实现打地鼠游戏

HarmonyOS - 基于ArkUI(JS)实现信件弹出效果

#打卡不停更# HarmonyOS - 基于ArkUI(JS)实现虚拟摇杆组件

HarmonyOS - 基于ArkUI(JS)实现黑白翻棋小游戏

HarmonyOS ArkUI之列表下拉刷新加载更多(TS)