当前位置: 首页 > 科技观察

2022强大之作:一个超精致的图片预览组件

时间:2023-03-13 06:38:50 科技观察

刚开始接触前端这个行业的时候,我有一个想法,那就是写一个超酷的图片预览库。还记得我用美图看的时候,那轻快的速度和交互,非常让人着迷。这个组件的不完整版本几年前就出过,后来断断续续维护过,总感觉少了点什么。今年春节没休息,都在上面开发,现在终于完美实现了!先来看看效果:缩略图完美渐变:指定位置放大:慢速滚动:什么是react-photo-viewreact-photo-view拥有无与伦比的预览交互体验:从打开图片开始,每一帧的动画、细节和交互都经过精心设计和反复调试,媲美原生图片预览的效果。pnpmireact-photo-view概述:从'react-photo-view'导入{PhotoProvider,PhotoView};导入'react-photo-view/dist/react-photo-view.css';exportdefaultfunctionMyComponent(){return();}为什么要单独开发?当然执着于实现也是一方面,但根本原因还是在强大的React生态中没有好用的图片预览解决方案。当时奉行借鉴的原则,在网上搜了一圈基于React的放大预览组件库。结果让我有点吃惊。图片放大预览库的数量明显不如轮播组件库。更让人窒息的是,在这些小得可怜的组件库中,有一半以上是基于开源库PhotoSwipe的二次封装。另外,没有可以在实际生产中使用的预览组件库。。。好像没有(也可能是我找不到),这种情况不仅仅体现在React库中,在其他框架Vue甚至原生相关库。当然,PhotoSwipe不是不能用,而是原生操作DOM的方式在React中显得格格不入,而且它的体积也在gzip12KB以上,显得有些臃肿,所以才有了这个大胆的想法。它有多好?它拥有非常完整的细节和功能:支持触摸手势,具有物理效果的拖动/平移/滑动,两指指定位置放大/缩小,全动画连接,打开/关闭/回弹/边缘触摸,其自然的交互效果图像自适应,具有合适的初始渲染尺寸,并根据调整自适应支持自定义预览或任意HTML元素键盘导航,完美适配桌面端支持自定义节点扩展,轻松实现全屏预览、旋转控制、图片引入等更多功能基于typescript,7KBGzipped,并通过简单易用的API支持服务器端渲染。也导出了支持ES2017及以上版本的JS,可以做到6KBGzipped。能在这样一卷书里加入大量的体验细节,实属不易。通过非常简单的自定义渲染可以实现更多的功能,非常符合React的理念,避免内置非刚需的功能。流行库对比下表统计了大部分场景需要的功能,展示了react-photo-view、PhotoSwipe和rc-image(ant-design)的对比:友好的文档比文档更重要的是什么,为此,我还准备了一份超美的文档(目前只有中文,有空我会翻译的~)https://react-photo-view.vercel.app/文末可以查看原文预览实施过程。图片跟随手指滚动,在onTouchStart时记录当前时间触发的位置状态,让它在onTouchMove时跟随手指移动,释放下面的onTouchEnd可以轻松实现。触摸边缘位置的反馈使得切换图片时需要仔细考虑细节:如果你在onTouchStart后立即移动图片,会导致很多误操作,比如你想让他滑动时上下滑动的逻辑切换图片。这时候就需要一个20px的移动缓冲来预测手指移动的方向。指定图片要放大的位置。使用transform:scale(value)对图片进行放大,但是放大的是图片的中心,放大的结果可能不是你想要的。一开始我是打算用transform-origin来实现的。想法不错,虽然是第一次在指定位置放大。如果减少的位置不是原来的位置,就会出现乱跳。显然,这种方法是行不通的。后来想了想也睡不着,在睡梦中找到灵感:为了便于计算和理解,我们将图片的中心点设为0,任意指定位置进行放大缩小,即,改变图片中心的位置。例如图片宽度为200,中心点位置为100,则以最左边位置为基准,放大一倍。现在图片宽度是400,那么中心点的位置应该是200。那么总结公式如下:constcenterClientX=innerWidth/2;//坐标偏移量转换constlastPositionX=centerClientX+lastX;//缩放偏移量constoffsetScale=nextScale/scale;//最终偏移位置constoriginX=clientX-(clientX-lastPositionX)*offsetScale-centerClientX;这种计算方式可以承接各种位置响应,比如双指缩放、双指滚动+缩放、边缘计算等。两指之间的距离需要初中直角三角形勾股定理:Math.sqrt((nextClientX-clientX)**2+(nextClientY-clientY)**2);之前版本的模拟滚动操作是使用transition实现的,通过手指滑动开始和结束的时间差,计算初始速度,估计transition来模拟一个距离让眼睛看起来像滚动的效果