Vant 是有赞开发的一套基于 Vue 2.0Mobile 组件库,在开发的过程中也踩了很多坑,今天我们就来聊一聊开发一个移动端 Modal 组件(在有赞该组件被称为 Popup )需要注意的一些

在任何一个合格的UI组件库中,Modal 组件应该是必备的组件之一。它一般用于用户处理事物,但又不希望跳转页面时,可以使用 Modal 在当前页面中打开一个浮层,承载对应的操作。相比PC端,移动端的 Modal 组件坑会更多,比如滚动穿透问题就不像PC端在 body 上添加 overflow: hidden 那么简单。

目录

一、API定义

二、水平垂直居中的方案

三、可恶的滚动穿透

四、position: fixed 失效

一、API定义

任何一个组件开始编码前都需要首先将API先定义好,才好根据API来提供对应的功能。Modal 组件提供了以下API:

更具体的 Api 介绍可以访问该链接查看:Popup

二、水平垂直居中方案

垂直居中的方案网上谷歌一下就能找到很多种,主流的方案有:

  1. absolute(fixed) + 负边距
  2. absolute(fixed) + transform
  3. flex
  4. table + vertical-align

首先说一下我们选择的是第二种:absolute(fixed) + transform,它是以上方案中最简单最方便的方案,代码实现量也很少。实现代码如下:

.modal {position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);
}

但是 transform 会导致一个巨大的,这个的具体细节会在下面的章节中详细讲到。

说完了我们选择的方案,再来说说为啥不选择其他的方案呢?

absolute(fixed) + 负边距

只能适合定高的场景,果断抛弃。如果要实现不定高度就要通过JS来计算了,增加了实现的复杂度。

flex

flex 布局一是在某些老版本的安卓浏览器上还不是很兼容,还有就是需要包裹一个父级才能水平垂直居中。

table + vertical-middle

CSS2 时代用这个方案来实现垂直居中是比较常见的方案,不足的地方就是代码实现量相对较大。

三、可恶的滚动穿透

开发过移动端UI组件的都知道,在移动端有个可恶的滚动穿透问题。这个问题可以描述为:在弹窗上滑动会导致下层的页面跟着滚动。

网上谷歌一下滚动穿透关键字其实可以发现很多种解决方案,每个方案也各有优缺点,但我们选择的解决方案是团队的一姐一篇移动端体验优化的博文中得到的启示(博文地址:花式提升移动端交互体验 | TinySymphony)。

具体的思路是:当容器可以滑动时,若已经在顶部,禁止下滑;若在底部,禁止上滑;容器无法滚动时,禁止上下滑。实现的方式就是在 document 上监听 touchstarttouchmove 事件,如滑动时,祖先元素并没有可滑动元素,直接阻止冒泡即可;否则判断手指滑动的方向,若向下滑动,判断是否滑动到了滑动元素的底部,若已经到达底部,阻止冒泡,向上滑动也类似。具体的代码实现可以看下面的代码:

const _ = require('src/util')
export default function (option) {const scrollSelector = option.scroll || '.scroller'const pos = {x: 0,y: 0}function stopEvent (e) {e.preventDefault()e.stopPropagation()}function recordPosition (e) {pos.x = e.touches[0].clientXpos.y = e.touches[0].clientY}function watchTouchMove (e) {const target = e.targetconst parents = _.parents(target, scrollSelector)let el = nullif (target.classList.contains(scrollSelector)) el = targetelse if (parents.length) el = parents[0]else return stopEvent(e)const dx = e.touches[0].clientX - pos.xconst dy = e.touches[0].clientY - pos.yconst direction = dy > 0 ? '10' : '01'const scrollTop = el.scrollTopconst scrollHeight = el.scrollHeightconst offsetHeight = el.offsetHeightconst isVertical = Math.abs(dx) < Math.abs(dy)let status = '11'if (scrollTop === 0) {status = offsetHeight >= scrollHeight ? '00' : '01'} else if (scrollTop + offsetHeight >= scrollHeight) {status = '10'}if (status !== '11' && isVertical && !(parseInt(status, 2) & parseInt(direction, 2))) return stopEvent(e)}document.addEventListener('touchstart', recordPosition, false)document.addEventListener('touchmove', watchTouchMove, false)
}

四、position: fixed 失效

在前端工程师的世界观里,position: fixed 一直是相对浏览器视口来定位的。有一天,你在固定定位元素的父元素上应用了 transform 属性,当你刷新浏览器想看看最新的页面效果时,你竟然发现固定定位的元素竟然相对于父元素来定位了。是不是感觉人生观都崩塌了。

这个问题,目前只在Chrome浏览器/FireFox浏览器下有。也有人给 Chrome 提bug:Fixed-position element uses transformed ancestor as the container,但至今尚未解决。

例如下面的代码:

<style>body {padding: 50px;}.demo {background: #ccc;height: 100px;transform: scale(1);}.fixed-box {position: fixed;top: 0;left: 0;width: 100px;height: 100px;background: red;}
</style><div class="demo"><div class="fixed-box"></div>
</div>

垂直居中方案 position: fixed + transform 的选择导致了 Modal 组件使用上的一个坑。当我们在 Modal 组件里面嵌套了一个 Modal 时,内层的Modal 就是相对外层的 Modal 来定位,而不是浏览器的 viewport。这也限制了我们 Modal 的使用场景,如果你想实现嵌套的 Modal,就要选择其他的垂直居中方案了,有舍必有得嘛。

关于 position: fixed 失效的更多细节可以参考以下几篇博文:

  • Eric’s Archived Thoughts: Un-fixing Fixed Elements with CSS Transforms
  • CSS3 transform对普通元素的N多渲染影响

总结

开发组件库不易,开发移动端组件库更不易。移动端组件库相对PC端会有更多的奇葩的坑。当遇到坑,肯定是要选择跨越它,而不是逃避它,因此也才有了我们这篇文章,后续我们也还会有一些介绍 Vant 组件库开发过程中遇到的坑,或者一些优化相关的文章,敬请期待。

如果觉得这篇文章讲的还不够,完整源代码实现请移步Github:popup。

移动端 Modal 组件开发杂谈相关推荐

  1. modal组件 vue_vue3:modal组件开发

    项目环境 @vue/cli 4.5.8 最终效果 需求分析 显示/隐藏 点击遮罩层能否关闭 宽度和zIndex自定义 标题栏 -显示标题和关闭按钮 主体 底部 -内置取消和确定功能 实现过程 搭建大体 ...

  2. React-Native 组件开发方法

    前言 React Native的开发思路是通过组合各种组件来组织整个App,在大部分情况下通过组合View.Image等几个基础的组件,可以非常方便的实现各种复杂的跨平台组件,不过在需要原生功能支持. ...

  3. [Asp.net core 3.1] 通过一个小组件熟悉Blazor服务端组件开发

    通过一个小组件,熟悉 Blazor 服务端组件开发.github:https://github.com/git-net/NBlazors 一.环境搭建 vs2019 16.4, asp.net cor ...

  4. 开发杂谈:后移动互联网时代我的一些思考

    在新时代下我们不能只顾低头拉车,更要懂得抬头看路. 本文出自门心叼龙的博客,属于原创类容,转载请注明出处.开发杂谈:后移动互联网时代我的一些思考_门心叼龙的专栏-CSDN博客_后移动互联网时代 这篇文 ...

  5. Vue 移动端UI组件库

    1. vonic vonic 一个基于 vue.js 和 ionic 样式的 UI 框架,用于快速构建移动端单页应用,很简约. 文档 | github地址 | 在线预览 2. vux vux 基于We ...

  6. Vue移动端UI组件库

    1. vonic vonic 一个基于 vue.js 和 ionic 样式的 UI 框架,用于快速构建移动端单页应用,很简约. 中文文档 | github地址 | 在线预览 image 2. vux ...

  7. ueditor上传组件显示乱码_最全面的移动端 UI组件设计详解:中篇

    上一期给大家讲解了<最全面的移动端UI组件设计详解:上篇>,主要分享了:布局组件和导航组件2个部分:这次给大家带来:基础组件.表单组件和反馈组件详解,希望你在设计APP.小程序.H5页面中 ...

  8. 使用vue加svg实现流程图代码_京东风格的移动端Vue组件库NutUI2.0来啦

    移动端 Vue 组件库 NutUI 自发布以来受到了广泛的关注.据不完全统计,目前至少有30多个京东的 web 项目正在使用 NutUI . 经过一段时间紧锣密鼓的开发,近期,京东正式发布了 NutU ...

  9. React Native组件开发指南

    React Native的组件开发一直处在一个比较尴尬的处境.在官方未给予相关示例与脚手架的情况下,社区中依然诞生了许许多多的React Native组件.因为缺少示例与规范,很多组件库仅含有一个in ...

  10. 移动端H5混合开发设置复盘与总结

    此篇接上一篇: 移动端H5混合开发,Touch触控,拖拽,长按, 滑屏 实现方案 https://www.cnblogs.com/buoge/p/9346699.html app 场布设置已经上线了, ...

最新文章

  1. Python的零基础超详细讲解(第二天)-Python的基础语法1
  2. ccna第四学期final一二三套题
  3. day16-小数据池
  4. hdu4179 限制最短路
  5. 怎么把json数据转化为数组_RESTful API 返回统一JSON数据格式是怎么实现的?
  6. ue4相机_[UE4]偏门实用技巧合集
  7. 信道容量受哪三个要素_影响信道容量的主要因素有哪些
  8. 【Win 10 应用开发】分析 URI 中的查询字符串
  9. sqlserver的登陆操作
  10. Elementui动态换肤
  11. PyQt5笔记(06) -- 菜单
  12. jupyter notebook 内核挂掉
  13. Hamcrest使用
  14. 第二代支付系统商业银行行内接入系统总体设计(初稿)
  15. 网络安全七大赛道:全面梳理(重磅深度)
  16. D-Tale,实现Pandas GUI高效数据分析
  17. 转型之路:从数字化到数智化〡数智洞察
  18. Golang入门笔记(14)—— 错误处理
  19. 计算机后来音乐,Computer Music
  20. H3C 交换机DRNI特性使用介绍

热门文章

  1. VC++窗口创建过程,图形绘制,时钟程序
  2. 《重构-改善既有代码的设计》学习笔记----Extract Method(提炼函数)
  3. 12)hInstance和hWnd写进子类
  4. P1019 单词接龙
  5. Android滑动页面返回(自定义控件)
  6. button与submit
  7. 几个清华和交大学霸的公众号,值得学习
  8. 【R语言实用技巧】类别变量的顺序自定义设置
  9. 用数据分析福尔摩斯探案集,里面有你不曾发现的秘密
  10. 走进R语言的世界——简单数据处理