• 计算一个页面内每个模块的曝光时间(停留时间)


    产品希望看到投放出去的活动页,用户对其页面内的什么信息比较感兴趣,对什么信息完全不感兴趣。=> 计算页面内每模块的停留时间

    第一次听到这个需求,我的大脑开始疯狂运转,然后想到了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。

    存在的问题:
    最后得到的数据量虽然不会很大,但是将这样的数据给数据组分析,存在一定的难度。这是在没有和产品对接时,自己想的办法,有点想复杂了。但是这种方式可以比较生动模拟出用户的行为。

    资源搜索网站大全 https://www.renrenfan.com.cn 广州VI设计公司https://www.houdianzi.com

    方案三: 固定模块尺寸,计算每模块的停留时间

    与我的产品对接了基本的规定:

    • 每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>
          <p>停留时间0:</p>
          <p v-for="item in movedata" v-if="parseInt(item.pos / 1300) === 0">{{0}}  ----  {{item.time}}</p>
        </div>
        <div>
          <p>停留时间1:</p>
          <p v-for="item in movedata" v-if="parseInt(item.pos / 1300) === 1">{{1}}  ----  {{item.time}}</p>
        </div>
        <div>
          <p>停留时间2:</p>
          <p v-for="item in movedata" v-if="parseInt(item.pos / 1300) === 2">{{2}}  ----  {{item.time}}</p>
        </div>
        <div>
          <p>停留时间3:</p>
          <p v-for="item in movedata" v-if="parseInt(item.pos / 1300) === 3">{{3}}  ----  {{item.time}}</p>
        </div>
        <div>
          <p>停留时间4:</p>
          <p v-for="item in movedata" v-if="parseInt(item.pos / 1300) === 4">{{4}}  ----  {{item.time}}</p>
        </div>
        <div>
          <p>停留时间5:</p>
          <p v-for="item in movedata" v-if="parseInt(item.pos / 1300) === 5">{{5}}  ----  {{item.time}}</p>
        </div>
        <div>
          <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的数组长度等于页面内的模块个数

  • 相关阅读:
    scrapy安装教程
    【bzoj4200】[Noi2015]小园丁与老司机 STL-map+dp+有上下界最小流
    【bzoj4889】[Tjoi2017]不勤劳的图书管理员 树状数组+分块+二分
    【bzoj4198】[Noi2015]荷马史诗 贪心+堆
    【bzoj2989】数列 KD-tree+旋转坐标系
    【bzoj4212】神牛的养成计划 Trie树+可持久化Trie树
    【bzoj4242】水壶 BFS+最小生成树+倍增LCA
    【bzoj4238】电压 DFS树
    【bzoj4240】有趣的家庭菜园 贪心+树状数组
    【bzoj4237】稻草人 分治+单调栈+二分
  • 原文地址:https://www.cnblogs.com/qianxiaox/p/14110853.html
Copyright © 2020-2023  润新知