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