300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > 移动端图片单指移动 双指放大缩小实现//touchmove的时候不让body滚动

移动端图片单指移动 双指放大缩小实现//touchmove的时候不让body滚动

时间:2020-03-23 12:22:11

相关推荐

移动端图片单指移动 双指放大缩小实现//touchmove的时候不让body滚动

移动端图片单指移动,双指放大缩小实现//touchmove的时候不让body滚动

思路1:移动放大缩小操作都直接放到图片上面

图片的放大缩小使用transform的scale属性操作,移动使用transform的translate属性操作,也可以使用matrix属性做2D转换,这个有六个值,14表示xy轴的放大倍数,56表示xy轴的偏移量,23表示度数,这里不操作旋转可以写成默认的0根据touches获取当前触摸位置,touches是一个数组,表示当前有几个手指触摸屏幕,可以判断一下,是单指的时候在ontouchstart时记录手指触摸的位置,然后在ontouchmove时计算现在手指的移动位置,计算两者的偏移量,在图片上使用transform属性的matrix或translate控制图片做出移动(可以在ontouchend的时候判断一下要不要移动回原位置,或者在放大一倍的时候就让回原位置,或者在ontouchmove的时候限制一下图片的移动范围)根据touches有两个值的时候做出判断,让图片根据手势放大缩小.在ontouchstart的时候进行根据两个手指的位置计算出来现在两个手指的距离(勾股定理)记录下来,在ontouchmove的时候计算当前手指的距离,拿这个距离和之前start时记录的距离相除,根据这个值来确定当前放大倍数.然后在图片上面做出操作,控制放大缩小程度.(这里会有个几个坑)

3.1 因为将放大和移动都放到图片dom上,所以两个属性之间会有一些相互影响,这个需要处理下

3.2 在放大的时候需要确定放大的中心,这时候有两种确定中心的情况,第一种:在ontouchstart的时候计算双指的中心位置,把这个确定为transform-origin,第二种是在ontouchmove的时候动态计算双指之间的位置在原始图片上的坐标,这里计算复杂一些,需要考虑到图片放大倍数和偏移量,需要通过记录下来的图片位置,和当前放大缩小的倍数计算当前我们看到的展示图片,和原始图片倍数是1,偏移量是0的时候的对应坐标,这里计算好对应的坐标才好计算下一步

3.3 在确定对应坐标的情况下,因为transform-origin改变在放大倍数不为1的时候会导致图片发生移动,这里需要做一下处理,因为要保证图片在移动的时候不能跳跃式移动,在修改transform-origin的时候我们需要根据当前放大倍数和现在transform-origin-原始transform-origin之间的偏移量来计算这个图片是会上下左右移动多少位置,需要在修改transform-origin的时候同步修改一下translate偏移量,让图片不会因为origin修改而发生位置改变

3.4 在确定中心之后就只需要通过计算双指之间的距离计算放大缩小倍数了

ps:这里也可以使用position来确定移动位置,不过同样需要计算

思路2:因为在scale为1的时候修改transform-origin不会导致图片的偏移,所以可以将放大的操作放到ing的父元素上面,让父元素占满屏幕,让图片只做位置移动

同样的三个方法:ontouchstart/ontouchmove/ontouchend这三个,在单指触摸的时候通过css控制图片dom移动,在放大的时候控制图片父元素放大,这样就可以保证放大的不影响图片,而且不怎么用计算当前放大的中心在哪和上面相同的需要在start记录位置,然后在move的时候记录移动的大小,计算移动的大小,修改位置双指放大缩小也是一样

下面是根据方法二写的例子,在react项目中的,其他项目也可以只要事件能挂上去就可以,怕覆盖原先事件可以使用监听,不过一般有这个事件的都有这个功能了,都不做这些了

看项目需求

这里的例子可以去闲鱼里搜闪回有品官方店里面的验货报告里面查看

// 在移动端如果想要在touchmove的时候不让body也滚动,在弹窗的最外层阻止事件冒泡就可以了const box: any = document.getElementsByClassName('ant-image-preview-wrap')box[0].ontouchmove = (e: any) => {e.preventDefault()e.stopPropagation()return false}

useEffect(() => {if (visible) {// 这里将触摸事件绑定到图片的父元素上面const imgBoxDom: any = document.getElementsByClassName('ant-image-preview-img-wrapper')// 记录move前的图片位置,在ontouchesstart和ontouchesmove有使用到let dingwei: {x: number; y: number } = {x: 0, y: 0 }// 计算双指之间的距离const getDistance = (start: {x: number; y: number }, stop: {x: number; y: number }) => {return Math.sqrt(Math.pow(stop.x - start.x, 2) + Math.pow(stop.y - start.y, 2))}const distance = {start: 1, stop: 1 }// 默认的放大倍数(即时)let scaleXY = 1// 默认放大倍数(双指操作结束)let scale = 1// 图片开始移动位置let trans: any// 是不是单个手指触摸(判断防止因为在触发双指时,两个手指都移动导致weizhi字段记录的坐标和双指不同时离开屏幕导致有触发单指的情况,这种情况导致的图片位置跳动)let isOne = trueimgBoxDom[0].ontouchstart = (e: any) => {e.preventDefault()if (e.touches.length == 1) {// 是单指触摸,保存一下现在的位置isOne = truedingwei = {x: e.changedTouches[0].pageX, y: e.changedTouches[0].pageY }trans = e.target.style.transformif (trans.indexOf('matrix') == 0) {trans = trans.split('(')trans = trans[1].split(',')} else {trans = [1, 0, 0, 1, 0, 0]}} else if (e.touches.length == 2) {// 双指就保存一下现在的双指距离isOne = falsedistance.start = getDistance({x: e.touches[0].screenX,y: e.touches[0].screenY,},{x: e.touches[1].screenX,y: e.touches[1].screenY,})}}imgBoxDom[0].ontouchmove = (e: any) => {e.preventDefault()e.stopPropagation()if (e.touches.length == 1) {// 开始移动,防止双指放大之后离开一指导致图片跳动,更新一下图片位置if (!isOne) {isOne = truedingwei = {x: e.changedTouches[0].pageX, y: e.changedTouches[0].pageY }}// 计算现在的单指移动位置const moveX = e.changedTouches[0].pageX - dingwei.xconst moveY = e.changedTouches[0].pageY - dingwei.y// 使用scaleXY是因为有可能父元素已经被放大缩小过,这时候移动的大小就不是显示的大小了,需要计算一下实际距离const style = `transform:matrix(1,0,0,1,${parseFloat(trans[4]) + moveX / scaleXY},${parseFloat(trans[5]) + moveY / scaleXY});transition:transform 0s;`e.target.style = style} else if (e.touches.length == 2) {// 计算一下现在放大倍数distance.stop = getDistance({x: e.touches[0].screenX,y: e.touches[0].screenY,},{x: e.touches[1].screenX,y: e.touches[1].screenY,})const big = distance.stop / distance.start// 最大三倍,最小1倍,只需要修改倍数,位移是不需要修改的,不过在放大的时候图片是可以以双指中心为origin放大的,很迷scaleXY = big - 1 + scalescaleXY = scaleXY < 1 ? 1 : scaleXYscaleXY = scaleXY > 3 ? 3 : scaleXYconst style = `transform:matrix(${scaleXY},0,0,${scaleXY},0,0);transition:transform 0s;`imgBoxDom[0].style = style}}imgBoxDom[0].ontouchend = (e: any) => {e.preventDefault()e.stopPropagation()scale = scaleXY}// 底下这里可以不做判断,这里是因为之前使用的antd的组件,直接在切换图片上面添加一个事件,切换图片让图片大小位置还原const btnDomLeft: any = document.getElementsByClassName('ant-image-preview-switch-left')const btnDomImg: any = document.getElementsByClassName('ant-image-preview-img')btnDomLeft[0].addEventListener('click', () => {btnDomImg[0].style = 'transform:matrix(1,0,0,1,0,0);transition:transform 0s;'imgBoxDom[0].style = `transform:matrix(1,0,0,1,0,0);transition:transform 0s;`})const btnDomRight: any = document.getElementsByClassName('ant-image-preview-switch-right')btnDomRight[0].addEventListener('click', () => {btnDomImg[0].style = 'transform:matrix(1,0,0,1,0,0);transition:transform 0s;'imgBoxDom[0].style = `transform:matrix(1,0,0,1,0,0);transition:transform 0s;`})}}, [visible])

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。