12个前端必会 H5 问题及解决方法

移动端常规写法

因此我们可以设置 maximum-scaleminimum-scale 与 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”>

click 点击事件延时与穿透

表现

监听元素 click 事件,点击元素触发时间延迟约 300ms

点击蒙层,蒙层消失后,下层元素点击触发。

产生原因

为什么会产生 click 延时?

iOS 中的 safari,为了实现双击缩放操作,在单击 300ms 之后,如果未进行第二次点击,则执行 click 单击操作。也就是说来判断用户行为是否为双击产生的。但是,在 App 中,无论是否需要双击缩放这种行为,click 单击都会产生 300ms 延迟。

为什么会产生 click 点击穿透?

双层元素叠加时,在上层元素上绑定 touch 事件,下层元素绑定 click 事件。由于 click 发生在 touch 之后,点击上层元素,元素消失,下层元素会触发 click 事件,由此产生了点击穿透的效果。

原理与解决方案

解决方案一:使用 touchstart 替换 click

前面已经介绍了,移动设备不仅支持点击,还支持几个触摸事件。那么我们现在基本思路就是用 touch 事件代替click 事件。

将 click 替换成 touchstart 不仅解决了 click 事件都延时问题,还解决了穿透问题。因为穿透问题是在 touch 和 click 混用时产生。

在原生中使用

el.addEventListener(“touchstart”, () => { console.log(“ok”); }, false);

在 vue 中使用

<button @touchstart=“handleTouchstart()”>点击

开源解决方案中,也是既提供了 click 事件,又提供了touchstart 事件。如 vant 中的 button 组件

那么,是否可以将 click 事件全部替换成 touchstart 呢?为什么开源框架还会给出 click 事件呢?

我们想象一种情景,同时需要点击和滑动的场景下。如果将 click 替换成 touchstart 会怎样?

事件触发顺序:  touchstarttouchmovetouchendclick

很容易想象,在我需要touchmove滑动时候,优先触发了touchstart的点击事件,是不是已经产生了冲突呢?

所以呢,在具有滚动的情况下,还是建议使用 click 处理。

在接下来的fastclick开源库中也做了如下处理。针对 touchstart 和 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;

}

主要目的就是,在使用 touchstart 合成 click 事件时,保证其不在滚动的父元素之下。

解决方案二:使用 fastclick 库

使用 npm/yarn 安装后使用

import FastClick from ‘fastclick’;

FastClick.attach(document.body, options);

同样,使用fastclick库后,click 延时和穿透问题都没了

按照我的惯例,只要涉及开源库,那么我们一定要去了解它实现的原理。主要是将现有的原生事件集合封装合成一个兼容性较强的事件集合。

fastclick源码 核心代码不长, 1000 行不到。有兴趣可以了解一下!

软键盘将页面顶起来、收起未回落问题

表现

Android 手机中,点击 input 框时,键盘弹出,将页面顶起来,导致页面样式错乱。

移开焦点时,键盘收起,键盘区域空白,未回落。

产生原因

我们在app 布局中会有个固定的底部。安卓一些版本中,输入弹窗出来,会将解压 absolute 和 fixed 定位的元素。导致可视区域变小,布局错乱。

原理与解决方案

软键盘将页面顶起来的解决方案,主要是通过监听页面高度变化,强制恢复成弹出前的高度。

// 记录原有的视口高度

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;

}

}

键盘不能回落问题出现在 iOS 12+ 和 wechat 6.7.4+ 中,而在微信 H5 开发中是比较常见的 Bug。

兼容原理,1.判断版本类型 2.更改滚动的可视区域

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),其中 window.scrollTo(0, clientHeight)恢复成原来的视口

iPhone X系列安全区域适配问题


表现

头部刘海两侧区域或者底部区域,出现刘海遮挡文字,或者呈现黑底或白底空白区域。

产生原因

iPhone X 以及它以上的系列,都采用刘海屏设计全面屏手势。头部、底部、侧边都需要做特殊处理。才能适配 iPhone X 的特殊情况。

解决方案

设置安全区域,填充危险区域,危险区域不做操作和内容展示。

危险区域指头部不规则区域,底部横条区域,左右触发区域。

具体操作为:viewport-fit meta 标签设置为 cover,获取所有区域填充。判断设备是否属于 iPhone X,给头部底部增加适配层

viewport-fit 有 3 个值分别为:

  • auto:此值不影响初始布局视图端口,并且整个web页面都是可查看的。

  • contain:视图端口按比例缩放,以适合显示内嵌的最大矩形。

  • cover:视图端口被缩放以填充设备显示。强烈建议使用 safe area inset 变量,以确保重要内容不会出现在显示之外。

设置 viewport-fit 为 cover

增加适配层

使用 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-topsafe-area-inset-rightsafe-area-inset-bottomsafe-area-inset-left  safe-area-inset-*由四个定义了视口边缘内矩形的  toprightbottom 和  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小组 提供方法

  1. 注册方法 bridge.register

bridge.register(‘enterApp’, function() {

broadcast.emit(‘ENTER_APP’)

})

  1. 回调方法 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

Vue 面试题

1.Vue 双向绑定原理
2.描述下 vue 从初始化页面–修改数据–刷新页面 UI 的过程?
3.你是如何理解 Vue 的响应式系统的?
4.虚拟 DOM 实现原理
5.既然 Vue 通过数据劫持可以精准探测数据变化,为什么还需要虚拟 DOM 进行 diff 检测差异?
6.Vue 中 key 值的作用?
7.Vue 的生命周期
8.Vue 组件间通信有哪些方式?
9.watch、methods 和 computed 的区别?
10.vue 中怎么重置 data?
11.组件中写 name 选项有什么作用?
12.vue-router 有哪些钩子函数?
13.route 和 router 的区别是什么?
14.说一下 Vue 和 React 的认识,做一个简单的对比
15.Vue 的 nextTick 的原理是什么?
16.Vuex 有哪几种属性?
17.vue 首屏加载优化
18.Vue 3.0 有没有过了解?
19.vue-cli 替我们做了哪些工作?

算法

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

  1. 冒泡排序
  2. 选择排序
  3. 快速排序
  4. 二叉树查找: 最大值、最小值、固定值
  5. 二叉树遍历
  6. 二叉树的最大深度
  7. 给予链表中的任一节点,把它删除掉
  8. 链表倒叙
  9. 如何判断一个单链表有环
  10. 给定一个有序数组,找出两个数相加为一个目标数

由于篇幅限制小编,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!有需要的程序猿(媛)可以帮忙点赞+评论666

统的?
4.虚拟 DOM 实现原理
5.既然 Vue 通过数据劫持可以精准探测数据变化,为什么还需要虚拟 DOM 进行 diff 检测差异?
6.Vue 中 key 值的作用?
7.Vue 的生命周期
8.Vue 组件间通信有哪些方式?
9.watch、methods 和 computed 的区别?
10.vue 中怎么重置 data?
11.组件中写 name 选项有什么作用?
12.vue-router 有哪些钩子函数?
13.route 和 router 的区别是什么?
14.说一下 Vue 和 React 的认识,做一个简单的对比
15.Vue 的 nextTick 的原理是什么?
16.Vuex 有哪几种属性?
17.vue 首屏加载优化
18.Vue 3.0 有没有过了解?
19.vue-cli 替我们做了哪些工作?

[外链图片转存中…(img-9CzDOgJs-1714131943094)]

算法

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

  1. 冒泡排序
  2. 选择排序
  3. 快速排序
  4. 二叉树查找: 最大值、最小值、固定值
  5. 二叉树遍历
  6. 二叉树的最大深度
  7. 给予链表中的任一节点,把它删除掉
  8. 链表倒叙
  9. 如何判断一个单链表有环
  10. 给定一个有序数组,找出两个数相加为一个目标数

    [外链图片转存中…(img-fQQVOahB-1714131943095)]

由于篇幅限制小编,pdf文档的详解资料太全面,细节内容实在太多啦,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!有需要的程序猿(媛)可以帮忙点赞+评论666

  • 21
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值