1 预加载
2 视频暂停、播放
3 图片从下到上由浅入深显示
4 兼容问题
4.1 IOS
4.2 安卓
4.3 其他
1 背景
原生video标签的使用
1 预加载
进入主内容有一个加载页。
技术实现
视频预加载使用video标签的preload属性。
将preload属性设置为metadata表示用户不想马上加载视频,但是需要预先获取其元数据(尺寸,轨道列表,时长等)。 请注意,从 Chrome 64 开始, preload 的默认值是 metadata(以前是 auto )。
<video id="video" preload="metadata" src="file.mp4" controls></video>
将 preload 属性设置为 auto 表示浏览器将缓存整个视频,无需暂停缓冲,可以支持完整播放。
<video id="video" preload="auto" src="file.mp4" controls></video>
这里使用的是 preload 属性设置为 auto,利用 loadedmetadata 监听是否加载完成。
video.addEventListener('loadedmetadata', function() {
if (video.buffered.length === 0) return;
const bufferedSeconds = video.buffered.end(0) - video.buffered.start(0);
console.log(bufferedSeconds + ' seconds of video are ready to play!');
});
由于 preload属性只是一个提示,浏览器可能会完全忽略 preload属性。写到这,请注意以下Chrome中的一些应用规则:
• 启用 Data Saver后 ,Chrome 会强制设置 preload 值为 none 。
• 在 Android 4.3中,由于 Android 的 bug,Chrome 会强制设置 preload 值为 none。
• 在蜂窝连接(2G,3G和4G)时,Chrome 会强制设置 preload 值为 metadata 。
2 视频暂停、播放
技术实现
利用 video 标签的 play() 和 pause() 方法实现播放和暂停,利用 timeupdate() 来监听视频的播放时间。
具体实现如下:
const myVideo = this.refs.video as HTMLAudioElement;
myVideo.addEventListener("timeupdate", () => {
const currentTime = myVideo.currentTime;
if (Math.floor(currentTime) === Math.floor(arrPauseTime[time])) {
myVideo.pause();
// myVideo.play();
return ;
}
})
3 图片从下到上由浅入深显示
技术实现
图片从下到上由浅入深显示。 样式上实现利用 filter 控制透明度,transition 定义切换效果,transform 位置变换。
.Bottom {
width: 100%;
height: 400px;
position: absolute;
bottom: -30px;
font-size: 32px;
color: #fff;
filter: opacity(0);
}
.Bottom.dyn {
filter: opacity(1);
transition: all 2s ease-in;
transform:translateY(-30px);
}
4 兼容问题
项目只要涉及M端,兼容问题就是一个不变的话题,本次也遇到一些兼容问题,记录下来以备后续方便查看。
4.1 IOS
4.1.1 点击落地页跳转链接后再回退不刷新页面
这里使用 popstate 来监听浏览器的回退操作。
其中 history.replaceState 更新当前的state对象或者当前历史实体的URL,第二个参数为空来传递空字符串应该可以防止将来对方法的更改。location.reload 用来刷新当前页面。
if (isIOS) {
window.addEventListener("popstate", () => {
window.location.reload(true);
}, false);
const state = {
title : "",
url : "#"
};
window.history.replaceState(state, "", "#");
}
4.1.2 视频播放过程中放入后台运行,再次进入视频播放出现问题
当我们点击了 Home 按钮,切换回主屏幕;进入任务切换窗口,切换到另一个 App放入后台运行,visibilitychange 监听页面的可见性,会有三个状态。
a. hidden:页面彻底不可见。
b. visible:页面至少一部分可见。
c. prerender:页面即将或正在渲染,处于不可见状态。
手机上的情况大多是页面进入后台,就是彻底不可见的时候,利用 document.hidden 通过判断页面显示与否来进行相应的处理。
if (isIOS) {
const myVideo = this.refs.video as HTMLAudioElement;
document.addEventListener("visibilitychange", () => {
if (document.hidden) {
myVideo.pause()
} else {
setTimeout(() => {
myVideo.play()
}, 1500)
}
});
}
注意:要有延迟,没有延迟的话,不生效;
4.2 安卓
4.2.1 video标签视频首次 play() 不生效
视频没有设置自动播放,利用 play() 进行播放,但是安卓端首次不生效,区分安卓和ios,在安卓上增加用户引导按钮,当用户点击体验后控制播放。
4.2.2 禁止横屏播放
x5-video-player-fullscreen="true"
x5-video-player-fullscreen:全屏设置。它有两个属性值,ture和false,true支持全屏播放防止横屏,false不支持全屏播放。其实,IOS 微信浏览器是Chrome的内核,相关的属性都支持,也是为什么X5同层播放不支持的原因。安卓微信浏览器是X5内核,一些属性标签比如playsinline就不支持,所以始终全屏。
4.2.3 同层播放遮盖了手势dom
由于部分安卓机对于control不生效,所以这里使用同层播放属性除去了control栏。
x5-video-player-type="h5"
x5-video-player-type: 启用同层H5播放器,就是在视频全屏的时候,div可以呈现在视频层上,也是WeChat安卓版特有的属性。同层播放别名也叫做沉浸式播放,播放的时候看似全屏,但是已经除去了control和微信的导航栏,只留下"X"和"<"两键。目前的同层播放器只在Android(包括微信)上生效,暂时不支持iOS。至于为什么同层播放只对安卓开放,是因为安卓不能像ISO一样局域播放,默认的全屏会使得一些界面操作被阻拦,如果是全屏H5还好,但是做直播的话,诸如弹幕那样的功能就无法实现了,所以这时候同层播放的概念就解决了这个问题。
对于手势dom的层级进行控制来解决这个问题。
4.2.4 同层播放界面默认出现"X"和"<"两键。
关闭或者返回视频都会提前结束视频获取不到最后视频播放完后的落地页,所以这部分利用监听页面大小的改变来处理退出全屏情况下的场景。
window.addEventListener('resize', () => {
//....
});
4.3 其他
4.3.1 视频开始播放时黑屏
如果网络慢,视频从开始播到能展现画面会有短暂的黑屏(处理视频源数据的时间),为了避免这个黑屏。
poster="/xxx.png"
其中,poster 属性规定视频下载时显示的图像,或者在用户点击播放按钮前显示的图像。如果未设置该属性,则使用视频的第一帧来代替。也可以在视频上加个div浮层(可以一个假的视频第一帧),然后用timeupdate方法监听,视屏播放及有画面的时候再移除浮层。
4.3.2 timeupdate的触发频率不是固定的
由于要监听当前视频的播放时间,所以会用到 timeupdate 事件,测试过程中发现的 timeupdate 触发频率不是固定的,每秒更新几次不等,设置差值时间不能用等于(用大于或小于),也不能太小,我这里用了 Math.floor() 向下取整返回小于或等于一个给定数字的最大整数。
if (Math.floor(currentTime) === Math.floor(pauseTime) && temp === 0) {
// ...
temp ++;
}
注意:
a. timeupdate 每秒更新几次不等,所以只要满足条件下脚本都会执行,这里我用了一个标志位加数来控制只执行一次。
b. android下一开始监听时有会出现video.duration为空,计算出NaN,要确保差值不为NaN,需要做判断,保证计算的差值是一个存在的数值。
参考:
https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/video
https://developer.mozilla.org/zh-CN/docs/Web/Guide/Events/Media_events
https://segmentfault.com/a/1190000009395289