原文:如何監聽頁面關閉或刷新動做-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;
}
複製代碼