微信小程序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,因此可以做个 ...
随机推荐
- javascript中的构造函数和继承
1.第一节 使用工厂模式创建一个构造函数CreatePerson function CreatePerson(name,sex){//构造函数:用于构造对象 可以说在js里类就是构造函数 //1.原料 ...
- BeanUtils.copyProperties()方法引入不同包
两个对象之间拷贝相同的属性,可以使用BeanUtils.copyProperties()方法, BeanUtils.copyProperties(obj1,obj2); 提示有三个包可选. A,选择o ...
- group by和count联合使用问题
要根据用户发布的产品数量来排序做分页,使用group ) FROM( SELECT uid,COU 工作中要根据用户发布的产品数量来排序做分页,使用group by uid 用count(uid) 来 ...
- VS2015 +Qt5 串口工具
简单的小工具是VS2015 + Qt5.6.1实现的,界面部分是Qt实现,串口是封装的WinAPI,把串口收发模块封装成了个Serialport.dll 供Qt界面调用. 由于VS2015需要CRT运 ...
- Spring中实现定时调度
1, 内容简介 所谓的定时调度,是指在无人值守的时候系统可以在某一时刻执行某些特定的功能采用的一种机制,对于传统的开发而言,定时调度的操作分为两种形式: 定时触发:到某一时间点上执行某些处理操作: ...
- SQl server 2012安装问题 error code 0x858C001b 解决方法
英文版系统安装中文版sql server的缘故,改安装英文版即可.
- ELK日志框架(2):log4net.ElasticSearch+ Kibana实现日志记录和显示
环境说明 1. windows server 2012 R2 64位 2. log4net.ElasticSearch 3. kibana-5.5.0-windows-x86.zip 架构说明 数据采 ...
- 使用 QDockWidget嵌套布局来实现复杂界面,方便用户可以自定义界面,自由组合窗口
http://www.cnblogs.com/findumars/p/5436533.html
- POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)
POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA) Description A ...
- 50行代码实现的高性能动画定时器 raf-interval
写在前面 raf-interval 是基于 window.requestAnimationFrame() 封装的定时器. Github: https://github.com/dntzhang/raf ...