怎么样精确统计用户在页面的停留时长?
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">作者:<span style="color: black;">今日头条技术</span></span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">链接:https://techblog.toutiao.com/2018/06/05/ru-he-jing-que-tong-ji-ye-mian-ting-liu-shi-chang/</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_png/IibUVnJ665WpWlCuGtRhnAXeqlpk2gmzPe7AVMe94tDfRsZC4L6xFicWB6WnJYxdB3w23GjibxcOUNiaWekSbUicrpQ/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;"><strong style="color: blue;"><span style="color: black;">1、背景</span></strong></h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">页面停留时间(Time on Page)简<span style="color: black;">叫作</span> Tp,是网站分析中很<span style="color: black;">平常</span>的一个指标,用于反映用户在某些页面上停留时间的长短,传统的Tp统计<span style="color: black;">办法</span>会存在<span style="color: black;">必定</span>的统计盲区,<span style="color: black;">例如</span><span style="color: black;">没法</span>监控单页应用,<span style="color: black;">无</span><span style="color: black;">思虑</span>用户切换Tab、最小化窗口等操作场景。基于<span style="color: black;">以上</span>背景,重新调研和实现了精确统计页面停留时长的<span style="color: black;">方法</span>,需要 兼容单页应用和多页应用,并且不耦合或入侵业务代码。</span></p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;"><strong style="color: blue;"><span style="color: black;">2、分析</span></strong></h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">咱们</span><span style="color: black;">能够</span>把一个页面生命周期抽象为三个动作:「进入」、「活跃状态切换」、「离开」</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_jpg/meG6Vo0MeviaOxMvmfIOy2EDrpfja4lb9yGgJzB3U8pKlweeKsthAXZl6vOg3YKgePbmw8oXSiaaVdJhS6icUibFRA/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">如下图,计算页面停留时长既<span style="color: black;">怎样</span>监控这三个动作,<span style="color: black;">而后</span>在对应触发的事件中记录时间戳,<span style="color: black;">例如</span>要统计活跃停留时长就把 active 区间相加<span style="color: black;">就可</span>,要统计总时长既 tn -t0 。</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_jpg/meG6Vo0MeviaOxMvmfIOy2EDrpfja4lb90WyPgo2I7dX6pfggic4rSQdqn1WLNjmicPYq5ib65fdFS6lsoCDtrQhRQ/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p><span style="color: black;">2.1 <span style="color: black;">怎样</span>监听页面的进入和离开?</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">针对</span>常规页面的 首次加载、页面关闭、刷新 等操作都<span style="color: black;">能够</span>通过 window.onload 和 window.onbeforeunload 事件来监听页面进入和离开,浏览器前进后退<span style="color: black;">能够</span><span style="color: black;">经过</span> pageshow 和 pagehide 处理。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">load / beforeunload</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">pageshow / pagehide</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">针对</span>单页应用内部的<span style="color: black;">转</span><span style="color: black;">能够</span>转化为两个问题:</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">监听路由变化</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">判断变化的URL<span style="color: black;">是不是</span>为<span style="color: black;">区别</span>页面 。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;"><span style="color: black;">2.1.1 监听路由变化</span></strong></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">日前</span>主流的单页应用大部分都是基于 browserHistory (history api) <span style="color: black;">或</span> hashHistory 来做路由处理,<span style="color: black;">咱们</span><span style="color: black;">能够</span><span style="color: black;">经过</span>监听路由变化来判断页面<span style="color: black;">是不是</span>有可能切换。<span style="color: black;">重视</span>是有可能切换,<span style="color: black;">由于</span>URL<span style="color: black;">出现</span>变化不<span style="color: black;">表率</span>页面<span style="color: black;">必定</span>切换,<span style="color: black;">详细</span>的路由配置<span style="color: black;">是由于</span>业务决定的(既URL和页面的匹配规则)。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">browserHistory</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">路由的变化本质都会调用 History.pushState() 或 History.replaceState() ,能监听到这两个事件就能<span style="color: black;">晓得</span>。<span style="color: black;">经过</span> popstate 事件能<span style="color: black;">处理</span>一半问题,<span style="color: black;">由于</span> popstate 只会在浏览器前进后退的时候触发,当调用 history.pushState() or history.replaceState() 的时候并不会触发。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">The popstate event is fired when the active history entry changes. If the history entry being activated was created by a call to history.pushState() or was affected by a call to history.replaceState(), the popstate event’s state property contains a copy of the history entry’s state object.</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">Note that just calling history.pushState() or history.replaceState() won’t trigger apopstateevent. The popstate event will be triggered by doing a browser action such as a click on the back or forward button (or calling。history.back() or history.forward() in JavaScript).</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">这儿</span>需要<span style="color: black;">经过</span>猴子补丁(Monkeypatch)<span style="color: black;">处理</span>,运行时重写 history.pushState 和 history.replaceState <span style="color: black;">办法</span>:</span></p><span style="color: black;">let</span> _wr = <span style="color: black;"><span style="color: black;">function</span> (<span style="color: black;">type</span>) </span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">{ </p> <span style="color: black;">let</span> orig = <span style="color: black;">window</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">.history</p> <span style="color: black;">return</span> <span style="color: black;"><span style="color: black;">function</span> () </span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">{</p> <span style="color: black;">let</span> rv = orig.apply(<span style="color: black;">this</span>, <span style="color: black;">arguments</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p> <span style="color: black;">let</span> e = <span style="color: black;">new</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> Event(type.toLowerCase())</p> e.arguments = <span style="color: black;">arguments</span> <span style="color: black;">window</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">.dispatchEvent(e)</p> <span style="color: black;">return</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> rv</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> }}</p><span style="color: black;">window</span>.history.pushState = _wr(<span style="color: black;">pushState</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">) </p><span style="color: black;">window</span>.history.replaceState = _wr(<span style="color: black;">replaceState</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">)</p><span style="color: black;">window</span>.addEventListener(<span style="color: black;">pushstate</span>, <span style="color: black;"><span style="color: black;">function</span> (<span style="color: black;">event</span>) </span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">{}) </p><span style="color: black;">window</span>.addEventListener(<span style="color: black;">replacestate</span>, <span style="color: black;"><span style="color: black;">function</span> (<span style="color: black;">event</span>) </span>{})<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">hashHistory</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">hashHistory 的实现是基于 hash 的变化,hash 的变化<span style="color: black;">能够</span><span style="color: black;">经过</span> hashchange 来监听</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;"><span style="color: black;">2.1.2 判断URL<span style="color: black;">是不是</span>为<span style="color: black;">区别</span>页面</span></strong></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">方法</span>1: 客户端定义</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">经过</span>业务方在初始化的时候配置页面规则,<span style="color: black;">而后</span>JS<span style="color: black;">经过</span>URL匹配<span style="color: black;">区别</span>的规则来区分<span style="color: black;">区别</span>的页面,这种<span style="color: black;">方法</span>在客户端数据上报的时候就<span style="color: black;">已然</span><span style="color: black;">知道</span>了<span style="color: black;">区别</span>的页面,伪代码:</span></p><span style="color: black;">new</span> <span style="color: black;">Tracer</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">({ </p> <span style="color: black;">rules</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">: [</p> { path: <span style="color: black;">/index</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> },</p> { <span style="color: black;">path</span>: <span style="color: black;">/detail/:id</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"> },</p> { <span style="color: black;">path</span>: <span style="color: black;">/user</span>, query: {tab: <span style="color: black;">profile</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">} }</p> ])<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">方法</span>2: 数据分析平台定义</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">假设<span style="color: black;">咱们</span><span style="color: black;">最后</span>上报后有一个数据分析平台来展现,<span style="color: black;">咱们</span><span style="color: black;">能够</span>在类似数据平台来配置页面规则,<span style="color: black;">这般</span>在客户端实现的代码<span style="color: black;">规律</span>就不需要区分页面,而是每次URL<span style="color: black;">出现</span>变化就将数据上报,<span style="color: black;">最后</span><span style="color: black;">经过</span>数据平台配置的页面URL规则来求和、过滤数据等。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">当数据展现平台不支持配置URL规则来区分页面的时候,<span style="color: black;">能够</span>采用<span style="color: black;">方法</span>1;当有数据平台支持的时候采用<span style="color: black;">方法</span>2更<span style="color: black;">恰当</span>;</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;"><span style="color: black;">2.1.3 <span style="color: black;">针对</span>页面进入和离开<span style="color: black;">关联</span>事件整理</span></strong></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_jpg/meG6Vo0MeviaOxMvmfIOy2EDrpfja4lb9YXhvvRx97lBblrZbiaML6ykJV1cs3wdLRwGYRWcibTuIXkAibyzNR3RWA/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p><span style="color: black;">2.2 <span style="color: black;">怎样</span>监听页面活跃状态切换?</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">能够</span><span style="color: black;">经过</span> Page Visibility API 以及在 window 上声明 onblur/onfocus 事件来处理。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;"><span style="color: black;">2.2.1 Page Visibility API</span></strong></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">一个网页的可见状态<span style="color: black;">能够</span><span style="color: black;">经过</span> Page Visibility API 获取,<span style="color: black;">例如</span>当用户 切换浏览器Tab、最小化窗口、电脑<span style="color: black;">睡觉</span> 的时候,系统API会派发一个当前页面可见状态变化的 visibilitychange 事件,<span style="color: black;">而后</span>在事件绑定函数中<span style="color: black;">经过</span> document.hidden <span style="color: black;">或</span> document.visibilityState 读取当前状态。</span></p><span style="color: black;">document</span>.addEventListener(<span style="color: black;">visibilitychange</span>, <span style="color: black;"><span style="color: black;">function</span> (<span style="color: black;">event</span>) </span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">{ </p> <span style="color: black;">console</span>.log(<span style="color: black;">document</span>.hidden, <span style="color: black;">document</span>.visibilityState)})<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;"><span style="color: black;">2.2.2 onblur/onfocus</span></strong></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">能够</span><span style="color: black;">经过</span> Page Visibility API 以及在 window 上声明 onblur/onfocus 事件来处理。<span style="color: black;">针对</span>PC端<span style="color: black;">来讲</span>,除了监听<span style="color: black;">以上</span><span style="color: black;">关联</span>事件外,还<span style="color: black;">能够</span><span style="color: black;">思虑</span>监听鼠标<span style="color: black;">行径</span>,<span style="color: black;">例如</span>当一<span style="color: black;">按时</span>间内鼠标<span style="color: black;">无</span>操作则认为用户<span style="color: black;">处在</span>非活跃状态。</span></p><span style="color: black;">2.3 什么<span style="color: black;">机会</span>上报数据?</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;"><span style="color: black;">2.3.1 页面离开时上报</span></strong></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">针对</span>页面刷新<span style="color: black;">或</span>关闭窗口触发的操作可能会<span style="color: black;">导致</span>数据丢失</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><strong style="color: blue;"><span style="color: black;">2.3.2 下次打开页面时上报</span></strong></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">会丢失历史<span style="color: black;">拜访</span>记录中的最后一个页面数据</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">日前</span>采用的<span style="color: black;">方法</span>2,<span style="color: black;">针对</span>单页内部<span style="color: black;">转</span>是即时上报,<span style="color: black;">针对</span>单页/多页应用触发 window.onbeforeunload 事件的时候会把当前页面数据暂存在 localStorage 中,当用户下次进入页面的时候会把暂存数据上报。有个细节问题,<span style="color: black;">倘若</span>用户下次打开页面是在<span style="color: black;">次日</span>,<span style="color: black;">针对</span>统计当天的活跃时长会有<span style="color: black;">必定</span>的误差,<span style="color: black;">因此</span>在数据上报的<span style="color: black;">同期</span>会把该条数据的页面进入时间/离开时间带上。</span></p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;"><strong style="color: blue;"><span style="color: black;">3、设计</span></strong></h3><span style="color: black;">3.1 UML类关系图</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">Tracer</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">核心类,用来实例化一个监控,对原生事件和自定义事件的封装,监听 enter activechange exit 事件来操作当前 Page 实例。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">P.S. 取名来自暴雪旗下游戏守望先锋英雄猎空(Tracer),直译为:<span style="color: black;">跟踪</span>者。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Page</p>页面的抽象类,用来实例化一个页面,封装了 enter exit active inactive 等操作,内部<span style="color: black;">经过</span> state 属性来<span style="color: black;">守护</span>当前页面状态。
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_jpg/meG6Vo0MeviaOxMvmfIOy2EDrpfja4lb92zKnjsJZQeSGchWAw3Pg2EP78eqaqPkw67EpxTdT1noPHwF1U6HAmQ/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p><span style="color: black;">3.2 事件派发关系图</span>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_jpg/meG6Vo0MeviaOxMvmfIOy2EDrpfja4lb9SV6lnIkZaW3N5rNUTa0iae6vt3bCacbvbjAzAsRTuvibJWiaa7tJJxicJw/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;">4、兼容性</span></h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">Desktop</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_png/meG6Vo0MeviaOxMvmfIOy2EDrpfja4lb9ia8ibXuJpr5TQ3x7XgXzE4jl4HEibvN3J4AhIbicj6ibJIexvvhBe1HiaW0w/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;">Mobile</p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><img src="https://mmbiz.qpic.cn/mmbiz_png/meG6Vo0MeviaOxMvmfIOy2EDrpfja4lb982j3vdFhS7oicHuNiaheJwnIFgnAOtCtYYA0NMz1tRicGRjlRMGbiaANEA/640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"></p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;">5、思考</span></h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;"><span style="color: black;">针对</span>页面停留时长的定义可能在<span style="color: black;">区别</span>场景会有差异,<span style="color: black;">例如</span>内部业务系统<span style="color: black;">或</span>OA系统,<span style="color: black;">制品</span>可能更关心用户在页面的活跃时长;而<span style="color: black;">针对</span><span style="color: black;">新闻</span>类型的<span style="color: black;">制品</span>,页面可见时长会更有价值。单一的数据对业务分析是有限的,<span style="color: black;">因此</span>在<span style="color: black;">详细</span>的代码实过程中<span style="color: black;">咱们</span>会把停留时长分三个指标,<span style="color: black;">这般</span>能更好的<span style="color: black;">帮忙</span><span style="color: black;">制品</span>/运营分析。</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">active 页面活跃时长</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">visible 页面可见时长 //仅支持Desktop</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">duration 页面总停留时长</span></p>
<h3 style="color: black; text-align: left; margin-bottom: 10px;"><span style="color: black;">6、参考</span></h3>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onhashchange</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">https://developer.mozilla.org/en-US/docs/Web/Events/popstate</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">https://developer.mozilla.org/en-US/docs/Web/API/PageVisibilityAPI</span></p>
<p style="font-size: 16px; color: black; line-height: 40px; text-align: left; margin-bottom: 15px;"><span style="color: black;">https://stackoverflow.com/questions/4570093/how-to-get-notified-about-changes-of-the-history-via-history-pushstate</span></p><span style="color: black;">关注公众号,查看<span style="color: black;">更加多</span><span style="color: black;">优秀</span><span style="color: black;">文案</span></span><img src="https://mmbiz.qpic.cn/sz_mmbiz_jpg/iaHzRIndsicSnwSDicyAwmrlnheAoZl5VHgDmY91vXbYYFnrv3V98tXxLHpXOvSWVnFZdcIk37yvGPVpAVz2gFeOw/640?wx_fmt=jpeg&tp=webp&wxfrom=5&wx_lazy=1&wx_co=1" style="width: 50%; margin-bottom: 20px;"><span style="color: black;"><span style="color: black;">近期</span>,整理一份Java资料</span><span style="color: black;">《<strong style="color: blue;">Java从0到1</strong>》</span><span style="color: black;">,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。</span><span style="color: black;">获取方式:关注公众号并回复 </span><span style="color: black;"><strong style="color: blue;">Java</strong></span><span style="color: black;"> 领取,<span style="color: black;">更加多</span>Java内容<span style="color: black;">持续</span>奉上。</span><strong style="color: blue;">明天见(。・ω・。)ノ♡</strong>
谢谢、感谢、感恩、辛苦了、有你真好等。 你的话语真是温暖如春,让我心生感激。
页:
[1]