介绍
圈选功能,可理解为是无痕埋点技术的具体应用产品。
使用方式:
1.web 在线网页
圈选功能管理后台上,提供了一个容器加载在线地址,通过点击指定元素的方式,获取元素的特殊标记并上报数据分析系统。数据筛选服务,根据上报的标记将无痕上报的数据进行分类统计。
2.混合 APP
指定的 APP 上开启圈选功能,通过拖拽定位圆点工具,获取对应的容器中加载的 web 页面的元素座标,并上报数据分析系统。数据筛选服务,根据上报的标记将无痕上报的数据进行分类统计。
实现原理
无痕埋点
首先不得不再次强调,圈选功能的基础是无痕埋点技术。圈选功能更容易理解为是一种筛选数据的工具,那么前提就是需要有数据,那么就需要通过无痕埋点技术优先将用户的行为数据都存储在数据仓库中(这里指的是全量上报数据的方式;大流量场景则不适用,可采用后置上报的方式,这里不过多展开)。
无痕埋点简单实现,通过根节点注册监听事件(事件委托),用户在页面中的所有操作行为,都会冒泡到顶层统一分析上报。主要内容包含 1.当前页面的唯一标识。2.用户的操作行为事件。3.交互元素的 xPath 路径,以及元素部分有效信息。4.浏览器系统信息、用户标识、网络等额外信息。
更多信息可查看日志无痕埋点技术。
圈选原理实现
通过平台工具加载指定内容模块,平台提供定位元素的工具。工具定位元素后,圈选 SDK 获取指定元素的相关信息,如 xPath 路径以及浏览器系统信息等,通过消息通信机制将指定信息传递到工具平台,并上报标记信息。数据分析后台通过这些上报的标记筛选出有效信息,并可视化展示。
圈选核心代码
1.圈选初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
|
Circle.init = function () { document.addEventListener( "mouseover", function (e) { if (!_circleDisabled && e.isTrusted !== false) { Circle.drawField(e.target); } }, true ); document.addEventListener( "mouseout", function (e) { if (!_circleDisabled && e.isTrusted !== false) { Circle.cleanDrawField(); } }, true ); document.addEventListener( "click", function (e) { if (!_circleDisabled) { if (e.isTrusted !== false) { Circle.cleanDrawField(); _circleDisabled = true; Circle.getNodeFieldInfo(e.target, function (data) { Messenger.send(0, data, "圈选节点信息"); setTimeout(function () { _circleDisabled = false; }, 500); }); } window.event ? (window.event.cancelBubble = true) : e.stopPropagation(); e.preventDefault ? e.preventDefault() : window.event.returnValue == false; } }, true ); };
|
2.获取圈选元素信息(核心)
UTM
方法为无痕埋点 SDK 中的方法。圈选 SDK 与无痕埋点 SDK 做了集成,所以能够直接调用无痕埋点中元素相关信息的获取方法。
1 2 3 4 5 6 7 8 9 10 11 12
|
Circle.getNodeFieldInfo = function (node) { return { utm: UTM.utmID(), path: UTM.utmPath(node), content: UTM.utmContent(node), }; };
|
3.圈选效果绘制
此处提取部分代码内容,仅供参考,也可以有更加优雅的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
|
function formatClass(obj) { var arr = []; for (var i in obj) { arr.push(i + ":" + obj[i]); } return arr.join(";") + ";"; }
Circle.drawField = function (node) { node.className += " " + circleClass; node.setAttribute( "style", (node.getAttribute("style") ? node.getAttribute("style") : "") + formatClass(_circlePlatform == "PC" ? _circle_hoverPC : _circle_hover) ); return node; };
Circle.cleanDrawField = function () { var re = new RegExp("\\s*" + circleClass, "gi"); var reStyle = new RegExp( formatClass(_circlePlatform == "PC" ? _circle_hoverPC : _circle_hover), "gi" ); Array.from(document.getElementsByClassName(circleClass)).forEach(function ( node ) { node.className = node.className.replace(re, ""); var sourceStyle = node.getAttribute("style").replace(reStyle, ""); if (sourceStyle) { node.setAttribute("style", sourceStyle); } else { node.removeAttribute("style"); } if (!node.className) { node.removeAttribute("class"); } }); Array.from(document.getElementsByClassName("circle-mask")).forEach(function ( node ) { node.parentNode.removeChild(node); }); };
|
4.消息通信
主要用了postMessage
做通信,既能解决跨域问题,也效率高。(安全性暂不展开讨论,部分代码仅供参考)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| var Messenger = Messenger || {};
Messenger.listen = function (MessageEvent) { if (typeof MessageEvent == "object" && MessageEvent.data) { var res = MessageEvent.data; if (res.code == 0) { _circleDisabled = false; if (res.data == "PC") { _circlePlatform = "PC"; Circle.init(); } else if (res.data == "APP") { _circlePlatform = "APP"; Circle.initHybridH5(); } } else if (res.code == 1) { if (res.data == "PC") { _circlePlatform = "PC"; Messenger.send( 1, { utm: UTM.utmID(), }, "页面信息" ); } } else if (res.code == 2) { if (res.data == "PC") { _isToolPlatform = true; var _event = new CustomEvent("isToolPlatform"); if ("dispatchEvent" in window) { window.dispatchEvent(_event); } } } else if (res.code == 10) { Circle.close(); } } };
Messenger.send = function (code, data, message, target) { if (!target) { target = parent.window; } target.postMessage({ code: code, data: data, message: message }, "*"); };
if ("postMessage" in window) { if ("addEventListener" in window) { window.addEventListener("message", Messenger.listen, false); } else if ("attachEvent" in window) { window.attachEvent("onmessage", Messenger.listen); } } else { window.navigator.Messenger = Messenger.listen; }
|
最后
日常开发中,我们一定会遇到或多或少的埋点需求,每一次的埋点需求,也就意味着开发需要做一次发布上线。如果通过无痕埋点+埋点圈选的方式,就能够解放开发同学的双手,同样也保障了系统的稳定性,更重要的是业务运营的相关人员,可以及时的获取到自己想要的数据,而不需要走开发的一系列冗长的流程,以能够应对市场的瞬息万变。
以上为圈选功能的简单实现,目前也大范围的在业务中实践使用,对开发的收益十分感人!感谢大佬们的阅读,不足之处请多多包涵。