微信小程序movable-view移動圖片和雙指縮放

先從movable-view開始提及吧. movable-view是微信小程序自定義的組件.其描述爲:」可移動的視圖容器,在頁面中能夠拖拽滑動」.小程序

值得注意的是文檔中有一段備註: 「當movable-view小於movable-area時,movable-view的移動範圍是在movable-area內;當movable-view大於movable-area時,movable-view的移動範圍必須包含movable-area(x軸方向和y軸方向分開考慮)」. 也就是說父容器movable-area是能夠比子容器movable-view小的,可是子容器的移動範圍必須包括父容器.微信小程序

先看官方實例代碼:數組

1 <view class="section">
 2   <view class="section__title">movable-view區域小於movable-areaview>
 3   <movable-area style="height: 200px;width: 200px;background: red;">
 4     <movable-view style="height: 50px; width: 50px; background: blue;" x="{{x}}" y="{{y}}" direction="all">
 5     movable-view>
 6   movable-area>
 7   <view class="btn-area">
 8     <button size="mini" bindtap="tap">click me to move to (30px, 30px)button>
 9   view>
10   <view class="section__title">movable-view區域大於movable-areaview>
11   <movable-area style="height: 100px;width: 100px;background: red;" direction="all">
12     <movable-view style="height: 200px; width: 200px; background: blue;">
13     movable-view>
14   movable-area>
15 view>

這裏面有個錯誤,應該是編寫人的一點小失誤吧. 第二個movable-area的屬性direction應該寫在movable-view上.微信

1  "height: 100px;width: 100px;background: red;" >
2     view style="height: 200px; width: 200px; background: blue;" direction="all">
3     view>
4

看下效果:app

1) 當movable-view區域小於movable-area時,子容器movable-view只能在父容器內移動. 下圖的效果是設置了屬性 out-of-bounds=」true」的效果. out-of-bounds能夠染子容器到達父容器邊界時有個超出邊界而後回彈的動畫. 並非真正能讓子容器移動到父容器之外.函數

2) 當movable-view區域大於movable-area時,子容器移動的範圍必須包括父容器.測試

第二種狀況中,把父容器看作手機屏幕可視區域,子容器看作要查看的長圖,大圖. 就能夠實現拖動查看圖片的效果. 若是圖片時動態加載的,不是固定的圖片,就要兼容圖片寬高小於屏幕可視寬高和圖片寬高大於可視屏幕寬高的可能性,也就是要考慮到以上兩種狀況.flex

咱們要在movable組件加載的同時設置好movable-view的寬高,由於movable組件加載成功後再去改變movable-view的大小,可移動區域是不會變的. 咱們能夠經過頁面中要查看的圖片的onload事件中獲取圖片寬高(目前我只發現bindload事件能獲取到圖片寬高),而後存儲起來imgWidth和imgHeight. 當用戶點擊圖片時,在bindtap事件中設置好movable-view的寬高,同時將movable-area的彈窗wx;if設置爲true.動畫

1   
2           <view class="flex-wrap flex-pic">
3               <view class="picList">            
4                   for="{{item.imglist}}" wx:for-item="itemImg" wx:key="*this" id="{{'rfnd_'+index}}" bindload="imageOnload" src="{{ itemImg}}" bindtap="showResizeModal" data-src="{{itemImg}}">           
5               view>
6           view>

由於要查看的是一個圖片列表, 我用了一個數組去存儲每一個圖片的寬高,而後經過圖片id來關聯ui

1   /**
 2    * 加載圖片
 3    */
 4   imageOnload:function(e){
 5     var id = e.currentTarget.id
 6     this.data.imgIdList[id] = {
 7       width:e.detail.width,
 8       height:e.detail.height
 9     }
10     
11   },

模板頁面

1 
 3 <template name="resizePic">
 4 
 5   <scroll-view class="backdrop"> 
 6     <view class="close-icon" bindtap="closeResizeModal"> 
 7       取消預覽
 8     view>
 9     <movable-area style="width:100%;height:100%;"  >
10         <movable-view direction="all" 
11         out-of-bounds="true"  x="{{img.x}}" y="{{img.y}}" >
12         <image  mode="widthFix" class="dtl-img" src="{{img.currentSrc}}">image>
13         movable-view>
14         
15     movable-area> 
16   scroll-view> 
17  template>
1   /**
 2    * 打開彈窗
 3    */
 4   showResizeModal: function (e) {
 5     var src = e.currentTarget.dataset.src;
 6     var x = 0
 7     var y =0
 8     try {
 9       var width = this.imgIdList[e.currentTarget.id].width; //圖片原寬
10       var height = this.imgIdList[e.currentTarget.id].height; //圖片原高
11      
12       //小程序默認固定寬320px,獲取top和left值,使圖片居中顯示
13       height = height * (320 / width);
14       width = 320;
15     
16       x = (app.windowWidth - width) / 2 
17       y = (app.windowHeight - height) / 2
18 
19     } catch (e) { }
20     var img = {
21       x: x,
22       y: y,
26      currentSrc: src,
27     };
28     this.setData({ img: img, isCheckDtl: true });
29     
30   },

部分CSS代碼

.backdrop{
  background: rgba(0, 0, 0, 1);
  width:100%;
  height: 100%;
  position: fixed;
  top:0;
  left:0;
}

以上基本上能夠完成一個點擊查看圖片的需求.

然而若是再支持雙指縮放的話,movable-view實現不了.我暫沒想出來怎麼實現,若是有人知道,但願可以指點迷津. 主要緣由是由於仍是我上文提到的那句話:」movable組件加載成功後再去改變movable-view的大小,可移動區域是不會變的」.縮放後圖片大小確定會改變的. 縮小還好,一旦放大,可移動區域仍是原來的不會改變.想象一下,若是一張寬度剛恰好時屏幕可視寬度的圖片,放大後,這張圖片就只能在屏幕可視寬度windowWidth的範圍中移動,看不到左也看不到右邊超出的部分.

因此若是既要可移動圖片又要可縮放,就不能用movable-view組件了,本身寫個吧. 原來bindtouchmove會觸發頁面的滾動條,可是如今微信好像已經修復了這個BUG,我今天在真機上測試沒有出現這個問題.

自定義控件resizePicModal.wxml:

1 
 2 <template name="resizePic">
 3   <scroll-view class="backdrop"  catchtouchmove="bindTouchMove" catchtouchend="bindTouchEnd" bindtouchstart="bindTouchStart" > 
 4     <view class="close-icon" bindtap="closeResizeModal"> 
 5       取消預覽
 6     view>
 7        <image catchtouchmove="bindTouchMove" bindtouchend="bindTouchEnd" bindtouchstart="bindTouchStart"  
 8       style=" transform: scale({{img.baseScale}}); position:absolute; top:{{img.top}}px; left:{{img.left}}px; "
 9       mode="widthFix" class="dtl-img" src="{{img.currentSrc}}">image> 
10 
11    
12   scroll-view> 
13  template>

JS: resizePicModal.js

1 /**
  2  * 使用方法:
  3  * 1) WXHTML要縮放的圖片 必須 傳入 src 以及綁定 bindtap事件,
  4  *    e.g:     
  5  *    
  6  * 2) WXHTML 要引入Modal模板(isCheckDtl無需再定義):
  7  *      
  8  *        
  9  *        
 10  *      
 11  * 3) JS頁面要引入JS文件,覆蓋當前頁面的事件:
 12  *    var resizePicModalService =  require ('../../components/resizePicModal/resizePicModal.js')
 13  *    var resizePicModal = {}
 14  * 4) 在onLoad事件中,實例化ResizePicModal
 15  *        resizePicModal = new resizePicModalService.ResizePicModal()
 16  */
 17 var app = getApp()
 18 let modalEvent = {
 19   distanceList: [0, 0],//存儲縮放時,雙指距離.只有兩個數據.第一項爲old distance.最後一項爲new distance
 20   disPoint: { x: 0, y: 0 },//手指touch圖片時,在圖片上的位置
 21   imgIdList:{},
 22   
 23   /**
 24    * 打開彈窗
 25    */
 26   showResizeModal: function (e) {
 27     var src = e.currentTarget.dataset.src;
 28     var x = 0
 29     var y =0
 30     try {
 31       var width = this.imgIdList[e.currentTarget.id].width; //圖片原寬
 32       var height = this.imgIdList[e.currentTarget.id].height; //圖片原高
 33      
 34       //小程序固定寬320px
 35       height = height * (320 / width);
 36       width = 320;
 37 
 38       x = (app.windowWidth - width) / 2 //> 0 ? (app.windowWidth - width) / 2 : 0;
 39       y = (app.windowHeight - height) / 2// > 0 ? (app.windowHeight - height) / 2 : 0;
 40 
 41     } catch (e) { }
 42     var img = {
 43       top: y,
 44       left: x,
 45       x: x, y: y,
 46       width: '100%',
 47       baseScale: 1,
 48       currentSrc: src,
 49     };
 50     this.setData({ img: img, isCheckDtl: true });
 51     
 52   },
 53   /**
 54    * 關閉彈窗
 55    */
 56   closeResizeModal:function(){
 57     this.setData({  isCheckDtl: false })
 58   },
 59   /**
 60    * 加載圖片
 61    */
 62   imageOnload:function(e){
 63     var id = e.currentTarget.id
 64     this.imgIdList[id] = {
 65       width:e.detail.width,
 66       height:e.detail.height
 67     }
 68     
 69   },
 70   /**
 71    * bindtouchmove
 72    */
 73   bindTouchMove: function (e) {
 74     if (e.touches.length == 1) {//一指移動當前圖片
 75       this.data.img.left = e.touches[0].clientX - this.disPoint.x
 76       this.data.img.top = e.touches[0].clientY - this.disPoint.y
 77 
 78       this.setData({ img: this.data.img })
 79     }
 80   
 82     if (e.touches.length == 2) {//二指縮放
 83       var xMove = e.touches[1].clientX - e.touches[0].clientX
 84       var yMove = e.touches[1].clientY - e.touches[0].clientY
 85       var distance = Math.sqrt(xMove * xMove + yMove * yMove);//開根號
 86       this.distanceList.shift()
 87       this.distanceList.push(distance)
 88       if (this.distanceList[0] == 0) { return }
 89       var distanceDiff = this.distanceList[1] - this.distanceList[0]//兩次touch之間, distance的變化. >0,放大圖片.<0 縮小圖片
 90       // 假設縮放scale基數爲1:  newScale = oldScale + 0.005 * distanceDiff
 91       var baseScale = this.data.img.baseScale + 0.005 * distanceDiff
 92       if(baseScale>0){
 93         this.data.img.baseScale = baseScale
 94         var imgWidth = baseScale * parseInt(this.data.img.imgWidth) 
 95         var imgHeight = baseScale * parseInt(this.data.img.imgHeight)
 96         this.setData({ img: this.data.img })
 97       }else{
 98         this.data.img.baseScale = 0
 99         this.setData({ img: this.data.img })
100       }
101       
102     }
103 
104   },
105   /**
106    * bindtouchend
107    */
108   bindTouchEnd: function (e) {
109     if (e.touches.length == 2) {//二指縮放
110       this.setData({ isCheckDtl: true })
111     }
112   },
113   /**
114    * bindtouchstart
115    */
116   bindTouchStart: function (e) {
117     this.distanceList = [0, 0]//回覆初始值
118     this.disPoint = { x: 0, y: 0 }
119     if (e.touches.length == 1) {
120       this.disPoint.x = e.touches[0].clientX - this.data.img.left
121       this.disPoint.y = e.touches[0].clientY - this.data.img.top
122     }
123 
124   }
125 }
126 
127 function ResizePicModal(){
128   let pages = getCurrentPages()
129   let curPage = pages[pages.length - 1]
130   Object.assign(curPage, modalEvent)//覆蓋原生頁面事件
131   this.page = curPage
132   curPage.resizePicModal = this
133   return this
134 }
135 module.exports = {
136   ResizePicModal
137 }

業務頁面wxml:引入自定義控件模板

1   <view class="flex-wrap flex-pic">
 2               <view class="picList">            
 3                   <image  wx:for="{{item.imglist}}" wx:for-item="itemImg" wx:key="*this" id="{{'rfnd_'+index}}" bindload="imageOnload" src="{{ itemImg}}" bindtap="showResizeModal" data-src="{{itemImg}}">image>           
 4               view>
 5   view>
 6 
 7  <view wx:if="{{isCheckDtl}}">
 8    <import src="/components/resizePicModal/resizePicModal.wxml"/>
 9   <template is="resizePic" data="{{img}}">template>
10  view>

業務頁面js,引用js文件,實例化resizePicModal

1 var that
2 var resizePicModal = {}
3 var app = getApp()
4 var resizePicModalService = require('../../components/resizePicModal/resizePicModal.js')
1  /**
 2    * 生命週期函數--監聽頁面加載
 3    */
 4   onLoad: function (options) {
 5     that = this 8     resizePicModal = new resizePicModalService.ResizePicModal()
  }

新手一枚,有未完善支出謝謝指點出來.

相關文章
相關標籤/搜索