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