公司開發微信小程序,pm想實現以下需求:
用手指縮放圖片。其實在實現這個需求之前,並不知道,微信公衆號以及微信小程序裏面有一個原生的api就自帶這個特效,並且微信朋友圈也是用的這個api。wx.previewImage,就是它。預覽圖片。除了不能預覽開發環境的本地電腦的圖片外,你手機真機的圖片,以及http服務器上的圖片都是能夠預覽的,並且縮放功能作得很流暢。下面就說說如何用js來實現這個功能吧。
文章裏面的思路參考此文章:連接描述小程序
先上源碼,而後在逐步剖析:微信小程序
Page({ data: { touch: { distance: 0, scale: 1, baseWidth: null, baseHeight: null, scaleWidth: null, scaleHeight: null } }, touchstartCallback: function(e) { // 單手指縮放開始,也不作任何處理 if(e.touches.length == 1) return console.log('雙手指觸發開始') // 注意touchstartCallback 真正代碼的開始 // 一開始我並無這個回調函數,會出現縮小的時候有瞬間被放大過程的bug // 當兩根手指放上去的時候,就將distance 初始化。 let xMove = e.touches[1].clientX - e.touches[0].clientX; let yMove = e.touches[1].clientY - e.touches[0].clientY; let distance = Math.sqrt(xMove * xMove + yMove * yMove); this.setData({ 'touch.distance': distance, }) }, touchmoveCallback: function(e) { let touch = this.data.touch // 單手指縮放咱們不作任何操做 if(e.touches.length == 1) return console.log('雙手指運動') let xMove = e.touches[1].clientX - e.touches[0].clientX; let yMove = e.touches[1].clientY - e.touches[0].clientY; // 新的 ditance let distance = Math.sqrt(xMove * xMove + yMove * yMove); let distanceDiff = distance - touch.distance; let newScale = touch.scale + 0.005 * distanceDiff // 爲了防止縮放得太大,因此scale須要限制,同理最小值也是 if(newScale >= 2) { newScale = 2 } if(newScale <= 0.6) { newScale = 0.6 } let scaleWidth = newScale * touch.baseWidth let scaleHeight = newScale * touch.baseHeight // 賦值 新的 => 舊的 this.setData({ 'touch.distance': distance, 'touch.scale': newScale, 'touch.scaleWidth': scaleWidth, 'touch.scaleHeight': scaleHeight, 'touch.diff': distanceDiff }) }, bindload: function(e) { // bindload 這個api是<image>組件的api相似<img>的onload屬性 this.setData({ 'touch.baseWidth': e.detail.width, 'touch.baseHeight': e.detail.height, 'touch.scaleWidth': e.detail.width, 'touch.scaleHeight': e.detail.height }) } })
由於參考的別人的博文寫的,本來想大體把源碼貼出來,好本身之後做爲筆記查看,但發佈未成功,因此仍是多寫一些思路吧。
也就是說,思路是借鑑的,實際是本身操做的。
其實這個特效主要用到了touch三兄弟事件。
更主要的仍是touchmove。
首先,咱們須要得到用戶的觸摸事件。只有得到了這個事件,小程序才能得知用戶但願縮放圖片,同時肯定圖片的縮放倍數。api
咱們發現微信提供 touchmove 事件,在用戶觸摸屏幕並在屏幕上移動手指時,這個事件就會被觸發。數組
手勢縮放的核心思想是:根據兩隻手指相對距離的變化來對圖片進行放大或縮小。所以,咱們須要知道兩隻手指相對距離的變化,才能作到良好的縮放體驗。服務器
touchmove 事件能夠實現的功能,大體能夠總結爲:微信
手指在屏幕上進行移動時,對應的組件上就會以 16 ms 一次的頻率不斷觸發 touchmove 事件;
手指離開屏幕後,則會觸發 touchend 事件。
touchmove 事件所包含的事件對象中有一個 touches 屬性,此屬性爲當前停留在屏幕中的觸摸點信息的數組。觸摸點的信息包括:ide
identifier:觸摸點的標誌符;
pageX 和 pageY:距離文檔左上角的距離;
clientX 和 clientY:距離屏幕可顯示區域左上角距離。
咱們能夠經過不斷獲取 clientX 和 clientY 數據的方式,來肯定手指在屏幕上的位置變化。函數
let xMove = e.touches[1].clientX - e.touches[0].clientX; let yMove = e.touches[1].clientY - e.touches[0].clientY;
distance 變量即爲兩隻手指之間的距離。在 touchmove 被觸發的時候,小程序就會計算一次 distance。this
咱們爲新的 distance 變量定名爲 newDistance,相應地,舊變量定名爲 oldDistance。code
以後,咱們設定一個新的變量 distanceDiff = newDistance - oldDistance,它反映兩次 touchmove 觸發瞬間,兩根手指相對距離的變化值。
distanceDiff 爲正數時,表示兩指間距離在變大,圖片須要被放大;反之,則表明兩指間距縮小,圖片須要被縮小。
到這裏,咱們已經能夠探測用戶的手指距離變化了。接下來,咱們須要根據用戶的手勢,肯定圖片縮放倍數,而後根據倍數縮放圖片。
首先,要肯定 distance 的變化值與圖片放大或縮小的變化率相關聯的規則。
咱們將圖片正常顯示時的尺寸定爲基準值,存放於變量 baseWidth 和 baseHeight 中。圖片須要放大的倍數設置爲變量 scale,它的初始值和最小值爲 1,最大值可根據須要來設置。
通過屢次試驗,咱們最後肯定了一個公式:
newScale = oldScale + 0.005 * distanceDiff
在每次 touchmove 被觸發後,經過探測手指距離變化而獲得的數據,來獲得圖片按比例縮放後的高寬值。
scaleWidth = scale * baseWidth; scaleHeight = scale * baseHeight;
wxml文件對應以下,就不作解釋了:
<view class="container"> <view bindtouchmove="touchmoveCallback" bindtouchstart="touchstartCallback"> <image src="../../resources/pic/cat.jpg" style="width: {{ touch.scaleWidth }}px;height: {{ touch.scaleHeight }}px" bindload="bindload"></image> </view> </view>
寫到這裏發現,就算小程序用不了這個js,個人ht5頁面也是能夠用的,哈哈。