h5 img js 点击图片放大_H5实现移动端图片预览:手势缩放, 手势拖动,双击放大......

查看示例效果:

一、功能介绍

图片预览主要有以下几个功能点组成:监听图片点击事件,进入图片预览模式

自定义手势事件, (双指缩放,滑动,双击。。。)

监听图片手势事件,通过 transform-matrix 实现图片的各种变换;

二、实现方法

1、图片预览模式

图片预览即点击图片在页面中插入一个黑色全屏背景框并将图片居中显示。封装时,为了只对指定图片添加功能,可通过监听指定类名或添加某种属性的img标签监听;另外需在对背景框绑定点击事件,退出预览模式。一下是一个简单示例代码://点击图片进入预览

var $Dom = document.querySelector(".preview");

$Dom.onclick = function() {

var temp = this.src;

var objE = document.createElement("div");

objE.innerHTML = '

' +

''+temp+'' +

'

';

document.body.appendChild(objE.children[0]);

//退出图片预览事件

var $bg = document.querySelector(".bgM");

$bg.onclick = function() {

var dm = document.querySelector(".bgM");

document.body.removeChild(dm);

}

//阻止事件冒泡

var $img = document.querySelector(".img-custom-img2");

$img.onclick = function(event) {

event.stopPropagation();

}

}

复制代码

css样式参考.bgM{

width: 100%;

height: 100%;

position: absolute;

top: 0;left: 0;right: 0;bottom: 0;

z-index: 1000;

background-color: rgba(0,0,0,0.85);

overflow: hidden;

}

.bgM img{

width: 100%;

max-height:100%;

position: absolute;

top: 0;left: 0;right: 0;bottom: 0;

z-index: 1001;

margin: auto;

}

复制代码

2、自定义手势事件

这里通过监听移动端touch事件实现自定义双指缩放,单指滑动,双击事件,并通过事件属性传递相关参数,如缩放比例,滑动距离等,详细实现方式参考这篇博客:请参考此博文:https://www.cnblogs.com/pangys/p/9119845.html 这里只大概说明;当触发touch事件的时候,会生成一个TouchEvent对象,我们可通过其属性e.touches.length来判断是否多点触控,通过e.touches[index].pageX,e.touches[index].pageY获取去触点坐标,通过e.target获取dom节点;

这里为了方便,直接监听document事件然后对目标元素触发事件,实际也可以直接对img监听事件,然后分别处理;

(1)手势事件监听touchstart事件,若e.touches.length>=2,为双指事件,获取触点坐标(触点坐标-目标元素.offsetLeft/Top)计算两个点中点 添加到事件属性中,改变相关状态,触发gesturestart事件;

监听touchmove事件,若e.touches.length>=2,获当前取触点坐标和gesturestart坐标,计算出缩放比例及角度,触发gesturechange事件;

监听touchend事件,根据前面事件记录的状态触发结束gestureend事件;

(2)滑动事件监听touchstart事件,若e.touches.length<2,为单指事件,获取触点坐标(触点坐标-目标元素.offsetLeft/Top)添加到事件属性中,记录事件状态;

监听touchmove事件,若e.touches.length<2,获当前取触点坐标和上一步坐标,计算出移动距离添加到事件属性中,触发swipeMove事件;

(3)双击事件

监听touchstart事件,若e.touches.length<2,为单指事件,获取触点坐标(触点坐标-目标元素.offsetLeft/Top)添加到事件属性中,获取当前时间挫记录到相关变量中,计算本次时间戳与上次事件时间戳之差,若时间差范围在指定范围(0~250)则触发doubleTouch事件;

(4)单击事件

监听touchstart事件,使用延时器450ms触发单击事件,若在450ms无其他事件则触发单击事件

参考代码:var isTouch = false;

var isDoubleTouch = false; //是否为多触点

var start = []; //存放触点坐标

var now, delta; //当前时间,两次触发事件时间差

var timer = null; //计时器,触发单击事件

var startPosition, movePosition, endPosition; //滑动起点,移动,结束点坐标

//事件声明

var gesturestart = new CustomEvent('gesturestart');

var gesturechange = new CustomEvent('gesturechange');

var gestureend = new CustomEvent('gestureend');

var swipeMove = new CustomEvent('swipeMove');

var doubleTouch = new CustomEvent("doubleTouch");

var oneTouch = new CustomEvent("oneTouch");

//监听touchstart事件

document.addEventListener('touchstart', function(e) {

if (e.touches.length >= 2) { //判断是否有两个点在屏幕上

isDoubleTouch = true;

start = e.touches; //得到第一组两个点

var screenMinPoint = getMidpoint(start[0], start[1]); //获取两个触点中心坐标

gesturestart.midPoint = [screenMinPoint[0] - e.target.offsetLeft, screenMinPoint[1] - e.target.offsetTop]; //获取中心点坐标相对目标元素坐标

e.target.dispatchEvent(gesturestart);

} else {

delta = Date.now() - now; //计算两次点击时间差

now = Date.now();

startPosition = [e.touches[0].pageX, e.touches[0].pageY];

if (delta > 0 && delta <= 250) { //双击事件

clearTimeout(timer);

doubleTouch.position = [e.touches[0].pageX - e.target.offsetLeft, e.touches[0].pageY - e.target.offsetTop];

e.target.dispatchEvent(doubleTouch);

} else { //滑动事件

timer = setTimeout(function(){

e.target.dispatchEvent(oneTouch);//单击事件

},450)

}

isTouch = true;

}

}, false);

//监听touchmove事件

document.addEventListener('touchmove', function(e) {

clearTimeout(timer);

if (e.touches.length >= 2 && isDoubleTouch) { //手势事件

var now = e.touches; //得到第二组两个点

var scale = getDistance(now[0], now[1]) / getDistance(start[0], start[1]); //得到缩放比例

var rotation = getAngle(now[0], now[1]) - getAngle(start[0], start[1]); //得到旋转角度差

gesturechange.scale = scale.toFixed(2);

gesturechange.rotation = rotation.toFixed(2);

e.target.dispatchEvent(gesturechange);

} else if (isTouch) {

movePosition = [e.touches[0].pageX, e.touches[0].pageY];

endPosition = movePosition;

movePosition = [movePosition[0] - startPosition[0], movePosition[1] - startPosition[1]];

startPosition = [e.touches[0].pageX, e.touches[0].pageY];

swipeMove.distance =[movePosition[0].toFixed(2) , movePosition[1].toFixed(2)];

e.target.dispatchEvent(swipeMove);

}

}, false);

//监听touchend事件

document.addEventListener('touchend', function(e) {

if (isDoubleTouch) {

isDoubleTouch = false;

gestureend.position = endPosition;

e.target.dispatchEvent(gestureend);

};

}, false);

/*

* 两点的距离

*/

function getDistance(p1, p2) {

var x = p2.pageX - p1.pageX,

y = p2.pageY - p1.pageY;

return Math.sqrt((x * x) + (y * y));

};

/*

* 两点的夹角

*/

function getAngle(p1, p2) {

var x = p1.pageX - p2.pageX,

y = p1.pageY - p2.pageY;

return Math.atan2(y, x) * 180 / Math.PI;

};

/*

* 获取中点

*/

function getMidpoint(p1, p2) {

var x = (p1.pageX + p2.pageX) / 2,

y = (p1.pageY + p2.pageY) / 2;

return [x, y];

}

复制代码

三、图片的变换

对于图片的每次操作都需在上一次操作的基础上进行叠加,如果直接使用width,top,left或scale,translate等css样式需要每次都记录当前图片状态的全部参数,而且计算较多,这里考虑使用transform-matrix实现图片的基本变换,这样只需创建一个数组作为变换矩阵,每次操作直接在当前变换矩阵上修改相关参数即可实现图像的变换:transform-matrix :可配置[a,b,c,d,e,f]6个参数,如下图所示,x和y是初始的坐标,x’ 和y’则是通过矩阵变换后得到新的坐标。变换矩阵,对原先的坐标施加变换,就能得到新的坐标了。依据矩阵变换规则即可得到: x’=ax+cy+e y’=bx+dy+f。

1d260a2f2b76486ee8240de1074a8a76.gif变换x方向y方向缩放ad

移动ef

(1) 获取目标元素及相关参数,绑定事件var $imgs = document.querySelector("#img_scan");

var clientWidth = document.body.clientWidth; //窗口宽

var clientHeight = document.body.clientHeight; //窗口高

var imgWidth = parseInt(window.getComputedStyle($imgs).width); //图片宽

var imgHeight = parseInt(window.getComputedStyle($imgs).height); //图片高

$imgs.addEventListener('gesturestart', gesturef, false);

$imgs.addEventListener('gesturechange', gesturef, false);

$imgs.addEventListener('gestureend', gesturef, false);

$imgs.addEventListener('swipeMove', gesturef, false);

$imgs.addEventListener('doubleTouch', gesturef, false);

$imgs.addEventListener('oneTouch', gesturef, false);

var tMatrix = [1, 0, 0, 1, 0, 0]; //x缩放,无,无,y缩放,x平移,y平移

var originLast, maxSwipeLeft, maxSwipeRight, maxSwipeTop, maxSwipeBottom; //上下左右可拖动距离

复制代码

(2)监听 gesturestart 设置 变换中心case "gesturestart":

var x = event.midPoint[0];

var y = event.midPoint[1];

originLast = event.midPoint;

$imgs.style.transformOrigin = x + "px " + y + "px";

break;

复制代码

(2)监听 gesturechange 进行缩放变换,这里设置了缩放范围为0.5 ~ 3;case "gesturechange":

var sc = parseFloat(event.scale);

tMatrix[0] = tMatrix[0] + sc - 1 > 0.5 && tMatrix[0] + sc - 1 < 3 ? tMatrix[0] + sc - 1 : tMatrix[0];

tMatrix[3] = tMatrix[3] + sc - 1 > 0.5 && tMatrix[3] + sc - 1 < 3 ? tMatrix[3] + sc - 1 : tMatrix[3];

var temp = tMatrix.join(",");

$imgs.style.transform = "matrix(" + temp + ")";

break;

复制代码

(3)监听 gestureend 获取移动边界范围边界case "gestureend":

maxMove();

break;

复制代码

可移动边界范围的计算:

对于图片中的任意点可拖动范围都是相同的,那么以缩放中心点来计算,如下图所示,对于图片中的缩放中心点p,有缩放后距离边距的距离,可移动的范围均为 缩放后增加或减少的距离 - (缩放中心点距离图片边缘的距离),即 | 缩放比例 - 1 | * p点距离边缘的距离;

4e9d8b48f010d33b05ae5e01d74f01d2.png

代码如下:function maxMove(){

//最大可拖动范围

var sca = tMatrix[0];

maxSwipeLeft = Math.abs(sca - 1) * originLast[0];

maxSwipeRight = Math.abs(sca - 1) * (imgWidth - originLast[0]);

maxSwipeTop = Math.abs(sca - 1) * originLast[1];

maxSwipeBottom = Math.abs(sca - 1) * (imgHeight - originLast[1]);

}

复制代码

(4)监听 swipeMove 拖动图片,需考虑是否在可拖动范围if (!maxSwipeLeft || !maxSwipeRight || !maxSwipeTop || !maxSwipeBottom) return;

if (event.distance[0] > 0 && maxSwipeLeft < tMatrix[4]) return;

if (event.distance[0] < 0 && maxSwipeRight < -tMatrix[4]) return;

if (event.distance[1] > 0 && maxSwipeTop < tMatrix[5]) return;

if (event.distance[1] < 0 && maxSwipeBottom < -tMatrix[5]) return;

tMatrix[4] = tMatrix[4] + parseInt(event.distance[0]);

tMatrix[5] = tMatrix[5] + parseInt(event.distance[1]);

var temp = tMatrix.join(",");

$imgs.style.transform = "matrix(" + temp + ")";

break;

复制代码

(5)监听 doubleTouch 实现双击点缩放case "doubleTouch":

originLast = event.position;

$imgs.style.transformOrigin = event.position[0] + "px " + event.position[1] + "px";

tMatrix[0] = 2;

tMatrix[3] = 2;

var temp = tMatrix.join(",");

$imgs.style.transform = "matrix(" + temp + ")";

maxMove();

break;复制代码

(6)监听 oneTouch 实现退出预览

case "oneTouch":

var $bg = document.querySelector(".bgM");

document.body.removeChild($bg);

break;

复制代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/454884.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[转载]建立团队沟通协作工作方式

很多初创团队、以及刚开始尝试敏捷的团队&#xff0c;没有工作协议的概念&#xff0c;热热闹闹&#xff0c;混混乱乱。本文介绍了关于工作协议的What, Why, Who, When, 以及How。 What:什么是工作协议 工作协议&#xff1a;由团队共同商议&#xff0c;达成一致遵守的一组规则、…

linux安装自带mysql吗_Linux下安装mysql

前提下必须要有这三个文件夹A.jpgB.jpg还要安装这两个软件&#xff1b;直接百度官网即可&#xff1b;先通过Xftp6这个软件&#xff0c;编译文件夹&#xff0c;C.jpg搭建mysql1.查看CentOS自带的mysqlrpm -qa | grep mysql2.卸载CentOS自带的mysqlrpm -e --nodeps 要卸载的软件3…

(转载)UI接口分层自动化测试框架设计思想

阅读本小节&#xff0c;需要读者具备如下前提条件&#xff1a; 1. 掌握一种编程语言基础&#xff0c;如java、python等。 2. 掌握一种单元测试框架&#xff0c;如java语言的testng框架、python的unittest框架。 3. 掌握目前主流的UI测试框架&#xff0c;移动端APP测试框架Ap…

170821-关于SpringMVC的知识点

1.SpringMVC 概述以及优势 SpringMVC和Spring的关系&#xff1a; 软件开发的三层架构&#xff1a; web层【表示层、表现层】---->Service层---->Dao[DataBase Access Object]---->数据库&#xff01; SpringMVC实际上是Spring的一个子模块&#xff0c;我们用Spring…

写在前面的一些话:《Learning OpenCV》中文版 .

2009-09-17 15:51 7578人阅读 评论(4) 收藏 举报 <!-- /* Font Definitions */ font-face {font-family:Helvetica; panose-1:2 11 5 4 2 2 2 2 2 4; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-format:other; mso-font-pitch:variable; mso-font-sign…

独家 | 一文读懂自然语言处理NLP(附学习资料)

前言 自然语言处理是文本挖掘的研究领域之一&#xff0c;是人工智能和语言学领域的分支学科。在此领域中探讨如何处理及运用自然语言。 对于自然语言处理的发展历程&#xff0c;可以从哲学中的经验主义和理性主义说起。基于统计的自然语言处理是哲学中的经验主义&#xff0c;基…

GNU/Linux下有多少是GNU的?

导读&#xff1a;一个葡萄牙的学生写了一篇文章 《How much GNU is there in GNU/Linux?》由酷壳网的陈皓整理编译为《GNU/Linux下有多少是GNU的》。这篇文章主要分布了今年4月份的Ubuntu Natty的Linux分发包。其主要是用代码行来做的分析&#xff0c;用两个饼图对比分析。 内…

Unity 富文本

参考链接&#xff1a;http://www.ceeger.com/Manual/StyledText.html 首先要说的是不仅仅ugui的text组件支持富文本&#xff0c;Debug.Log也是支持的 Debug.Log("<color#ffff00ff><b>爱生活</b></color> <color#00ffffff><b> 爱海澜&…

Linux shell 之 提取文件名和目录名的一些方法

很多时候在使用Linux的shell时&#xff0c;我们都需要对文件名或目录名进行处理&#xff0c;通常的操作是由路径中提取出文件名&#xff0c;从路径中提取出目录名&#xff0c;提取文件后缀名等等。例如&#xff0c;从路径/dir1/dir2/file.txt中提取也文件名file.txt&#xff0c…

bzoj 2752: [HAOI2012]高速公路(road)

Description Y901高速公路是一条重要的交通纽带&#xff0c;政府部门建设初期的投入以及使用期间的养护费用都不低&#xff0c;因此政府在这条高速公路上设立了许多收费站。Y901高速公路是一条由N-1段路以及N个收费站组成的东西向的链&#xff0c;我们按照由西向东的顺序将收费…

长沙java技术_长沙如何提高自身的Java技术

长沙如何提高自身的Java技术&#xff1f;Java自发行二十多年来&#xff0c;一直都是开发者的宠儿&#xff0c;在编程界的位置一直十分稳固。虽然Java人才需求量大&#xff0c;薪资水平高&#xff0c;但想要用Java语言胜任企业工作不容易。比如要成为一名Java架构师&#xff0c;…

互联网

2019独角兽企业重金招聘Python工程师标准>>> 转载于:https://my.oschina.net/u/3127489/blog/1550726

GCC笔记 命令行分析

1984年&#xff0c;Richard Stallman发起了自由软件运动&#xff0c;GNU (Gnus Not Unix)项目应运而生&#xff0c;3年后&#xff0c;最初版的GCC横空出世&#xff0c;成为第一款可移植、可优化、支持ANSI C的开源C编译器。GCC最初的全名是GNU C Compiler,之后&#xff0c;随着…

Session(数据)共享的前后端分离Shiro实战

1&#xff0c;前言本文期望描述如何使用Shiro构建基本的安全登录和权限验证。本文实战场景有如下特殊需求&#xff1a;1&#xff0c;在集群和分布式环境实现session共享&#xff1b;2&#xff0c;前端只使用HTML/CSS/JS。因此无法直接使用Shiro提供的SessionManager&#xff0c…

java 年计算_java实现计算某年某月的天数

在计算某年某月的天数时&#xff0c;需要注意平年闰年。分析&#xff1a;闰年具体的判定方法就要看它的判定条件&#xff1a;四年一闰 &#xff0c; 百年不闰 &#xff0c;400年再闰。而计算该年该月的天数&#xff0c;又分大月和小月&#xff0c;特殊月份2月之分。(视频教程推…

添加自定义菜单,报错40155

2019独角兽企业重金招聘Python工程师标准>>> 提交的json中&#xff0c;某个自定义菜单对应的URL访问是有问题的&#xff0c;请挨个检查一下。 转载于:https://my.oschina.net/selly1025/blog/1551496

【bzoj2132】圈地计划 网络流最小割

题目描述 最近房地产商GDOI(Group of Dumbbells Or Idiots)从NOI(Nuts Old Idiots)手中得到了一块开发土地。据了解&#xff0c;这块土地是一块矩形的区域&#xff0c;可以纵横划分为NM块小区域。GDOI要求将这些区域分为商业区和工业区来开发。根据不同的地形环境&#xff0c;每…

Linux基础

Linux的特点&#xff1a; 系统版本&#xff1a;常见的有debian、Redhat更适合做服务器&#xff0c;更安全和稳定&#xff0c;Ubuntu唯一的优势就是图形界面好&#xff0c;centos目前被redhat收购&#xff0c;红旗已经倒闭。 1、免费的/开源的&#xff1b;2、支持多线程/多用户&…

yum查询已经安装mysql_通过yum安装mysql

在linux中安装数据库首选MySQL&#xff0c;Mysql数据库的第一个版本就是发行在Linux系统上&#xff0c;其他选择还可以有postgreSQL&#xff0c;oracle等在Linux上安装mysql数据库&#xff0c;我们可以去其官网上下载mysql数据库的rpm包&#xff0c;http://dev.mysql.com/downl…

JAVA命令符找不到符号_[转]Java命令行编译文件时出现的错误,找不到符号或软件包不存在等...

标签(空格分隔)&#xff1a; Javajavascript习惯了eclipse的自动编译&#xff0c;Java命令行编译、执行文件只会最基础的部分&#xff0c;就是对单文件的编译和执行&#xff0c;并且不包含任何外部JAR包。但有时候你还非得用命令行&#xff0c;会碰到一些问题&#xff0c;博主这…