浏览器visibilitychange事件

  1. 需求:

    • 监听浏览器显示时,调用定时器
    • 监听浏览器隐藏时,关闭定时器,并将浏览时间传至服务器
    • 打开不同的商品根据后端返回的商品id保存时间,如果商品id相同就叠加
  2. 代码:

    // timer:保存setInterval函数
    // tags:保存商品id
    // timeObj:以tags为key值,保存所有商品的浏览时间
    // timeObj格式:
    //     tags = 1
    //     timeObj = {
    //         tags:{
    //             log_id: tags,
    //             // StayRegion: watchfunc(),
    //             StayTime: 0
    //         }
    //     }
    let timer, tags, timeObj
    
    // 页面隐藏时,保存时间函数
    function saveTimeObj() {
        // 关闭定时器
        clearInterval(timer)
    
        // 存储到本地
        sessionStorage.setItem('c_timeObj', JSON.stringify(timeObj))
    
        // 调用接口
        $.ajax({
            url: `${baseUrl}e2capi/SMS/SetStayLog`,
            type: 'post',
            data: {
                EnParams: encrypt(JSON.stringify(timeObj[tags]))
            },
        })
    }
    
    // 第一次进入页面时,定义对象格式
    let obj = {
        log_id: tags,
        StayTime: 0
    }
    
    // 判断本地是否有timeObj对象
    timeObj = sessionStorage.getItem('c_timeObj') ? JSON.parse(sessionStorage.getItem('c_timeObj')) : {}
    
    // 用于首次加载页面时防止无法触发visibilitychange页面显示事件
    timer = setInterval(() => {
    
        // 判断如果当前的tags是否已存在
        if (timeObj[tags]) {
            // 如果已存在直接递增浏览时间
            timeObj[tags].StayTime += 1
        } else {
            // 如果不存在,重新开启一个时间对象
            obj.StayTime += 1
            // 保存到对象中
            timeObj[tags] = obj
        }
    
        console.log('页面加载');
    }, 1000)
    
    // 监听页面显示隐藏
    document.addEventListener('visibilitychange', function () {
    
        if (document.hidden) {
            saveTimeObj(timeObj, tags)
    
            console.log(timeObj, '页面隐藏')
        } else {
            // 页面显示时,先关闭定时器,防止已经触发了页面首次加载时的定时器
            clearInterval(timer)
    
            // 开启定时器
            timer = setInterval(() => {
                // 判断如果当前的tags是否已存在
                if (timeObj[tags]) {
                    // 如果已存在直接递增浏览时间
                    timeObj[tags].StayTime += 1
                } else {
                    // 如果不存在,重新开启一个时间对象
                    obj.StayTime += 1
                    // 保存到对象中
                    timeObj[tags] = obj
                }
    
                console.log('页面显示');
            }, 1000)
        }
    });
    
  3. 问题1:

    手机浏览器页面跳转时,不触发visibilitychange隐藏事件,pc浏览器正常调用

  4. 解决方法1:

    在所有跳转按钮上绑定点击事件,点击时调用接口,延迟两毫秒后再进行跳转

    // 保存时间,延迟跳转
    function timeOutUrl(url) {
        saveTimeObj()
    
        setTimeout(() => {
            location.href = url
        }, 200)
    }
    
  5. 问题2:

    ​ visibilitychange事件,在pc浏览器进行页面跳转时可以正常触发页面隐藏事件,但在手机浏览器中,虽然可以触发,但是如果页面加载太快,会导致请求还没有发完页面就已经跳转了,因此会中断请求,但是如果加载太慢依然会触发visibilitychange的页面隐藏事件,如果按照以上封装的延迟跳转的方式,在网速稍慢的手机浏览器上的就会同时触发点击事件以及页面隐藏事件,后果就是连续发送两次一模一样的数据致服务器

  6. 解决方法2:

    在封装的saveTimeObj函数中先判断存储的时间和当前的时间不一致时,才发送接口

    // 页面隐藏时,保存时间函数
    function saveTimeObj() {
        // 关闭定时器
        clearInterval(timer)
    
        // 取本地中已保存的timeObj,用于判断需要新增还是直接取值递增
        let obj = sessionStorage.getItem('c_timeObj') ? JSON.parse(sessionStorage.getItem('c_timeObj')) : {}
    
        // 如果当前tags不存在,或者浏览时间有变化时,调用接口
        if(!obj[tags] || obj[tags].StayTime != timeObj[tags].StayTime){
    
            // 存储到本地
            sessionStorage.setItem('c_timeObj', JSON.stringify(timeObj))
    
            // 调用接口
            $.ajax({
                url: `${baseUrl}e2capi/SMS/SetStayLog`,
                type: 'post',
                data: {
                    EnParams: encrypt(JSON.stringify(timeObj[tags]))
                },
            })
            
        }
    }
    
  7. 完整代码:

    // timer:保存setInterval函数
    // tags:保存商品id
    // timeObj:以tags为key值,保存所有商品的浏览时间
    // timeObj格式:
    //     tags = 1
    //     timeObj = {
    //         tags:{
    //             log_id: tags,
    //             // StayRegion: watchfunc(),
    //             StayTime: 0
    //         }
    //     }
    let timer, tags, timeObj
    
    // 页面隐藏时,保存时间函数
    function saveTimeObj() {
        // 关闭定时器
        clearInterval(timer)
    
        // 取本地中已保存的timeObj,用于判断需要新增还是直接取值递增
        let obj = sessionStorage.getItem('c_timeObj') ? JSON.parse(sessionStorage.getItem('c_timeObj')) : {}
    
        // 如果当前tags不存在,或者浏览时间有变化时,调用接口
        if(!obj[tags] || obj[tags].StayTime != timeObj[tags].StayTime){
    
            // 存储到本地
            sessionStorage.setItem('c_timeObj', JSON.stringify(timeObj))
    
            // 调用接口
            $.ajax({
                url: `${baseUrl}e2capi/SMS/SetStayLog`,
                type: 'post',
                data: {
                    EnParams: encrypt(JSON.stringify(timeObj[tags]))
                },
            })
            
        }
    }
    
    // 第一次进入页面时,定义对象格式
    let obj = {
        log_id: tags,
        StayTime: 0
    }
    
    // 判断本地是否有timeObj对象
    timeObj = sessionStorage.getItem('c_timeObj') ? JSON.parse(sessionStorage.getItem('c_timeObj')) : {}
    
    // 用于首次加载页面时防止无法触发visibilitychange页面显示事件
    timer = setInterval(() => {
    
        // 判断如果当前的tags是否已存在
        if (timeObj[tags]) {
            // 如果已存在直接递增浏览时间
            timeObj[tags].StayTime += 1
        } else {
            // 如果不存在,重新开启一个时间对象
            obj.StayTime += 1
            // 保存到对象中
            timeObj[tags] = obj
        }
    
        console.log('页面加载');
    }, 1000)
    
    // 监听页面显示隐藏
    document.addEventListener('visibilitychange', function () {
    
        if (document.hidden) {
            saveTimeObj(timeObj, tags)
    
            console.log(timeObj, '页面隐藏')
        } else {
            // 页面显示时,先关闭定时器,防止已经触发了页面首次加载时的定时器
            clearInterval(timer)
    
            // 开启定时器
            timer = setInterval(() => {
                // 判断如果当前的tags是否已存在
                if (timeObj[tags]) {
                    // 如果已存在直接递增浏览时间
                    timeObj[tags].StayTime += 1
                } else {
                    // 如果不存在,重新开启一个时间对象
                    obj.StayTime += 1
                    // 保存到对象中
                    timeObj[tags] = obj
                }
    
                console.log('页面显示');
            }, 1000)
        }
    });
    

浏览器visibilitychange事件
http://localhost:8090//archives/liu-lan-qi-visibilitychange-shi-jian
作者
龟龟
发布于
2022年12月14日
更新于
2024年08月28日
许可协议