微信小程序movable view移動圖片和雙指縮放實(shí)例代碼
movable-area是微信小程序的新組件,可以用來移動視圖區(qū)域movable-view。移動方向可選擇任何、垂直和平行??梢苿訁^(qū)域里包含其他文本、圖片、按鈕等組件。可移動區(qū)域可綁定touchend等事件。movable-view的參數(shù)可調(diào)整動畫效果。
先從movable-view開始說起吧. movable-view是小程序自定義的組件.其描述為:"可移動的視圖容器,在頁面中可以拖拽滑動". 官方文檔地址:
https://mp.weixin.qq.com/debug/wxadoc/dev/component/movable-view.html.
值得注意的是文檔中有一段備注: "當(dāng)movable-view小于movable-area時(shí),movable-view的移動范圍是在movable-area內(nèi);當(dāng)movable-view大于movable-area時(shí),movable-view的移動范圍必須包含movable-area(x軸方向和y軸方向分開考慮)". 也就是說父容器movable-area是可以比子容器movable-view小的,但是子容器的移動范圍必須包括父容器.
先看官方實(shí)例代碼:
<view class="section">
<view class="section__title">movable-view區(qū)域小于movable-area</view>
<movable-area style="height: 200px;width: 200px;background: red;">
<movable-view style="height: 50px; width: 50px; background: blue;" x="{{x}}" y="{{y}}" direction="all">
</movable-view>
</movable-area>
<view class="btn-area">
<button size="mini" bindtap="tap">click me to move to (30px, 30px)</button>
</view>
<view class="section__title">movable-view區(qū)域大于movable-area</view>
<movable-area style="height: 100px;width: 100px;background: red;" direction="all">
<movable-view style="height: 200px; width: 200px; background: blue;">
</movable-view>
</movable-area>
</view>
這里面有個(gè)錯(cuò)誤,應(yīng)該是編寫人的一點(diǎn)小失誤吧. 第二個(gè)movable-area的屬性direction應(yīng)該寫在movable-view上.
<movable-area style="height: 100px;width: 100px;background: red;" > <movable-view style="height: 200px; width: 200px; background: blue;" direction="all"> </movable-view> </movable-area>
看下效果:
1) 當(dāng)movable-view區(qū)域小于movable-area時(shí),子容器movable-view只能在父容器內(nèi)移動. 下圖的效果是設(shè)置了屬性 out-of-bounds="true"的效果. out-of-bounds可以染子容器到達(dá)父容器邊界時(shí)有個(gè)超出邊界然后回彈的動畫. 并不是真正能讓子容器移動到父容器以外.
2) 當(dāng)movable-view區(qū)域大于movable-area時(shí),子容器移動的范圍必須包括父容器.
第二種情況中,把父容器看做手機(jī)屏幕可視區(qū)域,子容器看做要查看的長圖,大圖. 就可以實(shí)現(xiàn)拖動查看圖片的效果. 如果圖片時(shí)動態(tài)加載的,不是固定的圖片,就要兼容圖片寬高小于屏幕可視寬高和圖片寬高大于可視屏幕寬高的可能性,也就是要考慮到以上兩種情況.
我們要在movable組件加載的同時(shí)設(shè)置好movable-view的寬高,因?yàn)閙ovable組件加載成功后再去改變movable-view的大小,可移動區(qū)域是不會變的. 我們可以通過頁面中要查看的圖片的onload事件中獲取圖片寬高(目前我只發(fā)現(xiàn)bindload事件能獲取到圖片寬高),然后存儲起來imgWidth和imgHeight. 當(dāng)用戶點(diǎn)擊圖片時(shí),在bindtap事件中設(shè)置好movable-view的寬高,同時(shí)將movable-area的彈窗wx;if設(shè)置為true.
<!-- 要查看的圖片列表 -->
<view class="flex-wrap flex-pic">
<view class="picList">
<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>
</view>
</view>
因?yàn)橐榭吹氖且粋€(gè)圖片列表, 我用了一個(gè)數(shù)組去存儲每個(gè)圖片的寬高,然后通過圖片id來關(guān)聯(lián)
/**
* 加載圖片
*/
imageOnload:function(e){
var id = e.currentTarget.id
this.data.imgIdList[id] = {
width:e.detail.width,
height:e.detail.height
}
},
模板頁面
<!--components/resizePicModal/resizePicModal.wxml-->
<template name="resizePic">
<scroll-view class="backdrop">
<view class="close-icon" bindtap="closeResizeModal">
取消預(yù)覽
</view>
<movable-area style="width:100%;height:100%;" >
<movable-view direction="all"
out-of-bounds="true" x="{{img.x}}" y="{{img.y}}" >
<image mode="widthFix" class="dtl-img" src="{{img.currentSrc}}"></image>
</movable-view>
</movable-area>
</scroll-view>
</template>
/**
* 打開彈窗
*/
showResizeModal: function (e) {
var src = e.currentTarget.dataset.src;
var x = 0
var y =0
try {
var width = this.imgIdList[e.currentTarget.id].width; //圖片原寬
var height = this.imgIdList[e.currentTarget.id].height; //圖片原高
//小程序默認(rèn)固定寬320px,獲取top和left值,使圖片居中顯示
height = height * (320 / width);
width = 320;
x = (app.windowWidth - width) / 2
y = (app.windowHeight - height) / 2
} catch (e) { }
var img = {
x: x,
y: y,26 currentSrc: src,
};
this.setData({ img: img, isCheckDtl: true });
},
部分CSS代碼
.backdrop{
background: rgba(0, 0, 0, 1);
width:100%;
height: 100%;
position: fixed;
top:0;
left:0;
}
以上基本上可以完成一個(gè)點(diǎn)擊查看圖片的需求.
然而如果再支持雙指縮放的話,movable-view實(shí)現(xiàn)不了.我暫沒想出來怎么實(shí)現(xiàn),如果有人知道,希望能夠指點(diǎn)迷津. 主要原因是因?yàn)檫€是我上文提到的那句話:"movable組件加載成功后再去改變movable-view的大小,可移動區(qū)域是不會變的".縮放后圖片大小肯定會改變的. 縮小還好,一旦放大,可移動區(qū)域還是原來的不會改變.想象一下,如果一張寬度剛剛好時(shí)屏幕可視寬度的圖片,放大后,這張圖片就只能在屏幕可視寬度windowWidth的范圍中移動,看不到左也看不到右邊超出的部分.
所以如果既要可移動圖片又要可縮放,就不能用movable-view組件了,自己寫個(gè)吧. 原來bindtouchmove會觸發(fā)頁面的滾動條,但是現(xiàn)在微信好像已經(jīng)修復(fù)了這個(gè)BUG,我今天在真機(jī)上測試沒有出現(xiàn)這個(gè)問題.
自定義控件resizePicModal.wxml:
<!-- 縮放 -->
<template name="resizePic">
<scroll-view class="backdrop" catchtouchmove="bindTouchMove" catchtouchend="bindTouchEnd" bindtouchstart="bindTouchStart" >
<view class="close-icon" bindtap="closeResizeModal">
取消預(yù)覽
</view>
<image catchtouchmove="bindTouchMove" bindtouchend="bindTouchEnd" bindtouchstart="bindTouchStart"
style=" transform: scale({{img.baseScale}}); position:absolute; top:{{img.top}}px; left:{{img.left}}px; "
mode="widthFix" class="dtl-img" src="{{img.currentSrc}}"></image>
</scroll-view>
</template>
JS: resizePicModal.js
/**
* 使用方法:
* 1) WXHTML要縮放的圖片 必須 傳入 src 以及綁定 bindtap事件,
* e.g:
* <image bindtap="toggleDtl" data-src="{{item}}" wx:for="{{productCard.arrImg}}" wx:key="*this" src="{{item}}" style="width:100%" mode="widthFix"></image>
* 2) WXHTML 要引入Modal模板(isCheckDtl無需再定義):
* <view wx:if="{{isCheckDtl}}">
* <import src="/components/resizePicModal/resizePicModal.wxml"/>
* <template is="resizePic" data="{{img}}"></template>
* </view>
* 3) JS頁面要引入JS文件,覆蓋當(dāng)前頁面的事件:
* var resizePicModalService = require ('../../components/resizePicModal/resizePicModal.js')
* var resizePicModal = {}
* 4) 在onLoad事件中,實(shí)例化ResizePicModal
* resizePicModal = new resizePicModalService.ResizePicModal()
*/
var app = getApp()
let modalEvent = {
distanceList: [0, 0],//存儲縮放時(shí),雙指距離.只有兩個(gè)數(shù)據(jù).第一項(xiàng)為old distance.最后一項(xiàng)為new distance
disPoint: { x: 0, y: 0 },//手指touch圖片時(shí),在圖片上的位置
imgIdList:{},
/**
* 打開彈窗
*/
showResizeModal: function (e) {
var src = e.currentTarget.dataset.src;
var x = 0
var y =0
try {
var width = this.imgIdList[e.currentTarget.id].width; //圖片原寬
var height = this.imgIdList[e.currentTarget.id].height; //圖片原高
//小程序固定寬320px
height = height * (320 / width);
width = 320;
x = (app.windowWidth - width) / 2 //> 0 ? (app.windowWidth - width) / 2 : 0;
y = (app.windowHeight - height) / 2// > 0 ? (app.windowHeight - height) / 2 : 0;
} catch (e) { }
var img = {
top: y,
left: x,
x: x, y: y,
width: '100%',
baseScale: 1,
currentSrc: src,
};
this.setData({ img: img, isCheckDtl: true });
},
/**
* 關(guān)閉彈窗
*/
closeResizeModal:function(){
this.setData({ isCheckDtl: false })
},
/**
* 加載圖片
*/
imageOnload:function(e){
var id = e.currentTarget.id
this.imgIdList[id] = {
width:e.detail.width,
height:e.detail.height
}
},
/**
* bindtouchmove
*/
bindTouchMove: function (e) {
if (e.touches.length == 1) {//一指移動當(dāng)前圖片
this.data.img.left = e.touches[0].clientX - this.disPoint.x
this.data.img.top = e.touches[0].clientY - this.disPoint.y
this.setData({ img: this.data.img })
}
if (e.touches.length == 2) {//二指縮放
var xMove = e.touches[1].clientX - e.touches[0].clientX
var yMove = e.touches[1].clientY - e.touches[0].clientY
var distance = Math.sqrt(xMove * xMove + yMove * yMove);//開根號
this.distanceList.shift()
this.distanceList.push(distance)
if (this.distanceList[0] == 0) { return }
var distanceDiff = this.distanceList[1] - this.distanceList[0]//兩次touch之間, distance的變化. >0,放大圖片.<0 縮小圖片
// 假設(shè)縮放scale基數(shù)為1: newScale = oldScale + 0.005 * distanceDiff
var baseScale = this.data.img.baseScale + 0.005 * distanceDiff
if(baseScale>0){
this.data.img.baseScale = baseScale
var imgWidth = baseScale * parseInt(this.data.img.imgWidth)
var imgHeight = baseScale * parseInt(this.data.img.imgHeight)
this.setData({ img: this.data.img })
}else{
this.data.img.baseScale = 0
this.setData({ img: this.data.img })
}
}
},
/**
* bindtouchend
*/
bindTouchEnd: function (e) {
if (e.touches.length == 2) {//二指縮放
this.setData({ isCheckDtl: true })
}
},
/**
* bindtouchstart
*/
bindTouchStart: function (e) {
this.distanceList = [0, 0]//回復(fù)初始值
this.disPoint = { x: 0, y: 0 }
if (e.touches.length == 1) {
this.disPoint.x = e.touches[0].clientX - this.data.img.left
this.disPoint.y = e.touches[0].clientY - this.data.img.top
}
}
}
function ResizePicModal(){
let pages = getCurrentPages()
let curPage = pages[pages.length - 1]
Object.assign(curPage, modalEvent)//覆蓋原生頁面事件
this.page = curPage
curPage.resizePicModal = this
return this
}
module.exports = {
ResizePicModal
}
業(yè)務(wù)頁面wxml:引入自定義控件模板
<view class="flex-wrap flex-pic">
<view class="picList">
<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>
</view>
</view>
<!-- 縮放 -->
<view wx:if="{{isCheckDtl}}">
<import src="/components/resizePicModal/resizePicModal.wxml"/>
<template is="resizePic" data="{{img}}"></template>
</view>
業(yè)務(wù)頁面js,引用js文件,實(shí)例化resizePicModal
var that
var resizePicModal = {}
var app = getApp()
var resizePicModalService = require('../../components/resizePicModal/resizePicModal.js')
/**
* 生命周期函數(shù)--監(jiān)聽頁面加載
*/
onLoad: function (options) {
that = this 8 resizePicModal = new resizePicModalService.ResizePicModal()
}
總結(jié)
以上所述是小編給大家介紹的微信小程序movable view移動圖片和雙指縮放實(shí)例代碼,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
ES6使用export和import實(shí)現(xiàn)模塊化的方法
這篇文章主要介紹了ES6使用export和import實(shí)現(xiàn)模塊化的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-09-09
Bootstrap與KnockoutJs相結(jié)合實(shí)現(xiàn)分頁效果實(shí)例詳解
KnockoutJS是一個(gè)JavaScript實(shí)現(xiàn)的MVVM框架。接下來通過本文給大家介紹Bootstrap與KnockoutJs相結(jié)合實(shí)現(xiàn)分頁效果,對bootstrap knockoutjs相關(guān)知識感興趣的朋友一起學(xué)習(xí)吧2016-05-05
JS實(shí)現(xiàn)鼠標(biāo)經(jīng)過好友列表中的好友頭像時(shí)顯示資料卡的效果
需求為當(dāng)用戶鼠標(biāo)經(jīng)過好友列表中好友頭像時(shí),顯示該好友的基本資料,其實(shí)也就是類似QQ客戶端的那種功能,下面是具體的實(shí)現(xiàn)思路及過程2014-07-07
基于prototype擴(kuò)展的JavaScript常用函數(shù)庫
基于prototype擴(kuò)展的JavaScript常用函數(shù)庫實(shí)現(xiàn)代碼,學(xué)習(xí)js的朋友可以參考下。2010-11-11

