之前因为要实现视频的自动播放,就先做了一个原生的视频自动播放demo,但是真的想要在实际的项目中实现起来就步步是坑。坑,我已经踩过了,在这里分享一下react在移动端中如何实现视频的自动播放。

项目背景

这个项目是react结合Ios和Android实现的一个APP,应甲方爸爸的要求,实现一个朋友圈内视频的自动播放。大概就是这个样式。

需求分析

当拿到需求的时候第一反应应该就是去百度了吧。网上有很多列子,也有很多踩坑的经验,但是看下来很少有实际完成的。我们逐步来分析一下这个需求:

大方向是实现视频的自动播放,这是我们的主方向,确定!
根据这个我们可以先考虑一下以下几个问题

  1. 应该如何去创建视频元素
  2. 在什么的情况下才去播放这个视频?
  3. 然后在什么情况下,去暂停这个视频?
  4. 又怎么去视频去播放,怎么去暂停?
  5. 我们如何获取到当前是哪个视频?
  6. 又怎么获取到下一个即将来临的视频?
  7. 如何去兼容IOS和Android?
    这是我们在拿到这个需求之后所想到的问题,如果能够顺利的解决这些问题,那我们也就完成了这个需求。下面我们去实现它
实现
1.应该如何去创建视频元素

我们逐个的解决这些问题,先看第一个,《应该如何去创建视频元素》
上文有说到,这是在一个相当于在朋友圈一样的页面下实现的,第一步应该去搭建这个页面,都知道在朋友圈的内容很丰富,有图片,文字,视频,也有可能是两两结合。我建议在做结构搭建的时候用如下的结构:

<div><span>text</span><img></img><video> </video></div>

其主要目的是,有专门的盒子去装载这些内容,这个很重要。因为需要通过获取这个div来获取到div下的video
在这里讲解一下为什么要这么做,也就是实现这个需求的整体思路:在实现的过程中要先判断包含有video标签的div是否被滑到了可视区内,因为所处的环境需要渲染不同的DOM元素,所以每当一个div滑动到可视区内的时候都要用getElementsByTagName("video")来判断这个盒子里是否有video,如果有触发播放事件,如果没有,没有就算了,这是这个需求的整体思路,但是涉及到移动端的如何获取滚动高度,盒子是否滚动到可视区内,获取body的整体高度,video的一下元素属性等。

这里插播一些video的一些属性,和会出现的一些坑

  1. 在ios环境下,视频会被自动全屏播放,安卓环境下还好,为了应对这个问题我们需要一下两个属性:webkit-playsinline='true' playsInline={true},这两个属性规定了video不全屏播放。
  2. 以上两个属性的使用似乎还需要IOS和Android的配合,具体如何配置可自行百度
  3. IOS上触发视频自动播放时,如果视频未加载至可以播放的状态时会出现白屏现象,这个后面会写到我的处理方法。
  4. 浏览器有一个机制,会禁止视频的自动播放,需要用户去触发。把视频做成静音播放即可。属性:muted={true},否则会报错

接下来是关键的一步

2.在什么时候播放视频

应该在什么时候开始播放这个视频呢,答案实际大家都知道,当包含有video的盒子被滚动到可视区内,或者说是屏幕中央时开始播放视频,但是我们如何去判断盒子是否在我们想要的位置呢。接下来要用的阮一峰老师的用Javascript获取页面元素的位置这篇文章中的及段代码,这里先列举出来

// 文档的总高度getScrollHeight = () => {let bSH = '';let dSH = '';let scrollHeight = 0;if (document.body) {bSH = document.body.scrollHeight;}if (document.documentElement) {dSH = document.documentElement.scrollHeight;}scrollHeight = (bSH - dSH > 0) ? bSH : dSH;return scrollHeight;}// 浏览器的总高度getWindowHeight=() => {let windowHeight = 0;if (document.compatMode === "CSS1Compat") {windowHeight = document.documentElement.clientHeight;} else {windowHeight = document.body.clientHeight;}return windowHeight;}// 滚动条在Y轴上滚动的距离getScrollTop = () => {let scrollTop = 0, bodyScrollTop = 0, documentScrollTop = 0;if (document.body) {bodyScrollTop = document.body.scrollTop;}if (document.documentElement) {documentScrollTop = document.documentElement.scrollTop;}scrollTop = (bodyScrollTop - documentScrollTop > 0) ? bodyScrollTop : documentScrollTop;return scrollTop;}//获取DOM元素滚动的距离getElementViewTop = (element) => {let actualTop = element.offsetTop;let current = element.offsetParent;let elementScrollTop = '';while (current !== null) {actualTop += current.offsetTop;current = current.offsetParent;}if (document.body.scrollTop === 0) {elementScrollTop = document.documentElement.scrollTop;} else {elementScrollTop = document.body.scrollTop;}return actualTop - elementScrollTop;}

以上四个方法是实现这个需求的关键,

其中getScrollHeightgetWindowHeightgetScrollTop获取文档的总高度,在后面能够用到。getElementViewTop获取DOM元素滚动的距离是这个需求的灵魂所在。

有了这几个关键的方法,我们就可以动手实现自动播放了

  • 判断盒子是否滚动到相应位置,那就必须去监听滚动事件
window.addEventListener('scroll', this.winScroll);

这里有人会说我们是在移动端上实现的是不是应该去监听Touch事件,实际上是没有那个必要的,而且相对于滚动事件,Touch事件没有那么灵敏,而且会有一个惯性的滚动,这时候是不会被监听到的。是可以被禁掉,但是总体体验起来并不是很好。
至于是监听scroll还是Touch关键点是如何有效的获取到滚动的距离和发生滚动的这一动作
看代码:

elementScrollTop = document.documentElement.scrollTop || document.body.scrollTop

每个浏览器获取scrollTop的方法不尽相同,但是document.documentElement.scrollTopdocument.body.scrollTop只有一个能获取到值,也就是说当其中一个获取到值以后,另外一个就会为0,搞定了这里就不需要在去纠结是监听scroll还是Touch,有了监听事件后,就要去完善winScroll这个方法了。

winScroll = (e) => {let { videoIndex } = this.state; // 设置一个初始值,来获取div盒子let clientData = this.getViewport(); // 获取可视区的大小DOMobj = document.getElementById(`content_${videoIndex}`); // 获取div盒子let viedos = DOMobj.getElementsByTagName("video"); // 获取盒子下的video标签cliHeight = (clientData.height - DOMobj.offsetHeight) / 2; // 这里的cliHeight 是设置一个滑动的范围 let arr = this.getElementViewTop(DOMobj); // 原谅这里的不规范  arr 是用来保存获取到盒子距离顶部的距离if (viedos.length === 1) { // 判断当前盒子是否含有videoif (arr <= cliHeight && -arr <= DOMobj.offsetHeight / 2) { // 滑动到此范围内播放,滑出暂停viedos[0].controls = false; // 看下方解释viedos[0].play();} else {viedos[0].pause();}}this.changeVideoIndex(DOMobj); // 获取下一个盒子的方法};
3. 样式处理
viedos[0].controls = false

了解video的知道controls是控制是否显示浏览器自带的控制栏,这里处理的问题是上文说的IOS视频未加载好视频时出现白屏的情况,如果有controls会触发video自带的加载样式,而且能够有效的规避掉出现白屏的情况。但是还是会有问题
如果网速过慢,视频过大,加载时间长,就会影响隐藏controls
我做的处理是先隐藏controls在去执行播放,这样效果会好很多

另外看下在IOS和Android中导航栏的样式

这是Android上的,效果很不好,而且白屏的情况只在IOS 的环境下才会出现,所以我加了一个方法

getMODEL =() => {let client = '';if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) { //判断iPhone|iPad|iPod|iOSclient = 'iOS';} else if (/(Android)/i.test(navigator.userAgent)) { //判断Androidclient = 'Android';} else {client = 'PC';}return client;}

这里是获取当前设备环境,如果是IOS环境controls设定为true

4.触底

还有一种情况:当滚动条滚动到底部的时候还有一个视频没有被触发该如何处理,
我们需要在往winScroll方法中添加一下的方法

if (this.getScrollTop() + this.getWindowHeight() === this.getScrollHeight()) { // 判断是否触底,触底后索引值➕1this.setState({videoIndex: videoIndex += 1});if (viedos.length === 1) { // 判断倒数第二哥盒子是否有视频,有则停止播放viedos[0].pause();}DOMobj = document.getElementById(`content_${videoIndex}`); // 获取最后一个盒子viedos = DOMobj.getElementsByTagName("video");if (viedos.length === 1) {viedos[0].play();}}
5.什么时候获取下一个盒子

当我们获取到的盒子被滑出了可视区后,我们需要去获取下一个盒子

// 随着滚动改变videoIndexchangeVideoIndex = (dom) => {let { videoIndex } = this.state;let arr = this.getElementViewTop(dom);// console.log(arr);if (-arr > dom.offsetHeight / 2 - 100) { // 这里是实际控制视频到那个位置播放的判断,因为只有videoIndex改变了才会去改变获取到的DOMobjthis.setState({videoIndex: videoIndex += 1});} else if (-arr < 0) {if (videoIndex > 0) {this.setState({videoIndex: videoIndex -= 1});}}}

这就是winScroll中最后调用的那个方法。

到这里我们的需求基本上就实现了,当然环境不一样可能也会出现不同的问题,有问题可以发出来我们共同探讨。

最后我们的video标签应该是这样的

      <video  controls={type === 'iOS' ? true : false} poster={cover} muted={true} webkit-playsinline='true' playsInline={true} x5-playsinline='true' x-webkit-airplay='allow' preload='true'></video>

preload='true'这个属性是video进行预加载,我本以为可以解决白屏的问题,但是不行。
x-webkit-airplay="true"支持Airplay的设备(如:音箱、Apple TV)播放,如果没有需要可以不加

以上种种方法我这里属性和命名都存在不规范的行为,所以请广大程序员的体谅,有些地方在性能方法考虑的还不是很周到,欢迎大佬改良,批评指正。

写到最后有的人可能会说滚动事件触发的那么多,为什么不做防抖和节流的处理。我是这样想的:没必要

总结一下以上方法没有处理好的问题:

  1. 如何有效的规避掉IOS出现白屏的问题
  2. 实际我对视频是否播放和暂停的区间设置的并不是很准确,会出现同时有两个视频一起播放的问题。受第一个评论的大佬启发,可以在加一个方法,当下一个为video即将播放就暂停上一个的播放。如果觉得麻烦就把播放和暂停的区间设置的更加准确一点
分享一下心得

整个做完感觉很简单,但是在实现的过程中就会遇到很多坑,各种兼容问题,适配问题,样式问题等等。没遇到一个坑的时候就意味着我们又可以学到一个新的知识。
第一次拿到这个需求的时候也是抱着试试态度,当时没多想就用原生编写了一个demo,但是真正的拿到项目中的时候就发现问题了而且一度感觉这个东西很不好搞,但是满满的整理好思路逐个击破也就正好了。
这里我想说,当我们拿到一个需求的时候先去定一个最终的目标,然后在化解成一个个的小目标,最后就汇总成了我们自己的思维导图,在从后往前逐个完成就好了

基于react的移动端的视频自动播放功能已完成,有问题可以留言,有新的方式欢迎大佬指导。

react 移动端 实现video的自动播放相关推荐

  1. 微信公众号网页 H5 video 标签自动播放

    目录 微信公众号网页 H5 video 标签自动播放 问题描述 解决方案 微信公众号网页 H5 video 标签自动播放 环境:微信公众号网页 需求:H5 video 标签自动播放视频 video 标 ...

  2. 苹果mac系统下浏览器video无法自动播放问题

    我们在做手机Android/iOS开发的时候,声音一般都是无法自动播放的,桌面PC版的Safari浏览器在2017年也宣布禁止带有声音的多媒体自动播放功能,后来谷歌发布了最新的Chrome 66浏览器 ...

  3. 一个页面同时使用两个video标签自动播放在各个移动端浏览器存在的问题

    双video标签(一个为背景,一个屏幕居中展示)在各大浏览器中存在的问题: 移动端 一.安卓端: 1.华为自带浏览器:两个视频可以同时自动播放,但自动播放时默认都是静音播放. 2.百度浏览器:上方视频 ...

  4. 解决微信浏览器video标签自动播放视频失效

    正常在浏览器好好的视频,在微信内置浏览器中点击播放全屏,样式也不一样,自动播放失效.罪魁祸首是微信把video标签都成微信规则的了.下面方式可以解决视频播放全屏以及不能自动播放的问题. <vid ...

  5. video怎么自动播放

    要让视频自动播放,需要在 HTML 代码中将视频标签的 "autoplay" 属性设置为 "autoplay". 例如: <video src=" ...

  6. 解决在IOS系统及微信中audio、video不能自动播放的问题

    <video id="shakeVideo" src='video/shakingRedbagVideo.mp4' autoplay="autoplay" ...

  7. html 添加audio 无法自动播放,移动端不支持audio自动播放解决方案

    在开发webapp时,有时候你可能要加点背景音乐,这时我们会用到HTML5音频Audio. 你可能会这样写: 您的浏览器不支持音频播放. 做完后我们放PC端测试可以完美的进行自动播放(当然,是在你浏览 ...

  8. html5的video标签自动播放处理方法

    网上有很多解决方案,都不能真正的解决问题,于是自己尝试了一下. video 标签属性 src: 设置显示视频路径 controls: 显示控制栏 loop: 控制视频循环播放 autoplay: 自动 ...

  9. pc端、移动端插入背景音乐,自动播放,循环播放

    css代码(让音乐小图片在播放的时候自动旋转): .close_music_div img{animation:run 5s linear 0s infinite; } @keyframes run{ ...

  10. html5视频插件video不自动播放解决

    视频不能自动播放,而不能像网上的很多视频那样一开始就能播放(边下边放),造成这个问题的原因是一些描述mp4文件信息的moov atom元数据默认放置在了视频文件的最后,而所有的播放器(包括独立的.网络 ...

最新文章

  1. mysql存储base64位用什么类型_【漫画】面试现场:为什么MySQL数据库要用B+树存储索引?...
  2. OS / Linux / 系统阻塞在系统调用中时如果收到信号,系统如何处理?
  3. (转载)你好,C++(19)“老师,我这次四级考试过了没有?”——4.2 条件选择语句...
  4. centos-安装ifconfig
  5. android磁场传感器页面布局在哪,基于磁场检测的寻线小车传感器布局研究
  6. Django实现一个简单的中间件,不熟悉中间件的爬坑之路
  7. 美国纽约拟将电话亭变WiFi热点
  8. (@WhiteTaken)设计模式学习——组合模式
  9. ffmpeg.c函数结构简单分析(画图)
  10. Java多商户商城源码 PC+小程序+APP源码+H5 B2B2C商城源码
  11. Word给自动生成的目录页码添加括号
  12. RETINA 屏幕1px 边框实现
  13. python100天-如何系统地学习 Python,100天从新手到大师
  14. Vue刷新组件,页面刷新
  15. Python中单元测试和类的测试
  16. PHP之深度剖析:网站唯一登录,踢人效果
  17. 大数据----------------R语言下依赖库与依赖包的安装
  18. 前端、vue、Vue3弹幕实现;前端CSS实现弹幕
  19. 李大学:CTO,应该像CEO一样思考
  20. Linux系统下的nobody用户与nologin

热门文章

  1. 强化学习课程笔记之policy-based方法
  2. [已解决]VitrualBox 启动linux虚拟机后,无法访问网络解决方法
  3. matlab计算器设计流程图_matlab计算器设计
  4. 嵌入式linux调试dsi,DSI device tree configuration
  5. 关于南京市大学生办理住房补贴的流程示意图
  6. 原神 - 米游社 每日签到
  7. 如何连接新浪sae共享数据库
  8. linux内核将新驱动添加到menuconfig菜单
  9. 基于Ingress实现灰度发布(金丝雀发布)和蓝绿发布
  10. Acer 4750 安装黑苹果_傻瓜式黑苹果安装神器