├── README.md
├── index.js
└── package.json
/README.md:
--------------------------------------------------------------------------------
1 | # kk-vue-log
2 | 用于vue项目中的埋点小工具,主要功能有
3 |
4 | * 点击事件埋点,可自定义埋点参数和埋点要执行的方法。
5 | * 记录页面停留时间。
6 | * 记录页面跳转来源。
7 |
8 | ## 开始
9 |
10 | 安装
11 |
12 | ```
13 | npm install kk-vue-log -S
14 | ```
15 |
16 | 使用
17 |
18 | ```
19 | // 在main.js中
20 |
21 | // 引入
22 | import kkVueLog from "kk-vue-log"
23 |
24 | // 配置
25 | // options 除了以下几个配置,支持所有的axios配置项
26 |
27 | const options = {
28 |
29 | // 埋点数据上传的接口,必填
30 | url: "//127.0.0.1:3000/login",
31 |
32 | //埋点数据上传的方法, 可选,不填写默认 'get'
33 | method: 'post',
34 |
35 | //请求的 headers,(可选) 建议只放常量 (提示, 若需要加token这一类通过接口或者计算出来的参数, 需要放在请求拦截器里, 否则可能取不到值)
36 | headers:{
37 | 'NAME': 'name'
38 | },
39 | // 请求拦截执行函数 config为请求的配置 同axios请求拦截器的配置
40 | interceptorsRequest:function(config){
41 | config.headers={
42 | token: '123456'
43 | }
44 | },
45 |
46 | // 路由实例 (可选) 如果需要记录页面停留时间和页面跳转来源则必填
47 | router,
48 |
49 | //一个数组,(可选) 需要记录停留时间的页面vue路由path, 若写['*']则为所有页面
50 | durationRoute:['*'],
51 |
52 | // 是否需要记录跳转来源 (可选)
53 | needReferrer: false,
54 |
55 | //跳转来源的页面标记字段 (可选) 例如 http://www.baidu.com?from=baidu
56 | sign: 'from'
57 | }
58 |
59 | // 使用
60 | Vue.use(kkVueLog, options)
61 |
62 | ```
63 |
64 | ## 点击埋点
65 | 在需要埋点的元素或组件中。
66 | ```
67 |
click
68 |
69 | ```
70 | > 注意 一定要将自定义参数放在 params 对象里。
71 |
72 | ## 记录页面停留时间
73 | 参照开头,将所需字段配置好即可。
74 |
75 | 页面跳转的时候会自动向配置好的接口地址发送请求,自动携带两个参数:
76 |
77 | ``` duration```: 页面停留时间,单位毫秒;
78 |
79 | ``` url```: 页面url。
80 |
81 | ## 记录页面跳转来源
82 | 同样参照开头,将所需参数配置好即可。
83 |
84 | 页面跳转的时候会自动向配置好的接口地址发送请求,自动携带一个参数: 字段名为 options配置中sign字段的值,例如开头的例子中,请求参数为 {from: 'baidu'}
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | const axios = require("axios")
2 |
3 |
4 |
5 | /**
6 | * options对象中的参数说明
7 | * logFunction: 类型 Function, 自定义的埋点方法
8 | */
9 |
10 | // =====工具函数=====
11 | // 获取url search中的参数
12 |
13 |
14 | // 发起埋点接口 上报数据
15 | var kkLogUtils = {
16 | getQueryFromSearch: function (variable) {
17 | var query = window.location.search.substring(1);
18 | var vars = query.split("&");
19 | for (var i = 0; i < vars.length; i++) {
20 | var pair = vars[i].split("=");
21 | if (pair[0] == variable) {
22 | return pair[1];
23 | }
24 | }
25 | return (false);
26 | },
27 |
28 | // 获取url hash中的参数
29 | getQueryFromHash: function (variable) {
30 | var query = window.location.hash.substring(1);
31 | if (query.indexOf('?') > -1) {
32 | query = query.split('?')[1];
33 | }
34 |
35 | var vars = query.split("&");
36 | for (var i = 0; i < vars.length; i++) {
37 | var pair = vars[i].split("=");
38 | if (pair[0] == variable) {
39 | return pair[1];
40 | }
41 | }
42 | return (false);
43 | },
44 |
45 | // 获取url来源标记
46 | getReferrer: function (sign) {
47 | let referrer = kkLogUtils.getQueryFromSearch(sign) || kkLogUtils.getQueryFromHash(sign)
48 | return referrer
49 | },
50 |
51 | // 提交埋点数据
52 | submitLog: function (url, method = 'get', params) {
53 | if (method === 'get') {
54 | axios.get(url, {
55 | params
56 | })
57 | }
58 | if (method === 'post') {
59 | axios.post(url, params)
60 | }
61 | }
62 | }
63 |
64 | module.exports = function (Vue, options = {}) {
65 | // 添加请求拦截器
66 | if(options.interceptorsRequest && options.interceptorsRequest instanceof Function){
67 | axios.interceptors.request.use(function (config) {
68 | // 在发送请求之前 执行拦截函数
69 | options.interceptorsRequest(config);
70 | return config;
71 | }, function (error) {
72 | // 对请求错误做些什么
73 | return Promise.reject(error);
74 | });
75 | }
76 |
77 | // // 添加响应拦截器 暂时不用
78 | // axios.interceptors.response.use(function (response) {
79 | // // 对响应数据做点什么
80 | // return response;
81 | // }, function (error) {
82 | // // 对响应错误做点什么
83 | // return Promise.reject(error);
84 | // });
85 |
86 | // 如果配置信息中未配置埋点接口地址(url), 则报错
87 | if (!options || !options.url) {
88 | throw '埋点接口地址(url) 未配置'
89 | return false
90 | }
91 |
92 | const method = options.method || 'get'; // 埋点接口方法
93 | const durationRoute = options.durationRoute || null;
94 | const router = options.router;
95 | const sign = options.sign;
96 | // delete options.durationRoute;
97 | // delete options.router;
98 |
99 | /**
100 | * v-log指令中的参数说明
101 | * params: 类型 Object, 埋点需要上传的参数
102 | */
103 | Vue.directive('log', function (el, binding) {
104 | el.onclick = function () {
105 | // 如果传入的params不是一个对象, 则报错
106 | if (binding.value['params'] && Object.prototype.toString.call(binding.value['params']) !== '[object Object]') {
107 | throw 'params必须为一个对象'
108 | return false
109 | }
110 |
111 | let params = binding.value['params'] || {};
112 |
113 | //计算点击事件与页面初始化的时间差
114 | let logStart = (window.sessionStorage.getItem('logStart') || 0) - 0;
115 | let clickDelay = Date.now() - logStart;
116 | params.clickDelay = clickDelay;
117 |
118 | // 如果有自定义埋点方法,则执行自定义埋点方法
119 | if (options.logFunction && options.logFunction instanceof Function) {
120 | options.logFunction({
121 | ...params
122 | })
123 | return false
124 | }
125 |
126 | // ===== 如果有自定义埋点方法, 则使用默认埋点数据上报 =====
127 | kkLogUtils.submitLog(options.url, method, params)
128 | }
129 | })
130 |
131 |
132 | // ===== 记录页面进入时间 ======
133 | if (!router) {
134 | return false
135 | }
136 | router.beforeEach((to, from, next) => {
137 | (function () {
138 | let logStart = (window.sessionStorage.getItem('logStart') || 0) - 0;
139 | // 第一次进入页面,记录时间
140 | if (!logStart) {
141 | window.sessionStorage.setItem('logStart', Date.now())
142 | } else {
143 | // 每次进入一个新页面的时候,计算出上一个页面的停留时间
144 | let path = from.path;
145 | let logEnd = Date.now();
146 | let logStart = window.sessionStorage.getItem('logStart') - 0
147 | let duration = logEnd - logStart;
148 |
149 | // 刷新本页面开始时间
150 | window.sessionStorage.setItem('logStart', Date.now())
151 |
152 | if (!durationRoute || durationRoute.length === 0) {
153 | return false
154 | }
155 |
156 | // 埋点数据上报
157 | let params = {};
158 | params.duration = duration;
159 | params.url = window.location.href;
160 | if (durationRoute[0] === '*' || durationRoute.indexOf(from.path) > -1) {
161 | kkLogUtils.submitLog(options.url, method, params)
162 | }
163 | }
164 | })();
165 | next()
166 | })
167 |
168 | // ===== 记录页面来源 ======
169 | router.afterEach((to, from) => {
170 | (function () {
171 | if (!options.needReferrer) {
172 | return
173 | }
174 | let outReferrer = kkLogUtils.getReferrer(sign);
175 | let inReferrer = from.path;
176 | let params = {};
177 | if (!inReferrer || inReferrer === '/') {
178 | params[sign] = outReferrer
179 | } else {
180 | params[sign] = inReferrer
181 | }
182 | kkLogUtils.submitLog(options.url, method, params)
183 | })()
184 | })
185 |
186 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "_from": "kk-vue-log",
3 | "_id": "kk-vue-log@0.1.2",
4 | "_inBundle": false,
5 | "_integrity": "sha512-f/eqBCXRguvsFjDM67yA3cM+8+pr+cgpfZxmd+GC22DBon7pnGdoP5T1EdY0J7hF+mNPE1kUTgjQ65exA0/nzw==",
6 | "_location": "/kk-vue-log",
7 | "_phantomChildren": {},
8 | "_requested": {
9 | "type": "tag",
10 | "registry": true,
11 | "raw": "kk-vue-log",
12 | "name": "kk-vue-log",
13 | "escapedName": "kk-vue-log",
14 | "rawSpec": "",
15 | "saveSpec": null,
16 | "fetchSpec": "latest"
17 | },
18 | "_requiredBy": [
19 | "#USER",
20 | "/"
21 | ],
22 | "_resolved": "https://registry.npmjs.org/kk-vue-log/-/kk-vue-log-0.1.2.tgz",
23 | "_shasum": "f8f2b96326214caf67c254c5b65e43c1638eaaa1",
24 | "_spec": "kk-vue-log",
25 | "_where": "D:\\my\\node-dev\\client",
26 | "author": {
27 | "name": "wxw"
28 | },
29 | "bundleDependencies": false,
30 | "dependencies": {
31 | "axios": "^0.19.0"
32 | },
33 | "deprecated": false,
34 | "description": "vue埋点",
35 | "license": "ISC",
36 | "main": "index.js",
37 | "name": "kk-vue-log",
38 | "scripts": {
39 | "test": "echo \"Error: no test specified\" && exit 1"
40 | },
41 | "version": "0.1.3"
42 | }
43 |
--------------------------------------------------------------------------------