IOS
滑动不流畅
在滚动容器上增加滚动 touch 方法
.wrapper {
-webkit-overflow-scrolling: touch;
}
上拉边界下拉出现空白
document.body.addEventListener(
'touchmove',
function (e) {
if (e._isScroller) return
// 阻止默认事件
e.preventDefault()
},
{
passive: false,
}
)
在点击输入框,出现键盘后,弹出层被顶上去,而光标还停留在原处,即出现错位情况
Input/textarea
$('input.van-field__control, textarea.van-field__control').blur(function () {
setTimeout(function () {
var currentPosition = document.documentElement.scrollTop || document.body.scrollTop
window.scrollTo(0, currentPosition) //页面向上滚动
}, 200)
})
多个Input/textarea
$(function () {
var setTimerTop = 0
$(document)
.on('blur', 'input.van-field__control, textarea.van-field__control', function () {
event.preventDefault()
setTimerTop = setTimeout(function () {
window.scrollBy(0, 5) // 页面向上滚动
window.scrollBy(0, -5)
}, 500)
})
.on('focus', 'input.van-field__control, textarea.van-field__control', function () {
clearTimeout(setTimerTop)
})
})
iframe情况
$(function () {
var setTimerTop = 0
$(document)
.on('blur', 'input.van-field__control, textarea.van-field__control', function () {
event.preventDefault()
setTimerTop = setTimeout(function () {
parent.scrollBy(0, 5) // 页面向上滚动
parent.scrollBy(0, -5)
$('#hide-area-cb').focus()
}, 500)
})
.on('focus', 'input.van-field__control, textarea.van-field__control', function () {
clearTimeout(setTimerTop)
})
.on('focus', 'input.van-field__control[disabled]', function () {
setTimerTop = setTimeout(function () {
parent.scrollBy(0, 5) // 页面向上滚动
parent.scrollBy(0, -5)
}, 500)
})
})
日期转换 NAN 的问题
iOS 解析 YYYY-MM-DD HH:mm:ss
这种日期格式会报错 Invalid Date
,Android 无问题 查看开发手册发现可用:YYYY/MM/DD HH:mm:ss
,那么需替换其中的 - 为 /
const date = '2021-02-05 10:39:00'
console.log(new Date(date.replace(/\-/g, '/')))
fixed 失效的原因
软键盘唤起后,页面的 fixed 元素将失效,变成了 absolute,所以当页面超过一屏且滚动时,失效的 fixed 元素就会跟随滚动了。不仅限于 type=text 的输入框,凡是软键盘(比如时间日期选择、select 选择等等)被唤起,都会遇到同样地问题。 解决方法:不让页面滚动,而是让主体部分自己滚动,主体部分高度设为 100%,overflow: scroll;
<div class="warper">
<div class="main"></div>
<div>
<div class="bottom"></div>
</div>
</div>
.warper {
position: absolute;
width: 100%;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
.bottom {
position: fixed;
bottom: 0;
width: 100%;
}
移动端fixed布局
- ios6下,不固定,滑动会突然跳动
- 输入框在弹出键盘后,不吸附在键盘上方
- fixed的元素宽度不能自适应,在ios6下横竖屏切换的过程中
- iframe下,fixed元素高度超大
iOS 闪屏问题
如果保留height:100% 那么就添加 overflow:auto
去掉当前页面的height:100%
body{
-webkit-tap-highlight-color:rgba(0,0,0,0);
}
Android
如果视频没有播放的情况,双击进度条快进会吧整个video播放不了的情况出现,导致出现该问题的原因暂时不知什么原因引起
解决方法:添加一个蒙层,点击蒙层就播放视频,短暂的处理方案 vue 完整代码如下:
<template>
<div class="video_box">
<div class="cover" @click.stop.prevent="play" v-if="!played"></div>
<video
:src="src"
:poster="poster"
:id="`videoElement${index}`"
controls
playsinline
webkit-playsinline
webkit-inline
x5-video-player-type="h5-page"
x5-video-player-fullscreen="true"
x-webkit-airplay="allow"
x5-video-orientation="portraint"
/>
</div>
</template>
<script>
export default {
props: {
src: {
type: String,
default: '',
},
poster: {
type: String,
default: '',
},
index: {
type: Number,
default: 0,
},
},
data() {
return {
played: false,
}
},
methods: {
play() {
document.getElementById(`videoElement${this.index}`).play()
this.played = true
},
},
}
</script>
<style lang="scss" scoped>
.video_box {
position: relative;
width: 100%;
height: 194px;
.cover {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 1000;
}
video {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
}
</style>
video 属性返回 Infinity
;<video
controlslist='nodownload'
playsinline=''
webkit-playsinline=''
x5-video-player-type='h5-page'
x-webkit-airplay='true'
autoplay='autoplay'
controls='controls'
preload='auto'
style='width: 100%;height: auto;'
src=''
></video>
var player = document.querySelector('video')
window.onload = function () {
// 获取总时长
player.addEventListener('durationchange', (event) => {
console.log(player.duration)
// Infinity
})
// 监听缓存进度
player.addEventListener('progress', (event) => {
let bufvalue = player.buffered.end(player.buffered.length - 1)
console.log(parseInt(bufvalue))
// Infinity
})
}
前端 video 直播场景时,对延迟比较高要求(电商秒杀等场景)的可以通过监控 progress 来达到效果
注意:设置currentTime为最新的播放时长要控制好频率与快进时长,要不然会导致一直loading加载新的TS片段
var player = document.querySelector("video");
var videoCanskip = 0;
player.addEventListener("progress", function (event) {
// 返回表示音频/视频已缓冲部分的 TimeRanges 对象。
var startBuffered = player.buffered.start(0);
var endBuffered = player.buffered.end(0);
videoCanskip = parseInt(endBuffered - startBuffered);
console.log("video_可快进时长" + Math.ceil(videoCanskip));
}
// 设置currentTime 值 来播放最新内容
player.currentTime = videoCanskip;
QuotaExceededError
异常
sentry
平台收集到一个意外的error
,错误信息为QuotaExceededError
。 错误分析才知道,原来当超过可用配额时,IndexedDB
和缓存 API 都会抛出名为QuotaExceededError
的DOMError
。localStorage
预留5MB左右的储存空间(这个是大概固定的值)IndexedDB
的配额是动态计算的,可能浏览器实现各不相同,但可用存储量通常取决于设备上可用的存储量(随着手机内存的不断减少,webview
的配额也会减少,具体多少可以导致IndexedDB
是不可用,没有大量的测试数据来验证。但是测试出现问题的时候,手机内存在700以下就会出现这个问题,但是在其他的安卓设备这个值又是500以下,所以这个复现存储值不可靠)
我们可以规避掉这个风险,先检查有多少可用存储,如下:
if (navigator.storage && navigator.storage.estimate) {
const quota = await navigator.storage.estimate()
// quota.usage -> 已用字节数。
// quota.quota -> 最大可用字节数。
const percentageUsed = (quota.usage / quota.quota) * 100
console.log(`您已使用可用存储的 ${percentageUsed}%。`)
const remaining = quota.quota - quota.usage
console.log(`您最多可以再写入 ${remaining} 个字节。`)
}
https://web.dev/storage-for-the-web/#indexeddb-2 StorageManager:https://developer.mozilla.org/zh-CN/docs/Web/API/StorageManager
for-in
let obj = {
a: 1,
b: 2,
}
Object.prototype.c = function () {
console.log('c')
}
// 需要注意的是,for...in 循环会遍历对象自身及其原型链上可枚举的属性。
// 在这个例子中,我们将方法 c 添加到了 Object.prototype 上,因此它被认为是一个可枚举属性,可以被 for...in 循环遍历到。
// 如果我们使用 Object.defineProperty 方法定义属性,并将其 enumerable 设置为 false,那么该属性将不会被 for...in 循环遍历到。
for (const key in obj) {
console.log(key)
}
// a
// b
// c
// 属性描述符
const desc = Object.getOwnPropertyDescriptor(Object.prototype, 'hasOwnProperty')
console.log(desc)
// 使用 Object.defineProperty 方法定义属性
// 明确设置 enumerable 属性为 false,
// 避免在 for...in 循环中被遍历到
Object.defineProperty(Object.prototype, 'd', {
value: function () {
console.log('d')
},
writable: true,
enumerable: false,
configurable: true,
})
// 使用 hasOwnProperty 方法判断属性是否为对象自身属性
// 避免循环到原型链上的属性
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
console.log(key)
}
}
writing....