// 为什么叫《大事记》?

// 以前总有面试官问这样一个问题:“你在项目中遇到过最头疼的问题是什么,是怎么解决的?”

// 当时总觉得,已解决的问题都算不上头疼,所以回答总是不尽人意。

// 最近遇到微信端的这个问题,非常让人头疼,正好有小伙伴和我聊到面试经验,灵机一动,《大事记》由此而生

问题描述:

在安卓系统的微信浏览器里面,<video> 标签触发了 play() 事件,即开始播放之后

<video> 标签的层级会变成 MAX 级别,无论如何设置 z-index,都会遮挡别的脱离文档流的元素

分析原因:

微信的 X5 内核为了统一 <video> 在不同的手机上的呈现形式,对 <video> 进行了改造

这样的改造在 IOS 系统上一切正常,但在安卓系统就会有各种问题,比如这里的层级太高

解决方案:

当测试的同事将这个 bug 提给我的时候,我根本没想到,我即将面对一场苦不堪言的角斗

第一回合:隐藏 video

最初暴露的问题并不是页面底部的按钮,而是一个弹窗

在了解了问题的原因之后,我当时的思路是:

打开弹窗的时候,将 <video> 标签隐藏掉,关闭弹窗的时候再显示 <video>

隐藏标签的方法有很多:display:none;   visibility: hidden;  z-index: -1;   left: -9999px;  opacity: 0;

但 display:none 没有占位,visibility 和 z-index 不起作用,opacity 虽然不显示元素,但依旧点不到下面的元素

所以只有用定位的办法了

  let tag = document.createElement('style')
tag.id = id
tag.innerHTML = `video { position: relative; left: -9999; }`
body.appendChild(tag)

在打开弹窗的时候,通过上面的代码添加一个带有特殊 id 的 <style> 标签,然后在关闭时候根据 id 删除节点

为了防止多级弹窗的时候重复创建 <style>,在方法前面需要验证是否存在该 id

想通了这一系列逻辑之后,我猛然发现,页面底部的按钮也会被遮挡!

第二回合:跳转到单独页面播放

深思熟虑之后,我得出结论:遮挡问题无解

但问题还是要解决,于是我向 PM 提出,单独写一个播放页面,点击 <video> 的时候跳转到这个页面进行播放

经过一番唇枪舌剑的交锋,PM 妥协了,但要求尽量优化体验,打开的播放页看起来要像全屏播放一样

“这都不是事儿!” 我如是回道

播放页面确实不是事儿,可 <video> 真不是省油的灯

我原本想的是,全局添加一个 addEventListener('click'),如果点击的是 <video> 标签,就保存视频信息,并跳转到播放页面

document.addEventListener('click', (e) => {
let target = e.target
if (target.nodeName.toUpperCase() === 'VIDEO') {
this.setVideoUrl({
  url: target.src,
  poster: target.poster
})
this.$router.push(`/video`)
}
})

这下跳转是没问题了,但在点击的时候,实际上还触发了 <video> 的 play() 事件

从理论上来说,已经跳转页面了,这个 play() 事件并不需要阻止,但为了逻辑严谨,我还是做了尝试

e.preventdefault()
e.stopPropagation()
e.cancelBubble()
return false

然而这并不能阻止播放事件 play()

那就不阻止了

然后又了新的 Bug:部分机型从播放返回之后,<video> 是播放的状态,而且有层级问题

第三回合:禁用 controls

我重新回到那个问题:如何阻止播放事件?

稍作挣扎,我就换了一个思路:如果没有播放按钮,那就不需要阻止播放事件了

于是我给 <video> 添加了 controls=""

这样就没有播放工具栏,之后只需要手动添加一个三角形的播放图标,一切就完美了

页面上的 <video> 是作为描述内容的一部分,包含在一段富文本里面,从后端返回的

这样一来,<video> 相关的 DOM 节点只能通过 JS 修改,成本太高,所以我打算只用 CSS 来解决播放图标的问题

然后我画了一个播放的图标,给 <video> 添加了一个伪元素 :before,在伪元素里写好了样式,但毫无作用

原来 <video> 并不支持伪元素

“如果无法解决问题,那就让问题不存在”

我脑海中闪过这段话,然后有了新的方案:

我又画了一张图,然后将 <video> 的 poster 改成了这张图,问题解决了!

然后产品小姐姐跑过来:你对我的视频封面图做了什么?

决战:js 王道

既然 poster 不能改,那就只有通过 js 去操作 DOM,给 <video> 添加一个兄弟节点 <i class="video-play_btn"> 作为播放按钮

然后将 <video> 和播放按钮一起包在一个容器 <div class="video-wrapper"> 中

setVideoWrapper () {
this.$nextTick(() => {
let v = document.getElementsByTagName('video')
if (v && v[]) {
// 产品规定 页面中只会有一个 <video>
let target = v[]
// 防止重复创建 wrapper
if (target.parentNode.className === 'video-wrapper') return
// 清除 <video> 播放工具栏
target.controls = ''
target.className = 'video-hack'
// 创建播放按钮
let btn = document.createElement('i')
btn.className = 'video-play_btn'
// 创建容器
let wrap = document.createElement('div')
wrap.className = 'video-wrapper'
wrap.appendChild(btn)
wrap.appendChild(target.cloneNode())
// 插入容器并删除原本的 <video>
target.parentNode.insertBefore(wrap, target)
target.parentNode.removeChild(target)
}
})
}

再添加对应的 LESS 样式:

.video {
&-wrapper {
position: relative;
font-size:;
}
&-play {
&_btn {
position: absolute;
top:;
left:;
right:;
bottom:;
background: rgba(0, 0, 0, .1) url('img/url') center/80px 80px no-repeat;
}
}
}

终于,<video> 的问题彻底解决了,皆大欢喜,普天同庆

但我还是要吐槽一下,微信 <video> 的问题由来已久,开发团队也曾经说过要解决,但最后都不了了之

这大约都是时辰的错

大事记 - 安卓微信浏览器 video 标签层级过高的更多相关文章

  1. 防止微信浏览器video标签全屏的问题

    在微信浏览器里面使用video标签,会自动变成全屏,改成下面就好了,起码可以在video标签之上加入其他元素. <video id="videoID" webkit-play ...

  2. 解决微信浏览器video全屏的问题

    解决微信浏览器video全屏的问题 在微信浏览器里面使用video标签,会自动变成全屏,改成下面就好了,起码可以在video标签之上加入其他元素. <video id="videoID ...

  3. 关于移动端video标签层级问题

    这是在微信中正常页面,就是用了一个原生video标签没做任何处理.然后顶部是固定页面顶端的,这个时候向上滑动页面时,会出现下图现象 这个时候正常人都会想到z-index问题,我也是这样想的,可惜很抱歉 ...

  4. 微信浏览器 video - android适配

    阶段一: 直接裸用 video 标签, 安卓 - 会重新弹一个播放层, 和之前video的父盒子错位, 要多丑有多丑, 体验要多烂有多烂. 阶段二: video添加以下属性, 安卓可实现内联播放, 但 ...

  5. 部分安卓微信浏览器无法触发onchange事件

    这是安卓微信的一个遗留问题. 解决办法很简单: 将input标签 <input type=“file" name="image" accept="imag ...

  6. 微信内置浏览器video标签自动全屏的问题

    微信打开h5video视频的时候都会自动全屏播放,有时候影响用户体验 要禁止自动全屏就要加这几个属性 'x5-playsinline':'true', 'webkit-playsinline':'tr ...

  7. 解决安卓微信浏览器中location.reload 或者 location.href失效的问题

    在移动wap中,经常会使用window.location.href去跳转页面,这个方法在绝大多数浏览器中都不会 存在问题,但早上测试的同学会提出了一个bug:在安卓手机的微信自带浏览器中,这个是失效的 ...

  8. 安卓微信浏览器中location.href失效的问题

    在移动web中,经常会使用window.location.href去跳转页面,这个方法在绝大多数浏览器中都不会存在问题,但是在安卓手机的微信自带浏览器中,会出现一个奇怪的bug. window.loc ...

  9. 微信浏览器video播放视频踩坑

    video属性介绍 iOS的属性 playsinline On iPhone, video playsinline elements will now be allowed to play inlin ...

随机推荐

  1. PHP二维数组按照键值排序

    在开发过程中,我们常常需要对二维数组按照数组的某个键来排序,这里提供两个封装好的方法,可以放到公共函数模块里以后需要的时候直接调用即可. /** * 二维数组按照键值降序排序 * @param arr ...

  2. Python学习笔记【第十篇】:Python面向对象进阶

    保护对象的属性 如果有一个对象,当需要对其进行修改属性时,有2种方法 对象名.属性名 = 数据 ---->直接修改 对象名.方法名() ---->间接修改 为了更好的保存属性安全,即不能随 ...

  3. 微信公众号接入之排序问题小记 Arrays.sort()

    微信公众号作为强大的自媒体工具,对接一下是很正常的了.不过这不是本文的方向,本文的方向公众号接入的排序问题. 最近接了一个重构的小项目,需要将原有的php的公众号后台系统,转换为java系统.当然,也 ...

  4. Python - 安装并配置Anaconda环境

    1- 简介 官网:https://www.anaconda.com/ Anaconda是一个用于科学计算的Python发行版,适用于数据分析的Python工具,也可以用在大数据和人工智能领域. 支持 ...

  5. 性能调优之Mapping

    Mapping层级的调优可能会花费时间,但是性能调优的效果确实非常显著的 优化Target,Source之后,可以调优Mapping 通常的方法是尽可能减少组件及组件的字段间不必要的连线 即尽可能用最 ...

  6. 吐血整理 20 道 Spring Boot 面试题,我经常拿来面试别人!

    面试了一些人,简历上都说自己熟悉 Spring Boot, 或者说正在学习 Spring Boot,一问他们时,都只停留在简单的使用阶段,很多东西都不清楚,也让我对面试者大失所望. 下面,我给大家总结 ...

  7. ES6常用特性总览

    以前看过一遍es6,今天面试时被问到了一个很简单的es6特性,竟然没回答上来,特来重温一下es6,做个总结性笔记. 一.什么是es6 es6是新版本JavaScript语言的标准,在2015年6月发布 ...

  8. python之获取当前操作系统(平台)

    Python在不同环境平台使用时,需要判断当前是什么系统,比如常用的windows,linux等 下面介绍一些能够获取当前系统的命令 1.使用sys.platform获取 #!/usr/bin/env ...

  9. [Jenkins]Jenkins构建时提示java.io.IOException: No space left on device

    突然发现Jenkins的Job全部都停了,打开Jenkins发现所有的slave机器,均提示: 点开Dead(!),提示Thread has died,如下图: 看图好像说是Jenkins所在的服务器 ...

  10. 支付宝PC端单笔支付同步回调session失效问题

    一次调用支付宝PC场景下单笔支付之后同步回调遇到的session失效问题记录 问题描述: 调用支付宝接口:alipay.trade.page.pay,该接口请求参数中有两个返回地址需要设置,retur ...