iOS时间NaN的问题
iOS上的WebView的问题,iOS的Date不识别 “-”,解决思路就是 在 new Date(sz)之前,将字符串所有的“-”替换为”/"
但也有不少情况是不识别 “/”,所以最好的解决办法还是
- 后端直接返回可展示得信息前端不处理
- 需要时间判断的地方后端直接返回结果
安卓、IOS拉起本地APP并跳转特定页
-
微信外唤起:
用常规方式:通用的Scheme和IOS自己的Universal Links。都支持自定义参数。- IOS:Universal Links
https://www.xxxx.com/xxx
公司的Universal Links服务器地址 供IOS系统访问 重定向页面做转发
https://www.xxxx.com/apple-app-site-association
可以下载JSON配置文件,系统会通过规则匹配后,跳转APP - 安卓:直接自定义URL Scheme唤起APP,例如
alipays://
唤起支付宝APP
- IOS:Universal Links
-
微信内唤起:
-
- 由于微信禁止了通用的Scheme和IOS自己的Universal Links方式唤起APP,所以需要其他方式。
-
- 可以提示用户在外部浏览器打开页面后 利用schema唤起应用
-
- 直接接入微信OpenSDK。
注册认证的服务号,服务号绑定“JS接口安全域名”下的网页可使用此标签跳转满足一定条件的App。
- 直接接入微信OpenSDK。
-
IOS在APP内部网页跳转回到上一页时 为什么上一页没有被销毁而是被暂停 安卓却需要重新加载
在 iOS 和 Android 中,应用内嵌入的网页(通常通过 WKWebView 在 iOS 上和 WebView 在 Android 上实现)的行为有所不同,这主要是由于两个平台对 Web 视图的生命周期管理和内存管理策略不同。
iOS (WKWebView)
在 iOS 中,WKWebView 采用了一种更高效的内存管理机制。当用户从一个页面跳转到另一个页面时,WKWebView 并不会立即销毁前一个页面,而是将其暂停并保留在内存中。这种做法有几个优点:
性能优化:如果用户返回到前一个页面,该页面可以快速恢复,而不需要重新加载,从而提高了用户体验。
资源重用:保留前一个页面的状态和资源可以减少内存的频繁分配和释放,提高系统的整体性能。
状态保持:用户在前一个页面上的所有状态(如表单填写、滚动位置等)都可以被保留,提供了更好的连续性体验。
Android (WebView)
在 Android 中,WebView 的行为略有不同。默认情况下,当用户从一个页面跳转到另一个页面时,前一个页面会被销毁,并且当用户返回时需要重新加载。这是因为:
内存限制:Android 设备可能有不同的内存限制,尤其是在低端设备上。为了防止内存溢出,系统可能会选择销毁不再显示的页面。
进程管理:Android 系统对进程的管理更为严格,可能会根据内存压力和其他因素决定何时销毁或暂停进程。
默认配置:WebView 默认配置下,每个页面都是独立的,没有像 WKWebView 那样的内置缓存机制来保存页面状态。
当 iOS 设备呼出软键盘后,页面会自动滚动以确保输入框可见,导致浏览器可以上下拉动 导致页面效果不一致
window.addEventListener('keyboardWillShow',function(e){e.preventDefault();});
window.addEventListener('keyboardWillHide',function(e){e.preventDefault();});
IOS设备隐藏滚动条
::-webkit-scrollbar {
width: 0px; /*滚动条宽度*/
height: 0px; /*滚动条高度*/
display: none;
}
-webkit-overflow-scrolling: touch;//这是 iOS 设备上模拟原生滚动效果的一个属性。添加这个属性可以让滚动条完全隐藏:
document.body.style.overflow = 'hidden'; // 隐藏滚动条 或指定元素
软键盘弹出时,在Android系统下,H5所在容器(即WebView)高度会被压缩
onMounted(async () => {
window.addEventListener('resize', resizeReview);
}
function resizeReview() {//动态监听屏幕变化来改变元素尺寸 系数根据需求自己算这里约为17
let vhValue = window.innerHeight/17
document.getElementById('reviewDom').style.height=`${vhValue}vh`
}
禁止 iOS 浏览器中的连点放大
- 你可以通过设置 meta 标签来禁用双击缩放:
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
- 还可以给按钮添加逻辑
document.querySelector('button').addEventListener('click', function(event) {
event.preventDefault();
// 其他逻辑
});
- 或是在index.html中直接禁止相关操作
/*禁止ios缩放,双击和双指*/
window.onload = function() {
document.addEventListener("touchstart", function(event) {
if (event.touches.length > 1) {
event.preventDefault();
}
});
var lastTouchEnd = 0;
document.addEventListener(
"touchend",
function(event) {
var now = new Date().getTime();
if (now - lastTouchEnd <= 300) {
event.preventDefault();
}
lastTouchEnd = now;
},
false
);
document.addEventListener("gesturestart", function(event) {
event.preventDefault();
});
};
IOS和安卓客户端加载H5流程:
原生页面触发事件后 准备webview容器与对应的跳转链接 再进行加载。
IOS和安卓客户端切换页面(例如h5支付场景):
IOS的webview内部跳转时会暂停上一个页面的状态 甚至是loading动画。
返回后可以顺延播放非常丝滑。
安卓反而会销毁页面并跳转,类似PC浏览器同一页签下的跳转。
返回后会重新加载页面。
IOS和安卓与H5前端的通信的主要方式
1.链接传参
2.userAgent通用参数 userAgent.navigator //一个常见浏览器属性,包含当前浏览器的各种信息。格式并没有标准。不建议过度依赖userAgent,因为可能被篡改伪造。
3.window方法调用
window.JSInterface.putToken();//和客户端协商的方法名putToken 安卓
window.webkit.messageHandlers.putToken.postMessage({});//IOS
4.Bridge传参
-------------------------------------------------------------组件内调用 安卓IOS通用
import Bridge from '@/utils/jsBridge.js'
Bridge.callhandler("imgClick_ext", {//和客户端协商的方法名imgClick_ext
index: index,
fileArr: arr,
}, responseData => {
let res = JSON.parse(responseData);
console.log(res, 'res');
});
-------------------------------------------------------------jsBridge.js
function setupWebViewJavascriptBridge(callback) {
console.log("callback", callback)
if (window) {
if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
window.WVJBCallbacks = [callback];
var WVJBIframe = document.createElement('iframe');
WVJBIframe.style.display = 'none';
WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
document.documentElement.appendChild(WVJBIframe);
setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
}
}
//初始化
setupWebViewJavascriptBridge(function (bridge) {
console.log("setupWebViewJavascriptBridge")
try {
bridge.init(function (message, callback) {
callback(null);
})
} catch (e) { }
});
export default {
//js调APP方法 (参数分别为:app提供的方法名 传给app的数据 回调)
callhandler: function (method, params, callback) {
// console.log("callhandler", method)
setupWebViewJavascriptBridge(function (bridge) {
bridge.callHandler(method, params, callback)
})
},
// APP调js方法 (参数分别为:js提供的方法名 回调)
registerHandler(method, callback) {
// console.log("callhandler", method)
setupWebViewJavascriptBridge((bridge) => {
bridge.registerHandler(method, (data, responseCallback) => {
callback(data, responseCallback)
})
})
}
}
安卓IOS的webView或H5浏览器拿到的像素宽高,比手机屏幕高度差很多?
1.设备像素比(Device Pixel Ratio, DPR)不匹配:
手机屏幕的 DPR 通常大于 1,比如 2 或 3。这意味着物理像素与 CSS 像素并不相等。
H5 应用通过 JavaScript 获取的高度是基于 CSS 像素的,而不是物理像素。所以获取的高度会小于实际屏幕高度。
2.浏览器视口(Viewport)设置不当:
H5 应用需要通过 <meta name="viewport" ...> 标签正确设置视口参数,如宽度、缩放比例等。
如果视口设置有问题,就会导致 H5 应用获取的高度与实际屏幕高度不符。
3.滚动条高度未考虑:
有时浏览器会根据内容显示垂直滚动条,这部分高度需要单独计算。
如果 H5 应用没有正确处理滚动条高度,获取的高度就会小于屏幕实际高度。
4.浏览器差异:
不同的浏览器在获取高度方面可能会有一些差异,需要做兼容性处理。
怎么修改h5软键盘的文字,将右下角的回车换行更改为前往或发送?
文档中很多都是修改为前往,搜索,提交等。修改的属性,其实还是有另外一个属性的:enterkeyhint
<input enterkeyhint="enter">
<input enterkeyhint="done">
<input enterkeyhint="go">
<input enterkeyhint="next">
<input enterkeyhint="previous">
<input enterkeyhint="search">
<input enterkeyhint="send">
输入发送完成收回软键盘
const field = document.getElementById('live-field');//获取input控件DOM
field.blur(); // 收回软键盘 失去焦点
图片自适应
宽度100%,高度自适应
background-image: url(../assets/image.png);
background-repeat: no-repeat;
background-size: 100% auto;
微信开启了大字体模式,可能会导致页面布局失效。
- 这是因为微信会在 HTML 页面的根元素上添加一个 wx-wx-root 类名,并且会设置一些特殊的样式。
0. 微信官方文档
<script>
// 微信网页字体大小自定义适配 Demo
document.addEventListener("WeixinJSBridgeReady", function (params) {
// 1-1.设置禁止 Android 微信内网页字体大小默认缩放
WeixinJSBridge.invoke("setFontSizeCallback", {
fontSize: '2' // 默认档位 2
});
// 2.监听网页字体大小的事件,页面加载完成或用户手动修改字号会触发该事件
WeixinJSBridge.on('menu:setfont', function (e) { // e.fontSize 档位 e.fontScale 放大比例
// 3-1.业务逻辑
// rem方式,根据档位或放大比例设置根字号大小
// 非rem方式,根据档位或放大比例设置根节点命名空间className(如:wechat_fontsize_6)
});
}, false);
</script>
<style>
/* 1-2.设置禁止 iOS 微信内网页字体大小默认缩放 */
body {
-webkit-text-size-adjust: 100% !important;
text-size-adjust: 100% !important;
}
/* 3-2.业务逻辑 */
.wechat_fontsize_6 .title { }
</style>
或是自己判断再微信内 直接将全局字体大小写死
var u = navigator.userAgent;
var isWeixin = u.toLowerCase().indexOf("micromessenger") !== -1; // 微信内
1. 可以使用 CSS 媒体查询 检测是否在大字体模式下, 并针对这种情况进行特殊的样式调整:
/* 检测大字体模式 */
@media (max-width: 375px) and (-webkit-min-device-pixel-ratio: 3) {
/* 在大字体模式下的样式调整 */
body {
font-size: 16px !important; /* 重置字体大小 */
}
/* 其他需要调整的样式 */
}
2. 使用 JavaScript 动态修改 在页面加载时检测是否在大字体模式下, 并动态修改 DOM 元素:
// 检测是否在大字体模式
function isWeixinBigFont() {
return document.documentElement.classList.contains('wx-wx-root');
}
// 在页面加载时进行样式调整
window.addEventListener('load', function() {
if (isWeixinBigFont()) {
// 在大字体模式下进行样式调整
document.body.style.fontSize = '16px';
// 其他需要调整的样式
}
});
3. 使用第三方库进行适配 您可以使用一些第三方库,如 vant, cube-ui 等,它们提供了针对微信大字体模式的适配方案。这些库会自动检测当前环境,并提供相应的样式调整。
reolaceAll低版本浏览器不兼容问题
如果 replaceAll 在某些浏览器中不兼容,可以使用正则表达式配合 replace 方法来实现相同的功能:
const input = "some text to replace";
const output = input.replace(/text/g, "word");
console.log(output);
IOS的PT 安卓的DP
PT
- pt 在 iOS 开发中就是代表分辨率的最小单位。和 px 一样,也是一种「相对长度」。
- pt 这个单位的缘由是苹果的 Retina 屏的分辨率较高,为了更好的定义和展现自己的产品,苹果就自己定义了一个设计单位 pt,用来给 iOS 系统的设计师做基础设计,并可以根据公式变换成 px 以适应不同 PPI 的手机。
- pt 与 px 的转换方式是:pt = ppi / 163 px 。ppi 不能被 163 整除时,可以进行四舍五入。比如如果 ppi 是 350,那么 pt = 350 / 163 = 2.14px,就是说 1pt 约等于 2px。
- 以上公式中 163 这个数字的来源是:iPhone3 的 3.5 英寸屏幕的分辨率是 320*480px,它的 ppi 按照我们上文提到过的 ppi 计算公式,等于 163。苹果规定:ppi = 163 时,1pt = 1px。
DP
- dp 全称 Density-independent pixel,可以理解为是一种独立于 px 之外的设计单位,是 Andriod 系统用来给设计师做基础设计使用的,也可以根据公式变换成 px。
- 同 pt 一样,1dp 在任何设备上的大小都应该是一样的,但是代表几个 px 却是不固定的,以此来应对不同 ppi 的设备。
- dp 和 px 的转换方式是:dp = ppi / 160 px。原理同上文,但分母取了整数,被规定为 160,结果同样可四舍五入。
H5项目的Rem适配
前端还原设计稿很重要,目前最泛用的还是rem。
postcss-pxtorem 能够直接按照设计图的尺寸开发,并且能自动编译转换成rem
npm install postcss-pxtorem -D
autoprefixer 能够自动为你的CSS代码添加必要的浏览器前缀,以确保在各个现代和旧版浏览器中的兼容性。通过这个项目,开发者可以节省大量手动添加前缀的时间,从而更加专注于代码逻辑和设计。
npm install postcss-pxtorem -D
vite.config.js
export default defineConfig({
...
css: {
postcss: {
plugins: [
autoprefixer({
overrideBrowserslist: [
"Android 4.1",
"iOS 7.1",
"Chrome > 31",
"ff > 31",
"ie >= 8",
],
}),
postCssPxToRem({
// 自适应,px>rem转换
rootValue: 37.5, // 75表示750设计稿,37.5表示375设计稿
propList: ["*"], // 需要转换的属性,这里选择全部都进行转换
selectorBlackList: ["norem"], // 过滤掉norem-开头的class,不进行rem转换
}),
],
},
},
...
});
H5网页嵌在APP内部 手机锁屏后再打开 setInterval会重复执行
在H5网页嵌入到APP内部时,如果手机锁屏后再打开,可能会遇到setInterval重复执行的问题。这是因为当应用进入后台或屏幕锁定时,浏览器的定时器可能会暂停或重置,导致重新激活时定时器被重新启动。
问题原因
系统休眠:当手机锁屏时,操作系统可能会将应用置于休眠状态,暂停所有活动,包括JavaScript的定时器。
WebView恢复:当用户解锁手机并返回应用时,WebView可能需要重新加载或恢复页面,这会导致setInterval函数重新执行。
解决方法
- 使用 visibilitychange 事件
你可以监听 visibilitychange 事件来检测页面是否可见,并根据页面的可见性来控制 setInterval 的行为。
let intervalId;
function startInterval() {
if (intervalId) {
clearInterval(intervalId);
}
intervalId = setInterval(() => {
// 你的定时任务代码
console.log('定时任务执行');
}, 1000);
}
function stopInterval() {
if (intervalId) {
clearInterval(intervalId);
intervalId = null;
}
}
// 监听页面可见性变化
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
startInterval();
} else {
stopInterval();
}
});
// 页面初始加载时启动定时器
if (document.visibilityState === 'visible') {
startInterval();
}
- 使用 pagehide 和 pageshow 事件
你也可以使用 pagehide 和 pageshow 事件来处理页面隐藏和显示的情况。
let intervalId;
function startInterval() {
if (intervalId) {
clearInterval(intervalId);
}
intervalId = setInterval(() => {
// 你的定时任务代码
console.log('定时任务执行');
}, 1000);
}
function stopInterval() {
if (intervalId) {
clearInterval(intervalId);
intervalId = null;
}
}
// 监听页面隐藏和显示
window.addEventListener('pagehide', stopInterval);
window.addEventListener('pageshow', startInterval);
// 页面初始加载时启动定时器
startInterval();