80

移动端 Modal 组件开发杂谈

 6 years ago
source link: http://tech.youzan.com/moda-component-implement/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

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

一、API定义
二、水平垂直居中的方案
三、可恶的滚动穿透
四、position: fixed 失效

一、API定义

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

cb407ea5d40a45a90c37ff2fe7db56af.png

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

二、水平垂直居中方案

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

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

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

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

但是 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].clientX
    pos.y = e.touches[0].clientY
  }

  function watchTouchMove (e) {
    const target = e.target
    const parents = _.parents(target, scrollSelector)
    let el = null
    if (target.classList.contains(scrollSelector)) el = target
    else if (parents.length) el = parents[0]
    else return stopEvent(e)
    const dx = e.touches[0].clientX - pos.x
    const dy = e.touches[0].clientY - pos.y
    const direction = dy > 0 ? '10' : '01'
    const scrollTop = el.scrollTop
    const scrollHeight = el.scrollHeight
    const offsetHeight = el.offsetHeight
    const 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)
}
12345678910111213141516171819202122232425262728293031323334353637383940414243

四、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>  
12345678910111213141516171819202122

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

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

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

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

欢迎关注我们的公众号
coder_qrcode.png

Recommend

  • 93

    Vant 是有赞开发的一套基于 Vue 2.0 的 Mobile 组件库,在开发...

  • 69
    • 掘金 juejin.im 6 years ago
    • Cache

    APP后端开发杂谈

    Header头 header 头推荐加上字段: Authorization 用来存放access_token,通过该token对用户进行认证。可以理解其作用等同于cookie中的session_id,有该令牌就默认用户已经认证登陆过。 Signtur

  • 58
    • www.tuicool.com 5 years ago
    • Cache

    Modal Logic Playground

    So what's modal logic, anyway? Modal logicis a type of symbolic logic for capturing inferences about necessity and possibility . As with other logical systems,...

  • 42
    • www.tuicool.com 5 years ago
    • Cache

    Vue.js hunt for perfect modal

    Hey. Today we will pursue our dream of a perfect modal. Perfect means: It floats above everything else....

  • 44

    Looks fine, doesn’t it? Except that it’s blocking… Which means that, in order to open another modal, a user has to close the current one. That’s 2 actions and we can do better. For this approach we…

  • 19
    • www.tuicool.com 5 years ago
    • Cache

    Build a Modal Component with React

    I love modals because they save a lot of time required to load a new tab. In this post, we’re going to learn how to create an awesome reusable modal with React from scratch. These are the steps for this tutorial:...

  • 12

    UEFI开发探索80- YIE001PCIe开发板(终篇 移植杂谈) 请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/autho...

  • 0
    • blog.wsine.top 2 years ago
    • Cache

    Switch移动TV模式杂谈

    前言# 今天想要谈谈的是 Switch 游戏主机的 TV 模式。 Switch 最美好的地方,除了能够 Play Anywhere 之外,还有分享的快乐。但是要分享得够快乐,除了手柄以...

  • 2
    • blog.dteam.top 1 year ago
    • Cache

    Angular4 动态加载组件杂谈

    Angular4 动态加载组件杂谈 胡伟红 Posted at — Jul 6, 2017 阅读 134 最近接手了一个项目,客户提出了一个高大上的需求:要求只有一个主界面,所有组件通过 Tab 来显示。其实这个需求并不诡异,不喜欢界面跳转的客户都非常热...

  • 3

    一些关于开发的杂谈话题 - 测试  由 王巍 (onevcat) 发布于 2 天前2023-04-06T22:15:00+09:00 最后更新: 1 天前2023-04-07T11:25:10+09:00最近接手了一些陈旧项目的维护工作,需要把一部分质量很烂的代...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK