├── 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 |
--------------------------------------------------------------------------------