1.需求
朋友的一个公众号线上商城需要使用视频播放功能
- 后台 上传视频+视频封面
- 前台 视频列表使用后台上传封面展示(播放视频完成后也只显示封面图)
- 前台 视频点击后全屏播放(自定义的样式,而为微信提供的默认视频播放)
- 为减轻服务器压力,使用七牛云存储上传
2. 当时的思路整理
一开始想的很简单,①后台上传-> ②七牛云存储-> ③视频链接存储数据库-> ④前台显示
3. 产生问题
①②③很快解决了
但是④前台使用 在微信中 html5
- 苹果 video标签加载好,poster 封面正常显示,点击播放为苹果自带的视频播放逻辑,但退出播放后,封面图消失。
- 安卓 video标签加载时,poster封面一闪而过,然后将视频中的第一帧作为封面显示了(视频尺寸横竖宽高都不一样),然后视频播放为x5内核浏览器默认的视频播放逻辑,播放完后有令人讨厌的广告。
4.解决问题
上述得知 poster封面一闪而过 的问题的原因了,poster写得很清楚,播放了poster就失效了!
- poster失效的解决思路
页面加载后,将上传的封面图显示,外加一个三角播放图,视频隐藏
用户点击此区域,执行视频的显示、播放,封面图的隐藏
用户退出视频播放,执行视频的隐藏、暂停,封面图的显示
大概代码如下
① 页面加载
// html文件
// js文件
②用户点击(关键代码)
//js文件
function switchPlay(obj){
var videoObj = $(obj).find(".video1")
var locate_poster = $(obj).find(".video-preview")
//如果是播放状态的视频,则切换视频为暂停并隐藏,显示封面
if(videoObj.attr("data-box-flag")=="true" || videoObj.attr("data-box-flag")==true){
videoObj.get(0).pause();
videoObj.hide()
locate_poster.show();
}
else{
videoObj.show()
locate_poster.hide();
videoObj.get(0).play()
}
}
- 微信X5内核浏览器的官方文档关于H5同层播放器的说明
x5-video-player-type 启用H5同层播放器
通过video属性“x5-video-player-type”声明启用同层H5播放器
同层页面内播放是标准的视频播放形态,在video标签中添加属性来控制网页内部同层播放,可以在视频上方显示html元素。
示例: https://tencentx5.github.io/x5/video_page_samelayer.htm
详情可以参考: https://docs.qq.com/doc/DTUxGdWZic0RLR29B
依此可以解决 “” 问题
//html 文件
- Safari浏览器关于 HTML5 Audio 和 Video 的指南 关于全屏进入和退出事件的触发
这边写得很清楚,ios中当视频进入或退出全屏模式,webkitbeginfullscreen 和 webkitendfullscreen 分别触发
因此解决 “” ,就有了方法
// js文件
//当点击播放时,绑定全屏事件,退出全屏时 隐藏视频和显示自定义封面图
if(isiOS){
var video = videoObj.get(0);
video.addEventListener('webkitbeginfullscreen', function() {
_exitfullscreen = false;
});
video.addEventListener("webkitendfullscreen", function(){
locate_poster.show(); //自设定的封面图显示
videoObj.hide() // 视频隐藏
loadingdiv.hide();
});
}
完后后的效果
-
安卓
-
苹果
B站做出的效果(太完美了)
轻视频引流 福利哦!!
[B站在微信打开效果非常好] (https://m.bilibili.com/index.html)
最后-完整的文件
-html文件
-css文件
.img-box-hengv{
width: 100%;
/* height: 80px; */
display: flex;
overflow-x: auto;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
}
.img-box-hengv img{
width: 33%;
}
.pro-box-hengv{
box-sizing: border-box;
position: relative;
width: calc(33%);
float: left;
position: relative;
box-shadow: 0 0px 0px rgba(0, 0, 0, 0.5);
/*padding: 5px 20px 5px;*/
text-align: center;
}
.pro-box-hengv img{
width:100%;
border-radius: 5px;
padding: 2px;
}
.preview-videos {
width: 99%;
float: left;
padding: 2px;
border-radius: 5px;
background: #ccc;
}
.video1{
display:none;
}
.pro-box-video{
cursor:pointer;
}
.playdiv{
position:absolute;top: 40%;margin-top: -25px;margin-left: -25px;left: 50%;
}
.playimg{
width:50px!important;
height:50px!important;
}
.pro-box-focus{
position: fixed;
width: 100%;
z-index: 9999;
background-color: black;
height: auto;
top: 0;
}
.pro-box-focus video{
position: absolute;
top: 50%;
left: 50%;
padding:0!important;
}
.pro-box-focus .playdiv{
top:50%!important;
position:fixed!important;
}
.video-close-btn{
position: absolute;
width: 36px;
height: 36px;
background: rgba(0,0,0,0.5) url(/weixinpl/mshop/images/icon-closew.png) no-repeat center;
right: 50px;
top: 10px;
background-size: 50%, 25%, 25%;
border-radius: 5px;
}
.loadingdiv{
position: absolute;
top: 40%;
margin-top: -8px;
margin-left: -8px;
left: 50%;
width: 16px!important;
height: 16px;
background: url(/weixinpl/common/qiniu-sdk/images/ui-anim_basic_16x16.gif) no-repeat scroll 0 0 transparent;
float: left;
z-index: 9999;
display:none;
}
.video-preview{
border-radius: 5px;
padding: 2px;
}
- js文件
/**
* 手機播放視頻時,切換全屏系列動作,兼容蘋果和安卓
* @param obj 點擊 包裹視頻整個dom
*/
var u = navigator.userAgent;
var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1; //android终端
var isiOS = u.indexOf('iPhone') > -1 ; //ios终端
var _exitfullscreen = true; //全屏标识,在此暂未用到,但是需要预留
/**
* 手機端視頻兼容播放js
* @autor raulin 20191220
* 説明:微信端以及安卓/手機 存在很多不兼容的情況,簡單的做了一些適配
* 需配合 對應的 html代碼 和 css 使用
*/
function switchPlay(obj){
var videoObj = $(obj).find(".video1") //视频
var playDiv = $(obj).find(".playdiv") // 播放按钮
var loadingdiv = $(obj).find(".loadingdiv") // 加载图
var poster = $(obj).find(".qiniu-poster") //七牛拿过来的第一张封面图,用于全屏时的 垂直居中
var locate_poster = $(obj).find(".video-preview") // 自定义封面图(为了美观)
var videohFlag = parseInt(videoObj.css("height")) //未播放前的视频高度
var pw = parseInt(poster.css("width")) //七牛封面图的宽度
var ph = parseInt(poster.css("height")) //七牛封面图的高度
var dataBoxFlag = videoObj.attr("data-box-flag") //判断是否已经进入全屏状态(安卓适用)
if(dataBoxFlag=="true" || dataBoxFlag==true){
console.log("正在蒙版中,所以不处理播放逻辑,处理缩小逻辑")
//暂停视频
videoObj.get(0).pause();
//去除模拟全屏状态
$(obj).removeClass("pro-box-focus");
$(".video-close-btn").remove(); //全屏的关闭按钮去除
$(obj).css("height","auto");
//视频尺寸位置还原
videoObj.css({"margin-left":"","margin-top":""})
videohFlag = videoObj.attr("data-videoh-flag")
videoObj.css("height",videohFlag+"px")
//显示封面图+播放按钮图,隐藏视频
locate_poster.show();
videoObj.hide()
playDiv.show()
loadingdiv.hide();
//标注全屏状态为false
videoObj.attr("data-box-flag","false")
return;
}
loadingdiv.show();
if(isiOS){
var video = videoObj.get(0);
video.addEventListener('webkitbeginfullscreen', function() {
_exitfullscreen = false;
});
video.addEventListener("webkitendfullscreen", function(){
locate_poster.show();
videoObj.hide()
loadingdiv.hide();
});
video.addEventListener('pause', function(e) {
pauseTimestamp = new Date().getTime();
console.log('触发了 暂停', pauseTimestamp);
});
videoObj.show()
locate_poster.hide();
videoObj.get(0).play()
}else{
locate_poster.hide();
videoObj.show()
videoObj.get(0).play()
$(obj).addClass("pro-box-focus");
$(obj).css("height",document.documentElement.clientHeight+"px");
videoObj.css("height","auto")
k = 0;
if(pw>0){
console.log(pw+"-"+ph)
k = parseFloat(ph/pw);
}
if(k>0){
w = document.body.clientWidth
mt = -1*(w*k)/2
}else{
mt = -1*(parseInt(videoObj.css("height"))/2)
}
ml = -1*(document.body.clientWidth/2)
videoObj.css({"margin-left":ml+"px","margin-top":mt+"px"})
playDiv.hide()
videoObj.attr("data-videoh-flag",videohFlag)
videoObj.attr("data-box-flag","true")
videoObj.attr("data-play-flag","true")
videoObj.parent().append("")
loadingdiv.hide();
}
}
/**
* 全屏狀態下 ,播放 停止 與退出
* @param obj 視頻dom / 播放按鈕dom
* @param flag 0 obj為視頻dom 1 obj為播放按鈕dom
*/
function switchplaycheck(obj,flag=0){
var videoObj = $(obj)
var playDiv = $(obj).siblings(".playdiv")
if(flag==1){
videoObj = $(obj).siblings(".video1")
playDiv = $(obj)
}
boxFlag = videoObj.attr("data-box-flag")
if(boxFlag=="false"|| boxFlag==false){
switchPlay(videoObj.parent().parent().get(0))
return;
}
console.log("点到video啦")
playFlag = videoObj.attr("data-play-flag")
if(playFlag == "true"){
videoObj.get(0).pause();
videoObj.attr("data-play-flag","false")
playDiv.show()
}else{
videoObj.get(0).play();
videoObj.attr("data-play-flag","true")
playDiv.hide()
}
}