計算一個頁面內每個模塊的曝光時間(停留時間)
產品希望看到投放出去的活動頁,用戶對其頁面內的什麼信息比較感興趣,對什麼信息完全不感興趣。=> 計算頁面內每模塊的停留時間
第一次聽到這個需求,我的大腦開始瘋狂運轉,然後想到了plan 1, plan 2, plan3...中間還有很多失敗想法我已經忘記了,這裏方案三是我最終採用的方法。
方案一:根據頁面dom將頁面分模塊
var bodyChildrenLists = $('body').children()
var bodyChildDomLsit = []
var initHeight = 0
for (var i = 0; i < bodyChildrenLists.length; i++) {
if (bodyChildrenLists[i].tagName !== 'SCRIPT') {
bodyChildDomLsit.push({
className: bodyChildrenLists[i].className,
height: bodyChildrenLists[i].offsetHeight
})
}
}
存在的問題:
不同人的代碼風格差異性大,該方案不適合這類代碼風格
<body>
<div class="container">
<div class="header"></div>
<div class="nav"></div>
<div class="footer"></div>
</div>
</body>
這種方式很好,就是,,,如果大家的代碼風格很一致的情況下使用比較好。
方案二:計算出用戶打開頁面後的所有行爲
var scrollTop = 0
var time = Date.now()
window._stayStatus = {
// 記錄運動軌跡, down > 1 向下移動 down 向上移動, sliderDis 移動距離, time 移動耗時, initDis 初始距離, initTime 初始時間
moveData: [],
enterTime: Date.now()
}
var moveData = window._stayStatus.moveData
var currentMoveIndex = 0
function move () {
var currentTime = Date.now()
var currentScrollTop = $(window).scrollTop()
var dis = currentScrollTop - scrollTop
var disTime = currentTime - time
// 上一次滑動頁面和這次滑動頁面的時間差大於100ms,就視作用戶在某一個段時間做了停留
if (disTime > 100) {
if (moveData[currentMoveIndex] && moveData[currentMoveIndex].down === 0) {
moveData[currentMoveIndex].time += disTime
} else {
moveData.push({
down: 0,
initTime: time, // initTime表示進入該狀態的初始時間
initDis: currentScrollTop, //initDis 表示進入該狀態的初始位置
sliderDis: dis, // 在該狀態內滑動的距離
time: disTime // 在該狀態經歷的時間(ms)
})
}
} else {
// 向下滑動
if (dis >= 0) {
// 如果之前已經是向下滑動的狀態,只需要在原來的數據上累加滑動距離和滑動時間
if (moveData[currentMoveIndex] && moveData[currentMoveIndex].down > 0) {
moveData[currentMoveIndex].sliderDis += dis
moveData[currentMoveIndex].time += disTime
} else {
moveData.push({
down: 1,
initTime: currentTime,
initDis: currentScrollTop,
sliderDis: dis,
time: disTime
})
}
} else {
if (moveData[currentMoveIndex] && moveData[currentMoveIndex].down < 0) {
moveData[currentMoveIndex].sliderDis += dis
moveData[currentMoveIndex].time += disTime
} else {
moveData.push({
down: -1,
initTime: currentTime,
initDis: currentScrollTop,
sliderDis: dis,
time: disTime
})
}
}
}
currentMoveIndex = moveData.length - 1
time = currentTime
scrollTop = currentScrollTop
}
window.onscroll = function (e) {
move()
}
根據以上方法獲取到的數據如下:
表示:用戶在距頂部2px時停留了2728ms後,向下滑動了612px,滑動時間爲595ms,然後又在距頂部612px停留了8649ms,最後向上滑動了604px,經歷了167ms。
存在的問題:
最後得到的數據量雖然不會很大,但是將這樣的數據給數據組分析,存在一定的難度。這是在沒有和產品對接時,自己想的辦法,有點想複雜了。但是這種方式可以比較生動模擬出用戶的行爲。
方案三: 固定模塊尺寸,計算每模塊的停留時間
與我的產品對接了基本的規定:
- 每1300px高度作爲爲一個模塊,進行埋點統計。
- 每屏曝光範圍大於400px時作爲有效曝光,開始記錄時長。
- 每一模塊的上報時間均爲在模塊內滑動時間及靜止停留時間加和。
- 設當前模塊爲模塊0,當用戶未到達模塊1時,反覆滑動時間均記做模塊0內時間。
- 設當前模塊爲模塊0,當用戶到達模塊1後又通過滑動行爲返回模塊0,此時會重新記錄一次模塊0數據
- 最後一次上報時間爲用戶離開該頁面(進入下一流程頁面或關閉瀏覽器),需統計能夠監測到的用戶離開行爲及場景。
根據以上需求,我做了一個小demo,代碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="//lib04.xesimg.com/lib/jQuery/1.11.1/jquery.min.js"> </script>
<script src="//zt.xueersi.com/apStatic/js/qz-rem.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
.section {
height: 1300px;
border-bottom: 1px solid #f00;
box-sizing: border-box;
padding-top: 400px;
}
</style>
</head>
<body>
<div id="app">
<div class="section">
<p>停留時間0:</p>
<p v-for="item in movedata" v-if="parseInt(item.pos / 1300) === 0">{{0}} ---- {{item.time}}</p>
</div>
<div class="section">
<p>停留時間1:</p>
<p v-for="item in movedata" v-if="parseInt(item.pos / 1300) === 1">{{1}} ---- {{item.time}}</p>
</div>
<div class="section">
<p>停留時間2:</p>
<p v-for="item in movedata" v-if="parseInt(item.pos / 1300) === 2">{{2}} ---- {{item.time}}</p>
</div>
<div class="section">
<p>停留時間3:</p>
<p v-for="item in movedata" v-if="parseInt(item.pos / 1300) === 3">{{3}} ---- {{item.time}}</p>
</div>
<div class="section">
<p>停留時間4:</p>
<p v-for="item in movedata" v-if="parseInt(item.pos / 1300) === 4">{{4}} ---- {{item.time}}</p>
</div>
<div class="section">
<p>停留時間5:</p>
<p v-for="item in movedata" v-if="parseInt(item.pos / 1300) === 5">{{5}} ---- {{item.time}}</p>
</div>
<div class="section">
<p>停留時間6:</p>
<p v-for="item in movedata" v-if="parseInt(item.pos / 1300) === 6">{{6}} ---- {{item.time}}</p>
</div>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script>
new Vue({
el: '#app',
data: {
movedata: [],
scrollTop: $(window).scrollTop(),
time: Date.now(),
stayTime: 0
},
mounted () {
// 部分頁面存在頁面滾動到某一高度時,刷新後頁面也會固定在該高度的問題,初始化movedata數據
var index = parseInt(this.scrollTop / 1300) + 1
for (var i = 0; i <= index; i++) {
this.movedata.push({
pos: i * 1300,
time: 0
})
}
window.onscroll = () => {
this.scrollTop = $(window).scrollTop()
}
setInterval(() => {
var currentTime = Date.now()
var disTime = currentTime - this.time
// 計算當前是展現在屏幕中的模塊序號,一個屏幕內最多展現兩個模塊,currentIndex永遠指定的是上面的模塊
var currentIndex = parseInt(this.scrollTop / 1300)
var length = this.movedata.length
if (currentIndex + 1 >= length) {
for (var i = length; i <= currentIndex + 1; i++) {
this.movedata.push({
pos: 1300 * i,
time: disTime
})
}
} else {
// 計算當前的滾動高度超出滿屏的多少
var modeDis = this.scrollTop - this.movedata[currentIndex].pos
// 表示一屏中上面的模塊展示區域超過400,可以累加停留時間
if ((1300 - modeDis) > 400) {
this.movedata[currentIndex].time += disTime
}
// 表示一屏中下面的模塊展示區域超過400,可以累加停留時間
if (modeDis > 400) {
this.movedata[currentIndex + 1].time += disTime
}
}
this.time = currentTime
}, 1000)
}
})
</script>
</body>
</html>
使用這種方式,movedata的數組長度等於頁面內的模塊個數