前言
本文将介绍如何经过js实现移动端图片预览,包括图片的 预览模式,手势缩放,手势拖动,双击放大等基本功能;代码地址http://pangyongsheng.github.io/imgPreview/css
图片预览主要有如下几个功能点组成:html
图片预览即点击图片在页面中插入一个黑色全屏背景框并将图片居中显示。封装时,为了只对指定图片添加功能,可经过监听指定类名或添加某种属性的img标签监听;另外需在对背景框绑定点击事件,退出预览模式。一下是一个简单示例代码:git
//点击图片进入预览 var $Dom = document.querySelector(".preview"); $Dom.onclick = function() { var temp = this.src; var objE = document.createElement("div"); objE.innerHTML = '<div class="bgM" >' + '<img src="'+temp+'" id="img_scan" class="img-custom-img2"/>' + '</div>'; 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样式参考github
.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;
}
复制代码
这里经过监听移动端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节点;bash
监听touchstart事件,若e.touches.length<2,为单指事件,获取触点坐标(触点坐标-目标元素.offsetLeft/Top)添加到事件属性中,获取当前时间挫记录到相关变量中,计算本次时间戳与上次事件时间戳之差,若时间差范围在指定范围(0~250)则触发doubleTouch事件;markdown
监听touchstart事件,使用延时器450ms触发单击事件,若在450ms无其余事件则触发单击事件
app
参考代码:dom
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实现图片的基本变换,这样只需建立一个数组做为变换矩阵,每次操做直接在当前变换矩阵上修改相关参数便可实现图像的变换:oop
transform-matrix :可配置[a,b,c,d,e,f]6个参数,以下图所示,x和y是初始的坐标,x’ 和y’则是经过矩阵变换后获得新的坐标。变换矩阵,对原先的坐标施加变换,就能获得新的坐标了。依据矩阵变换规则便可获得: x’=ax+cy+e y’=bx+dy+f。
变换 | x方向 | y方向 |
---|---|---|
缩放 | a | d |
移动 | e | f |
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; //上下左右可拖动距离 复制代码
case "gesturestart": var x = event.midPoint[0]; var y = event.midPoint[1]; originLast = event.midPoint; $imgs.style.transformOrigin = x + "px " + y + "px"; break; 复制代码
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; 复制代码
case "gestureend": maxMove(); break; 复制代码
可移动边界范围的计算:
代码以下:
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]); } 复制代码
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; 复制代码
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;复制代码
case "oneTouch": var $bg = document.querySelector(".bgM"); document.body.removeChild($bg); break; 复制代码