利用 IntersectionObserver 实现自定义埋点曝光指令
visually.ts
ts
export default (Vue) => {
const options = {
root: null, // 默认浏览器视窗
threshold: 1 // 元素完全出现在浏览器视窗内才执行 callback 函数。
}
const timer = {} // 增加定时器对象
// 当元素的移动趋势是出现在视窗内部时,元素全部在浏览器视窗内才会触发此 callback。
// 此时 entry.isIntersecting 为 true
// 当元素的移动趋势是离开视窗时,元素一触碰到视窗边界就会触发此 callback
// 此时 entry.isIntersecting 为 false
const callback = (entries, observer) => {
entries.forEach(entry => {
let visuallyData = null
try {
visuallyData = JSON.parse(entry.target.getAttribute('visually-data'))
} catch (e) {
visuallyData = null
console.error('埋点数据格式异常', e)
}
// 没有埋点数据取消上报
if (!visuallyData) {
observer.unobserve(entry.target)
return
}
// 必须出现在视窗内 5 秒以上,才会上报埋点信息
if (entry.isIntersecting) {
timer[visuallyData.id] = setTimeout(function () {
// 上报埋点信息
// sendUtm(visuallyData).then(res => {
// if (res.success) {
// // 上报成功后取消监听
// observer.unobserve(entry.target)
// visuallyList.push(visuallyData.id)
// timer[visuallyData.id] = null
// }
// })
}, 5000)
} else {
if (timer[visuallyData.id]) {
clearTimeout(timer[visuallyData.id])
timer[visuallyData.id] = null
}
}
})
}
const observer = new IntersectionObserver(callback, options)
const visuallyList = [] // 记录已经上报过的埋点信息
const addListenner = (ele, binding) => {
if (visuallyList.indexOf(binding.value) !== -1) return
observer.observe(ele)
}
const removeListener = (ele) => {
observer.unobserve(ele)
}
// 自定义曝光指令
Vue.directive('visually', {
bind: addListenner,
unbind: removeListener
})
}注册
ts
import visually from '@/directives/visually'
Vue.use(visually)使用
html
<h1
v-visually
:visually-data="JSON.stringify({a:1,b:2})"
style="border: 1px solid red;"
>
This is an about page
</h1>