Como ingeniero de front-end que ha desarrollado múltiples proyectos H5, es inevitable encontrar algunos problemas de compatibilidad, como trepar por el foso durante el proceso de desarrollo . Ahora resumiré estos problemas uno por uno y daré el principio de la generación de pozos y el esquema convencional de llenado de pozos en esta etapa . Aquí hay un resumen paso a paso.
Operación regular, ¡ por favor, dale me gusta y mira de nuevo! ¡Tus likes son una de las motivaciones de mi creación!
pregunta
A continuación se presentan algunos problemas comunes que encontré. Si encuentra otros problemas, agréguelos en el área de comentarios y los agregaré después de la práctica. ¡Gracias! (actualice este artículo con frecuencia)
Resumen de problemas relacionados con el móvil H5:
-
problema de 1px -
Disposición Responsive -
Deslizar iOS no es fluido -
El menú desplegable del borde desplegable de iOS aparece en blanco en blanco -
El widget de página acerca o aleja el comportamiento indeterminado -
clic Penetración y retraso de clics -
El teclado en pantalla aparece y empuja la página hacia arriba, pero no hacia abajo. -
Problema de adaptación de la barra inferior del iPhone X -
Guardar páginas como imágenes y problemas y soluciones de códigos QR -
Problema para compartir la cuenta pública H5 de WeChat -
H5 llama a problemas y soluciones relacionados con SDK -
Esquemas y estrategias relacionados con la depuración H5
Descripción general de las tecnologías básicas relacionadas con el móvil H5

Principios y práctica
Los dos artículos anteriores han discutido el problema de 1px y el problema de diseño receptivo en detalle, y han dado los principios y soluciones.
Para evitar la pérdida, salte al canal de acceso directo después de Me gusta y favorito : **1px** [1] canal y diseño receptivo [2] canal
A continuación, veamos los principios y soluciones de otros problemas.
Todas las siguientes soluciones han sido probadas con éxito por mí y son saludables y seguras. Por favor, bájalas y cómelas. Debido a razones de espacio, los detalles de implementación de algunas soluciones secundarias aún no se han discutido y debe estudiarlos usted mismo.
Deslizar iOS no es fluido
Actuación
Deslizar la página hacia arriba y hacia abajo provocará un congelamiento, el dedo dejará la página y la página dejará de moverse inmediatamente. El rendimiento general es que el deslizamiento no es suave y no hay inercia deslizante.
causa
¿Por qué el deslizamiento no es fluido en la vista web de iOS y cómo se define?
Eventualmente encontré la respuesta en la safari
documentación (la documentación está vinculada en la sección de Recursos).

Resulta que en iOS 5.0 y versiones posteriores, hay dos valores definidos para deslizar auto
y touch
el valor predeterminado es auto
.
-webkit-overflow-scrolling: touch; /* 当手指从触摸屏上移开,会保持一段时间的滚动 */
-webkit-overflow-scrolling: auto; /* 当手指从触摸屏上移开,滚动会立即停止 */
复制代码
solución
1. Agregue un método táctil de desplazamiento al contenedor de desplazamiento
Establezca el -webkit-overflow-scrolling
valor entouch
.wrapper {
-webkit-overflow-scrolling: touch;
}
复制代码
Configure la barra de desplazamiento para ocultar:
.container ::-webkit-scrollbar {display: none;}
Puede hacer que position:fixed;
los elementos con posicionamiento fijo se desplacen con la página
2. Establecer desbordamiento
Establecer externo overflow
a hidden
, establecer elemento de contenido overflow
a auto
. Si el elemento interior excede el cuerpo, se produce un desplazamiento y la parte más allá del cuerpo queda oculta.
body {
overflow-y: hidden;
}
.wrapper {
overflow-y: auto;
}
复制代码
¡Una combinación de los dos es aún mejor!
El menú desplegable del borde desplegable de iOS aparece en blanco en blanco
Actuación
Mantenga presionado el dedo en la pantalla para tirar hacia abajo y aparecerá un área blanca en la parte superior de la pantalla. Mantenga presionado el dedo en la pantalla y tire hacia arriba, habrá un área blanca adicional en la parte inferior.
causa
En iOS, arrastre el dedo hacia arriba y hacia abajo en la pantalla para activar un touchmove
evento . El objeto desencadenado por este evento es el webview
contenedor , el contenedor se arrastrará naturalmente y el resto estará en blanco.
solución
1. Supervise los eventos para prohibir el deslizamiento
Hay tres eventos táctiles móviles, que se definen como
1. touchstart :手指放在一个DOM元素上。
2. touchmove :手指拖曳一个DOM元素。
3. touchend :手指从一个DOM元素上移开。
复制代码
Obviamente, lo que necesitamos controlar es el touchmove
evento , así que encontré este pasaje en la documentación del W3C
Tenga en cuenta que la velocidad a la que el agente de usuario envía eventos touchmove está definida por la implementación y puede depender de las capacidades del hardware y otros detalles de la implementación.
Si se llama al método preventDefault en el primer evento touchmove de un punto de contacto activo, debería evitar cualquier acción predeterminada causada por cualquier evento touchmove asociado con el mismo punto de contacto activo, como el desplazamiento.
touchmove
La velocidad de los eventos está definida por la implementación y depende de las capacidades del hardware y otros detalles de la implementación.
preventDefault
método que evita todos los comportamientos predeterminados, como el desplazamiento, en el mismo punto de contacto.
A partir de esto, encontramos una solución, a través del monitoreo touchmove
, deje que los lugares que deben deslizarse se deslicen, y los lugares que no necesitan deslizarse tienen prohibido deslizarse.
Vale la pena señalar que queremos filtrar los elementos que tienen contenedores de desplazamiento.
La implementación es la siguiente:
document.body.addEventListener('touchmove', function(e) {
if(e._isScroller) return;
// 阻止默认事件
e.preventDefault();
}, {
passive: false
});
复制代码
2. Los compromisos de desplazamiento completan los espacios en blanco y decoran con otras características
En muchos casos, no podemos resolver este problema y cambiar nuestra forma de pensar. Dependiendo del escenario, podemos usar el menú desplegable como una operación funcional .
Por ejemplo: Actualizar la página después de bajar

Acercar o alejar la página comportamiento indeterminado
Actuación
Toque dos veces o pellizque un elemento de la página y la página se acercará o alejará.
causa
El propio HTML generará un comportamiento de acercamiento o alejamiento. Por ejemplo, en los navegadores de PC, puede controlar libremente el acercamiento o el alejamiento de la página. Pero en dispositivos móviles, no necesitamos este comportamiento. Por lo tanto, debemos prohibir este comportamiento incierto para mejorar la experiencia del usuario.
Principios y Soluciones
meta
Hay un viewport
atributo estándar de etiquetas meta HTML , que se usa para controlar el zoom de la página y generalmente se usa en terminales móviles. Como se muestra en la siguiente figura MDN

Escritura convencional terminal móvil
<meta name="viewport" content="width=device-width, initial-scale=1.0">
复制代码
Entonces podemos configurar maximum-scale
y usar paraminimum-scale
evitar este problema.user-scalable=no
<meta name=viewport
content="width=device-width, initial-scale=1.0, minimum-scale=1.0 maximum-scale=1.0, user-scalable=no">
复制代码
clic clic retardo y penetración de eventos
Actuación
Escuche los click
eventos y haga clic en el elemento para activar un retraso de aprox 300ms
.
Haga clic en la capa de máscara, después de que desaparezca la capa de máscara, el elemento subyacente hace clic para activar.
causa
¿Por qué hay un retraso de clic?
En safari en iOS, para realizar la operación de zoom con doble clic, después de 300 ms de clic, si no se realiza el segundo clic, se realiza la operación de click
clic . Es decir, determinar si el comportamiento del usuario se debe a un doble clic. click
Sin embargo, en la aplicación, hay un retraso de 300 ms en un solo clic , ya sea que se requiera o no el comportamiento de doble toque para hacer zoom .
¿Por qué clic clic a través?
Cuando se superponen elementos de dos capas, los eventos se vinculan al elemento superior y los touch
eventos al elemento inferior se vinculan click
. Dado que click
ocurre touch
después de , haga clic en el elemento superior, el elemento desaparece y el elemento inferior activará el click
evento , que produce el efecto de penetración del clic.
Principios y Soluciones
Solución 1: Reemplazar click con touchstart
Como se mencionó anteriormente, los dispositivos móviles admiten no solo clics, sino también varios eventos táctiles. Así que nuestra idea básica ahora es reemplazar eventos touch
con click
eventos.
click
Reemplazar con touchstart
no solo resuelve el problema de retrasar los click
eventos , sino que también resuelve el problema de la penetración. Porque el problema de penetración ocurre cuando touch
y click
mezclan.
usar en nativo
el.addEventListener("touchstart", () => { console.log("ok"); }, false);
复制代码
usar en vista
<button @touchstart="handleTouchstart()">点击</button>
复制代码
En las soluciones de código abierto, se proporcionan click
eventos y eventos touchstart
. como button
componentes

Entonces, ¿es posible reemplazar todos los click
eventos con touchstart
? ¿Por qué los marcos de código abierto todavía dan click
eventos ?
Imaginemos una situación que requiere hacer clic y deslizar al mismo tiempo. ¿Qué pasa si click
reemplazas con touchstart
?
Secuencia de activación de eventos:
touchstart
,touchmove
,touchend
,click
.
¿Es fácil imaginar que cuando necesito touchmove
deslizar, el evento de clic que se activa primero touchstart
tiene un conflicto?
Por lo tanto, en el caso de hacer scroll, se recomienda utilizar el click
procesamiento .
fastclick
El siguiente procesamiento también se realiza en la siguiente biblioteca de código abierto. Parte del código fuente fue interceptado para touchstart
y touchend
.
// If the target element is a child of a scrollable layer (using -webkit-overflow-scrolling: touch) and:
// 1) the user does a fling scroll on the scrollable layer
// 2) the user stops the fling scroll with another tap
// then the event.target of the last 'touchend' event will be the element that was under the user's finger
// when the fling scroll was started, causing FastClick to send a click event to that layer - unless a check
// is made to ensure that a parent layer was not scrolled before sending a synthetic click (issue #42).
this.updateScrollParent(targetElement);
复制代码
// Don't send a synthetic click event if the target element is contained within a parent layer that was scrolled
// and this tap is being used to stop the scrolling (usually initiated by a fling - issue #42).
scrollParent = targetElement.fastClickScrollParent;
if (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) {
return true;
}
复制代码
El propósito principal es asegurarse de que no esté debajo del elemento principal de desplazamiento cuando se usa el evento touchstart
sintético .click
Solución 2: use la biblioteca FastClick
usar después de npm/yarn
la instalación
import FastClick from 'fastclick';
FastClick.attach(document.body, options);
复制代码
Del mismo modo, fastclick
después de usar la biblioteca, los click
problemas de retraso y penetración desaparecen .
Según mi práctica, siempre que se trate de una biblioteca de código abierto, debemos comprender el principio de su implementación. Principalmente encapsula la colección de eventos nativa existente en una colección de eventos más compatible.
El código fuente de fastclick [3] El código central no es largo, menos de 1000 líneas. ¡Interesado en averiguarlo!
El teclado en pantalla empuja la página hacia arriba, pero no hacia abajo.
Actuación
En un teléfono Android, cuando se hace clic en el input
cuadro , aparece el teclado y la página se empuja hacia arriba, lo que da como resultado un estilo de página desordenado.
Cuando se quita el foco, el teclado se retrae, el área del teclado está en blanco y no retrocede.
causa
Tendremos un fondo fijo en el diseño de la aplicación. En algunas versiones de Android, la ventana emergente de entrada se descomprimirá absolute
y fixed
los elementos. Hace que el área visible se reduzca y el diseño se desordene.
Principios y Soluciones
La solución para que el teclado en pantalla empuje la página hacia arriba es principalmente monitorear el cambio de altura de la página y restaurarla a la fuerza a la altura antes de la ventana emergente.
// 记录原有的视口高度
const originalHeight = document.body.clientHeight || document.documentElement.clientHeight;
window.onresize = function(){
var resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
if(resizeHeight < originalHeight ){
// 恢复内容区域高度
// const container = document.getElementById("container")
// 例如 container.style.height = originalHeight;
}
}
复制代码
El problema de que el teclado no puede retroceder ocurre en iOS 12+ y wechat 6.7.4+, y es un error relativamente común en el desarrollo de WeChat H5.
Principio de compatibilidad, 1. Determinar el tipo de versión 2. Cambiar el área visible de desplazamiento
const isWechat = window.navigator.userAgent.match(/MicroMessenger\/([\d\.]+)/i);
if (!isWechat) return;
const wechatVersion = wechatInfo[1];
const version = (navigator.appVersion).match(/OS (\d+)_(\d+)_?(\d+)?/);
// 如果设备类型为iOS 12+ 和wechat 6.7.4+,恢复成原来的视口
if (+wechatVersion.replace(/\./g, '') >= 674 && +version[1] >= 12) {
window.scrollTo(0, Math.max(document.body.clientHeight, document.documentElement.clientHeight));
}
复制代码
window.scrollTo(x-coord, y-coord)
, quewindow.scrollTo(0, clientHeight)
vuelve a la ventana gráfica original
Problema de adaptación del área segura de la serie iPhone X
Actuación
En los costados o en la parte inferior de los flequillos en la cabeza, hay flequillos que bloquean el texto, o un área en blanco sobre un fondo negro o blanco.
causa
El iPhone X y la serie anterior utilizan el diseño de Liu Haiping y los gestos de pantalla completa . La cabeza, la base y los costados necesitan un tratamiento especial. Para adaptarse a la situación especial del iPhone X.
solución
Establezca un área segura, rellene el área peligrosa y no realice operaciones ni muestre contenido en el área peligrosa.
El área peligrosa se refiere al área irregular de la cabeza, el área de la barra horizontal en la parte inferior y las áreas de activación izquierda y derecha.

La operación específica es: viewport-fit
meta
establecer la etiqueta en cover
, obtener todos los rellenos de área. Determine si el dispositivo pertenece al iPhone X y agregue una capa de adaptación en la parte inferior de la cabeza
viewport-fit
Hay 3 valores:
auto
: este valor no afecta el puerto de visualización del diseño inicial y se puede ver toda la página web.contain
: La ventana gráfica se escala para ajustarse al rectángulo más grande que se muestra en línea.cover
: La ventana gráfica se escala para llenar la pantalla del dispositivo. Se recomienda encarecidamente el uso desafe area inset
variables para garantizar que el contenido importante no aparezca fuera de la pantalla.
Establezca el ajuste de la ventana gráfica encover
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes, viewport-fit=cover">
复制代码
Agregar una capa de adaptación
使用 safe area inset
变量
/* 适配 iPhone X 顶部填充*/
@supports (top: env(safe-area-inset-top)){
body,
.header{
padding-top: constant(safe-area-inset-top, 40px);
padding-top: env(safe-area-inset-top, 40px);
padding-top: var(safe-area-inset-top, 40px);
}
}
/* 判断iPhoneX 将 footer 的 padding-bottom 填充到最底部 */
@supports (bottom: env(safe-area-inset-bottom)){
body,
.footer{
padding-bottom: constant(safe-area-inset-bottom, 20px);
padding-bottom: env(safe-area-inset-bottom, 20px);
padding-top: var(safe-area-inset-bottom, 20px);
}
}
复制代码
safe-area-inset-top
,safe-area-inset-right
,safe-area-inset-bottom
,safe-area-inset-left
safe-area-inset-*
由四个定义了视口边缘内矩形的top
,right
,bottom
和left
的环境变量组成,这样可以安全地放入内容,而不会有被非矩形的显示切断的风险。对于矩形视口,例如普通的笔记本电脑显示器,其值等于零。 对于非矩形显示器(如圆形表盘,iPhoneX
屏幕),在用户代理设置的四个值形成的矩形内,所有内容均可见。
其中 env()
用法为 env( <custom-ident> , <declaration-value>? )
,第一个参数为自定义的区域,第二个为备用值。
其中 var()
用法为 var( <custom-property-name> , <declaration-value>? )
,作用是在 env()
不生效的情况下,给出一个备用值。
constant()
被 css
2017-2018 年为草稿阶段,是否已被标准化未知。而其他iOS 浏览器版本中是否有此函数未知,作为兼容处理而添加进去。
详情请查看文章末尾的参考资料。
兼容性

页面生成为图片和二维码问题
表现
在工作中有需要将页面生成图片或者二维码的需求。可能我们第一想到的,交给后端来生成更简单。但是这样我们需要把页面代码全部传给后端,网络性能消耗太大。
解决方案
生成二维码
使用 QRCode 生成二维码
import QRCode from 'qrcode';
// 使用 async 生成图片
const options = {};
const url = window.location.href;
async url => {
try {
console.log(await QRCode.toDataURL(url, options))
} catch (err) {
console.error(err);
}
}
复制代码
将 await QRCode.toDataURL(url, options)
赋值给 图片 url
即可
生成图片
主要是使用 htmlToCanvas
生成 canvas
画布
import html2canvas from 'html2canvas';
html2canvas(document.body).then(function(canvas) {
document.body.appendChild(canvas);
});
复制代码
但是不单单在此处就完了,由于是 canvas
的原因。移动端生成出来的图片比较模糊。
我们使用一个新的 canvas
方法多倍生成,放入一倍容器里面,达到更加清晰的效果,通过超链接下载图片 下载文件简单实现,更完整的实现方式之后更新
const scaleSize = 2;
const newCanvas = document.createElement("canvas");
const target = document.querySelector('div');
const width = parseInt(window.getComputedStyle(target).width);
const height = parseInt(window.getComputedStyle(target).height);
newCanvas.width = width * scaleSize;
newCanvas.height = widthh * scaleSize;
newCanvas.style.width = width + "px";
newCanvas.style.height =width + "px";
const context = newCanvas.getContext("2d");
context.scale(scaleSize, scaleSize);
html2canvas(document.querySelector('.demo'), { canvas: newCanvas }).then(function(canvas) {
// 简单的通过超链接设置下载功能
document.querySelector(".btn").setAttribute('href', canvas.toDataURL());
}
复制代码
根据需要设置
scaleSize
大小
微信公众号分享问题
表现
在微信公众号 H5 开发中,页面内部点击分享按钮调用 SDK,方法不生效。
解决方案
解决方法:添加一层蒙层,做分享引导。
因为页面内部点击分享按钮无法直接调用,而分享功能需要点击右上角更多来操作。
然后用户可能不知道通过右上角小标里面的功能分享。又想引导用户分享,这时应该怎么做呢?
技术无法实现的,从产品出发。

如果技术上实现复杂,或者直接不能实现。不要强行钻牛角尖哦,学会怼产品,也是程序员必备的能力之一。
H5 调用 SDK 相关解决方案
产生原因
在 Hybrid App 中使用 H5 是最常见的不过了,刚接触的,肯定会很生疏模糊。不知道 H5 和 Hybrid 是怎么交互的。怎样同时支持 iOS 和 Android 呢?现在来谈谈 Hybrid 技术要点,原生与 H5 的通信。
解决方案

使用 DSBridge
同时支持 iOS 与 Android
文档见参考资料
SDK小组 提供方法
-
注册方法 `bridge.register`
bridge.register('enterApp', function() {
broadcast.emit('ENTER_APP')
})
复制代码
-
回调方法 `bridge.call`
export const getSDKVersion = () => bridge.call('BLT.getSDKVersion')
复制代码
事件监听与触发法
const broadcast = {
on: function(name, fn, pluralable) {
this._on(name, fn, pluralable, false)
},
once: function(name, fn, pluralable) {
this._on(name, fn, pluralable, true)
},
_on: function(name, fn, pluralable, once) {
let eventData = broadcast.data
let fnObj = { fn: fn, once: once }
if (pluralable && Object.prototype.hasOwnProperty.call(eventData, 'name')) {
eventData[name].push(fnObj)
} else {
eventData[name] = [fnObj]
}
return this
},
emit: function(name, data, thisArg) {
let fn, fnList, i, len
thisArg = thisArg || null
fnList = broadcast.data[name] || []
for (i = 0, len = fnList.length; i < len; i++) {
fn = fnList[i].fn
fn.apply(thisArg, [data, name])
if (fnList[i].once) {
fnList.splice(i, 1)
i--
len--
}
}
return this
},
data: {}
}
export default broadcast
复制代码
踩坑注意
方法调用前,一定要判断 SDK 是否提供该方法 如果 Android 提供该方法,iOS 上调用就会出现一个方法调用失败等弹窗。 怎么解决呢?
提供一个判断是否 Android、iOS。根据设备进行判断
export const hasNativeMethod = (name) =>
return bridge.hasNativeMethod('BYJ.' + name)
}
export const getSDKVersion = function() {
if (hasNativeMethod('getSDKVersion')) {
bridge.call('BYJ.getSDKVersion')
}
}
复制代码
同一功能需要iOS,Android方法名相同,这样更好处理哦
H5 调试相关方案策略
表现
调试代码一般就是为了查看数据和定位 bug。分为两种场景,一种是开发和测试时调试,一种是生产环境上调试。
为什么有生产环境上调试呢?有些时候测试环境上没法复现这个 bug,测试环境和生产环境不一致,此时就需要紧急生产调试。
在 PC 端开发时,我们可以直接掉出控制台,使用浏览器提供的工具操作devtools或者查看日志。但是在 App 内部我们怎么做呢?
原理与解决方案
1. vconsole
控制台插件
使用方法也很简单
import Vconsole from 'vconsole'
new Vconsole()
复制代码

有兴趣看看它实现的基本原理,我们关注的点应该在 vsconsole 如何打印出我们所有 log 的 腾讯开源vconsole[4]
上述方法仅用于开发和测试。生产环境中不允许出现,所以,使用时需要对环境进行判断。
import Vconsole from 'vconsole'
if (process.env.NODE_ENV !== 'production') {
new Vconsole()
}
复制代码
2. 代理 + spy-debugger
操作稍微有点麻烦,不过我会详细写出,大致分为 4 个步骤
-
安装插件\(全局安装\)
sudo npm install spy-debugger -g
复制代码
-
手机与电脑置于同一 wifi 下,手机设置代理
设置手机的 HTTP 代理,代理 IP 地址设置为 PC 的 IP 地址,端口为spy-debugger
的启动端口
spy-debugger 默认端口:9888
Android :设置 - WLAN - 长按选中网络 - 修改网络 - 高级 - 代理设置 - 手动
IOS :设置 - Wi-Fi - 选中网络, 点击感叹号, HTTP 代理手动
-
手机打开浏览器或者 app 中 H5 页面 -
打开桌面日志网站进行调试,点击 npm 控制台监听地址。查看抓包和 H5 页面结构
这种方式可以调试生成环境的页面,不需要修改代码,可以应付大多数调试需求
总结
本篇文章耗费作者一个多星期的业余时间,存手工敲打 4500 +字,同时收集,整理之前很多坑点和边写作边思考和总结。如果能对你有帮助,便是它最大的价值。都看到这里还不点赞,太过不去啦!😄
由于技术水平有限,文章中如有错误地方,请在评论区指出,感谢!
关于移动端 H5 的文章告一段落了,之后实践中遇到的问题都将在此文中更新。另外准备做一个移动端 H5 开源项目。多关注下 我的github[5]动态哦!
之后,应该回去研究下开源和面试题相关内容分享,想持续了解更多,不妨点赞和关注呗。
参考资料
-
Safari CSS Reference[6] -
MDN touch 事件 -
MDN css var\(\)[7] -
MDN css env\(\)[8] -
csswg env\(\) drafts[9] -
fastclick 源码[10] -
DSBridge-Android[11] & DSBridge-iOS[12] -
qrcodejs 源码[13] -
html2canvas 源码[14] -
关于H5页面在iPhoneX适配[15] -
vant 相关文档[16]
参考资料
https://juejin.cn/post/6844904023145857038: https://juejin.cn/post/6844904023145857038
[2]
https://juejin.cn/post/6844904021552005128: https://juejin.cn/post/6844904021552005128
[3]
https://github.com/ftlabs/fastclick/blob/master/lib/fastclick.js: https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fftlabs%2Ffastclick%2Fblob%2Fmaster%2Flib%2Ffastclick.js
[4]
https://github.com/Tencent/vConsole/blob/dev/src/core/core.js: https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2FTencent%2FvConsole%2Fblob%2Fdev%2Fsrc%2Fcore%2Fcore.js
[5]
https://github.com/suoyuesmile/suo-blog: https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fsuoyuesmile%2Fsuo-blog
[6]
https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariCSSRef/Articles/StandardCSSProperties.html#//apple_ref/css/property/-webkit-overflow-scrolling: https://link.juejin.cn?target=https%3A%2F%2Fdeveloper.apple.com%2Flibrary%2Farchive%2Fdocumentation%2FAppleApplications%2FReference%2FSafariCSSRef%2FArticles%2FStandardCSSProperties.html%23%2F%2Fapple_ref%2Fcss%2Fproperty%2F-webkit-overflow-scrolling
[7]
https://developer.mozilla.org/zh-CN/docs/Web/CSS/var: https://link.juejin.cn?target=https%3A%2F%2Fdeveloper.mozilla.org%2Fzh-CN%2Fdocs%2FWeb%2FCSS%2Fvar
[8]
https://developer.mozilla.org/zh-CN/docs/Web/CSS/env: https://link.juejin.cn?target=https%3A%2F%2Fdeveloper.mozilla.org%2Fzh-CN%2Fdocs%2FWeb%2FCSS%2Fenv
[9]
https://drafts.csswg.org/css-env-1/: https://link.juejin.cn?target=https%3A%2F%2Fdrafts.csswg.org%2Fcss-env-1%2F
[10]
https://github.com/ftlabs/fastclick/blob/master/lib/fastclick.js: https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fftlabs%2Ffastclick%2Fblob%2Fmaster%2Flib%2Ffastclick.js
[11]
https://github.com/wendux/DSBridge-Android: https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fwendux%2FDSBridge-Android
[12]
https://github.com/wendux/DSBridge-IOS: https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fwendux%2FDSBridge-IOS
[13]
https://github.com/davidshimjs/qrcodejs: https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fdavidshimjs%2Fqrcodejs
[14]
https://github.com/niklasvh/html2canvas: https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fniklasvh%2Fhtml2canvas
[15]
https://www.cnblogs.com/lolDragon/p/7795174.html: https://link.juejin.cn?target=https%3A%2F%2Fwww.cnblogs.com%2FolDragon%2Fp%2F7795174.html
[dieciséis]
https://youzan.github.io/vant/#/zh-CN/button: https://link.juejin.cn?target=https%3A%2F%2Fyouzan.github.io%2Fvant%2F%23% 2Fzh-CN%2Fbotón
Autor: suoyuesmile
https://github.com/suoyuesmile/suo-blog/blob/master/articals/h5/0003.md