先从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移动图片和双指缩放的更多相关文章

  1. 微信小程序-显示外链图片 bug

    微信小程序-显示外链图片 bug 显示外链图片 bug 403 bug 禁止外链,未授权 https://httpstatuses.com/403 image component 图片.支持 JPG. ...

  2. 微信小程序--canvas画布实现图片的编辑

    技术:微信小程序   概述 上传图片,编辑图片大小,添加文字,改变文字颜色等 详细 代码下载:http://www.demodashi.com/demo/14789.html 概述 微信小程序--ca ...

  3. 微信小程序:本地资源图片无法通过 WXSS 获取,可以使用网络图片或者 base64或者使用image标签

    微信小程序:本地资源图片无法通过 WXSS 获取,可以使用网络图片或者 base64或者使用image标签 一.问题 报错信息: VM696:2 pages/user/user.wxss 中的本地资源 ...

  4. (干货)微信小程序之上传图片和图片预览

    这几天一直负责做微信小程序这一块,也可以说是边做边学习吧,把自己做的微信小程序的一些功能分享出来,与大家探讨一下,相互学习相互进步. 先看下效果图 只写了一下效果样式的话希望大家不要太在意,下面马路杀 ...

  5. 微信小程序开发之多图片上传+服务端接收

    前言: 业务需求,这次需要做一个小程序同时选中三张图片一起上传到服务端,后端使用的.NET WEBAPI接收数据保存. 使用技术: 在这章中将会使用到微信小程序wx.uploadFile(Object ...

  6. 微信小程序之上传图片和图片预览

    这几天一直负责做微信小程序这一块,也可以说是边做边学习吧,把自己做的微信小程序的一些功能分享出来,与大家探讨一下,相互学习相互进步. 先看下效果图 只写了一下效果样式的话希望大家不要太在意,下面马路杀 ...

  7. 微信小程序开发:背景图片设置

    本文链接:https://blog.csdn.net/michael_f2008/article/details/86543134开发微信小程序时,不能直接在wxss文件里引用本地图片,运行时会报错: ...

  8. 微信小程序--地图上添加图片

    如何在微信小程序地图添加上,添加图片? 在微信小程序中,地图的层级最高,所以我们没有办法,通过定位,在地图上添加图片等信息; 处理办法: 添加控件:controls; 其中有个属性position,进 ...

  9. 转:【微信小程序】 微信小程序-拍照或选择图片并上传文件

    调用拍照API:https://mp.weixin.qq.com/debug/wxadoc/dev/api/media-picture.html?t=20161222#wxchooseimageobj ...

  10. 微信小程序使用canvas绘制图片的注意事项

    1.单位换算问题,canvas的尺寸单位是px,所以单位需要做个换算,可以通过wx.getSystemInfo获取屏幕宽高(单位是px),微信小程序无论什么机型,屏幕宽度都是750rpx,因此可以做个 ...

随机推荐

  1. Java学习笔记--监视目录变化

    1.在实际开发中可能会需要监视某个目录下的文件所发生的变化.   2.在java7之前的做法 在一个独立的线程中使用File类的listFiles方法来定时检查目录中的内容,并与之前的内容进行比较   ...

  2. Javaee需不需要培训?培训完可以顺利找到工作吗?

    Javaee需不需要培训?培训完可以顺利找到工作吗? 在IT行业中Java以它通用性.高效性.平台移植性和安全性遍布各个领域,它的火热也给IT市场发展带来一定影响,随着Java技术的广泛运营,企业对J ...

  3. Oracle数据库概念和一些基本的SQL语句

    1.数据 定义:描述事物的符号.例如:文本.音频.视频都是数据. 2.数据库 存放数据的仓库,存放在计算机中,按照一定格式存放,可以为用户共享. 3.数据库的发展阶段 1.网状数据库 2.层次数据库 ...

  4. Entity Framework入门教程: Entity Framework支持的查询方式

    Entity Framework支持的查询方式有三种 LINQ to Entities Entity SQL Native SQL [LINQ to Entities] LINQ(语言集成查询)是从V ...

  5. 【LeetCode】232. Implement Queue using Stacks

    题目: Implement the following operations of a queue using stacks. push(x) -- Push element x to the bac ...

  6. c++ new delete 常踩的坑

    WeTest 导读 c++ 是公司开发最常用的语言之一, 那New和Delete 这两个函数是所有开发者即爱又恨的函数.由new 和delete引发的bug , coredump , 让多少程序员加了 ...

  7. javascript运动框架(二)

    紧接着上面写的... 给div加一个边框,border:1px solid black window.onload = function(){      var div = document.getE ...

  8. VB6之摄像头控制

    参考文献:http://www.cnblogs.com/xidongs/archive////.html 直接上代码: 'code by lichmama from cnblogs.com '@vb6 ...

  9. Linux最小化安装

    1,linux安装网络自动配置: 2,linux硬盘分配 1,/boot 用来存放与 Linux 系统启动有关的程序,比如启动引导装载程序等,建议大小为 100-200MB . 2,swap 实现虚拟 ...

  10. Linux工具之bc计算器进制的转换

    bc是Linux下的命令行式的计算器. 题目虽然叫任意进制,但是因为bc的限制,输入进制是2~16范围:输出进制是2~999范围.这与常见计算器的进制范围是一致的,比如windows计算器最高也只能处 ...