异形屏兼容框架

异形屏兼容框架


《异形》系列电影从1979年第一集上映至今将近40年,从最初以恐怖电影的名头上映,到现在成为科幻电影历史上的经典... ... 搞错了,接下来不是影评,是知识点!


背景

现在的手机制造者在体积不变的情况下,尽量让屏幕变大,确实在屏幕设计上煞费了苦心,为了增大液晶屏的占比,「异形」出现了!水滴屏、刘海屏等各种「异型屏」的独特界面设计替代了原本规规矩矩的布局,用户开心了,前端同学可头疼了,不仅要保证页面正常展示,还要考虑到用户的视觉体验。这些「异型屏」的出现意味着我们需要花费大量的精力在适配上,或者常常忘记了适配,造成功能遮挡或缺失,影响用户体验。

为了解决这一通用需求,我们决定做一个支持通用吸顶吸底,兼容各种异型屏的框架组件,用了这个组件你就不用为了这些兼容头疼,组件都会帮大家实现。本文就从这里展开 ~

浏览器介绍

目前 html5 规范中并没有异型屏相关 API,因此针对 app、移动浏览器、PC浏览器等终端的处理会有差异。

APP 端内

android、iOS 上的异型屏设备都是最近2年出现并增多的,说明后还有存量的完整屏幕的设备。此外,android、iOS 系统底层对于异型屏顶栏支持度也不一致,通常只有较新的系统才能支持特效较炫酷的能力。所以,单靠 FE 无法解决大量不同设备(主要是 android)和不同系统(iOS 系统版本不一)的兼容性问题。

基于 APP 和 M 页通常都有成熟的通信框架,为了保证兼容性需要 APP 开发人员协助:

  1. 通过在 url 中增加参数向 app 声明要实现顶栏穿透效果;(如果APP默认都穿透,可以忽略);

  2. APP 提供顶栏穿透是否成功的判断方法;

  3. 如果顶栏穿透成功,则 APP 返回顶栏的高度。FE 利用顶栏高度做顶部偏移;

APP 浏览器

依赖各浏览器APP的能力,得每一个浏览器应用挨个适配,无法毕其功于一役。

PC 浏览器

PC 端基本不存在异型屏的场景,暂不考虑。

框架的出现:

在没有异型屏框架出现之前,前端同学在开发页面需要实现一系列相关逻辑:顶部是否支持穿透、实现穿透能力、获取顶栏高度等,而且实现方法各异,不可复用,可维护性不高。现在使用异型屏框架一步就可实现顶部穿透能力, 只需要把你页面的代码包裹在这个框架内,如下代码所示:

import { PageBaseBox } from '@zz-common/zz-ui';
Vue.use(PageBaseBox);
<!-- 默认带有标题任务栏,底部可吸底 -->
<z-page-base-box>
  <div>自定义模块部分1</div>
  <div>自定义模块部分2</div>
  <template v-slot:fixedFooter>
    <div class="footer">底部模块-可编辑样式</div>
  </template>
</z-page-base-box>

除了顶部穿透,还可扩展以下功能:

  • Ta 支持通用吸顶,吸底;兼容水滴屏、刘海屏等各种异型屏。

  • Ta 支持连续累加吸顶(目前支持2级)或连续覆盖吸顶。

  • Ta 可支持serviceWork或异常监控等。

  • Ta 可支持各页面统一添加特定模块或功能(如页面统一导航条)

一段简短的视频演示:

接下来简单来看下源码,提炼出这个框架中几处实现逻辑:

基本功能 - 吸顶&吸底:

吸顶用到了 position:sticky,但是兼容性不是很好,这里做了兼容处理:

  // 是否支持某属性
  cssSupport (attr?: any, value?: any) {
    if (fixedMainDom && fixedMainDom.style && attr in fixedMainDom.style) {
      fixedMainDom.style[attr] = value
      fixedSubDom.style[attr] = value
      return fixedMainDom.style[attr] === value
    } else {
      return false
    }
  }

  initDome () {
    ...
    // 使用判断
    if (this.cssSupport('position', 'sticky')) {
      return
    } else {
      // do SomeThingA
    }
  }
  

其中 do SomeThingA 做了什么?

监听页面滚动事件(为了提高性能,增加了滚动节流),识别元素吸顶时机;计算需要吸顶元素距离顶部的高,来获取top值。

这里使用position:fixed,而将吸顶设置top: 0就可以了。这个时候问题出现了,页面元素与iphoneX的刘海屏中隐藏不掉的时间和信号任务栏,重!叠!了!

img这里是一张顶部重叠的图

吸顶的界面兼容,不同的 「异形」,预留不同的顶部高度,也就是top值。判断如果是在客户端内,可以让客户端同学配合,获取任务栏的高度TaskHeight并提供给前端(这里不做赘述),然后拿到这个值,统一在框架外增加paddingTop,任务栏部分舍弃不用,避免h5内容被覆盖。若在端外,浏览器已经统一处理,不需要添加paddingTop

同理,吸底也是直接使用position:fixed;bottom:0

img这里是一张底部重叠的图

这里需要注意的是,iphoneX的底部操作条覆盖了底部内容,导致按钮失效了,这里还需要做一个兼容。

// 如果是iphoneX,添加特有class
<div :class="['page_base', {'is_iphonex': isIphoneX}]">
    <div class="fixed_footer"></div>
</div>
// this.isIphoneX = navigator.userAgent.toLocaleUpperCase().indexOf('IPHONE') >= 0 && window.screen.height >= 812
// 样式
<style scoped lang="scss">
  $fixedBottomIPhoneX: 50px;
  .page_base.is_iphonex{
    margin-bottom: $fixedBottomIPhoneX;
    .fixed_footer{
      bottom: $fixedBottomIPhoneX
    }
  }
</style>

基本布局 - Slot实现:

作为一个框架,需要控制它包含的吸顶模块,吸底模块,连续吸顶等。开发一个页面,内容布局多种多样,怎么识别模块呢?

为此,在框架中添加了一些特殊身份slot,还支持传入自定义slot。针对特殊身份的solt,做了一些处理,如:吸顶/吸底计算等

<!-- z-page-base-box 默认带有标题任务栏,底部可吸底 -->
<z-page-base-box>
  <template v-slot:fixedHeaderSlot>
    <div class="header">自定义任务栏信息</div>
  </template>
  <div>自定义模块部分1</div>
  <div>自定义模块部分2</div>
  <template v-slot:fixedFooter>
    <div class="footer">底部模块-可编辑样式</div>
  </template>
</z-page-base-box>

连续吸顶,覆盖吸顶 - Dom跟随:

  • 首先先来说一下覆盖吸顶,一层盖住一层,直接外部传参给组件,告诉组件要不要进行覆盖,那么层级的所有top都为任务栏的高度taskHeigth,这个不难理解。(见本文开头,一段简短的视频演示)

  • 接下来连续吸顶:头部吸顶,一级吸顶,二级吸顶 

这里可以看到一级吸顶高度变化了,二级吸顶dom会跟随,这是怎么做到的呢?

这里使用MutationObserver创建一个观察者。

MutationObserver接口提供了监视对DOM树所做更改的能力,译名dom变动观察器

// api定义
var observe = new MutationObserver(function(mutations,observer){
})

MutationObserver有三个方法,分别如下:

  • 1、observe:设置观察目标,接受两个参数,target:观察目标,options:通过对象成员来设置观察选项

  • 2、disconnect:阻止观察者观察任何改变

  • 3、takeRecords:清空记录队列并返回里面的内容

  // 添加观察者
  addAbserve (target) {
    observe = new MutationObserver((mutations,observe) => {
      this.mainHeight = this.getTargetRect(abserveTarget).height
    })
    // childList:设置true,表示观察目标子节点的变化,比如添加或者删除目标子节点,不包括修改子节点以及子节点后代的变化;
    //subtree:设置为true,目标以及目标的后代改变都会观察
    observe.observe(target, {childList: true, subtree: true})
  }
  // 移除观察者
  removeAbserve () {
    observe && observe.disconnect()
  }

功能增强

由于是一个框架,包裹页面内容,因此可以增加一些通用UI, 例如:增加底部导航栏、增加侧边功能栏,增加广告位等 也可以统一加一些通用功能,例如:serviceWork、异常监控等。

这里是小编的一个解题思路,抛砖引玉,如果大家有好的想法欢迎沟通交流!

本月文章预告

接下来我们会陆续发布转转业务团队,针对C端经典问题的一些解决方案,包括滚动、ssr降级等;并会在月底发布团队整理的前端常用网络和浏览器相关知识。


文末福利

转发本文并留下评论,我们将抽取第 10 名留言者(依据公众号后台排序),转转纪念 T 恤一件或转转随机手办一个,可任选其一,大家快转发起来吧~

 或

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值