原文:如何监听页面关闭或刷新动做-fengxianqiphp
其实这篇文章也能够叫如何监听并上传用户观看的视频时长。最近有需求作到,监听用户播放视频的动做并上报播放事件,须要上报的是用户观看视频的时长。这里就有几种状况了,一是用户点击播放,而后直到视频播放完毕,触发video.ended事件,此时上报用户的观看时长,这个比较好处理。第二种状况是用户点击播放后离开或刷新页面,在用户离开前须要把事件上报,这里主要会触发window.onunload事件,看起来能够作到,其实有坑。html
因为公司采用的技术方案是.m3u8(hls),而这种格式目前PC浏览器只有Safari才支持,chrome、Firefox或移动端安卓其余的大部分浏览器都不支持播放这种格式。所以,用原生video标签的方案是不行了,得找一些插件或播放器。最终选择了DPlayer这个播放器,一个比较不错的开源播放器,简单易用。 说回正事,上报用户观看视频的时长。ios
经评论区 @音客 指点,使用Navigator.sendBeacon()将会更好的支持上报事件,这是一个专门处理数据埋点的api,可是使用时请注意浏览器兼容性问题,目前(2018.06)移动端Android 5以上支持,ios须要11.3版本以上,具体请看CanIUse。 本篇使用new Image()
方法能够做为sendBeacon()
的不兼容时的降级处理方法,更多请参考:使用 navigator.sendBeacon() 上报数据。ajax
用户观看视频结束时上报观看时长。chrome
const dp = new DPlayer({
container: document.getElementById('dplayer'),
screenshot: true,
video: {
url: 'xx.m3u8',
pic: 'xx.jpg',
type: 'customHls',
customType: {
'customHls': function (video, player) {
const hls = new Hls();
hls.loadSource(video.src);
hls.attachMedia(video);
}
}
}
});
// 是否播放的标记
var isPlay = false;
dp.on('play', function () {
console.log('player start');
isPlay = true;
});
复制代码
dp.on('ended', function () {
console.log('player ended');
sendVideoPlayEvent(); //上报事件方法
isPlay = false;
});
复制代码
用户关闭页面或刷新浏览器时会触发onunload
事件,用户开始观看视频到离开页面,这一段时间就是用户观看视频的时长。api
window.onunload = function () {
sendVideoPlayEvent();
isPlay = false;
console.log('onunload');
};
复制代码
经测试发现,sendVideoPlayEvent时,若是采用ajax,不管是post或get方式,将无效。这里的缘由多是页面关闭太快,ajax没法执行。 查了不少解决方案,最后发现,须要经过巧妙的方法来发起这个事件。就是利用img标签的src属性,将img插入到body中时会发起一个请求来获取资源,而服务端能够对这个路由进行处理,最后发现这种方法是可行的,成功地在onunload中上报事件了。浏览器
function sendVideoPlayEvent() {
if (isPlay) {
var videoId = getQueryString('videoId');
var duration = dp.video.currentTime; // 视频播放时间能够直接经过currentTime得到
var img = new Image();
img.style.display = 'none';
img.src = `/api/video/play?duration=${duration}&videoId=${videoId}`; // 服务端处理接口
document.body.appendChild(img);
}
}
function getQueryString(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
var r = window.location.search.substr(1).match(reg);
if (r != null) return unescape(r[2]); return null;
}
复制代码