├── pc-or-h5.html ├── README.md └── reportEvent.js /pc-or-h5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 上报事件 8 | 9 | 10 | 11 |
上报事件
12 |
多事件上报
13 | 14 |
手动上报事件
15 | 16 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 简书地址:[https://www.jianshu.com/p/870ae491fb08](https://www.jianshu.com/p/870ae491fb08) 2 | 3 | # **reportEvent** 4 | 5 | 一个支持常规`PC`、`H5`,单网页应用`React`、`Vue`、`Angurla` 的上报事件小插件,使用简单,代码轻量。
6 | 参数自动序列化,自带一个唯一uuid `frontUvId` 存储在本地 `eventFrontUvId` 中,每次上报事件都会携带这个参数 7 | 8 | ## **直接调用** 9 | 10 | 适用于路由切换、接口请求完毕、onload、接口或方法回调等场景。callback为非必填
11 | 12 | ### window.reportEvent.reportEventFunc(object,callback); 13 | 14 | > window.reportEvent.reportEventFunc({code:1,id:2},(res)=>{ 15 | > console.log('调用完成=>',res) 16 | > }); 17 | 18 | ## **自动绑定click事件,完成上报** 19 | 20 | 支持数组传参和对象的方式传递参数,上报方法会检测类型,如果是数组,会循环数组,并多次上报里边的对象;对象直接上报,传递的参数需要JSON.stringify(对象或者数组)
21 | **目前自动绑定只做了click** 22 | 23 | ## PC or H5 24 | 25 | > 对象:
26 | > `
`
27 | > 数组:
28 | > `
` 29 | 30 | ## React 31 | 32 | > 对象:
33 | > `
`
34 | > 数组:
35 | > `
` 36 | 37 | ## Vue 38 | 39 | > 对象:
40 | > `
`
41 | > 数组:
42 | > `
` -------------------------------------------------------------------------------- /reportEvent.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: shiweihua 3 | * @Date: 2019-05-14 16:21:29 4 | * @Last Modified by: shiweihua 5 | * @Last Modified time: 2019-05-19 16:20:09 6 | */ 7 | (function (w) { 8 | 9 | //上报事件的提交地址 10 | const REPORT_EVENT_URL = 'url'; 11 | //唯一ID对应内存里的key 12 | const EVENT_FRONT_UVID = 'eventFrontUvId'; 13 | //事件委托的对象 14 | var EVENT_DOM = document.getElementsByTagName("body")[0]; 15 | //上报事件的绑定类型对应的绑定名称 16 | const REPORT_EVENT_FUNC = 'data-reporteventfunc'; 17 | //上报事件数据对应的绑定参数名称 18 | const REPORT_EVENT_DATA = 'data-reporteventdata'; 19 | 20 | var reportEvent = { 21 | _ajax: function (obj) { 22 | let xhr = new XMLHttpRequest(); 23 | xhr.open(obj.type || 'POST', obj.url, true); 24 | xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 25 | xhr.onreadystatechange = function () { 26 | if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 304)) { 27 | obj.callback && obj.callback(JSON.parse(xhr.response)) 28 | } 29 | }; 30 | xhr.send(obj.data); 31 | }, 32 | //按条件循环方法,配合filterEmptyObj使用 33 | _each: function (data, callback) { 34 | for (let x in data) { 35 | let d = callback(x, data[x]); 36 | if (d === false) { 37 | break; 38 | } 39 | } 40 | }, 41 | //过滤空对象 42 | _filterEmptyObj: function (obj) { 43 | let o = {}; 44 | this._each(obj, function (i, d) { 45 | if (d !== null) { 46 | o[i] = d; 47 | } 48 | }); 49 | return o; 50 | }, 51 | //用于生成frontUvId 52 | _creatfrontUvId4: function (len, radix) { 53 | var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); 54 | var uuid = [], i; 55 | radix = radix || chars.length; 56 | 57 | if (len) { 58 | for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix]; 59 | } else { 60 | var r; 61 | uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'; 62 | uuid[14] = '4'; 63 | for (i = 0; i < 36; i++) { 64 | if (!uuid[i]) { 65 | r = 0 | Math.random() * 16; 66 | uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; 67 | } 68 | } 69 | } 70 | 71 | return uuid.join(''); 72 | }, 73 | //对frontUvId逻辑处理 74 | _getFrontUvId: function () { 75 | //读取本地存储的frontUvId 76 | let eventFrontUvId = localStorage.getItem(EVENT_FRONT_UVID); 77 | //有frontUvId就直接返回,没有重新生成,保存在本地,并返回 78 | if (eventFrontUvId === null) { 79 | //生成新的frontUvId 80 | eventFrontUvId = this._creatfrontUvId4(32,16); 81 | //frontUvId存在本地 82 | localStorage.setItem(EVENT_FRONT_UVID, eventFrontUvId); 83 | } 84 | return eventFrontUvId; 85 | }, 86 | //过滤空参数 + 序列化对象 87 | _serialize: function (obj) { 88 | //清空为null的对象 89 | obj = this._filterEmptyObj(obj); 90 | //序列化参数 91 | let parameter = '?'; 92 | for (let key in obj) { 93 | parameter += `${key}=${obj[key]}&` 94 | } 95 | parameter = parameter.substring(0, parameter.length - 1); 96 | return parameter; 97 | }, 98 | //上报事件方法 99 | reportEventFunc: function (obj, callback) { 100 | //拿frontUvId 101 | obj.frontUvId = this._getFrontUvId(); 102 | //post提交接口 103 | this._ajax({ 104 | type: 'POST', 105 | url: `${REPORT_EVENT_URL}${this._serialize(obj)}`, 106 | data: {}, 107 | callback: (res) => { 108 | callback && callback(res) 109 | } 110 | }) 111 | }, 112 | //获取元素属性,调用上报事件 113 | getDomAttribute: function (dom) { 114 | //获取属性参数 115 | let eventData = dom.getAttribute(REPORT_EVENT_DATA); 116 | if (!eventData) { 117 | return; 118 | } 119 | //判断类型,如果是字符串类型,转换类型 120 | eventData = typeof eventData == 'string' ? eval('(' + eventData + ')') : JSON.parse(eventData); 121 | //此判断es5写法,对兼容有要求的可以更换为 Object.prototype.toString.call(eventData) === '[object Array]' 122 | //如果是对象直接上报事件 123 | if (!Array.isArray(eventData)) { 124 | this.reportEventFunc(eventData); 125 | return; 126 | } 127 | //如果是数组,循环上报事件 128 | for (let si = 0; si < eventData.length; si++) { 129 | this.reportEventFunc(eventData[si]); 130 | } 131 | } 132 | } 133 | 134 | 135 | w.onload = function () { 136 | 137 | //事件委托,检测拥有指定参数 138 | EVENT_DOM.onclick = function (ev) { 139 | var ev = ev || w.event; 140 | //查找当前dom的dom树 141 | for (let i = 0; i < ev.path.length; i++) { 142 | if (ev.path[i].getAttribute && ev.path[i].getAttribute(REPORT_EVENT_FUNC) == 'click') { 143 | //只需要传入满足条件的节点 144 | reportEvent.getDomAttribute(ev.path[i]); 145 | } 146 | } 147 | }; 148 | } 149 | w.reportEvent = reportEvent; 150 | 151 | })(window) 152 | --------------------------------------------------------------------------------