前言

开发过小程序的同学可能对这两个内置组件并不陌生,他们配合用来实现在页面中可以拖拽滑动,其中:

  • movable-area表示元素可移动的区域,它决定元素移动的区域范围
  • movable-view表示可移动的视图容器,它决定了什么元素可以移动

使用上要求movable-view必须是movable-area的直接子节点,否则不能移动。

这两个组件对于比较常规的可拖拽移动产品需求可以轻松应对,但是针对一些稍微复杂的需求,可能需要对他们的用法原理要进一步掌握理解。

重新认识movable-area和movable-view

在微信小程序官网介绍movable-area时,有过这样的一段提示:

  1. tip: 当 movable-view 小于 movable-area 时,movable-view的移动范围是在 movable-area 内;
  2. tip: 当 movable-view 大于 movable-area 时,movable-view的移动范围必须包含movable-area(x轴方向和 y 轴方向分开考虑)

上面两个组件比较大小是基于各自的尺寸大小而言的,也就是对应矩形的区域面积而言。

其实官网上面对二者关系的说明不是太详细,有很多情况需要区分开;本人在项目做了不同的尝试,下面是总结的不同情况,有不对的地方还请大家斧正。

movable-area和movable-view的一方完全包含另一方

针对movable-areamovable-view其中一方的尺寸大小可以完全覆盖另一方的尺寸大小时,其移动范围表现比较好理解。

例如下图为movable-view的尺寸完全覆盖movable-area的区域时,movable-view的可以移动范围演示图:

movable-view不管怎么移动都要完全包含住movable-area,也就是说movable-area不能超出movable-view的区域范围;反之亦然。

那么大家有没有想过,若不满足一方能完全包含另一方,也就是二者区域存在交叉时,movable-view的移动范围是怎么表现的呢?

movable-area与movable-view区域交叉

所谓区域交叉,是指一方不能完全覆盖另一方时,二者区域有部分重叠;针对这种情况其表现是有差异,这时movable-view的移动范围就要针对x轴方向和 y 轴方向分开考虑。

总结来说:

二者交叉时,不看movable-areamovable-view的区域谁大谁小,而是看movable-view宽高值最大的那个方向。

举个例子:movable-view的width比其height大,因为其跟movable-area区域交叉,那么两个不同方向的最大移动范围表现:

  • 水平方向:movable-view的width要完全包含movable-area的width
  • 垂直方向: movable-view的height要被movable-area的包含覆盖

如下移动演示图:

movable-area区域大小为0,而movable-view不为0

movable-view的区域大于0,而movable-area的面积为0的在移动过程会有怎样的表现呢?

首先,看下movable-area区域为0的两种形式:

  • movable-area组件的widthheight都为0
  • movable-area组件的widthheight其中只有一个为0

那么在这两种情况下,movable-view的移动范围是什么呢,思考几秒钟。

其实,针对movable-area的宽高都为0的情况,可以将上图的黑色正方块想象成一个尺寸为0的一个点,只不过在界面不会展示,但是其位置还在对应位置,那么movable-view就是围绕该不可见点的位置移动,不能超过这个范围,如下图所示,为了方便展示将该点位置用红色点表示。

针对movable-area的width和height任一个为0的情况,与二者同时为0将其想象一个点的情况主要区别是,可以将movable-area想象其为一条不可见的直线,它也不会在界面展示,但是它决定了movable-view移动范围,我们以width为0,height不为0的情况来说明movable-view的移动范围,如下图演示:

movable-area与movable-view区域大小同时为0

首先介绍本节前说明一下:

  • moable-view为0不代表不能移动,例如其子元素有尺寸,依然可以移动
  • 在二者区域都为0的情况下,页面是不会展示对应元素的,下图以演示目的会将其画出来表示其在页面的位置

movable-area或者movable-view区域为0的情况,有两种情况:要么元素的width和height都为0,或者二者不同时为0。

下面我们来介绍下movable-view在其width和height不同时为0情况下(同时为0不会有移动的元素)的移动范围,该前提下要区分movable-area区域为0的情况。

  • movable-area的宽高同时为0,movable-view的width不为0,height为0的情况(height不为0 的情况类似)。

  • movable-area的宽高不同时为0

    • movable-areamovable-view的width都不为0,或者height都不为0,其表现如下图演示:

    • movable-area的有width为0,height不为0,而movable-view的width不为0,height为0的情况移动范围演示如下图,相反的情况类似;

由上面的演示可以得知:

movable-areamovable-view同时为0的情况,跟二者区域不为0且存在交叉的情况下表现类似。

movable-view的子元素内容超过其尺寸

movable-areamovable-view元素必须设置widthheight,但是有时我们movable-view的子元素内容超过其设置的宽高,这时其表现如何呢?

先说结论:

拖拽滑动元素的移动范围是由movable-areamovable-view元素决定的,与movable-view的子元素尺寸没有关系。

也就是说,movable-areamovable-view的宽高一旦设置后,移动范围就固定了,如下图所演示。

movable-view决定可拖动元素

要实现元素可拖动,至少要满足:

  • 可拖动元素必须通过movable-view设置
  • movable-view必须为movable-area的直接子元素

说明一下,可以在movable-area中设置多个movable-view表示设置多个可滑动的块,例如这文章# 微信小程序基于movable-area实现DIY T恤/logo定制实现的拖动。

实现一个卡片多段式拖动

例如有一个产品需求屏幕内一个卡片支持多段式滑动,例如下图所示的三段式:

要求:页面数据初始化后卡片移动到h2的为位置,用户手动拖动到h2 ~ h1的中间位置靠上时,卡片移动到h1的位置,中间位置靠下的话还是移动到h2的位置,h1~h0之间的移动后卡片位置策略与h2 ~ h1一样。

一个实现思路:可以借鉴上面讨论的movable-areamovable-view区域都为0,但是二者存在交叉的情况,具体实现:

  • movable-area设置其区域尺寸为width为0,height为100vh
  • movable-view设置其区域尺寸width为100vw,height为0
  • movable-view的子元素内容即为卡片的展示内容

这样,movable-view在垂直方向的移动范围就是movable-area的高度范围,相当于在垂直方向,movable-area的长度大于movable-view,所以后者的移动范围不能超出前者。

wxml的结构如下所示:

<movable-area
style="width: 0; height: 100vh;"
>
<movable-view
direction="vertical"
y="{{offsetY}}"
style="width: 100vw; height: 0;"
bindchange="onChange"
bind:touchend="onTouchEnd"
bind:touchcancel="onTouchEnd"
>
<view class="movable-content">
<view class="card">
...
</view>
</view>
</movable-view>
</movable-area>

可以在movable-view的change事件中收集卡片滑动后的y方向的偏移值,在触摸事件的结束最后统一计算卡片的最终滑动偏移量值。

Page({
// 下面的h0、h1、h2、100vh 分别表示需求要求设置的卡片多段式滑动范围
data: {
offsetY: h2,
segs: [{
value: h0,
mix_value: h0,
max_value: (h0 + h1)/2
}, {
value: h1,
mix_value: (h0 + h1)/2,
max_value: (h1 + h2)/2
}, {
value: h2,
mix_value: (h1 + h2)/2,
max_value: 100vh
}]
},
...
onChange(event) {
if (event.detail.source) {
this._offsetY = event.detail.y
}
},
onTouchEnd() {
const y = this._offsetY;
const idx = this.segs.findIndex(item => {
return (
y >= item.min_value && y <= item.max_value
);
});
if (idx !== -1) {
this.setData({
offsetY: this.segs[idx].value
})
}
}
})

图文并茂演示小程序movable-view的可移动范围的更多相关文章

  1. 关于微信小程序获取view的动态高度填坑

    wx.createSelectorQuery().select('#box').boundingClientRect(function (rect) { width = rect.width heig ...

  2. mPaaS 小程序架构解析 | 实操演示小程序如何实现多端开发

    对于 mPaaS 小程序开发框架,想必读者们并不陌生.它源自于支付宝小程序框架,继承了易开发性.跨平台性及 Native 性能,不仅帮助开发者实现面向自有 App 投放小程序,还可快速构建打包,覆盖支 ...

  3. 小程序获取view元素的高度

    页面wxml <!--page/index/index.wxml--> <view id='demo'> <text>哈哈哈哈哈</text> < ...

  4. 【微信小程序】view顶部固定或底部固定 + scroll-view中的元素view也可以使用position:fixed;固定选中元素位置

    1.顶端固定核心代码如下: <view class="page__hd" style="position:fixed; top:0;width: 750rpx;&q ...

  5. 微信小程序将view动态填满全屏

    一.在app.js利用官方方法获取设备信息,将获取到的screenHeight.windowHeight度量单位统一由rpx换算为px 注:官方文档给出 [rpx换算px (屏幕宽度/750)  ][ ...

  6. 关于小程序去除view/navigator 点击后默认阴影效果

    hover:class  :定义容器在被触发时的样式 通常无用,但若不去除则影响用户体验: 为避免被覆盖,约定在wxss底部添加class,比如: <!-- wxml --> <na ...

  7. 微信小程序 -- scroll view

    效果图:横向滚动和纵向滚动 scroll view使用方法文档,前面已经介绍查找文档方法,此处不再赘述 一.横向滚动 创建一个页面scroll-nav 然后,在.wxml文件中排版 <!--水平 ...

  8. 一个小时快速搭建微信小程序教程

    「小程序」这个划时代的产品发布快一周了,互联网技术人都在摩拳擦掌,跃跃欲试.可是小程序目前还在内测,首批只发放了 200 个内测资格(泪流满面).本以为没有 AppID 这个月就与小程序无缘了,庆幸的 ...

  9. 一个小时快速搭建微信小程序

    「小程序」这个划时代的产品发布快一周了,互联网技术人都在摩拳擦掌,跃跃欲试.可是小程序目前还在内测,首批只发放了 200 个内测资格(泪流满面).本以为没有 AppID 这个月就与小程序无缘了,庆幸的 ...

随机推荐

  1. 绕过 Docker ,大规模杀死容器

    关注「开源Linux」,选择"设为星标" 回复「学习」,有我为您特别筛选的学习资料~ 作者 | Connor Brewster 译者 | Sambodhi 策划 | Tina 要让 ...

  2. MySQL实时在线备份恢复方案

    开源Linux 长按二维码加关注~ 上一篇:2020年MySQL数据库面试题总结 快照和复制技术的结合可以保证我们得到一个实时的在线MySQL备份解决方案. 当主库发生误操作时,只需要恢复备库上的快照 ...

  3. Java操作Hadoop、Map、Reduce合成

    原始数据: Map阶段 1.每次读一行数据, 2.拆分每行数据, 3.每个单词碰到一次写个1 <0, "hello tom"> <10, "hello ...

  4. 理解ASP.NET Core - 发送Http请求(HttpClient)

    注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 前言 在.NET中,我们有很多发送Http请求的手段,如HttpWebRequest.WebC ...

  5. 渗透:zANTI

    Zanti简介 Zanti是由Zimperium公司打造的Android平台下的渗透测试工具包. Zanti支持两种中间人攻击方式,分别为MIMT攻击和ARP攻击,中间人内带有多个攻击模块,例如MAC ...

  6. 从MySQL全备文件中恢复单个库或者单个表

    从MySQL全备文件中恢复单个库或者单个表 提取建库语句 sed -n '/^-- Current Database: db_cms/,/^-- Current Database: `/p' back ...

  7. Git中的三种对象

    1.Git中有三种对象 commit 每执行一次git commit,git都会对当前工作目录的所有文件生成一次镜像,工作区下的目录对应的对象是tree,工作区下的文件对应的对象是blob,tree下 ...

  8. 理解RESTful Api设计

    REST REST(REpresentational State Transfer)是 Roy Fielding 博士于 2000 年在他的博士论文中提出来的一种软件架构风格(一组架构约束条件和原则) ...

  9. 记一次IIS网站启动不了的问题排查

    今天清理了下机器中的IIS网站,将很久不用的网站都删除. 因为需要删除的比较多,正在使用的很少,就将网站全部删除了,然后准备重新添加需要用的. 在添加了网站后,点击启动按钮,发现网站启动不了,因为网站 ...

  10. 论文阅读 Dynamic Network Embedding by Modeling Triadic Closure Process

    3 Dynamic Network Embedding by Modeling Triadic Closure Process link:https://scholar.google.com.sg/s ...