#夏日挑战赛#【FFH】实现组件拖拽(OpenHarmony JS UI) 原创 精华

FFH_PETSJ
发布于 2022-6-15 18:51
浏览
2收藏

本文正在参加星光计划3.0–夏日挑战赛
【FFH】实现组件拖拽(OpenHarmony JS UI)

原本打算实现canvas画布的拖拽效果,过程中尝试过几种方式,总结了一下分享出来。

Demo效果

#夏日挑战赛#【FFH】实现组件拖拽(OpenHarmony JS UI)-鸿蒙开发者社区

实现拖拽的效果主要有两种方式:

  1. 使用鸿蒙JS API官方文档提供的Drag事件 *
  2. 使用传统html方式的Touch事件
    这两种方式就目前实现拖拽效果来看并没有太大的差别,Move事件已经能满足大多数需要获取坐标的场景比如拖拽效果,至于新提供的Drag事件API还有什么特别的地方以后再继续探究。

*Ark UI

据我了解,传统的Web前端开发中,canvas是不支持move移动事件的,在但是鸿蒙自研的Ark UI框架中很好地改进了这一点,既移植了Web前端开发的优点(js+hml+css这一框架就对前端页面的开发很友好),又改进了不少它的缺点,使得Move事件的编写变得更简洁更易上手,而Web开发中需要在canvas外层套上一层个div容器,通过div来间接拖拽。

拖拽原理

组件位置实时跟随手指触屏坐标变化,鸿蒙JS UI提供了hml和js数据双向绑定的特性,因此可以很方便的进行数据更新。

拖拽实现

Drag

Drag事件包含三个事件对象DragEven,dragstart(开始拖拽)、drag(拖拽过程中)、dragend(拖拽结束)

<div style="position : absolute; border-color : red; border-width : 2px;
     left : {{ left }}; top : {{ top }}; width : {{w}}px; height : {{h}}px" ondrag="ondrag" 
     class="canvas">
     <canvas ref="canvas_1" style="width : 568px; height : 720px"></canvas>
</div>

hml中使用div包裹canvas画布,并将样式中的left和top与js进行绑定,并在data{}中初始化。

export default {
    data: {
        top: 600, //---距离屏幕顶部的距离
        left: 80, //---距离屏幕左端的距离
		w: 570, //---画布宽高
		h:690
    },
}

编写ondrag对应的方法:

ondrag(e){
      let nx = e.globalX;
      let ny = e.globalY;
      this.left = nx;
      this.top = ny;
}

上面利用了drag事件提供的除了通用属性外的额外属性:globalX和globalY——获取当前(全屏)触点的坐标(相对于左上角)。

下面引用官方文档的解释:
DragEvent对象属性列表(继承BaseEvent)7+

属性 类型 说明
type string 事件名称
globalX number 距离屏幕左上角坐标原点横向距离
globalY number 距离屏幕左上角坐标原点纵向距离
timestamp number 时间戳

因此,可以通过将globalX、globalY赋值给div的left和top使组件位置改变。

问题

仅仅是这样的话,触点的位置一直指向div组件的左上角,因为div的左上角坐标始终跟触点的坐标绑定。
那如何让图片始终跟随手指按下的位置开始移动?

改进

  1. 获取触摸开始时的坐标
  2. 计算移动坐标使得刚开始触摸的位置跟随手指移动
dragStart(e){
      x = e.globalX;
      y = e.globalY;
},
ondrag(e){
      let nx = e.globalX;
      let ny = e.globalY;
//        console.info("left="+ (nx-x))
//        console.info("top="+ (ny-y))
      if(nx+570-x<=gloX && ny+690-y<=gloY && nx-x>0 && ny-y>0){ //---这里screenX、screenY为屏幕宽高,避免超出屏幕范围
          this.left = nx-x;
          this.top = ny-y;
      }
}

这样便简单实现了组件根据手指开始触屏位置跟随移动的功能。

Touch

利用Touch事件的方式跟Drag的原理一样,最大区别只在于系统获取坐标位置的所提供的方法不同.

moveStart(e){
      x = e.touches[0].globalX;
      y = e.touches[0].globalY;
},
onMove(e){
      let nx = e.touches[0].globalX;
      let ny = e.touches[0].globalY;
      if(nx+this.screenX-x<=gloX && ny+this.screenY-y<=gloY && nx-x>0 && ny-y>0){
          this.left = nx-x;
          this.top = ny-y;
      }
}

Tips

在用Drag事件写的时候踩过坑:使用Previewer调试的时候,我发现用Drag事件写的拖拽效果体验不太好,而move事件能很流畅地进行拖拽,而Drag有时候能触发dragStart事件但是组件并不移动。(也许是跟调试器有关)
最终调试时,把

dragStart(e){
      x = e.globalX;
      y = e.globalY;
},

换成

moveStart(e){
      x = e.touches[0].globalX;
      y = e.touches[0].globalY;
},

瞬间流畅了,而移动“时”事件使用onMove或onDrag的效果都没有差别。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-6-15 18:56:29修改
8
收藏 2
回复
举报
2条回复
按时间正序
/
按时间倒序
析翳
析翳

AMG手机能实现操作吗?

 

回复
2022-6-17 00:28:49
seiichi123
seiichi123

这个实现效果很棒

回复
2022-7-29 10:55:04
回复
    相关推荐