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

更新日期: 2019-05-28阅读: 3k标签: 模块
产品希望看到投放出去的活动页,用户对其页面内的什么信息比较感兴趣,对什么信息完全不感兴趣。=> 计算页面内每模块的停留时间

第一次听到这个需求,我的大脑开始疯狂运转,然后想到了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>
      <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的数组长度等于页面内的模块个数


来自:https://segmentfault.com/a/1190000019321315


链接: https://fly63.com/article/detial/3459

ES6模块功能:export和import的加载方式

ES6之前已经出现了js模块加载的方案,最主要的是CommonJS和AMD规范。commonjs主要应用于服务器,实现同步加载,如nodejs。AMD规范应用于浏览器,如requirejs,为异步加载。

Node的https模块_创建HTTPS服务器

Node的https模块:HTTPS服务器使用HTTPS协议,需要证书授权,SSL安全加密后传输,使用443端口

如何让 node 运行 es6 模块文件,及其原理

最新版的 node 支持最新版 ECMAScript 几乎所有特性,但有一个特性却一直到现在都还没有支持,那就是从 ES2015 开始定义的模块化机制。而现在我们很多项目都是用 es6 的模块化规范来写代码的,包括 node 项目

module、export、require、import的使用

module每个文件就是一个模块。文件内定义的变量、函数等等都是在自己的作用域内,都是自身所私有的,对其它文件不可见。在module中有一个属性exports,即:module.exports。它是该模块对外的输出值,是一个对象。

Node.js - 模块系统

模块是Node.js 应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个 Node.js 文件就是一个模块,这个文件可能是JavaScript 代码、JSON 或者编译过的C/C++ 扩展。Node.js 提供了 exports 和 require 两个对象

ES模块基础用法及常见使用问题

ES6中引入了模块(Modules)的概念,相信大家都已经挺熟悉的了,在日常的工作中应该也都有使用。本文会简单介绍一下ES模块的优点、基本用法以及常见问题。

ES6 export 和 export default的区别

ES6中 export 和 export default 与 import使用的区别,使用 react native 代码详解,现在流行的前端框架,angular+ 主要使用 export 导出模块,react native 中使用 export default 导出模块,如今编辑器非常强大,安装插件会自动弹出模块名称,知道其导出怎么使用就可以了

export和export default的区别

export与export default均可用于导出常量、函数、文件、模块;你可以在其它文件或模块中通过import+(常量 | 函数 | 文件 | 模块)名的方式,将其导入,以便能够对其进行使用;

关于export和export default你不知道的事

网上有很多关于export和export default的文章,他们大部门都是只讲了用法,但是没有提到性能,打包等关键的东西。大家应该应该能理解import * from xxx会把文件中export default的内容都打包到文件中,而import {func} from xxx只会把文件中的func导入

最全的前端模块化方案

模块化主要是用来抽离公共代码,隔离作用域,避免变量冲突等。将一个复杂的系统分解为多个模块以方便编码。会讲述以下内容:CommonJS、AMD 及 核心原理实现、CMD 及 核心原理实现

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!