微信小程序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 相关文章推荐
扩展jquery实现客户端表格的分页、排序功能代码
Mar 16 Javascript
JavaScript起点(严格模式深度了解)
Jan 28 Javascript
JS 加入收藏夹的代码(主流浏览器通用)
May 13 Javascript
JS delegate与live浅析
Dec 21 Javascript
控制input输入框中提示信息的显示和隐藏的方法
Feb 12 Javascript
JavaScript将数字转换成大写中文的方法
Mar 23 Javascript
值得分享的Bootstrap Ace模板实现菜单和Tab页效果
Dec 30 Javascript
js输出数据精确到小数点后n位代码
Jul 02 Javascript
Angular异步变同步处理方法
Aug 13 Javascript
小程序实现五星点评效果
Nov 03 Javascript
Vue实现返回顶部按钮实例代码
Oct 21 Javascript
Javascript中window.name属性详解
Nov 19 Javascript
原生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
phpfans留言版用到的install.php
2007/01/04 PHP
php根据身份证号码计算年龄的实例代码
2014/01/18 PHP
PHP四大安全策略
2014/03/12 PHP
动态表单验证的操作方法和TP框架里面的ajax表单验证
2017/07/19 PHP
javascript定时保存表单数据的代码
2011/03/17 Javascript
jQuery+.net实现浏览更多内容(改编php版本)
2013/03/28 Javascript
jQuery实现HTML5 placeholder效果实例
2014/12/09 Javascript
JQuery实现展开关闭层的方法
2015/02/17 Javascript
js实现的Easy Tabs选项卡用法实例
2015/09/06 Javascript
JS实现的仿淘宝交易倒计时效果
2015/11/27 Javascript
JS组件Bootstrap实现弹出框效果代码
2016/04/26 Javascript
JavaScript页面实时显示当前时间实例代码
2016/10/23 Javascript
浅析javascript中的Event事件
2016/12/09 Javascript
JavaScript使用正则表达式获取全部分组内容的方法示例
2017/01/17 Javascript
详解Vue中状态管理Vuex
2017/05/11 Javascript
详解node.js中的npm和webpack配置方法
2018/01/21 Javascript
小程序云开发获取不到数据库记录的解决方法
2019/05/18 Javascript
深入学习Vue nextTick的用法及原理
2019/10/08 Javascript
jquery实现点击左右按钮切换图片
2021/01/27 jQuery
[28:28]Ti4 冒泡赛第二天NEWBEE vs NaVi 2
2014/07/15 DOTA
[03:37]2014DOTA2国际邀请赛 主赛事第一日胜者组TOPPLAY
2014/07/19 DOTA
python实现ipsec开权限实例
2014/11/11 Python
基于Python3 逗号代码 和 字符图网格(详谈)
2017/06/22 Python
Python 实现字符串中指定位置插入一个字符
2018/05/02 Python
python django下载大的csv文件实现方法分析
2019/07/19 Python
python离线安装外部依赖包的实现
2020/02/13 Python
英国领先的杂志订阅网站:Magazine.co.uk
2018/01/25 全球购物
英国索普公园票务和酒店套餐:Thorpe Breaks
2019/09/14 全球购物
Haggar官网:美国男装品牌
2020/02/16 全球购物
什么是Assembly(程序集)
2014/09/14 面试题
行政人员工作职责
2013/12/05 职场文书
房地产开发计划书
2014/01/10 职场文书
家长写给老师的建议书
2014/03/13 职场文书
大学生学习计划书
2014/09/15 职场文书
2015小学教育教学工作总结
2015/07/21 职场文书
MySQL数据库实验之 触发器和存储过程
2022/06/21 MySQL