H5页面遇到的一些坑

前言

先废话几句,感觉自己就像变傻了一样=_=,写代码的质量对自己产生质疑,很想问自己,你真的是加班加傻了吗?而且也变懒了,博客好久都没更新,也尝试着更新一些内容,但是没有很好的素材,这次主要记录这段时间工作中遇到的一些问题。
这段时间的主要任务就是做H5相关的页面,之前对H5没有特别深的理解,比如说移动端的适配、不同手机的兼容性处理、页面的整体布局,标签的语义化、对webpack打包的配置等。

问题一:移动端的适配

首先要理解几个概念,css像素、物理像素、设备独立像素(dpr)、viewport、rem,其中dpr=物理像素/css像素。

viewport

手机浏览器是把页面放在一个虚拟的‘窗口’,通常这个虚拟的‘窗口’比屏幕要宽,如果把每个网页挤到一个很小的窗口中,用户可以通过平移或缩放来看网页的不同部分。但是在后期的优化过程中引入来viewport,让网页开发者来控制viewport的大小和缩放。
我会在<head>标签中写入如下的代码:
<meta name=”viewport” content=”width=device-width, initial-scale=1, maximum-scale=1″>
width:控制viewport的大小,可以指定一个值,如800、600或特殊的值,如device-width为设备的宽度。
initial-scale:初始缩放比例,也就是页面第一次load的时候的缩放比例。
maximum-scale:允许用户缩放到的最大比例。
user-scalable:用户是否可以手动缩放。
把width设为device-width就可把它当成理想中的宽度。

css像素

单位像素,即px,就是用css操作的像素。

物理像素

设备像素,我们用css操作像素,然后使用物理像素来表达,在Retina屏出来以前,css像素===物理像素,也就是1css像素的图像就是通过1物理像素进行表达,但是Retina屏出来之后,比如2倍屏,也就是dpr=2,代表1css像素等于2个物理像素。

rem

rem是一个CSS单位,他是根据根元素来定义字体大小。比如,如果根元素的字体大小为font-size=16px,则表示1rem=16px;
动态的设置根元素:

(function(doc, win) {
  var docEl = doc.documentElement,
    resizeEvt = "orientationchange" in window ? "orientationchange" : "resize",
    recalc = function() {
      var clientWidth = docEl.clientWidth;
      if (!clientWidth) return;
      docEl.style.fontSize = 20 * (clientWidth / 320) + "px";
    };
  if (!doc.addEventListener) return;
  win.addEventListener(resizeEvt, recalc, false);
  doc.addEventListener("DOMContentLoaded", recalc, false);
})(document, window);

问题二:android与ios手机适配

这段时间遇到两次页面在一些系统较低的手机上就会出现页面崩溃的现象,影响最深的是android4.4.4与ios8.7.4的手机。查了相关的资料,发现手机使用的webkit内核的webview,只需在使用的一些css属性前面加上-webkit-前缀,比如:

//定位上下左右居中
@mixin center {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  -webkit-transform: translate(-50%, -50%);
}

问题三:适配iphone X

H5页面在iphone X不会占满全屏,解决方式:在head标签中加入viewport-fit=cover

<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">

问题四:长按图片A把保存图片B

A
B

B
A

如上图,长按图片A分享图片B,他们之间的区别主要是下面部分不同,从两只猫咪那里开始,用户看到的界面与保存图片不一样。当时看到这个需求的时候,感觉很矛盾,但是的确现在H5的活动页也都实现了这样的功能,我就开始查找资料,看似一个简单的功能,我居然花了将近两天的时间,同时也是我粗心。。好了,切入正题
首先,保存为图片我用的方案是:

1.使用html2canvas将html转为canvas;
2。使用第三方库Canvas2Image.js,将canvas转换为image,当然你也可以不用这个库,直接使用基于原生canvas的toDataURL方法将canvas输出为data:URL类型的图片地址。

以上为转化为图片的步骤,现在解决保存的图片与看到的不一样。这次是猫咪下面不一样,但是猫咪是在整个背景图上的,我的做法是,写了两个container,一个是用户看到的A界面,一个是用于保存的B界面,然后让A界面盖在B界面上,但是,这样保存的图片也是保存的A界面,然后,我又开始寻找解决方式,最后发现 pointer-events这个神奇的CSS属性,在A界面的根元素上加上pointer-events: none,这个属性可以让事件忽略某个元素及其字节点,仿佛这个元素不存在一般。添加这个属性后,长按事件就可以透过A直接到达底层的B图片,从而出发保存图片的事件。

问题四:Android与IOS部分手机不能自动播放音频

<audio>在某些ios手机上不能自动播放,设置autoplay属性或者调用play()都不行。最后查了相关资料,原因是ios对此做了限制,必须在用户发生交互行为时才能播放。比较常见的解决办法:是在用户触摸屏幕任何地方就触发播放音频,这样能在最早的时机播放音乐。有些ios时机使用用户触发还是没有播放,然后我就暴力的加了一个点击事件。

//用的是vue
  mounted() {
    window.addEventListener("touchstart", this.playing, false);
    window.addEventListener("click", this.playing, false);
}

  methods: {
    //控制音乐播放
    playPause() {
      window.removeEventListener("touchstart", this.playing, false);
      window.removeEventListener("click", this.playing, false);
      const audio = this.$refs.audio;
      if (audio.paused) {
        audio.play();
        this.isPlay = true;
      } else {
        audio.pause();
        this.isPlay = false;
      }
    },
    //音乐播放
    playing() {
      const audio = this.$refs.audio;
      audio.play();
    },
}

问题五:ios中使用type="file"上传图片出现图片旋转

解决这个问题使用了一个第三方库:exif-js,使用这个库来获取照片方向角属性。相关代码如下:

 //获取照片方向角属性,用户旋转控制
    getRotate(file, callback) {
      let self = this;
      let Orientation = null;
      EXIF.getData(file, function() {
        EXIF.getAllTags(this);
        Orientation = EXIF.getTag(this, "Orientation");
        console.log("Orientation:", Orientation);
        callback.call(self, Orientation);
      });
    }
传入的callback是下面这个函数:
function getResult(res) {
        if (!res) return;
        if (navigator.userAgent.match(/iphone/i)) {
          //如果方向角不为1,都需要进行旋转
          if (res != "" && res != 1) {
            console.log("需要旋转处理");
            switch (res) {
              case 6:
                console.log("需要顺时针(向左)90度旋转");
                this.rotateV = res;
                break;
              case 8:
                console.log("需要逆时针(向右)90度旋转");
                this.rotateV = res;
                break;
              case 3:
                console.log("需要180度旋转");
                this.rotateV = res;
                break;
              case 4:
                console.log("需要180度旋转");
                this.rotateV = res;
            }
          }
        }
      }

问题六:ios中position: fixed在微信浏览器中下拉出现“脱离”的现象

做一个单页的H5,效果如下,看着也挺简单的。
perface

但是微信浏览器下拉的时候会出现"分层",顶部tabBar采用了固定定位。
解决方法:

//让body固定定位
html {
    width: 100%;
}
body {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

//使用了IScroll.js 否则会出现滑动时卡顿
  mounted() {
   //初始化IScroll,
    this.calHeight();
  },
  methods: {
    handleTab(type) {
      if (!type) return;
      this.tab = type;
      this.calHeight();
     //注意:切换tab的时候,对myScroll刷新(等待100ms,是给渲染器进行重绘的时间,你也可 
     //以等待0s,根据HTML的复杂度来给等待时间)
      setTimeout(() => {
        myScroll.refresh();
      }, 100)
    },
    calHeight() {
      var $container = document.querySelector(`.container`);
      var $other = document.querySelector(".tab-bar");
      $container.style.height =
        document.documentElement.clientHeight - $other.clientHeight + "px";
      myScroll = new IScroll(`#container`, {
        mouseWheel: true,
        scrollbars: true
      });
    }
  }

//页面结构
<div id="app">
    <div class="tab-bar"></div>
    <div class="container" id="container">
        <div class="disclaimer-content">
           <!--滑动的内容 -->
        </div>
    </div> 
</div>

//style
.container {
    width: 100%;
    height: 100%;
    color: #333;
    margin-top: 1rem;
}

总结

在这段时间总是犯一些很智障的问题,其实有些时候仔细想一想,就能定位出是哪里出现问题,但在思考的过程中,总是有一些局限性。too young,学无止境,一起加油。嘻嘻。

参考链接

深入探究iOS下fixed定位导致的问题

相关文章

此处评论已关闭