移动端沉浸式探测

2018-12-18  本文已影响16人  yibuyisheng

背景

有时候我们的 H5 应用既要能运行在各种容器内,也要能运行在浏览器中,并且在容器中尽量采用沉浸式方式呈现。

在容器中,是需要根据不同容器来设置不同的状态栏背景色的,不然就很可能看不见系统展示在状态栏上的文字了。而在浏览器中,不采用沉浸式方式呈现,因此是不需要理会的。

方案

可以借助 window.innerHeight 和 window.screen.height 来判断,关于这俩的含义,可以在 MDN 上查到。

实际上,在移动端,H5 页面中,window.screen.height 拿到的是逻辑像素值,window.innerHeight 拿到的是物理像素值或者逻辑像素值。并且,在页面初始化过程中,window.innerHeight 有可能会发生变化(最后稳定的值才是正确的)。

为了应对上述情况,必须要在初始化的时候不停地检查,直到最终拿到稳定结果。

《First, Understand Your Screen》

代码

async function isImmersion() {
  const check = () => {
    // windowHeight 是期望存储视口的逻辑像素值
    let windowHeight = window.innerHeight / window.devicePixelRatio;
    if (
      // 如果 window.screen.height 比 window.innerHeight 大,
      // 说明 window.innerHeight 肯定是逻辑像素值。
      window.screen.height - window.innerHeight > 0
      && window.screen.height - window.innerHeight < 130
    ) {
      windowHeight = window.innerHeight;
    }

    // iPhone X 飞猪下面 window.screen.height 和 windowHeight 差一丢丢(其余场景都可以用相等来判断)。
    return window.screen.height - windowHeight < 1;
  };

  if (document.readyState !== 'complete') {
    await new Promise((resolve) => {
      document.addEventListener('DOMContentLoaded', resolve);
    });
  }

  return new Promise((resolve, reject) => {
    const checkResults = [];
    setTimeout(() => {
      checkResults.push(check());
      const length = checkResults.length;
      if (
        length >= 3
        && checkResults[length - 1] === checkResults[length - 2]
        && checkResults[length - 2] === checkResults[length - 3]
      ) {
        resolve(checkResults[length - 1]);
      }
    }, 100);

    setTimeout(() => {
      reject(new Error('Check immersion timeout.'));
    }, 1000);
  });
}

上一篇 下一篇

猜你喜欢

热点阅读