Skip to content

IOS

滑动不流畅

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

css
.wrapper {
  -webkit-overflow-scrolling: touch;
}

上拉边界下拉出现空白

javascript
document.body.addEventListener(
  'touchmove',
  function (e) {
    if (e._isScroller) return
    // 阻止默认事件
    e.preventDefault()
  },
  {
    passive: false,
  }
)

在点击输入框,出现键盘后,弹出层被顶上去,而光标还停留在原处,即出现错位情况

Input/textarea

javascript
$('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

javascript
$(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情况

javascript
$(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,那么需替换其中的 - 为 /

javascript
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;

html
<div class="warper">
  <div class="main"></div>
  <div>
    <div class="bottom"></div>
  </div>
</div>
css
.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 完整代码如下:

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

解决参考:https://stackoverflow.com/questions/38443084/how-can-i-add-predefined-length-to-audio-recorded-from-mediarecorder-in-chrome

javascript
;<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片段

javascript
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 都会抛出名为 QuotaExceededErrorDOMErrorlocalStorage 预留5MB左右的储存空间(这个是大概固定的值) IndexedDB 的配额是动态计算的,可能浏览器实现各不相同,但可用存储量通常取决于设备上可用的存储量(随着手机内存的不断减少,webview 的配额也会减少,具体多少可以导致 IndexedDB 是不可用,没有大量的测试数据来验证。但是测试出现问题的时候,手机内存在700以下就会出现这个问题,但是在其他的安卓设备这个值又是500以下,所以这个复现存储值不可靠)

我们可以规避掉这个风险,先检查有多少可用存储,如下:

javascript
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

javascript
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....