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

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

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

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

问题描述:

在安卓系统的微信浏览器里面,<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. sql并集union和union all的区别

    union : 对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序; union all:  对两个结果集进行并集操作,包括重复行,不进行排序; intersect : 对两个结果集进行交 ...

  2. Spark基础-scala学习(二、面向对象)

    面向对象编程之类 //定义一个简单的类 scala> :paste // Entering paste mode (ctrl-D to finish) //类默认public的 class He ...

  3. ubuntu下makeinfo安装,其实真正安装的是texinfo包

    操作系统环境:ubuntu 在终端中执行命令:sudo apt-get install texinfo   今天在打包的时候有个包需要 makeinfo,当时就各种搜结果就没有 makeinfo 这个 ...

  4. 程序员IT计算机中常见英语单词

    abstract 抽象的 abstract base class (ABC)抽象基类 abstract class 抽象类 abstraction 抽象.抽象物.抽象性 access 存取.访问 ac ...

  5. 浅尝Spring Cloud Sleuth

    Spring Cloud Sleuth提供了分布式追踪(distributed tracing)的一个解决方案.其基本思路是在服务调用的请求和响应中加入ID,标明上下游请求的关系.利用这些信息,可以方 ...

  6. jdk8 分隔字符串最新方法

    //已字符串分隔方法最新 方法 StringJoiner stringJoiner=new StringJoiner(","); stringJoiner.add("a& ...

  7. 05 Tensorflow中变量的初始化

    打开Python Shell,输入import tensorflow as tf,然后可以执行以下代码. 1.创建一个2*3的矩阵,并让所有元素的值为0.(类型为tf.float) a = tf.ze ...

  8. OSI七层协议模型、TCP/IP四层模型和五层协议体系结构之间的关系

    一.OSI七层模型 OSI七层协议模型主要是:应用层(Application).表示层(Presentation).会话层(Session).传输层(Transport).网络层(Network).数 ...

  9. MyEclipse 皮肤、主题、背景色

    第一步:打开myeclipse--->help--->install from site--->Add将路径粘贴在这里.等待安装颜色主题.https://raw.github.com ...

  10. JavaScript 系列博客(四)

    JavaScript 系列博客之(四) 前言 本篇介绍 JavaScript 中的对象.在第一篇博客中已经说到 JavaScript 是一种''对象模型''语言.所以可以这样说,对象是 JavaScr ...