前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >「实战」如何用H5实现原生体验的图片预览组件

「实战」如何用H5实现原生体验的图片预览组件

作者头像
用户1097444
发布2022-06-29 17:17:01
3K0
发布2022-06-29 17:17:01
举报
文章被收录于专栏:腾讯IMWeb前端团队

| 导语 手Q终端原生的图片预览器支持图片翻页和各种手势,这些用H5怎样实现?基于alloyFinger,本文将介绍在手Q动漫上的图片预览组件是如何做到媲美原生体验的手势效果,同时也介绍一下关于图片手势效果里隐含的一些细节。希望对要实现手势交互和动画的前端同学有所启发。

作者:朱晓华--腾讯web前端工程师

@IMWeb前端社区

一、实现效果

先来看实现效果。目前已经上线的图片预览组件的路径如下:手Q动态——动漫——社区——点击图片。

类比手Q的AIO里的图片预览器,支持的手势和功能分别如下:

手Q动漫这里之所以没有直接用手Q原生的图片预览器,而是新造一个轮子,主要原因是手Q动漫的图片预览器有一些定制的功能和ui展示,用web来实现更快捷可控一些。从上表可以看出,除了旋转图片之外,基本上跟手Q原生体验无异。旋转图片在alloyFinger中有提供方法支持,但由于本需求中使用场景少而且涉及更复杂的坐标变换,因此我目前还没添加上。后续工作量许可的情况下会支持。

二、实现基础

图片预览组件目前是基于alloyFinger.js来做手势支持,transform.js来做CSS3的变换,to.js来做动画的过渡函数。

关于alloyFinger.js组件 https://github.com/AlloyTeam/AlloyFinger 组件提供了单击、双击、长按、拖动、旋转等手势支持。基于这些手势有很多玩法。这里就不详细叙述了。

关于transform.js组件 http://alloyteam.github.io/AlloyTouch/transformjs/ alloyFinger只提供了手势支持,但手势具体要实现的图片位置变换或者缩放的效果,需要由transform.js来支持。transform.js给dom元素添加了css3的属性对应的js属性,例如translateX, translateY, translateZ, scaleX, scaleY, scaleZ, rotateX, rotateY, rotateZ, skewX, skewY, originX, originY, originZ。 获取属性只需要var x = ele.translateX,而设置css3属性只需要ele.transalteX = 10,非常方便。

关于to.js组件 https://github.com/AlloyTeam/AlloyFinger/blob/master/asset/to.js to.js组件以requestAnimationFrame为基础,提供了设置dom元素属性的过渡函数,支持传入渐入渐出相关的函数。用法如下:

三、实现细节

1. 翻页的实现

理论上支持图片无限翻页,这里实现的方法是: 任何时候都保持三张图片在容器中并且中间的图片在屏幕内。翻页之后再通过删除前一张和补充后一张来维持三张图片的状态。 这样的好处是:更少的dom节点和更好的动画性能、支持用户主动添加和删除图片、支持异步添加图片。

2. 在origin、scale和translate三个因素下的坐标变换

正常情况下,图片缩放是只需要设置scale为你所需要的倍数就行了。双击缩放和双指缩放的原理差不多,都是需要先设置css3的transform的坐标变换中心origin,只不过双指缩放是以两个手指连线的中点作为缩放原点。因此开始的代码只需要是:

但在放大2倍的情况下,两个手指再次放到图片上另一个位置缩放的时候,图片会跳动。原因是,在有scale的情况下,改变了origin值,要保持图片位置不变,则需要同时改变translate来平移图片。 例如,对于宽高都是100的图片,在当前origin=(0,0),scale=2,translate=(0,0)的情况下,当你修改origin=(50,50)时,scale=2不变,应有translate=(50,50)。 ps:对于transform.js的origin,默认是0表示是图片50%的位置,只能设置px值不能设置比例 例如下图中,图1是当前图片从当前中心点放大两倍的情况,实际上等同与从图2平移到图3。

“容易证明”得以下数学公式↓↓↓ 以X轴为例,假设放大倍数是s,计算新的translateX的数学公式如下:

谨记这个公式,下面基本上所有涉及到缩放状态的变换都以这个为基础。

在这个公式的使用时机是每次touchstart的时候,都要重新调整origin和translate的值,然后手指缩放的touchmove里再对scale做改变。就能实现多次变换位置的缩放了。代码例如:

3. 手势细节-边界检测

图片放大之后,支持拖动图片查看细节。实现的原理很简单,touchmove的时候,改变图片的translate值即可。对比手Q的AIO的图片预览,在拖动图片到图片边缘的时候,检测边界并禁止继续拖动。 (1) 当图片的缩放原点origin为(0,0)时 以X轴为例,假设图片宽度为w,放大倍数为s,则translateX的区间为

图示边界的四种情况:

(2) 但实际过程中,因为图片的原点origin不一定是(0,0),因此上述区间不适用 解决方法也简单,根据当前的origin和translate,通过translateX2 = translateX1 + (originX2 - originX1) * s公式,计算出图片当前位置在origin=(0,0)的时候translate应该是哪些值。然后再套用上面的区间来判断边界即可。

4. 手势细节-自动贴边

当图片放大再缩小的时候,图片有可能还是超出边界了。因此,在手指松开之后,需要让图片自动贴近到该方向的屏幕边缘。 自动贴边得益于上述的边界检测的方法,在touchend中判断超出边界之后,自动把translate设置到最近的边界值。

5. 手势细节-惯性

单指拖动图片然后松开手指时,手Q原生的图片预览器有继续滑动一段距离的惯性效果。 滑动到终点之后,图片真正停在的点是在延长点上。那延长点要怎么计算呢,这里可以用向量的知识来指导坐标的计算方法。

假设起点起点坐标(x1, y1),终点坐标(x2, y2),滑动距离是l,需要计算延长点(x3, y3)的公式如下:

当然这里有个小问题,就是滑动距离l的定义。如果拖动的起点和终点距离很小,那么滑动距离也应该很小才对。否则就导致轻轻拖动一下,惯性却非常大。因此滑动距离是拖动距离的一个小比例值。

上述的实现惯性的方法其实只能算近似模拟,不符合现实生活中曲线运动的问题的惯性运动轨迹。 实际上的运动延长线的方向,应该是曲线在终点位置的切线。而且实际的惯性滑动距离,也是跟当前的速度有关,而不是一个恒定的比例值。这里后期优化的时候,会考虑这些点。

6. 手势细节-回弹

交互上,图片放大和缩小是有倍数限制的,超过最大/最小倍数值的时候,会让用户继续放大一部分,但再超过一定的阈值之后会停止放大,并在手指松开之后回弹到最大/最小倍数。这样的交互形式让用户对放大缩小的最大限制有一个直观的了解,避免生硬的交互体验。 这里的实现原理很简单:在alloyFinger的pinch回调中,设置最大倍数为max+n,其中n为超出阈值。在touchend的回调中,设置缩小值回弹到max。

四、总结

感谢@dntzhang 提供alloyFinger的支持,感谢@javinzhong 提供的先行实验版。我的工作是站在两位巨人的肩膀上才得以实现。 总的来说,这个项目除了加深自己对web手势和css3动画的理解之外,对于深入挖掘图片手势的细节和效果也是很有帮助。很多产品细节是需要不断地打磨和优化的,对自己的工作需要多的细节追求和精力倾注才能有好的成果,与君共勉(不小心抖了个鸡汤-_-)

扫码下方二维码,

随时关注更多前端干货文章!

微信:IMWebTech

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2017-04-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯IMWeb前端团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、实现效果
  • 二、实现基础
  • 三、实现细节
    • 1. 翻页的实现
      • 2. 在origin、scale和translate三个因素下的坐标变换
        • 3. 手势细节-边界检测
          • 4. 手势细节-自动贴边
            • 5. 手势细节-惯性
              • 6. 手势细节-回弹
              • 四、总结
              相关产品与服务
              容器服务
              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档