微信小程序movable-view移动图片和双指缩放
先从movable-view开始说起吧. movable-view是小程序自定义的组件.其描述为:"可移动的视图容器,在页面中可以拖拽滑动". 官方文档地址:https://mp.weixin.qq.com/debug/wxadoc/dev/component/movable-view.html.
值得注意的是文档中有一段备注: "当movable-view小于movable-area时,movable-view的移动范围是在movable-area内;当movable-view大于movable-area时,movable-view的移动范围必须包含movable-area(x轴方向和y轴方向分开考虑)". 也就是说父容器movable-area是可以比子容器movable-view小的,但是子容器的移动范围必须包括父容器.
先看官方实例代码:
<view class="section">
<view class="section__title">movable-view区域小于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区域大于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>
这里面有个错误,应该是编写人的一点小失误吧. 第二个movable-area的属性direction应该写在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) 当movable-view区域小于movable-area时,子容器movable-view只能在父容器内移动. 下图的效果是设置了属性 out-of-bounds="true"的效果. out-of-bounds可以染子容器到达父容器边界时有个超出边界然后回弹的动画. 并不是真正能让子容器移动到父容器以外.
2) 当movable-view区域大于movable-area时,子容器移动的范围必须包括父容器.

第二种情况中,把父容器看做手机屏幕可视区域,子容器看做要查看的长图,大图. 就可以实现拖动查看图片的效果. 如果图片时动态加载的,不是固定的图片,就要兼容图片宽高小于屏幕可视宽高和图片宽高大于可视屏幕宽高的可能性,也就是要考虑到以上两种情况.
我们要在movable组件加载的同时设置好movable-view的宽高,因为movable组件加载成功后再去改变movable-view的大小,可移动区域是不会变的. 我们可以通过页面中要查看的图片的onload事件中获取图片宽高(目前我只发现bindload事件能获取到图片宽高),然后存储起来imgWidth和imgHeight. 当用户点击图片时,在bindtap事件中设置好movable-view的宽高,同时将movable-area的弹窗wx;if设置为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>
因为要查看的是一个图片列表, 我用了一个数组去存储每个图片的宽高,然后通过图片id来关联
/**
* 加载图片
*/
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">
取消预览
</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; //图片原高 //小程序默认固定宽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,
currentSrc: src,
};
this.setData({ img: img, isCheckDtl: true }); },
部分CSS代码
.backdrop{
background: rgba(0, 0, 0, 1);
width:100%;
height: 100%;
position: fixed;
top:;
left:;
}
以上基本上可以完成一个点击查看图片的需求.
然而如果再支持双指缩放的话,movable-view实现不了.我暂没想出来怎么实现,如果有人知道,希望能够指点迷津. 主要原因是因为还是我上文提到的那句话:"movable组件加载成功后再去改变movable-view的大小,可移动区域是不会变的".缩放后图片大小肯定会改变的. 缩小还好,一旦放大,可移动区域还是原来的不会改变.想象一下,如果一张宽度刚刚好时屏幕可视宽度的图片,放大后,这张图片就只能在屏幕可视宽度windowWidth的范围中移动,看不到左也看不到右边超出的部分.
所以如果既要可移动图片又要可缩放,就不能用movable-view组件了,自己写个吧. 原来bindtouchmove会触发页面的滚动条,但是现在微信好像已经修复了这个BUG,我今天在真机上测试没有出现这个问题.
自定义控件resizePicModal.wxml:
<!-- 缩放 -->
<template name="resizePic">
<scroll-view class="backdrop" catchtouchmove="bindTouchMove" catchtouchend="bindTouchEnd" bindtouchstart="bindTouchStart" >
<view class="close-icon" bindtap="closeResizeModal">
取消预览
</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文件,覆盖当前页面的事件:
* var resizePicModalService = require ('../../components/resizePicModal/resizePicModal.js')
* var resizePicModal = {}
* 4) 在onLoad事件中,实例化ResizePicModal
* resizePicModal = new resizePicModalService.ResizePicModal()
*/
var app = getApp()
let modalEvent = {
distanceList: [0, 0],//存储缩放时,双指距离.只有两个数据.第一项为old distance.最后一项为new distance
disPoint: { x: 0, y: 0 },//手指touch图片时,在图片上的位置
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 }); },
/**
* 关闭弹窗
*/
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) {//一指移动当前图片
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 缩小图片
// 假设缩放scale基数为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]//回复初始值
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
}
业务页面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>
业务页面js,引用js文件,实例化resizePicModal
var that
var resizePicModal = {}
var app = getApp()
var resizePicModalService = require('../../components/resizePicModal/resizePicModal.js')
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
that = this resizePicModal = new resizePicModalService.ResizePicModal()
}
新手一枚,有未完善支出谢谢指点出来.
微信小程序movable-view移动图片和双指缩放的更多相关文章
- 微信小程序-显示外链图片 bug
微信小程序-显示外链图片 bug 显示外链图片 bug 403 bug 禁止外链,未授权 https://httpstatuses.com/403 image component 图片.支持 JPG. ...
- 微信小程序--canvas画布实现图片的编辑
技术:微信小程序 概述 上传图片,编辑图片大小,添加文字,改变文字颜色等 详细 代码下载:http://www.demodashi.com/demo/14789.html 概述 微信小程序--ca ...
- 微信小程序:本地资源图片无法通过 WXSS 获取,可以使用网络图片或者 base64或者使用image标签
微信小程序:本地资源图片无法通过 WXSS 获取,可以使用网络图片或者 base64或者使用image标签 一.问题 报错信息: VM696:2 pages/user/user.wxss 中的本地资源 ...
- (干货)微信小程序之上传图片和图片预览
这几天一直负责做微信小程序这一块,也可以说是边做边学习吧,把自己做的微信小程序的一些功能分享出来,与大家探讨一下,相互学习相互进步. 先看下效果图 只写了一下效果样式的话希望大家不要太在意,下面马路杀 ...
- 微信小程序开发之多图片上传+服务端接收
前言: 业务需求,这次需要做一个小程序同时选中三张图片一起上传到服务端,后端使用的.NET WEBAPI接收数据保存. 使用技术: 在这章中将会使用到微信小程序wx.uploadFile(Object ...
- 微信小程序之上传图片和图片预览
这几天一直负责做微信小程序这一块,也可以说是边做边学习吧,把自己做的微信小程序的一些功能分享出来,与大家探讨一下,相互学习相互进步. 先看下效果图 只写了一下效果样式的话希望大家不要太在意,下面马路杀 ...
- 微信小程序开发:背景图片设置
本文链接:https://blog.csdn.net/michael_f2008/article/details/86543134开发微信小程序时,不能直接在wxss文件里引用本地图片,运行时会报错: ...
- 微信小程序--地图上添加图片
如何在微信小程序地图添加上,添加图片? 在微信小程序中,地图的层级最高,所以我们没有办法,通过定位,在地图上添加图片等信息; 处理办法: 添加控件:controls; 其中有个属性position,进 ...
- 转:【微信小程序】 微信小程序-拍照或选择图片并上传文件
调用拍照API:https://mp.weixin.qq.com/debug/wxadoc/dev/api/media-picture.html?t=20161222#wxchooseimageobj ...
- 微信小程序使用canvas绘制图片的注意事项
1.单位换算问题,canvas的尺寸单位是px,所以单位需要做个换算,可以通过wx.getSystemInfo获取屏幕宽高(单位是px),微信小程序无论什么机型,屏幕宽度都是750rpx,因此可以做个 ...
随机推荐
- css实现选项卡
<style> *{ margin: ; padding: ; text-decoration: none; list-style: none; outline:none; } .box{ ...
- js数值使用及数组转json,转化后的json传入后台解析
var storeArray=new Array(); $("input[name='storeid']").each(function(i){ var curStoreObj = ...
- ReactiveCocoa源码解析(四) Signal中的静态属性静态方法以及面向协议扩展
上篇博客我们聊了Signal的几种状态.Signal与Observer的关联方式以及Signal是如何向关联的Observer发送事件的.本篇博客继续上篇博客的内容,来聊一下Signal类中静态的ne ...
- WCF学习——构建第二个WCF应用程序(五)
一.创建数据服务 1.在“解决方案资源管理器”中,使用鼠标左键选中“WcfService”项目,然后在菜单栏上,依次选择“项目”.“添加新项”. 2.在“添加新项”对话框中,选择“Web”节点,然后选 ...
- VB6之GDI+加载PNG图片
原生的VB6不支持PNG个图片,因为刚有VB的时候还没有PNG的概念呢.不过,利用GDI+加载解析个PNG简直是砍瓜切菜般简单. GDI+的模块是我在网上下载的,地址应该是:http://vistas ...
- MySQL触发器更新和插入操作
一.触发器概念 触发器(trigger):监视某种情况,并触发某种操作,它是提供给程序员和数据分析员来保证数据完整性的一种方法,它是与表事件相关的特殊的存储过程,它的执行不是由程序调用,也不是手工启动 ...
- Java用Cookie简单限制点赞次数
楼主最近在搞一个当下比较流行的点赞功能,这个功能也是让程序员又爱又恨啊 说起爱,点赞是个社会化的动作,全民都在为美好的事情,行为,动作,点赞. 说起恨,你很难在用户没有登录的情况下限制恶意点赞的机器人 ...
- ES6速记手册
1.三元操作符 这是一个很好的节省代码当你想要编写一个如果. . else语句在一线. 普通写法: const x = 20;let big;if (x > 10) { 速记: const bi ...
- Android - service and thread
服务(Service)是Android中实现后台程序运行的方案.适合执行那些不需要和用户交互并长期执行的任务. 服务并非运行在一个独立的进程中,而是依赖于创建服务时所在的应用程序.当某个应用程序进程被 ...
- Codeforces_776E: The Holmes Children (数论 欧拉函数)
题目链接 先看题目中给的函数f(n)和g(n) 对于f(n),若自然数对(x,y)满足 x+y=n,且gcd(x,y)=1,则这样的数对对数为f(n) 证明f(n)=phi(n) 设有命题 对任意自然 ...