移动端H5开发-常用技巧篇

313 阅读9分钟

引言

多年开发工作都是在 H5 的世界里遨游。总结了 H5 开发经验总结了一些常用技巧,记录下来,防止自己忘记,如有疑问,欢迎大家留言一起讨论

HTML

meta 标签

  • meta 元素可提供有关页面的元信息。下面是一些与移动端 H5 相关比较特殊的 meta 标签
<meta name="screen-orientation" content="portrait" />            // 禁止屏幕旋转
<meta name="full-screen" content="yes" />                        // 全屏显示
<meta name="browsermode" content="application" />                // UC应用模式,页面默认全屏
<meta name="x5-orientation" content="portrait" />                // QQ强制竖屏
<meta name="x5-fullscreen" content="true" />                     // QQ强制全屏
<meta name="x5-page-mode" content="app" />                       // QQ应用模式
<meta name="renderer" content="webkit" />                        // 启用360浏览器的极速模式
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> // 优先使用 IE 最新版本和 Chrome

语义化标签

  • HTML5 语义化标签能够让页面的结构更清晰,有利于 SEO,并且能够帮助辅助技术更好的阅读和转译你的网页。推荐使用语义化标签编写 HTML
<header></header>         // 定义文档的头部区域
<nav></nav>               // 定义导航链接的部分
<main></main>             // 定义文档的主体部分
<section></section>       // 定义文档中的节
<footer></footer>         // 定义页面的页脚
<aside></aside>           // 定义页面的侧边栏内容
<article></article>       // 定义一个文章区域

电话号码拨号与识别

  • 使用 a 标签实现点击手机号码唤起拨号页面
<a href="tel:4008001010" class="phone">400-800-1010</a>

在 iOS Safari 浏览器上会将类似为电话号码的数字识别为电话链接,比如:7 位数字,形如:1234567 带括号及加号的数字,形如:(+86)123456789 双连接线的数字,形如:00-00-00111 11 位数字,形如:13800138000

关闭识别

<meta name="format-detection" content="telephone=no" />

邮箱识别

使用 a 标签实现点击邮箱地址弹出邮件发送的功能


<a href="mailto:434387059@qq.com" class="email">434387059@qq.com</a>

Android手机上会对符合邮箱格式的字符串进行识别,我们可以通过如下的 meta 来关闭邮箱的自动识别


<meta name="format-detection" content="email=no" />

CSS

animation动画

animation: name duration timing-function delay iteration-count direction;
描述
animation-name规定需要绑定到选择器的 keyframe 名称。
animation-duration规定完成动画所花费的时间,以秒或毫秒计。
animation-timing-function规定动画的速度曲线。
animation-delay规定在动画开始之前的延迟。
animation-iteration-count规定动画应该播放的次数。
animation-direction规定是否应该轮流反向播放动画。
animation-fill-mode规定动画在执行时间之外应用的值。
animation-play-state规定动画是正在运行还是暂停。

单行文本、多行文本省略

  • 单行文本省略
white-space:nowrap;(不换行,强制不换行)注:默认值为normal
overflow:hidden;(溢出部分隐藏)
text-overflow:ellipsis;(溢出部分用...代替)
  • 多行文本省略
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;  //使用自适应布局
-webkit-line-clamp: 2;  //设置超出行数,要设置超出几行显示省略号就把这里改成几
-webkit-box-orient: vertical;

1px 边框

移动端 H5 项目越来越多,设计师对于 UI 的要求也越来越高,比如 1px 的边框。在高清屏下,移动端的 1px 会很粗。

那么为什么会产生这个问题呢?主要是跟一个东西有关,DPR(devicePixelRatio) 设备像素比,它是默认缩放为 100%的情况下,设备像素和 CSS 像素的比值。目前主流的屏幕 DPR=2(iPhone 8),或者 3(iPhone 8 Plus)。拿 2 倍屏来说,设备的物理像素要实现 1 像素,而 DPR=2,所以 css 像素只能是 0.5。 常用方案

/* 底边框 */
.b-border {
  position: relative;
}
.b-border:before {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: #d9d9d9;
  -webkit-transform: scaleY(0.5);
  transform: scaleY(0.5);
  -webkit-transform-origin: 0 0;
  transform-origin: 0 0;
}
/* 上边框 */
.t-border {
  position: relative;
}
.t-border:before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 1px;
  background: #d9d9d9;
  -webkit-transform: scaleY(0.5);
  transform: scaleY(0.5);
  -webkit-transform-origin: 0 0;
  transform-origin: 0 0;
}
/* 右边框 */
.r-border {
  position: relative;
}
.r-border:before {
  content: '';
  position: absolute;
  right: 0;
  bottom: 0;
  width: 1px;
  height: 100%;
  background: #d9d9d9;
  -webkit-transform: scaleX(0.5);
  transform: scaleX(0.5);
  -webkit-transform-origin: 0 0;
  transform-origin: 0 0;
}
/* 左边框 */
.l-border {
  position: relative;
}
.l-border:before {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 1px;
  height: 100%;
  background: #d9d9d9;
  -webkit-transform: scaleX(0.5);
  transform: scaleX(0.5);
  -webkit-transform-origin: 0 0;
  transform-origin: 0 0;
}

/* 四条边 */
.setBorderAll {
  position: relative;
  &:after {
    content: ' ';
    position: absolute;
    top: 0;
    left: 0;
    width: 200%;
    height: 200%;
    transform: scale(0.5);
    transform-origin: left top;
    box-sizing: border-box;
    border: 1px solid #e5e5e5;
    border-radius: 4px;
  }
}

css 中的 1px 并不等于移动设备的 1px,是因为不同的手机有不同的像素密度。在 window 对象中有一个 devicePixelRatio 属性,他可以反应 css 中的像素与设备的像素比

devicePixelRatio 的官方的定义为:设备物理像素和设备独立像素的比例

完美实现 1px 的方法如下,兼容 DPR(设备像素比) 1-4 的设备


@line-color: #ccc;

[retina] {
  position: relative;
}

[retina]::before {
  position: absolute;
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  font-size: 20px;
  content: ' ';
  pointer-events: none;
}

/* 设备像素比为 1 */
@media only screen and (-webkit-min-device-pixel-ratio: 1), only screen and (min-device-pixel-ratio: 1) {
  [retina]::before {
    width: 100%;
    height: 100%;
    transform: scale(1);
    transform-origin: 0 0;
  }

  [retina='line-bottom']::before {
    height: 1px;
  }

  [retina='line-top']::before {
    height: 1px;
  }

  [retina='line-left']::before {
    width: 1px;
  }

  [retina='rect-input']::before {
    border-width: 1px;
  }
}

/* 设备像素比为 1.5 */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 1.5) {
  [retina]::before {
    width: 150%;
    height: 150%;
    font-size: 30px;
    transform: scale(0.666667);
    transform-origin: 0 0;
  }

  [retina='line-bottom']::before {
    height: 1px;
  }

  [retina='line-top']::before {
    height: 1px;
  }

  [retina='line-left']::before {
    width: 1px;
  }

  [retina='rect-input']::before {
    border-width: 1px;
  }

  [retina='rect-input']::before {
    border-width: 1px;
  }
}

/* 设备像素比为 2 */
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio: 2) {
  [retina]::before {
    width: 200%;
    height: 200%;
    font-size: 40px;
    transform: scale(0.5);
    transform-origin: 0 0;
  }

  [retina='line-bottom']::before {
    height: 1px;
  }

  [retina='line-top']::before {
    height: 1px;
  }

  [retina='line-left']::before {
    width: 1px;
  }

  [retina='rect-input']::before {
    border-width: 1px;
  }
}

/* 设备像素比为 3 */
@media only screen and (-webkit-min-device-pixel-ratio: 3), only screen and (min-device-pixel-ratio: 3) {
  [retina]::before {
    width: 300%;
    height: 300%;
    font-size: 60px;
    transform: scale(0.333333);
    transform-origin: 0 0;
  }

  [retina='line-bottom']::before {
    height: 2px;
  }

  [retina='line-top']::before {
    height: 2px;
  }

  [retina='line-left']::before {
    width: 2px;
  }

  [retina='rect-input']::before {
    border-width: 2px;
  }
}

/* 设备像素比为 4 */
@media only screen and (-webkit-min-device-pixel-ratio: 4), only screen and (min-device-pixel-ratio: 4) {
  [retina]::before {
    width: 400%;
    height: 400%;
    font-size: 80px;
    transform: scale(0.25);
    transform-origin: 0 0;
  }

  [retina='line-bottom']::before {
    height: 2px;
  }

  [retina='line-top']::before {
    height: 2px;
  }

  [retina='line-left']::before {
    width: 2px;
  }

  [retina='rect-input']::before {
    border-width: 2px;
  }
}

[retina='line-bottom']::before {
  bottom: 0;
  left: 0;
  background-color: @line-color;
  transform-origin: 0 100%;
}

[retina='line-top']::before {
  top: 0;
  left: 0;
  background-color: @line-color;
}

[retina='line-left']::before {
  top: 0;
  left: 0;
  background-color: @line-color;
}

[retina='rect-input']::before {
  top: 0;
  left: 0;
  box-sizing: border-box;
  border-color: @input-border-color;
  border-style: solid;
  border-radius: 1em;
}


屏蔽用户选择

禁止用户选择页面中的文本

.container {
  user-select: none;
}

清除输入框内阴影

在 safari 浏览器中,输入框默认有内部阴影,可以这样关闭:

input { -webkit-appearance: none; }

禁止保存或拷贝图像

img {
  -webkit-touch-callout: none;
}

iOS 滑动不流畅

ios 手机上下滑动页面会产生卡顿,手指离开页面,页面立即停止运动。整体表现就是滑动不流畅,没有滑动惯性。 iOS 5.0 以及之后的版本,滑动有定义有两个值 auto 和 touch,默认值为 auto

在滚动容器上增加滚动 touch 方法

body{
-webkit-overflow-scrolling: touch;
}

用户设置字号放大或者缩小导致页面布局错误

设置字体禁止缩放

body {
  -webkit-text-size-adjust: 100% !important;
  text-size-adjust: 100% !important;
  -moz-text-size-adjust: 100% !important;
}

android系统中元素被点击时产生边框

部分android系统点击一个链接,会出现一个边框或者半透明灰色遮罩, 不同生产商定义出来额效果不一样。去除代码如下

a,button,input,textarea{
  -webkit-tap-highlight-color: rgba(0,0,0,0)
  -webkit-user-modify:read-write-plaintext-only; 
}

JS

移动端click屏幕产生200-300 ms的延迟响应

移动设备上的web网页是有300ms延迟的,往往会造成按钮点击延迟甚至是点击失效。解决方案:

  • fastclick可以解决在手机上点击事件的300ms延迟
  • zepto的touch模块,tap事件也是为了解决在click的延迟问题

触摸事件的响应顺序

  1. ontouchstart
  2. ontouchmove
  3. ontouchend
  4. onclick
var attachFastClick = require('fastclick');
attachFastClick(document.body);

safari 浏览器日期转换出现 NaN 的问题

将日期字符串的格式符号替换成'/'

'yyyy-MM-dd'.replace(/-/g, '/')

audio 和 video 在 ios 和 andriod 中自动播放

这个不是bug,由于自动播放网页中的音频或视频,会给用户带来一些困扰或者不必要的流量消耗,所以苹果系统和安卓系统通常都会禁止自动播放和使用 JS 的触发播放,必须由用户来触发才可以播放。加入自动触发播放的代码

$('html').one('touchstart', function() {
  audio.play()
})

视频自动播放

由于安卓和微信版本不同 自动全屏,不能全屏,不能自动播放,Android,IOS,巴拉巴拉……多到令人发指

播放自动视频的两个前提条件

  • 设置自动播放 autoplay
  • 设置静音 muted

如果视频是静音播放 并且视频小 就把视频导出每张jpg 然后序列帧播放 本文序列化图片视频方案参考链接:www.zhangxinxu.com/wordpress/2…

##### CSS代码:

.container { width: 256px; height: 464px; margin: auto; background-color: #000; position: relative; } .container > img { position: absolute; width: 100%; height: 100%; } .loading { position: absolute; height: 8px; width: 150px; border: 1px solid #eee; background: linear-gradient(to top, #eee, #eee); background-size: 0 100%; transition: background-size .1s; left: 0; top: 0; right: 0; bottom: 0; margin: auto; } .loading::before { content: attr(data-percent)'%'; position: absolute; left: 0; top: -1.5em; font-size: 12px; color: #eee; }


##### HTML代码:

```
JS代码:
var urlRoot = './thumbs/';
var indexRange = [1, 47];
var maxLength = indexRange[1] - indexRange[0] + 1;
// loading
var eleContainer = document.getElementById('container');
var eleLoading = document.getElementById('loading');
// 存储预加载的DOM对象和长度信息
var store = {
    length: 0
};
// 图片序列预加载
for ( var start = indexRange[0]; start <= indexRange[1]; start++) {
    (function (index) {
        var img = new Image();
        img.onload = function () {
            store.length++;
            // 存储预加载的图片对象
            store[index] = this;
            play();
        };
        img.onerror = function () {
            store.length++;
            play();
        };
        img.src = urlRoot + index + '.jpg';
    })(start);
}

var play = function () {
    // loading进度
    var percent = Math.round(100 * store.length / maxLength);
    eleLoading.setAttribute('data-percent', percent);
    eleLoading.style.backgroundSize = percent + '% 100%';
    // 全部加载完毕,无论成功还是失败
    if (percent == 100) {
        var index = indexRange[0];
        eleContainer.innerHTML = '';
        // 依次append图片对象
        var step = function () {
            if (store[index - 1]) {
                eleContainer.removeChild(store[index - 1]);
            }
            eleContainer.appendChild(store[index]);
            // 序列增加
            index++;
            // 如果超过最大限制
            if (index <= indexRange[1]) {
                setTimeout(step, 42);
            } else {
                // 本段播放结束回调
                // 我这里就放一个重新播放的按钮
                eleContainer.insertAdjacentHTML('beforeEnd', '<button onclick="play()">再看一遍英姿</button>');
            }
        };
        // 等100%动画结束后执行播放
        setTimeout(step, 100);
    }
};

<video // 设置后,音频会初始化为静音,注意浏览器只有设置静音,才能自动播放 muted // 视频会马上自动开始播放,不会停下来等着数据载入结束。 autoplay="autoplay" // 布尔属性;指定后,会在视频结尾的地方,自动返回视频开始的地方 loop="loop" // 一个布尔属性,标志视频将被“inline”播放,即在元素的播放区域内。 x5-playsinline="true" playsinline="true" webkit-playsinline="true" // 一个布尔属性,用于禁用使用有线连接的设备(HDMI、DVI等)的远程播放功能。 x-webkit-airplay="allow" // 这个视频优先加载 preload="auto" // 启用同层H5播放器,就是在视频全屏的时候,div可以呈现在视频层上,也是WeChat安卓版特有的属性。同层播放别名也叫做沉浸式播放 x5-video-player-type="h5" // :全屏设置。它又两个属性值,ture和false,true支持全屏播放 x5-video-player-fullscreen="true"

// 标签为媒介元素(比如 和 )定义媒介资源。

以上代码pc端能自动播放,如果需要自动播放视频 需要添加如下代码

function doPlay(){ WeixinJSBridge.invoke('getNetworkType', {}, function (e) { var video1=video1 = ("#video1") var video2=video2 = ("#video2") video1[0].play()video1[0].play() video2[0].play() }) }

if (window.WeixinJSBridge) { doPlay() } else { document.addEventListener("WeixinJSBridgeReady", function(){ doPlay() }, false); }

需要注意的是,监听WeixinJSBridgeReady事件后,回调函数里需要调用一下invoke,在invoke中操作视频才可以生效。另外,页面不需要引入jweixin-1.0.0.js,微信浏览器会自带api。但是如此 有的安卓机还是不能自动播放 需要使用[JSMpeg](https://github.com/phoboslab/jsmpeg),记得mp4格式要转换成ts格式

1.  区分开iOS和安卓,iOS用原生video标签,安卓用JSMpeg,绘制画面到canvas上。
1.  iOS用mp4或者其他原生video标签支持的视频格式,安卓用ts格式。(其中ts格式需要用ffmpeg来转一下,下文会提及)
1.  监听WeixinJSBridgeReady事件,调用视频播放方法,实现自动播放。

var isAndroid = window.navigator.userAgent.match(/android/ig) if (isAndroid) { // 安卓 var src = "static.shikehuyu.com/vincent/wx-…" player = new JSMpeg.Player(src, { canvas: canvas, autoplay: true, progressive: false, loop: true, onVideoDecode: function() { canvas.style.display = 'block' canvas.style.height = 80 / (canvas.width / canvas.height) + "vw" } }) }else{ // ios 自动播放 }


以上视频自动播放总结:iOSvideoAndroidJSMpeg,然后依靠监听WeixinJSBridgeReady事件,实现微信H5视频行内自动播放,

  


  


## H5常用的插件

### dom生成图片

**[dom-to-image](https://github.com/tsayen/dom-to-image)**

**[html2canvas](http://html2canvas.hertzen.com/)**

常规案例: 生成海报、长按保存图

如果生成图片是另一种的话 用img标签 z-index层级设置最上面 opacity设置0 H5用户可长按页面调起actionSheet识别或保存图片
如果图片是网络图片的话 需要转成base64

// 确保引入html2canvas 下面代码是jquery function imageUrlToBase64(url) { return fetch(url) .then(response => response.blob()) .then(blob => { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result); reader.onerror = reject; reader.readAsDataURL(blob); }); }); } const imageUrl = '线上网址图片' imageUrlToBase64(imageUrl).then(base64 => { // console.log(base64); // 在此处可以使用转换后的 Base64 数据 newdetail_image=base64 newhtml+= '

'+ '
'+ '
'+data.data.name+'
' $('.posterbg-itemcontent').html(newhtml)

setTimeout(()=>{
    html2canvas(document.getElementById("poster-content"), {
        scale: 1,
        width: 750,
        height: 1413,
        useCORS: true,
        allowTaint: true,
        backgroundColor: null,
        logging: false
    }).then(function (canvas1) {
        // img.setAttribute("crossOrigin",'Anonymous')
        // console.log(canvas1,'canvas1')
        var dataURL = canvas1.toDataURL("image/jpeg", 1)
        // console.log(dataURL,'dataURL')
        $("#userpic").attr("src",dataURL);

    });
},1000)
})
.catch(error => {
console.error('转换出错:', error);

});



### 视差引擎
- **[Parallax.js](https://github.com/wagerfield/parallax)**是一个**简单的,轻量级的**视差引擎。你可以将它作为作为`jQuery``Zepto`插件来使用,也可以以**纯JS的方式**来使用。最-最-最厉害的是它可以对智能设备的**方向作出反应**,即使在没有陀螺仪或运动检测硬件可用的时候,也可使用光标的位置来代替。


- Vue.js组件用于视差图像滚动效果
**[vue-parallax](https://github.com/apertureless/vue-parallax)**

### 移动端全屏播放视频[JSMpeg](<https://github.com/phoboslab/jsmpeg>)
移动端全屏播放视频主要规避了原生video标签存在的如下兼容问题:1.原生UI不一致2.国产浏览器对播放器劫持(点名:QQ浏览器、百度浏览器、UC浏览器......)3.内联播放且视频层级无法覆盖
- 一个用 JavaScript 编写的视频播放器
- 由 MPEG-TS 解复用器、MPEG1 视频和 MP2 音频解码器、WebGL 和 Canvas2D 渲染器和 WebAudio 声音输出组成
- 可以通过 Ajax 加载静态视频,并允许通过 WebSockets 进行低延迟流式传输(约 50 毫秒)
- 可以在 iPhone 5S 上以 30fps 的速度解码 720p 视频
- 可以在任何现代浏览器(Chrome、Firefox、Safari、Edge)中使用,并且压缩后仅 20kb

### [canvas-confetti](https://www.kirilv.com/canvas-confetti/) 是一个使用 canvas 的五彩纸屑特效 JS 插件