vue 环境下,封装一个滚动模块曝光事件

516 阅读1分钟

背景

写业务代码的时候,可能经常遇到滚动,然后,具体曝光某个模块的情况

下面是封装的函数,还有具体的使用

code

import { jsBridge } from 'xxx-xx';
export default {
    data () {
        return {
            viewHeight: null,
            scrollEventFun: null
        }
    },
    mounted () {
        // 页面渲染完成,执行曝光检测
        setTimeout(() => {
            this.viewHeight = window.innerHeight;
            this.scrollEvent();
            // 监听scroll事件
            this.scrollEventFun = this.throttle(this.scrollEvent, 300);
            window.addEventListener('scroll', this.scrollEventFun, false);
        }, 1000);
    },
    beforeDestroy () {
        // 防止内存溢出
        window.removeEventListener('scroll', this.scrollEventFun, false);
    },
    methods: {
        getOffsetTop (element) {
            let actualTop = element.offsetTop;
            let current = element.offsetParent;
            while (current !== null) {
                actualTop += current.offsetTop;
                current = current.offsetParent;
            }
            return actualTop;
        },
        // time 必然触发执行的时间间隔
        throttle (fun, threshhold = 160) {
            let timeout;
            let startTime = new Date();
            return function () {
                let context = this;
                let args = arguments;
                let curTime = new Date() - 0;

                clearTimeout(timeout);

                if (curTime - startTime >= threshhold) {
                    fun.apply(context, args);
                    startTime = curTime;
                } else {
                    timeout = setTimeout(function () {
                        fun.apply(context, args);
                    }, threshhold);
                }
            };
        },
        // 获取窗口滚动高度
        scrollTop () {
            return document.documentElement.scrollTop || document.body.scrollTop || window.pageYOffset;
        },
        scrollEvent () {
            let $scrollTop = this.scrollTop();
            let nodeArr = document.querySelectorAll('.has-exp');
            for (let i = 0; i < nodeArr.length; i++) {
                let domTop = this.getOffsetTop(nodeArr[i]) + nodeArr[i].getBoundingClientRect().height / 3;
                // 当正文部分露出即发此曝光
                if (nodeArr[i].getAttribute('detail-article') === '1') {
                    domTop = this.getOffsetTop(nodeArr[i]);
                }
                let topHeight = this.getOffsetTop(nodeArr[i]) - $scrollTop;
                // console.log('topHeight', topHeight);
                let bottomHeight = domTop - $scrollTop;
                if (topHeight >= 0 && bottomHeight <= this.viewHeight) {
                    if (!nodeArr[i].getAttribute('data-exposure')) {
                        nodeArr[i].setAttribute('data-exposure', '1');
                        const _this = this;
                        new Promise((resolve) => {
                            resolve();
                        }).then(() => {
                            let expData = nodeArr[i].getAttribute('exp-data');
                            _this.expPost(expData);
                        });
                    }
                }
                if (topHeight > this.viewHeight) return false;
            }            
        },
        expPost (mapData) {
            if (mapData) {
                mapData = JSON.parse(mapData);
            }
            const message = {
                action: 'exposure',
                map: mapData
            };
            console.log(`曝光统计log: ${JSON.stringify(message)}`);
            jsBridge(message);
        }
    }
};

<div class="has-exp" exp-data="{'key': 'val'}">
我是要曝光的模块
</div>