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.pswp.cn/news/454884.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/454884.shtml
英文地址,請注明出處:http://en.pswp.cn/news/454884.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[轉載]建立團隊溝通協作工作方式

很多初創團隊、以及剛開始嘗試敏捷的團隊&#xff0c;沒有工作協議的概念&#xff0c;熱熱鬧鬧&#xff0c;混混亂亂。本文介紹了關于工作協議的What, Why, Who, When, 以及How。 What:什么是工作協議 工作協議&#xff1a;由團隊共同商議&#xff0c;達成一致遵守的一組規則、…

私有云促進企業管理變革 助力企業快步前行

在全球經濟迅速發展和科學技術突飛猛進的情況下, 無論是制造型企業還是服務型行業&#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…

Android深入源代碼分析理解Aidl總體調用流程(雷驚風)

2017年開始上班的第一天。老不想工作了&#xff0c;假期感覺還沒開始就已經結束了&#xff0c;唉&#xff0c;時間就是這樣&#xff0c;新的一年開始了&#xff0c;盡管非常不想干正事&#xff0c;沒辦法&#xff0c;必須干起來。由于后邊的路還非常長&#xff0c;距離六十歲還…

(轉載)UI接口分層自動化測試框架設計思想

閱讀本小節&#xff0c;需要讀者具備如下前提條件&#xff1a; 1. 掌握一種編程語言基礎&#xff0c;如java、python等。 2. 掌握一種單元測試框架&#xff0c;如java語言的testng框架、python的unittest框架。 3. 掌握目前主流的UI測試框架&#xff0c;移動端APP測試框架Ap…

如何提高閱讀源代碼的效率 .

如何提高閱讀源代碼的效率 記得在開源流行之前&#xff0c;我看過的代碼緊限于所參與的項目&#xff0c;能有個幾萬行就不錯哩。后來很多優秀開源項目都相繼蹦出來了&#xff0c;閱讀的代碼量那叫一個大呀&#xff01;不得不看。我現在掉到android這個大坑里&#xff0c;每天都…

170821-關于SpringMVC的知識點

1.SpringMVC 概述以及優勢 SpringMVC和Spring的關系&#xff1a; 軟件開發的三層架構&#xff1a; web層【表示層、表現層】---->Service層---->Dao[DataBase Access Object]---->數據庫&#xff01; SpringMVC實際上是Spring的一個子模塊&#xff0c;我們用Spring…

pojo類中list存儲其他字段_List集合流處理類型小結

本文為博主原創&#xff0c;未經允許不得轉載對應實體類importlombok.Getter;importlombok.Setter;GetterSetterpublic classStudent {privateString name;private intage;privateString className;privateString birthday;}1.根據字段取出某一個字段屬性的集合List studentLis…

Hash表的擴容(轉載)

Hash表&#xff08;Hash Table&#xff09;hash表實際上由size個的桶組成一個桶數組table[0...size-1] 。 當一個對象經過哈希之后。得到一個對應的value , 于是我們把這個對象放到桶table[ value ]中。當一個桶中有多個對象時。我們把桶中的對象組織成為一個鏈表。 這在沖突處…

寫在前面的一些話:《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;基…

python mock測試_使用mock測試python中的函數

對于測試覆蓋&#xff0c;我想測試文件signalC中該函數的異常塊&#xff1a;class SignalC:def readSignal(self, a):try:with open(os.path.join(self.newSubFolder, "my file" .csv), a) as csvfile:writer csv.writer(csvfile, delimiter,, quotechar|,quotingc…

如何更好閱讀源代碼 .

寫在前面的話&#xff1a;    自從我在linuxaid.com.cn上發表一些文章開始&#xff0c;就不斷的有網友發來電子郵件&#xff0c;或者是就其中某些問題進行探討&#xff0c;或者是查詢其他文章的地址&#xff08;往往這些網友看的是其他網站轉載的我的文章&#xff09;&#x…

wins系統flask綁定mysql_flask如何連接mssql,網上大多是sqlite和mysql教程?

這個居然也冒出來&#xff0c;刨墳了。我們不喜歡寫原生SQL語句&#xff0c;那個寫著費勁&#xff0c;日常開發時候&#xff0c;我們怎么CRUD數據庫呢&#xff1f;一般使用ORM&#xff0c;對象關系映射(英語&#xff1a;Object Relational Mapping&#xff0c;簡稱ORM)。主力使…

hdu 6086 -- Rikka with String(AC自動機 + 狀壓DP)

題目鏈接 Problem DescriptionAs we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them:Yuta has n 01 strings si, and he wants to know the number of 01 antisymmetric strings …

課堂動手動腦問題

對于隨機數&#xff0c;java通過Math.random&#xff08;&#xff09;來實現&#xff0c;比如要得到一個隨機數我們可以int a&#xff1b; a&#xff08;int&#xff09;Math.random();但對于隨機數&#xff0c;它是從0到1之間的數&#xff0c;所以必須通過int把它轉為整數&…

GNU/Linux下有多少是GNU的?

導讀&#xff1a;一個葡萄牙的學生寫了一篇文章 《How much GNU is there in GNU/Linux?》由酷殼網的陳皓整理編譯為《GNU/Linux下有多少是GNU的》。這篇文章主要分布了今年4月份的Ubuntu Natty的Linux分發包。其主要是用代碼行來做的分析&#xff0c;用兩個餅圖對比分析。 內…

便攜式三星mysql_JDBC鏈接mysql - 三星藍

package chp07;importjava.sql.Connection;importjava.sql.DriverManager;importjava.sql.ResultSet;importjava.sql.SQLException;importjava.sql.Statement;public classJDBC_Test {//創建靜態全局變量staticConnection conn;staticStatement st;public static voidmain(Stri…

C++ 類、對象、class

一、對象初始化 1.不能在類聲明中對數據成員初始化&#xff0c;因為類只是一個抽象類型&#xff0c;不占存儲空間&#xff0c;無處容納數據。 2.若某類的數據成員都是public&#xff0c;則可以像結構體一樣初始化&#xff0c;如 Time t{12,21,04}&#xff1b; 若數據成員有priv…

Unity 富文本

參考鏈接&#xff1a;http://www.ceeger.com/Manual/StyledText.html 首先要說的是不僅僅ugui的text組件支持富文本&#xff0c;Debug.Log也是支持的 Debug.Log("<color#ffff00ff><b>愛生活</b></color> <color#00ffffff><b> 愛海瀾&…