微信小程序movable view移动图片和双指缩放实例代码


Posted in Javascript onAugust 08, 2017

movable-area是微信小程序的新组件,可以用来移动视图区域movable-view。移动方向可选择任何、垂直和平行。可移动区域里包含其他文本、图片、按钮等组件。可移动区域可绑定touchend等事件。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 view移动图片和双指缩放实例代码 微信小程序movable view移动图片和双指缩放实例代码                             

第二种情况中,把父容器看做手机屏幕可视区域,子容器看做要查看的长图,大图. 就可以实现拖动查看图片的效果. 如果图片时动态加载的,不是固定的图片,就要兼容图片宽高小于屏幕可视宽高和图片宽高大于可视屏幕宽高的可能性,也就是要考虑到以上两种情况.

我们要在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,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;
}

以上基本上可以完成一个点击查看图片的需求.

然而如果再支持双指缩放的话,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 8  resizePicModal = new resizePicModalService.ResizePicModal()
 }

总结

以上所述是小编给大家介绍的微信小程序movable view移动图片和双指缩放实例代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
JS+flash实现chrome和ie浏览器下同时可以复制粘贴
Sep 22 Javascript
JS冒泡事件的快速解决方法
Dec 16 Javascript
javascript使用for循环批量注册的事件不能正确获取索引值的解决方法
Dec 20 Javascript
JS实现的数组全排列输出算法
Mar 19 Javascript
JavaScript 总结几个提高性能知识点(推荐)
Feb 20 Javascript
微信运维交互机器人的示例代码
Nov 12 Javascript
JavaScript设计模式之代理模式实例分析
Jan 16 Javascript
利用vue重构有赞商城的思路以及总结整理
Feb 21 Javascript
D3.js(v3)+react 实现带坐标与比例尺的散点图 (V3版本)
May 09 Javascript
对TypeScript库进行单元测试的方法
Jul 18 Javascript
vue利用全局导航守卫作登录后跳转到未登录前指定页面的实例代码
May 19 Javascript
vue3弹出层V3Popup实例详解
Jan 04 Vue.js
原生JS+Canvas实现五子棋游戏
May 28 #Javascript
React-router v4 路由配置方法小结
Aug 08 #Javascript
用Vue.extend构建消息提示组件的方法实例
Aug 08 #Javascript
基于Vue实现页面切换左右滑动效果
Jun 29 #Javascript
VUE实现表单元素双向绑定(总结)
Aug 08 #Javascript
ES6模块化的import和export用法方法总结
Aug 08 #Javascript
Vue项目中quill-editor带样式编辑器的使用方法
Aug 08 #Javascript
You might like
php+mysql分页代码详解
2008/03/27 PHP
php将access数据库转换到mysql数据库的方法
2014/12/24 PHP
php查看当前Session的ID实例
2015/03/16 PHP
PHP安装threads多线程扩展基础教程
2015/11/17 PHP
PHP中include()与require()的区别说明
2017/02/14 PHP
thinkPHP数据查询常用方法总结【select,find,getField,query】
2017/03/15 PHP
php插入mysql数据返回id的方法
2018/05/31 PHP
文本框的字数限制功能jquery插件
2009/11/24 Javascript
jquery事件与函数的使用介绍
2013/09/29 Javascript
深入浅析JavaScript中的作用域和上下文
2016/03/26 Javascript
jQuery实现的无限级下拉菜单功能示例
2016/09/12 Javascript
Ztree新增角色和编辑角色回显问题的解决
2016/10/25 Javascript
js/jq仿window文件夹移动/剪切/复制等操作代码
2017/03/08 Javascript
js求数组中全部数字可拼接出的最大整数示例代码
2017/08/25 Javascript
JavaScript定义函数的三种实现方法
2017/09/23 Javascript
ES6解构赋值实例详解
2017/10/31 Javascript
解决vue中修改了数据但视图无法更新的情况
2018/08/27 Javascript
vue组件库的在线主题编辑器的实现思路
2020/04/03 Javascript
Python ORM框架SQLAlchemy学习笔记之数据添加和事务回滚介绍
2014/06/10 Python
Python爬虫获取图片并下载保存至本地的实例
2018/06/01 Python
Django数据库类库MySQLdb使用详解
2019/04/28 Python
Python 如何展开嵌套的序列
2020/08/01 Python
瑞典首都斯德哥尔摩的多元奢侈时尚品牌:Acne Studios
2017/07/09 全球购物
澳大利亚制造的羊皮靴:Original UGG Boots
2017/11/13 全球购物
极简鞋类,赤脚的感觉:Lems Shoes
2019/08/06 全球购物
如何写一封打动人心的求职信
2014/02/17 职场文书
超市开业庆典策划方案
2014/05/14 职场文书
财会专业毕业生自荐信
2014/07/09 职场文书
党的群众路线教育实践活动个人整改落实情况汇报
2014/10/28 职场文书
勤俭节约倡议书范文
2015/04/29 职场文书
堂吉诃德读书笔记
2015/06/30 职场文书
Go语言带缓冲的通道实现
2021/04/26 Golang
MongoDB使用profile分析慢查询的步骤
2021/04/30 MongoDB
Python实战之实现简易的学生选课系统
2021/05/25 Python
Java数组与堆栈相关知识总结
2021/06/29 Java/Android
Go获取两个时区的时间差
2022/04/20 Golang