├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .github └── FUNDING.yml ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.en.md ├── README.md ├── demo ├── css │ └── style.css ├── js │ ├── main-for-vue2.js │ ├── main-for-vue3.js │ └── routes.js ├── vue2.html └── vue3.html ├── dist ├── main.d.ts ├── modules │ ├── cnzz.d.ts │ ├── getVueVersion.d.ts │ └── pushCNZZ.d.ts ├── types.d.ts ├── vue-cnzz-analytics.js ├── vue-cnzz-analytics.js.map ├── vue-cnzz-analytics.min.js └── vue-cnzz-analytics.min.js.map ├── package.json ├── rollup.config.ts ├── scripts └── verifyCommit.js ├── src ├── global.d.ts ├── main.ts ├── modules │ ├── cnzz.ts │ ├── getVueVersion.ts │ └── pushCNZZ.ts └── types.ts ├── tsconfig.json ├── vue-cnzz-analytics.d.ts └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false, 7 | "targets": { 8 | "browsers": "> 1%, IE 11, not op_mini all, not dead" 9 | }, 10 | "useBuiltIns": "usage", 11 | "corejs": 2 12 | } 13 | ] 14 | ], 15 | "plugins": [ 16 | "@babel/plugin-proposal-class-properties" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | insert_final_newline = true 10 | max_line_length = 80 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | max_line_length = 0 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/* 2 | demo/* 3 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | browser: true, 6 | }, 7 | extends: ['eslint:recommended', 'prettier'], 8 | parser: '@typescript-eslint/parser', 9 | parserOptions: { 10 | ecmaVersion: 2020, 11 | }, 12 | plugins: ['@typescript-eslint', 'prettier'], 13 | rules: { 14 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 15 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 16 | 'prettier/prettier': 'warn', 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: https://github.com/chengpeiquan/sponsor 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true 4 | } 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 chengpeiquan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.en.md: -------------------------------------------------------------------------------- 1 | This package is no longer maintained, please use [@web-analytics/vue](https://analytics.js.org/vue/) , which has an easier method of use while maintaining the original functions. 2 | 3 | --- 4 | 5 |

6 | vue-cnzz-analytics 7 |

8 | 9 |

10 | 11 | 12 | 13 |

14 |
15 |
16 | 17 | [简体中文](https://github.com/analyticsjs/vue-cnzz-analytics/blob/master/README.md) | English 18 | 19 | Only 3 kB, this plugin base on the CNZZ analytics, it can help you quickly to collect the page views on your website, including single page web application. 20 | 21 | >Since the version v2.0.0, it supports the Vue 3.0, and is compatible with the Vue 2.0, you can see the live demo to learn more.
If you haven’t started using Vue 3.0, welcome to read the tutorial [learning Vue3](https://vue3.chengpeiquan.com/) . 22 | 23 | ## Features 24 | 25 | * Asynchronously load the CNZZ analytics scripts, no need to modify the entry HTML. 26 | 27 | * Support the deployment of multiple site IDs and corresponding data reporting. 28 | 29 | * Supports automatic reporting of PV data generated by route switching (This feature need [Vue Router](https://router.vuejs.org/), It can support hash mode and history mode). 30 | 31 | * Support manual submission of page views reports. 32 | 33 | * Support manual submission of event reports. 34 | 35 | * Since the version v2.0.0, the plugin can automatically recognize the Vue version at Vue 2.0 or Vue 3.0 . 36 | 37 | * Since the version v2.1.0, Hooks API is provided (So the usage of CDN installation is slightly adjusted) 38 | 39 | ## Project 40 | 41 | As long as Vue and Vue Router are introduced, the projects can be used normally, no matter what method is used to develop your project, e.g. : 42 | 43 | * Vue-CLI scaffolding project 44 | 45 | * Vite project 46 | 47 | * Introduce the HTML page of Vue related CDN 48 | 49 | * VuePress project 50 | 51 | It is not limited to SPA single page projects, it can also be used in SSG / SSR projects. 52 | 53 | ## Preview 54 | 55 | Both live demos have enabled debug mode, and you can open the console to view the report. 56 | 57 | Vue 2.0 :[vue-cnzz-analytics demo for Vue 2.x](https://analyticsjs.github.io/vue-cnzz-analytics/demo/vue2.html "vue-cnzz-analytics demo for Vue 2.x") 58 | 59 | Vue 3.0 :[vue-cnzz-analytics demo for Vue 3.x](https://analyticsjs.github.io/vue-cnzz-analytics/demo/vue3.html "vue-cnzz-analytics demo for Vue 3.x") 60 | 61 | ## Options 62 | 63 | Option|Required|Type|Description 64 | :-:|:-:|:-:|- 65 | router|false|object|Vue Router(It is optional since v2.2.0.) 66 | siteIdList|true|number[]|The site ids for CNZZ analytics, if only one site needs to be reported, just keep one item in the array. 67 | isDebug|false|boolean|if `true`, it will open the debug mode,you can see the log in the console. 68 | 69 | Tips: Please remember to turn off the debug mode before publish. 70 | 71 | ## Install 72 | 73 | You can install the plugin from NPM. 74 | 75 | ```bash 76 | npm install vue-cnzz-analytics --save-dev 77 | ``` 78 | 79 | Can also use the CDN URL in your HTML. 80 | 81 | ```html 82 | 83 | ``` 84 | 85 | ## Usage 86 | 87 | If use NPM, you must import the plugin in `main.js` . 88 | 89 | ```js 90 | import cnzzAnalytics from 'vue-cnzz-analytics' 91 | ``` 92 | 93 | Then, refer to the sample code in Vue 2.0 and Vue 3.0 below to use it. 94 | 95 | When the route is switched, the new URL address will be reported to CNZZ analytics after the visit. 96 | 97 | ### Use in the Vue 2.0 98 | 99 | See:[main.js - Vue 2.0 demo](https://analyticsjs.github.io/vue-cnzz-analytics/demo/js/main-for-vue2.js) 100 | 101 | >Since the version v2.1.0, if you use CDN in your HTML, must be use `cnzzAnalytics.default` to use the plugin. 102 | 103 | ```js 104 | Vue.use(cnzzAnalytics, { 105 | router: router, 106 | siteIdList: [ 107 | 11111, 108 | 22222 109 | ], 110 | isDebug: false 111 | }); 112 | ``` 113 | 114 | ### Use in the Vue 3.0 115 | 116 | See:[main.js - Vue 3.0 demo](https://analyticsjs.github.io/vue-cnzz-analytics/demo/js/main-for-vue3.js) 117 | 118 | >Since the version v2.1.0, if you use CDN in your HTML, must be use `cnzzAnalytics.default` to use the plugin. 119 | 120 | ```js 121 | createApp(app) 122 | .use(router) 123 | .use(cnzzAnalytics, { 124 | router: router, 125 | siteIdList: [ 126 | 11111, 127 | 22222 128 | ], 129 | isDebug: false 130 | }) 131 | .mount('#app'); 132 | ``` 133 | 134 | ### Use in the VuePress 135 | 136 | The plugin can also be used in [VuePress](https://vuepress.vuejs.org/zh/) project. 137 | 138 | In the `/docs/.vuepress` folder under the project, create a file named `enhanceApp.js`, and write the following code in this file. 139 | 140 | You can see [App Level Enhancements - VuePress](https://vuepress.vuejs.org/guide/basic-config.html#app-level-enhancements) to learn more. 141 | 142 | ```js 143 | import cnzzAnalytics from 'vue-cnzz-analytics' 144 | 145 | export default ({ Vue, router }) => { 146 | Vue.use(cnzzAnalytics, { 147 | router: router, 148 | siteIdList: [ 149 | 11111, 150 | 22222 151 | ], 152 | isDebug: false 153 | }); 154 | }; 155 | ``` 156 | 157 | You can turn on the debug mode in the development environment to learn about related reports (remember to turn off debug before going online). 158 | 159 | ## API 160 | 161 | Since the version v2.1.0, you can use the Global API `$pushCNZZ` and the Hooks API `usePush` in your project, they both support the Vue 2.0 and 3.0. 162 | 163 | >The APIs can't be used directly, it needs to cooperate with the [Methods](#Methods) to operate the specific functions. 164 | 165 | ### The Global API 166 | 167 | In the Vue 2.0: 168 | 169 | ```js 170 | // xxx.vue in Vue 2.0 171 | export default { 172 | // ... 173 | mounted () { 174 | this.$pushCNZZ.pv('/example-url/'); 175 | }, 176 | // ... 177 | } 178 | ``` 179 | 180 | In the Vue 3.0, you can use the Global Properties: 181 | 182 | ```js 183 | // xxx.vue in Vue 3.0 184 | import { getCurrentInstance } from 'vue' 185 | 186 | export default { 187 | setup () { 188 | const app = getCurrentInstance(); 189 | app.appContext.config.globalProperties.$pushCNZZ.pv('/example-url/'); 190 | } 191 | } 192 | ``` 193 | 194 | You can also import the proxy component in the current instance to operate: 195 | 196 | ```js 197 | // xxx.vue in Vue 3.0 198 | import { getCurrentInstance } from 'vue' 199 | 200 | export default { 201 | setup () { 202 | const { proxy } = getCurrentInstance(); 203 | proxy.$pushCNZZ.pv('/example-url/'); 204 | } 205 | } 206 | ``` 207 | 208 | ### The Hooks API 209 | 210 | In the Vue 2.0: 211 | 212 | ```js 213 | // xxx.vue in Vue 2.0 214 | import { usePush } from 'vue-cnzz-analytics' 215 | 216 | export default { 217 | // ... 218 | data () { 219 | return { 220 | cnzz: usePush() 221 | } 222 | }, 223 | mounted () { 224 | this.cnzz.pv('/example-url/'); 225 | }, 226 | // ... 227 | } 228 | ``` 229 | 230 | In the Vue 3.0, just use it as if you were using the route `const router = useRouter();`. 231 | 232 | ```js 233 | // xxx.vue in Vue 3.0 234 | import { usePush } from 'vue-cnzz-analytics' 235 | 236 | export default { 237 | setup () { 238 | const cnzz = usePush(); 239 | cnzz.pv('/example-url/'); 240 | } 241 | } 242 | ``` 243 | 244 | If the name of the hook API has already been declared, you can rename it when import. 245 | 246 | ```js 247 | import { usePush as useCnzz } from 'vue-cnzz-analytics' 248 | const cnzz = useCnzz(); 249 | ``` 250 | 251 | ## Methods 252 | 253 | All methods are needs to be triggered through the API, and the methods supported by the Global API and the Hooks API are exactly the same. 254 | 255 | Method|Description 256 | :--|:-- 257 | Manually report the page views|[Click here to see.](#manually-report-the-page-views) 258 | Manually report the event analysis|[Click here to see.](#manually-report-the-event-analysis) 259 | 260 | >Since there are still many users of Vue 2.0, the following examples only use the operation method of Vue 2.0 to demonstrate. Vue 3.0 can call specific methods according to the description of the Hooks API. 261 | 262 | Tips: If multiple site IDs are configured, the data will be reported to all sites at the same time. 263 | 264 | ### Manually report the page views 265 | 266 | If you switch content rendering on some pages through Tab, but you need to report access data, you can use this method to manually report. 267 | 268 | Method|Description 269 | :-:|- 270 | pv|Manually perform PV data reporting. 271 | 272 | **Params** 273 | 274 | Param|Required|Type|Description 275 | :-:|:-:|:-:|- 276 | pageUrl|false|string|The URL submitted for the report must be a relative path starting with `/`, if not filled, it will be submitted as the domain name root directory by default. 277 | fromUrl|false|string|The URL of the incoming page must be an absolute address beginning with `http` or `https`, if it is not filled in, the statistics platform will consider the source of the visit to be a direct input address. 278 | 279 | **Example** 280 | 281 | ```js 282 | this.$pushCNZZ.pv('/example-url/', 'https://example.com/example-from-url/'); 283 | ``` 284 | 285 | ### Manually report the event analysis 286 | 287 | For example, there is a "exchange" function button on your page. If you want to count the clicks of this button, you can perform click analysis by binding the button to report events. 288 | 289 | Method|Description 290 | :-:|- 291 | event|Manually perform event analysis data reporting. 292 | 293 | **Params** 294 | 295 | Param|Required|Type|Description 296 | :-:|:-:|:-:|- 297 | category|true|string|The name of the location where the event occurred, e.g. `banner` 298 | action|true|string|The description of the behavior that generated the event, e.g. `click` 299 | label|false|string|The name of the label that generated the event can be used to record the event sub-id, e.g. `bannerId_123`. (@default: '') 300 | value|false|number|The score of the event. (@default: 0) 301 | nodeId|false|string|The id of the element that generated the event. (@default: '') 302 | 303 | **Example** 304 | 305 | ```js 306 | this.$pushCNZZ.event( 307 | this.category, 308 | this.action, 309 | this.label, 310 | this.value, 311 | this.nodeId 312 | ); 313 | ``` 314 | 315 | ## CHANGELOG 316 | 317 | See:[releases](https://github.com/analyticsjs/vue-cnzz-analytics/releases) 318 | 319 | ## License 320 | 321 | [MIT License](https://github.com/analyticsjs/vue-cnzz-analytics/blob/master/LICENSE) © 2019 [chengpeiquan](https://github.com/chengpeiquan) 322 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 本包不再维护,请使用 [@web-analytics/vue](https://analytics.js.org/vue/) ,在保持原有功能的基础上,具有更简单的使用方法。 2 | 3 | --- 4 | 5 |

6 | vue-cnzz-analytics 7 |

8 | 9 |

10 | 11 | 12 | 13 |

14 |
15 |
16 | 17 | 简体中文 | [English](https://github.com/analyticsjs/vue-cnzz-analytics/blob/master/README.en.md) 18 | 19 | 一个只有 3 kB 大小的插件,可以帮你轻松解决 SPA 单页面项目浏览数据不准确的问题,基于 Vue 路由访问轨迹自动向友盟统计平台上报 PV / 事件数据。 20 | 21 | >本插件自 v2.0.0 开始,最新版插件支持在 Vue 3.0 项目下使用,同时兼容 Vue 2.0 项目的使用,具体使用方法请看下方说明以及在线 demo 。
对 Vue 3.0 感兴趣,但还在观望的同学,欢迎阅读我踩坑总结的:[Vue3.0学习教程与实战案例](https://vue3.chengpeiquan.com/) (持续更新ing) 22 | 23 | ## 功能 24 | 25 | * 异步载入友盟统计脚本,无需修改入口 HTML 26 | 27 | * 支持部署多个站点 ID ,并对应进行数据上报(跨部门合作项目,双方均要收集数据时非常有用) 28 | 29 | * 支持自动上报路由切换产生的 PV 数据(需引入 [Vue Router](https://router.vuejs.org/),支持 hash 模式和 history 模式的地址) 30 | 31 | * 支持手动提交 PV 上报 32 | 33 | * 支持手动提交事件分析上报 34 | 35 | * 自动识别 Vue 版本,自动适配 Vue 2.0 / Vue 3.0 使用(本插件 v2.0.0 版本新增) 36 | 37 | * 提供了 Hooks API(本插件 v2.1.0 版本新增,因此 CDN 安装的用法略有调整,请留意使用说明) 38 | 39 | ## 项目 40 | 41 | 理论上只要引入了 Vue (必须) 和 Vue Router (自 v2.2.0 起是可选) 的项目均可以正常使用,包括但不限于以下类型: 42 | 43 | * Vue-CLI 脚手架项目 44 | 45 | * Vite 项目 46 | 47 | * 引入 Vue 相关 CDN 的 HTML 页面 48 | 49 | * VuePress 项目 50 | 51 | 也不仅限于 SPA 单页面项目,在 SSG / SSR 项目里也可以使用。 52 | 53 | ## 预览 54 | 55 | 两个在线 demo 均已开启 debug 模式,可开启控制台查看上报情况。 56 | 57 | Vue 2.0 版本:[vue-cnzz-analytics demo for Vue 2.x](https://analyticsjs.github.io/vue-cnzz-analytics/demo/vue2.html "vue-cnzz-analytics demo for Vue 2.x") 58 | 59 | Vue 3.0 版本:[vue-cnzz-analytics demo for Vue 3.x](https://analyticsjs.github.io/vue-cnzz-analytics/demo/vue3.html "vue-cnzz-analytics demo for Vue 3.x") 60 | 61 | ## 选项 62 | 63 | 选项|是否必填|选项类型|选项说明 64 | :-:|:-:|:-:|- 65 | router|否|object|Vue Router(自 v2.2.0 版本开始为可选,无路由的单页则不必传该选项) 66 | siteIdList|是|number[]|友盟统计的站点 id 列表,只有一个站点需要上报就保留一个 id 即可 67 | isDebug|否|boolean|是否开启 debug 模式,默认 `false`,开启后会在 F12 控制台打印上报信息 68 | 69 | 友情提示:上线前记得关闭 debug 模式。 70 | 71 | ## 安装 72 | 73 | 方式一:通过 NPM 安装 74 | 75 | ```bash 76 | npm install vue-cnzz-analytics --save-dev 77 | ``` 78 | 79 | 方式二:通过 CDN 安装 80 | 81 | ```html 82 | 83 | ``` 84 | 85 | ## 启用 86 | 87 | 通过 NPM 安装的项目,需要先在 main.js 里引入插件(通过 CDN 则无需该步骤)。 88 | 89 | ```js 90 | import cnzzAnalytics from 'vue-cnzz-analytics' 91 | ``` 92 | 93 | 安装插件后,在 main.js 引入以下代码(注意 Vue 2.0 和 Vue 3.0 的用法区别),即可开启自动上报功能,首次访问页面会部署统计代码并提交第一次访问数据上报。 94 | 95 | 后续在路由切换过程中,也会根据路由的切换提交相应的 URL 信息到友盟统计。 96 | 97 | ### 在 Vue 2.0 里使用 98 | 99 | 可参考demo:[main.js - Vue 2.0 demo](https://analyticsjs.github.io/vue-cnzz-analytics/demo/js/main-for-vue2.js) 100 | 101 | >自 v2.1.0 版本开始,如果是通过 CDN 安装,需要使用 `cnzzAnalytics.default` 去激活插件,通过 NPM 安装的脚手架项目则使用 `cnzzAnalytics` 就可以 102 | 103 | ```js 104 | // 启动插件 105 | Vue.use(cnzzAnalytics, { 106 | router: router, 107 | siteIdList: [ 108 | 11111, 109 | 22222 110 | ], 111 | isDebug: false 112 | }); 113 | ``` 114 | 115 | ### 在 Vue 3.0 里使用 116 | 117 | 可参考demo:[main.js - Vue 3.0 demo](https://analyticsjs.github.io/vue-cnzz-analytics/demo/js/main-for-vue3.js) 118 | 119 | >自 v2.1.0 版本开始,如果是通过 CDN 安装,需要使用 `cnzzAnalytics.default` 去激活插件,通过 NPM 安装的脚手架项目则使用 `cnzzAnalytics` 就可以 120 | 121 | ```js 122 | /** 123 | * 初始化Vue 124 | */ 125 | createApp(app) 126 | // 启动路由 127 | .use(router) 128 | 129 | // 启动插件 130 | .use(cnzzAnalytics, { 131 | router: router, 132 | siteIdList: [ 133 | 11111, 134 | 22222 135 | ], 136 | isDebug: false 137 | }) 138 | 139 | // 挂载到节点上 140 | .mount('#app'); 141 | ``` 142 | 143 | ### 在 VuePress 里使用 144 | 145 | 插件也支持在Vue的静态文档 [VuePress](https://vuepress.vuejs.org/zh/) 项目里使用。 146 | 147 | 在项目下的 `/docs/.vuepress` 文件夹下,创建一个 `enhanceApp.js`,按照下面的方式引入即可启动数据上报功能。 148 | 149 | 官方文档传送门:[应用级别的配置 - VuePress](https://vuepress.vuejs.org/zh/guide/basic-config.html#%E5%BA%94%E7%94%A8%E7%BA%A7%E5%88%AB%E7%9A%84%E9%85%8D%E7%BD%AE) 150 | 151 | ```js 152 | import cnzzAnalytics from 'vue-cnzz-analytics' 153 | 154 | export default ({ Vue, router }) => { 155 | Vue.use(cnzzAnalytics, { 156 | router: router, 157 | siteIdList: [ 158 | 11111, 159 | 22222 160 | ], 161 | isDebug: false 162 | }); 163 | }; 164 | ``` 165 | 166 | 可在开发环境打开 debug 模式了解相关的上报情况(上线前记得关闭 debug )。 167 | 168 | ## API 169 | 170 | 自 v2.1.0 版本开始,插件支持直接调用的全局 API `$pushCNZZ` 和按需导入的钩子 API `usePush` 两种方式。 171 | 172 | 这两种方式在 Vue 2.0 和 3.0 里均可以使用,只不过按照使用习惯和从 Vue 官方推荐的角度来说,全局 API 更适合 Vue 2.0 项目,钩子 API 更适合 Vue 3.0 项目。 173 | 174 | > 插件的 API 不可以直接使用,需要配合 API 里面的 [方法](#方法) 才可以操作到具体功能。 175 | 176 | ### 全局 API 177 | 178 | 在 Vue 2.0 里,只需要通过我们熟悉的 `this` 去操作即可: 179 | 180 | ```js 181 | // xxx.vue in Vue 2.0 182 | export default { 183 | // ... 184 | mounted () { 185 | this.$pushCNZZ.pv('/example-url/'); 186 | }, 187 | // ... 188 | } 189 | ``` 190 | 191 | 在 Vue 3.0 里,可以按照官方文档的推荐,导入当前实例变量,通过当前实例变量去操作全局方法: 192 | 193 | ```js 194 | // xxx.vue in Vue 3.0 195 | import { getCurrentInstance } from 'vue' 196 | 197 | export default { 198 | setup () { 199 | const app = getCurrentInstance(); 200 | app.appContext.config.globalProperties.$pushCNZZ.pv('/example-url/'); 201 | } 202 | } 203 | ``` 204 | 205 | 也可以导入当前实例里的代理组件去操作: 206 | 207 | ```js 208 | // xxx.vue in Vue 3.0 209 | import { getCurrentInstance } from 'vue' 210 | 211 | export default { 212 | setup () { 213 | const { proxy } = getCurrentInstance(); 214 | proxy.$pushCNZZ.pv('/example-url/'); 215 | } 216 | } 217 | ``` 218 | 219 | ### 钩子 API 220 | 221 | >钩子 API 需要在用到的组件里 import 导入才可以使用。 222 | 223 | 在 Vue 2.0 里,你可以绑定一个钩子变量去使用: 224 | 225 | ```js 226 | // xxx.vue in Vue 2.0 227 | import { usePush } from 'vue-cnzz-analytics' 228 | 229 | export default { 230 | // ... 231 | data () { 232 | return { 233 | // 创建钩子变量 234 | cnzz: usePush() 235 | } 236 | }, 237 | mounted () { 238 | // 通过钩子变量去触发方法 239 | this.cnzz.pv('/example-url/'); 240 | }, 241 | // ... 242 | } 243 | ``` 244 | 245 | 在 Vue 3.0 里,就像在使用路由 `const router = useRouter();` 一样去使用就可以。 246 | 247 | ```js 248 | // xxx.vue in Vue 3.0 249 | import { usePush } from 'vue-cnzz-analytics' 250 | 251 | export default { 252 | setup () { 253 | // 创建钩子变量 254 | const cnzz = usePush(); 255 | 256 | // 通过钩子变量去触发方法 257 | cnzz.pv('/example-url/'); 258 | } 259 | } 260 | ``` 261 | 262 | 另外,如果 API 与其他插件冲突的话(比如你同时使用了 [vue-baidu-analytics](https://github.com/analyticsjs/vue-baidu-analytics)),你可以在导入的时候重命名: 263 | 264 | ```js 265 | import { usePush as useCnzz } from 'vue-cnzz-analytics' 266 | const cnzz = useCnzz(); 267 | ``` 268 | 269 | ## 方法 270 | 271 | 方法需要通过 API 去触发,全局 API 和 钩子 API 支持的方法都是完全一样的。 272 | 273 | 方法功能|使用说明 274 | :--|:-- 275 | 手动上报页面 PV|[点击查看](#手动上报页面PV) 276 | 手动上报事件分析|[点击查看](#手动上报事件分析) 277 | 278 | > 由于目前 Vue 2.0 的使用者还比较多,下面的举例均只用 Vue 2.0 的操作方法进行演示,Vue 3.0 可根据钩子 API 的说明去调用具体的方法。 279 | 280 | 注:如果配置了多个站点 ID ,数据都会同时上报给所有站点。 281 | 282 | ### 手动上报页面 PV 283 | 284 | 如果你有些页面是通过 Tab 切页进行内容渲染切换,但又需要上报访问数据的话,就可以使用这个方法来进行手动上报。 285 | 286 | 方法名称|功能说明 287 | :-:|- 288 | pv|手动执行 PV 数据上报 289 | 290 | **参数** 291 | 292 | 参数|是否必填|参数类型|参数说明 293 | :-:|:-:|:-:|- 294 | pageUrl|否|string|提交上报的 URL ,必须是以 `/` 开头的相对路径,如果不填,则会默认提交为域名根目录 295 | fromUrl|否|string|来路页面的url,必须是以 `http` 或 `https` 开头的绝对地址,如果不填,则统计平台会认为访问来源为直接输入地址 296 | 297 | **使用示范** 298 | 299 | ```js 300 | this.$pushCNZZ.pv('/example-url/', 'https://example.com/example-from-url/'); 301 | ``` 302 | 303 | ### 手动上报事件分析 304 | 305 | 比如你的页面上有个 “换一换” 的功能按钮,想要统计这个按钮的点击情况,就可以通过给按钮绑定上报事件来进行点击情况分析。 306 | 307 | 方法名称|功能说明 308 | :-:|- 309 | event|手动执行事件分析数据上报 310 | 311 | **参数** 312 | 313 | 参数|是否必填|参数类型|参数说明 314 | :-:|:-:|:-:|- 315 | category|是|string|产生该事件的位置名称,比如 `首页banner` 316 | action|是|string|产生该事件的行为描述,比如 `点击` 317 | label|否|string|产生该事件的标签名称,可以用来记录事件子 id,比如 `bannerId_123`,默认为空 318 | value|否|number|该事件的分值,默认 0 319 | nodeId|否|string|产生该事件的元素id,默认为空 320 | 321 | **使用示范** 322 | 323 | ```js 324 | this.$pushCNZZ.event( 325 | this.category, 326 | this.action, 327 | this.label, 328 | this.value, 329 | this.nodeId 330 | ); 331 | ``` 332 | 333 | ## 更新记录 334 | 335 | 点击查看:[releases](https://github.com/analyticsjs/vue-cnzz-analytics/releases) 336 | 337 | ## License 338 | 339 | [MIT License](https://github.com/analyticsjs/vue-cnzz-analytics/blob/master/LICENSE) © 2020 [chengpeiquan](https://github.com/chengpeiquan) 340 | -------------------------------------------------------------------------------- /demo/css/style.css: -------------------------------------------------------------------------------- 1 | #app, 2 | .section { 3 | display: flex; 4 | flex-direction: column; 5 | justify-content: flex-start; 6 | align-items: center; 7 | } 8 | .section { 9 | margin-bottom: 40px; 10 | } 11 | .title { 12 | font-size: 40px; 13 | color: #000; 14 | } 15 | .link { 16 | color: #666; 17 | text-decoration: none; 18 | } 19 | .link:hover { 20 | color: #000; 21 | } 22 | .nav { 23 | margin-bottom: 20px; 24 | } 25 | .nav .item { 26 | color: #666; 27 | margin: 0 10px 20px; 28 | } 29 | .nav .cur { 30 | color: #000; 31 | font-weight: bold; 32 | } 33 | .label { 34 | display: flex; 35 | justify-content: center; 36 | align-items: center; 37 | margin-bottom: 20px; 38 | } 39 | .text { 40 | display: flex; 41 | justify-content: flex-end; 42 | align-items: center; 43 | width: 60px; 44 | font-size: 14px; 45 | color: #333; 46 | margin-right: 20px; 47 | } 48 | .input { 49 | display: flex; 50 | align-items: center; 51 | width: 240px; 52 | height: 40px; 53 | font-size: 14px; 54 | box-sizing: border-box; 55 | padding: 0 10px; 56 | } 57 | .button { 58 | padding: 5px 20px; 59 | cursor: pointer; 60 | } -------------------------------------------------------------------------------- /demo/js/main-for-vue2.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 初始化路由 3 | * routes是来自 js/routes.js 里面的配置 4 | */ 5 | const router = new VueRouter({ 6 | routes, 7 | linkActiveClass: 'cur', 8 | linkExactActiveClass: 'cur' 9 | }); 10 | 11 | 12 | /** 13 | * 引入统计插件 14 | * @description 自 v2.1.0 版本开始,需要使用 .default 去激活插件 15 | */ 16 | Vue.use(cnzzAnalytics.default, { 17 | router: router, 18 | siteIdList: [ 19 | 11111, 20 | 22222 21 | ], 22 | isDebug: true 23 | }); 24 | 25 | 26 | /** 27 | * 初始化Vue 28 | */ 29 | const app = new Vue({ 30 | el: '#app', 31 | router, 32 | data () { 33 | return { 34 | pageUrl: '', 35 | fromUrl: '', 36 | category: '', 37 | action: '', 38 | label: '', 39 | value: '', 40 | nodeId: '', 41 | 42 | // 也可以绑定一个钩子变量去使用 43 | cnzz: cnzzAnalytics.usePush() 44 | } 45 | }, 46 | mounted () { 47 | this.cnzz.pv('/use-push-api/?from=mounted'); 48 | }, 49 | methods: { 50 | /** 51 | * 提交 pv 52 | * @description 支持两种推送方式 53 | */ 54 | pv () { 55 | // 使用默认全局 API 56 | this.$pushCNZZ.pv( 57 | this.pageUrl, 58 | this.fromUrl 59 | ); 60 | 61 | // 使用钩子 API 62 | // this.cnzz.pv( 63 | // this.pageUrl, 64 | // this.fromUrl 65 | // ); 66 | }, 67 | 68 | /** 69 | * 提交事件 70 | * @description 支持两种推送方式 71 | */ 72 | event () { 73 | // 使用默认全局 API 74 | // this.$pushCNZZ.event( 75 | // this.category, 76 | // this.action, 77 | // this.label, 78 | // this.value, 79 | // this.nodeId 80 | // ); 81 | 82 | // 使用钩子 API 83 | this.cnzz.event( 84 | this.category, 85 | this.action, 86 | this.label, 87 | this.value, 88 | this.nodeId 89 | ); 90 | } 91 | } 92 | }); 93 | -------------------------------------------------------------------------------- /demo/js/main-for-vue3.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 导入需要用到的组件 3 | */ 4 | const { createRouter, createWebHashHistory } = VueRouter; 5 | const { createApp, getCurrentInstance, ref } = Vue; 6 | const { usePush } = cnzzAnalytics; 7 | 8 | 9 | /** 10 | * 初始化路由 11 | * routes是来自 js/routes.js 里面的配置 12 | */ 13 | const router = createRouter({ 14 | history: createWebHashHistory(), 15 | routes, 16 | linkActiveClass: 'cur', 17 | linkExactActiveClass: 'cur' 18 | }); 19 | 20 | 21 | /** 22 | * 创建实例 23 | */ 24 | const app = { 25 | setup () { 26 | /** 27 | * 新的推荐方式 28 | * @description 创建一个钩子变量去使用,更适合于 TypeScript 项目 29 | */ 30 | const cnzz = usePush(); 31 | 32 | /** 33 | * 原来的方式 34 | * @description 从当前实例里,导入代理组件去操作,对 TS 项目不够友好 35 | */ 36 | // const instance = getCurrentInstance(); 37 | // const { proxy } = instance; 38 | 39 | 40 | // 初始化要用到的数据 41 | const pageUrl = ref(''); 42 | const fromUrl = ref(''); 43 | const category = ref(''); 44 | const action = ref(''); 45 | const label = ref(''); 46 | const value = ref(''); 47 | const nodeId = ref(''); 48 | 49 | /** 50 | * 提交 pv 51 | * @description 支持两种推送方式 52 | */ 53 | const pv = () => { 54 | // 通过钩子去操作 55 | cnzz.pv( 56 | pageUrl.value, 57 | fromUrl.value 58 | ); 59 | 60 | // 也可以通过全局属性去操作 61 | // instance.appContext.config.globalProperties.$pushCNZZ.pv( 62 | // pageUrl.value, 63 | // fromUrl.value 64 | // ); 65 | 66 | // 也可以通过代理组件去操作 67 | // proxy.$pushCNZZ.pv( 68 | // pageUrl.value, 69 | // fromUrl.value 70 | // ); 71 | } 72 | 73 | // 提交事件的操作 74 | const event = () => { 75 | // 通过钩子去操作 76 | cnzz.event( 77 | category.value, 78 | action.value, 79 | label.value, 80 | value.value, 81 | nodeId.value 82 | ); 83 | 84 | // 也可以通过全局属性去操作 85 | // instance.appContext.config.globalProperties.$pushCNZZ.event( 86 | // category.value, 87 | // action.value, 88 | // label.value, 89 | // value.value, 90 | // nodeId.value 91 | // ); 92 | 93 | // 也可以通过代理组件去操作 94 | // proxy.$pushCNZZ.event( 95 | // category.value, 96 | // action.value, 97 | // label.value, 98 | // value.value, 99 | // nodeId.value 100 | // ); 101 | } 102 | 103 | // Vue 3.0 需要把模板要用到的东西 return 出去 104 | return { 105 | // 数据 106 | pageUrl, 107 | fromUrl, 108 | category, 109 | action, 110 | label, 111 | value, 112 | nodeId, 113 | 114 | // 方法 115 | pv, 116 | event 117 | } 118 | } 119 | }; 120 | 121 | 122 | /** 123 | * 初始化Vue 124 | */ 125 | createApp(app) 126 | // 启动路由 127 | .use(router) 128 | 129 | // 启动插件 130 | .use(cnzzAnalytics.default, { 131 | router: router, 132 | siteIdList: [ 133 | 11111, 134 | 22222 135 | ], 136 | isDebug: true 137 | }) 138 | 139 | // 挂载到节点上 140 | .mount('#app'); 141 | -------------------------------------------------------------------------------- /demo/js/routes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 定义路由信息 3 | */ 4 | const routes = [ 5 | { 6 | path: '/', 7 | redirect: '/page1' 8 | }, 9 | { 10 | path: '/page1', 11 | component: { 12 | template: '
当前是 Page1 的路由
' 13 | } 14 | }, 15 | { 16 | path: '/page2', 17 | component: { 18 | template: '
当前是 Page2 的路由
' 19 | } 20 | }, 21 | { 22 | path: '/page3', 23 | component: { 24 | template: '
当前是 Page3 的路由
' 25 | } 26 | } 27 | ]; -------------------------------------------------------------------------------- /demo/vue2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | [Vue2] vue cnzz analytics demo 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 |

Hello Vue2 App!

17 | [ 切换到vue3 ] 18 |
19 | 20 |
21 |

切换路由自动上报测试

22 | 27 | 28 |
29 | 30 |
31 |

提交pv测试

32 | 36 | 40 | 41 |
42 | 43 |
44 |

提交event测试

45 | 49 | 53 | 57 | 61 | 65 | 66 |
67 |
68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /demo/vue3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | [Vue3] vue cnzz analytics demo 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 |

Hello Vue3 App!

17 | [ 切换到vue2 ] 18 |
19 | 20 |
21 |

切换路由自动上报测试

22 | 27 | 28 |
29 | 30 |
31 |

提交pv测试

32 | 36 | 40 | 41 |
42 | 43 |
44 |

提交event测试

45 | 49 | 53 | 57 | 61 | 65 | 66 |
67 |
68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /dist/main.d.ts: -------------------------------------------------------------------------------- 1 | import type { Options, Vue } from '@/types' 2 | export declare function usePush(): { 3 | pv: (pageUrl: string, fromUrl?: string) => void 4 | event: ( 5 | category: string, 6 | action: string, 7 | label: string, 8 | value: number, 9 | nodeId: string 10 | ) => void 11 | } 12 | export default function install( 13 | Vue: Vue, 14 | { router, siteIdList, isDebug }: Partial 15 | ): boolean 16 | -------------------------------------------------------------------------------- /dist/modules/cnzz.d.ts: -------------------------------------------------------------------------------- 1 | declare class CNZZ { 2 | siteId: number 3 | isDebug: boolean 4 | constructor(siteId?: number, isDebug?: boolean) 5 | init(): void 6 | setAccount(): void 7 | trackPageview(pageUrl: string, fromUrl?: string): void 8 | trackEvent( 9 | category: string, 10 | action: string, 11 | label: string, 12 | value: number, 13 | nodeId: string 14 | ): void 15 | } 16 | export default CNZZ 17 | -------------------------------------------------------------------------------- /dist/modules/getVueVersion.d.ts: -------------------------------------------------------------------------------- 1 | import type { Vue } from '@/types' 2 | declare const getVueVersion: (Vue: Vue) => number 3 | export default getVueVersion 4 | -------------------------------------------------------------------------------- /dist/modules/pushCNZZ.d.ts: -------------------------------------------------------------------------------- 1 | declare class PushCNZZ { 2 | siteIdList: number[]; 3 | isDebug: boolean; 4 | constructor(siteIdList: number[], isDebug: boolean); 5 | init(): void; 6 | pv(pageUrl: string, fromUrl?: string): void; 7 | event(category: string, action: string, label: string, value: number, nodeId: string): void; 8 | } 9 | export default PushCNZZ; 10 | -------------------------------------------------------------------------------- /dist/types.d.ts: -------------------------------------------------------------------------------- 1 | import PushCNZZ from '@m/pushCNZZ' 2 | export interface Options { 3 | router: any 4 | siteIdList: number[] 5 | isDebug: boolean 6 | } 7 | export interface Vue { 8 | prototype: any 9 | $pushCNZZ: PushCNZZ 10 | version: number | string 11 | config: any 12 | } 13 | -------------------------------------------------------------------------------- /dist/vue-cnzz-analytics.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * name: vue-cnzz-analytics 3 | * version: v2.2.0 4 | * author: chengpeiquan 5 | */ 6 | ;(function (global, factory) { 7 | typeof exports === 'object' && typeof module !== 'undefined' 8 | ? factory(exports) 9 | : typeof define === 'function' && define.amd 10 | ? define(['exports'], factory) 11 | : ((global = 12 | typeof globalThis !== 'undefined' ? globalThis : global || self), 13 | factory((global.cnzzAnalytics = {}))) 14 | })(this, function (exports) { 15 | 'use strict' 16 | 17 | /*! ***************************************************************************** 18 | Copyright (c) Microsoft Corporation. 19 | 20 | Permission to use, copy, modify, and/or distribute this software for any 21 | purpose with or without fee is hereby granted. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 24 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 25 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 26 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 27 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 28 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 29 | PERFORMANCE OF THIS SOFTWARE. 30 | ***************************************************************************** */ 31 | function __spreadArray(to, from, pack) { 32 | if (pack || arguments.length === 2) 33 | for (var i = 0, l = from.length, ar; i < l; i++) { 34 | if (ar || !(i in from)) { 35 | if (!ar) ar = Array.prototype.slice.call(from, 0, i) 36 | ar[i] = from[i] 37 | } 38 | } 39 | return to.concat(ar || from) 40 | } 41 | 42 | var CNZZ = (function () { 43 | function CNZZ(siteId, isDebug) { 44 | if (siteId === void 0) { 45 | siteId = 0 46 | } 47 | if (isDebug === void 0) { 48 | isDebug = false 49 | } 50 | this.siteId = siteId 51 | this.isDebug = isDebug 52 | } 53 | CNZZ.prototype.init = function () { 54 | window._czc = window._czc ? window._czc : [] 55 | var SCRIPT = document.createElement('script') 56 | SCRIPT['async'] = true 57 | SCRIPT['src'] = 58 | 'https://s9.cnzz.com/z_stat.php?id=' + 59 | this.siteId + 60 | '&web_id=' + 61 | this.siteId 62 | document.querySelector('head').appendChild(SCRIPT) 63 | if (this.isDebug) { 64 | console.log( 65 | '[vue-cnzz-analytics] siteId load done.\nsiteId: ' + this.siteId 66 | ) 67 | } 68 | } 69 | CNZZ.prototype.setAccount = function () { 70 | window._czc.push(['_setAccount', this.siteId]) 71 | } 72 | CNZZ.prototype.trackPageview = function (pageUrl, fromUrl) { 73 | if (!pageUrl || typeof pageUrl !== 'string') { 74 | pageUrl = '/' 75 | } 76 | if (pageUrl.includes('http')) { 77 | var PAGE_CUT = pageUrl.split('/') 78 | var HOST_NAME = PAGE_CUT[0] + '//' + PAGE_CUT[2] 79 | pageUrl = pageUrl.replace(HOST_NAME, '') 80 | } 81 | if (!fromUrl || (fromUrl && typeof fromUrl !== 'string')) { 82 | fromUrl = '' 83 | } 84 | if (typeof fromUrl === 'string' && !fromUrl.includes('http')) { 85 | fromUrl = '' 86 | } 87 | this.setAccount() 88 | if (fromUrl) { 89 | window._czc.push(['_trackPageview', pageUrl, fromUrl]) 90 | } else { 91 | window._czc.push(['_trackPageview', pageUrl]) 92 | } 93 | if (this.isDebug) { 94 | console.log( 95 | '[vue-cnzz-analytics] track pv done.\nsiteId: ' + 96 | this.siteId + 97 | '\npageUrl: ' + 98 | pageUrl + 99 | '\nfromUrl: ' + 100 | fromUrl 101 | ) 102 | } 103 | } 104 | CNZZ.prototype.trackEvent = function ( 105 | category, 106 | action, 107 | label, 108 | value, 109 | nodeId 110 | ) { 111 | if ( 112 | typeof category !== 'string' || 113 | typeof action !== 'string' || 114 | !category || 115 | !action 116 | ) { 117 | throw new Error( 118 | '[vue-cnzz-analytics] Missing necessary category and operation information, and must be of type string.' 119 | ) 120 | } 121 | if (!label || typeof label !== 'string') { 122 | label = '' 123 | } 124 | if (!Number(value)) { 125 | value = 0 126 | } 127 | if (!nodeId || typeof nodeId !== 'string') { 128 | nodeId = '' 129 | } 130 | this.setAccount() 131 | if (nodeId) { 132 | window._czc.push([ 133 | '_trackEvent', 134 | category, 135 | action, 136 | label, 137 | value, 138 | nodeId, 139 | ]) 140 | } else { 141 | window._czc.push(['_trackEvent', category, action, label, value]) 142 | } 143 | if (this.isDebug) { 144 | console.log( 145 | '[vue-cnzz-analytics] track event done.\nsiteId: ' + 146 | this.siteId + 147 | '\ncategory: ' + 148 | category + 149 | '\naction: ' + 150 | action + 151 | '\nlabel: ' + 152 | label + 153 | '\nvalue: ' + 154 | value + 155 | '\nnodeId: ' + 156 | nodeId 157 | ) 158 | } 159 | } 160 | return CNZZ 161 | })() 162 | 163 | var PushCNZZ = (function () { 164 | function PushCNZZ(siteIdList, isDebug) { 165 | this.siteIdList = __spreadArray([], siteIdList) 166 | this.isDebug = isDebug 167 | } 168 | PushCNZZ.prototype.init = function () { 169 | var _this = this 170 | this.siteIdList.forEach(function (siteId) { 171 | var SITE = new CNZZ(siteId, _this.isDebug) 172 | SITE.init() 173 | }) 174 | } 175 | PushCNZZ.prototype.pv = function (pageUrl, fromUrl) { 176 | var _this = this 177 | this.siteIdList.forEach(function (siteId) { 178 | var SITE = new CNZZ(siteId, _this.isDebug) 179 | SITE.trackPageview(pageUrl, fromUrl) 180 | }) 181 | } 182 | PushCNZZ.prototype.event = function ( 183 | category, 184 | action, 185 | label, 186 | value, 187 | nodeId 188 | ) { 189 | var _this = this 190 | this.siteIdList.forEach(function (siteId) { 191 | var SITE = new CNZZ(siteId, _this.isDebug) 192 | SITE.trackEvent(category, action, label, value, nodeId) 193 | }) 194 | } 195 | return PushCNZZ 196 | })() 197 | 198 | var getVueVersion = function (Vue) { 199 | var version = 2 200 | var VUE_VERSION = String(Vue.version) 201 | if (VUE_VERSION.slice(0, 2) === '2.') { 202 | version = 2 203 | } 204 | if (VUE_VERSION.slice(0, 2) === '3.') { 205 | version = 3 206 | } 207 | return version 208 | } 209 | 210 | var __GLOBAL__ = { 211 | pushCNZZ: {}, 212 | } 213 | function usePush() { 214 | function pv(pageUrl, fromUrl) { 215 | return __GLOBAL__.pushCNZZ.pv(pageUrl, fromUrl) 216 | } 217 | function event(category, action, label, value, nodeId) { 218 | return __GLOBAL__.pushCNZZ.event(category, action, label, value, nodeId) 219 | } 220 | return { 221 | pv: pv, 222 | event: event, 223 | } 224 | } 225 | function install(Vue, _a) { 226 | var router = _a.router, 227 | siteIdList = _a.siteIdList, 228 | _b = _a.isDebug, 229 | isDebug = _b === void 0 ? false : _b 230 | if (typeof document === 'undefined' || typeof window === 'undefined') { 231 | return false 232 | } 233 | if (!siteIdList) { 234 | throw new Error( 235 | '[vue-cnzz-analytics] Missing tracking domain ID, add at least one of cnzz analytics.' 236 | ) 237 | } 238 | var pushCNZZ = new PushCNZZ(siteIdList, isDebug) 239 | __GLOBAL__.pushCNZZ = pushCNZZ 240 | var VUE_VERSION = getVueVersion(Vue) || 2 241 | switch (VUE_VERSION) { 242 | case 2: 243 | Vue.prototype.$pushCNZZ = pushCNZZ 244 | break 245 | case 3: 246 | Vue.config.globalProperties.$pushCNZZ = pushCNZZ 247 | break 248 | } 249 | if (siteIdList && Array.isArray(siteIdList)) { 250 | pushCNZZ.init() 251 | } 252 | if (router) { 253 | router.afterEach(function () { 254 | var PAGE_URL = window.location.href 255 | pushCNZZ.pv(PAGE_URL) 256 | }) 257 | } 258 | } 259 | 260 | exports.default = install 261 | exports.usePush = usePush 262 | 263 | Object.defineProperty(exports, '__esModule', { value: true }) 264 | }) 265 | //# sourceMappingURL=vue-cnzz-analytics.js.map 266 | -------------------------------------------------------------------------------- /dist/vue-cnzz-analytics.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"vue-cnzz-analytics.js","sources":["../node_modules/tslib/tslib.es6.js","../src/modules/cnzz.ts","../src/modules/pushCNZZ.ts","../src/modules/getVueVersion.ts","../src/main.ts"],"sourcesContent":["/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n});\r\n\r\nexport function __exportStar(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n}\r\n\r\nexport function __spreadArray(to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || from);\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nvar __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n","/**\n * 定义基础配置\n * 官方文档 https://developer.umeng.com/docs/67963/detail/74517\n */\nclass CNZZ {\n siteId: number\n isDebug: boolean\n\n constructor(siteId: number = 0, isDebug: boolean = false) {\n this.siteId = siteId\n this.isDebug = isDebug\n }\n\n /**\n * 初始化\n */\n init() {\n window._czc = window._czc ? window._czc : []\n const SCRIPT = document.createElement('script')\n SCRIPT['async'] = true\n SCRIPT[\n 'src'\n ] = `https://s9.cnzz.com/z_stat.php?id=${this.siteId}&web_id=${this.siteId}`\n document.querySelector('head').appendChild(SCRIPT)\n\n if (this.isDebug) {\n console.log(\n `[vue-cnzz-analytics] siteId load done.\\nsiteId: ${this.siteId}`\n )\n }\n }\n\n /**\n * 设置要响应的站点\n */\n setAccount() {\n window._czc.push(['_setAccount', this.siteId])\n }\n\n /**\n * 提交PV、UV\n */\n trackPageview(pageUrl: string, fromUrl?: string) {\n // 如果页面链接没传或者无效链接,则默认为根域名\n if (!pageUrl || typeof pageUrl !== 'string') {\n pageUrl = '/'\n }\n\n // 如果页面链接带上了域名,则需要过滤掉\n if (pageUrl.includes('http')) {\n const PAGE_CUT = pageUrl.split('/')\n const HOST_NAME = `${PAGE_CUT[0]}//${PAGE_CUT[2]}`\n pageUrl = pageUrl.replace(HOST_NAME, '')\n }\n\n // 如果来路url异常,则设置为空\n if (!fromUrl || (fromUrl && typeof fromUrl !== 'string')) {\n fromUrl = ''\n }\n\n // 如果来路url没有带上http/https,也是设置为空\n if (typeof fromUrl === 'string' && !fromUrl.includes('http')) {\n fromUrl = ''\n }\n\n // 设置响应id并提交数据\n this.setAccount()\n\n if (fromUrl) {\n window._czc.push(['_trackPageview', pageUrl, fromUrl])\n } else {\n window._czc.push(['_trackPageview', pageUrl])\n }\n\n if (this.isDebug) {\n console.log(\n `[vue-cnzz-analytics] track pv done.\\nsiteId: ${this.siteId}\\npageUrl: ${pageUrl}\\nfromUrl: ${fromUrl}`\n )\n }\n }\n\n /**\n * 提交点击事件\n */\n trackEvent(\n category: string,\n action: string,\n label: string,\n value: number,\n nodeId: string\n ) {\n // 前两个是必填项\n if (\n typeof category !== 'string' ||\n typeof action !== 'string' ||\n !category ||\n !action\n ) {\n throw new Error(\n '[vue-cnzz-analytics] Missing necessary category and operation information, and must be of type string.'\n )\n }\n\n // 重置一些无效的默认值\n if (!label || typeof label !== 'string') {\n label = ''\n }\n\n if (!Number(value)) {\n value = 0\n }\n\n if (!nodeId || typeof nodeId !== 'string') {\n nodeId = ''\n }\n\n // 设置响应id并提交数据\n this.setAccount()\n\n if (nodeId) {\n window._czc.push(['_trackEvent', category, action, label, value, nodeId])\n } else {\n window._czc.push(['_trackEvent', category, action, label, value])\n }\n\n if (this.isDebug) {\n console.log(\n `[vue-cnzz-analytics] track event done.\\nsiteId: ${this.siteId}\\ncategory: ${category}\\naction: ${action}\\nlabel: ${label}\\nvalue: ${value}\\nnodeId: ${nodeId}`\n )\n }\n }\n}\n\nexport default CNZZ\n","import CNZZ from '@m/cnzz'\n\n/**\n * 定义推送操作\n */\nclass PushCNZZ {\n siteIdList: number[]\n isDebug: boolean\n\n constructor(siteIdList: number[], isDebug: boolean) {\n this.siteIdList = [...siteIdList]\n this.isDebug = isDebug\n }\n\n /**\n * 批量部署站点\n */\n init() {\n this.siteIdList.forEach((siteId: number) => {\n const SITE = new CNZZ(siteId, this.isDebug)\n SITE.init()\n })\n }\n\n /**\n * 批量提交pv上报\n */\n pv(pageUrl: string, fromUrl?: string) {\n this.siteIdList.forEach((siteId: number) => {\n const SITE = new CNZZ(siteId, this.isDebug)\n SITE.trackPageview(pageUrl, fromUrl)\n })\n }\n\n /**\n * 批量提交事件上报\n */\n event(\n category: string,\n action: string,\n label: string,\n value: number,\n nodeId: string\n ) {\n this.siteIdList.forEach((siteId: number) => {\n const SITE = new CNZZ(siteId, this.isDebug)\n SITE.trackEvent(category, action, label, value, nodeId)\n })\n }\n}\n\nexport default PushCNZZ\n","import type { Vue } from '@/types'\n\n/**\n * 获取Vue的版本\n * @return 2=Vue2.x, 3=Vue3.x\n */\nconst getVueVersion = (Vue: Vue): number => {\n let version: number = 2\n\n // 获取Vue的版本号\n const VUE_VERSION: string = String(Vue.version)\n\n // Vue 2.x\n if (VUE_VERSION.slice(0, 2) === '2.') {\n version = 2\n }\n\n // Vue 3.x\n if (VUE_VERSION.slice(0, 2) === '3.') {\n version = 3\n }\n\n return version\n}\n\nexport default getVueVersion\n","import PushCNZZ from '@m/pushCNZZ'\nimport getVueVersion from '@m/getVueVersion'\nimport type { Options, Vue } from '@/types'\n\n/**\n * 全局的数据\n */\nconst __GLOBAL__ = {\n pushCNZZ: {} as PushCNZZ,\n}\n\n/**\n * 暴露 Hooks\n * @description 解决 Vue 3.0 使用全局变量很麻烦的问题\n * @example\n * import { usePush } from 'vue-cnzz-analytics'\n * const cnzz = usePush();\n * cnzz.pv('/');\n */\nexport function usePush() {\n // 提交 pv\n function pv(pageUrl: string, fromUrl?: string) {\n return __GLOBAL__.pushCNZZ.pv(pageUrl, fromUrl)\n }\n\n // 提交事件\n function event(\n category: string,\n action: string,\n label: string,\n value: number,\n nodeId: string\n ) {\n return __GLOBAL__.pushCNZZ.event(category, action, label, value, nodeId)\n }\n\n return {\n pv,\n event,\n }\n}\n\n/**\n * 定义插件\n */\nexport default function install(\n Vue: Vue,\n { router, siteIdList, isDebug = false }: Partial\n) {\n /**\n * 一些环境和参数的检查\n */\n if (typeof document === 'undefined' || typeof window === 'undefined') {\n return false\n }\n\n if (!siteIdList) {\n throw new Error(\n '[vue-cnzz-analytics] Missing tracking domain ID, add at least one of cnzz analytics.'\n )\n }\n\n /**\n * 挂载推送的方法\n */\n const pushCNZZ = new PushCNZZ(siteIdList, isDebug)\n __GLOBAL__.pushCNZZ = pushCNZZ\n\n /**\n * 挂载全局变量到 Vue 上\n * 获取Vue版本(获取失败则默认为2)\n */\n const VUE_VERSION: number = getVueVersion(Vue) || 2\n switch (VUE_VERSION) {\n case 2:\n Vue.prototype.$pushCNZZ = pushCNZZ\n break\n case 3:\n Vue.config.globalProperties.$pushCNZZ = pushCNZZ\n break\n }\n\n /**\n * 部署站点并初始化\n */\n if (siteIdList && Array.isArray(siteIdList)) {\n pushCNZZ.init()\n }\n\n /**\n * 路由切换时执行PV上报\n */\n if (router) {\n router.afterEach(() => {\n // 获取要上报的链接(当前版本不需要拼接了)\n const PAGE_URL: string = window.location.href\n\n // 上报数据\n pushCNZZ.pv(PAGE_URL)\n })\n }\n}\n"],"names":["__spreadArray","to","from","pack","arguments","length","i","l","ar","Array","prototype","slice","call","concat"],"mappings":"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"} -------------------------------------------------------------------------------- /dist/vue-cnzz-analytics.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * name: vue-cnzz-analytics 3 | * version: v2.2.0 4 | * author: chengpeiquan 5 | */ 6 | !(function (t, e) { 7 | 'object' == typeof exports && 'undefined' != typeof module 8 | ? e(exports) 9 | : 'function' == typeof define && define.amd 10 | ? define(['exports'], e) 11 | : e( 12 | ((t = 13 | 'undefined' != typeof globalThis 14 | ? globalThis 15 | : t || self).cnzzAnalytics = {}) 16 | ) 17 | })(this, function (t) { 18 | 'use strict' 19 | var e = (function () { 20 | function t(t, e) { 21 | void 0 === t && (t = 0), 22 | void 0 === e && (e = !1), 23 | (this.siteId = t), 24 | (this.isDebug = e) 25 | } 26 | return ( 27 | (t.prototype.init = function () { 28 | window._czc = window._czc ? window._czc : [] 29 | var t = document.createElement('script') 30 | ;(t.async = !0), 31 | (t.src = 32 | 'https://s9.cnzz.com/z_stat.php?id=' + 33 | this.siteId + 34 | '&web_id=' + 35 | this.siteId), 36 | document.querySelector('head').appendChild(t), 37 | this.isDebug && 38 | console.log( 39 | '[vue-cnzz-analytics] siteId load done.\nsiteId: ' + 40 | this.siteId 41 | ) 42 | }), 43 | (t.prototype.setAccount = function () { 44 | window._czc.push(['_setAccount', this.siteId]) 45 | }), 46 | (t.prototype.trackPageview = function (t, e) { 47 | if (((t && 'string' == typeof t) || (t = '/'), t.includes('http'))) { 48 | var n = t.split('/'), 49 | i = n[0] + '//' + n[2] 50 | t = t.replace(i, '') 51 | } 52 | ;(!e || (e && 'string' != typeof e)) && (e = ''), 53 | 'string' != typeof e || e.includes('http') || (e = ''), 54 | this.setAccount(), 55 | e 56 | ? window._czc.push(['_trackPageview', t, e]) 57 | : window._czc.push(['_trackPageview', t]), 58 | this.isDebug && 59 | console.log( 60 | '[vue-cnzz-analytics] track pv done.\nsiteId: ' + 61 | this.siteId + 62 | '\npageUrl: ' + 63 | t + 64 | '\nfromUrl: ' + 65 | e 66 | ) 67 | }), 68 | (t.prototype.trackEvent = function (t, e, n, i, o) { 69 | if ('string' != typeof t || 'string' != typeof e || !t || !e) 70 | throw new Error( 71 | '[vue-cnzz-analytics] Missing necessary category and operation information, and must be of type string.' 72 | ) 73 | ;(n && 'string' == typeof n) || (n = ''), 74 | Number(i) || (i = 0), 75 | (o && 'string' == typeof o) || (o = ''), 76 | this.setAccount(), 77 | o 78 | ? window._czc.push(['_trackEvent', t, e, n, i, o]) 79 | : window._czc.push(['_trackEvent', t, e, n, i]), 80 | this.isDebug && 81 | console.log( 82 | '[vue-cnzz-analytics] track event done.\nsiteId: ' + 83 | this.siteId + 84 | '\ncategory: ' + 85 | t + 86 | '\naction: ' + 87 | e + 88 | '\nlabel: ' + 89 | n + 90 | '\nvalue: ' + 91 | i + 92 | '\nnodeId: ' + 93 | o 94 | ) 95 | }), 96 | t 97 | ) 98 | })(), 99 | n = (function () { 100 | function t(t, e) { 101 | ;(this.siteIdList = (function (t, e, n) { 102 | if (n || 2 === arguments.length) 103 | for (var i, o = 0, s = e.length; o < s; o++) 104 | (!i && o in e) || 105 | (i || (i = Array.prototype.slice.call(e, 0, o)), (i[o] = e[o])) 106 | return t.concat(i || e) 107 | })([], t)), 108 | (this.isDebug = e) 109 | } 110 | return ( 111 | (t.prototype.init = function () { 112 | var t = this 113 | this.siteIdList.forEach(function (n) { 114 | new e(n, t.isDebug).init() 115 | }) 116 | }), 117 | (t.prototype.pv = function (t, n) { 118 | var i = this 119 | this.siteIdList.forEach(function (o) { 120 | new e(o, i.isDebug).trackPageview(t, n) 121 | }) 122 | }), 123 | (t.prototype.event = function (t, n, i, o, s) { 124 | var c = this 125 | this.siteIdList.forEach(function (r) { 126 | new e(r, c.isDebug).trackEvent(t, n, i, o, s) 127 | }) 128 | }), 129 | t 130 | ) 131 | })(), 132 | i = { pushCNZZ: {} } 133 | ;(t.default = function (t, e) { 134 | var o = e.router, 135 | s = e.siteIdList, 136 | c = e.isDebug, 137 | r = void 0 !== c && c 138 | if ('undefined' == typeof document || 'undefined' == typeof window) 139 | return !1 140 | if (!s) 141 | throw new Error( 142 | '[vue-cnzz-analytics] Missing tracking domain ID, add at least one of cnzz analytics.' 143 | ) 144 | var u = new n(s, r) 145 | switch ( 146 | ((i.pushCNZZ = u), 147 | (function (t) { 148 | var e = 2, 149 | n = String(t.version) 150 | return ( 151 | '2.' === n.slice(0, 2) && (e = 2), 152 | '3.' === n.slice(0, 2) && (e = 3), 153 | e 154 | ) 155 | })(t) || 2) 156 | ) { 157 | case 2: 158 | t.prototype.$pushCNZZ = u 159 | break 160 | case 3: 161 | t.config.globalProperties.$pushCNZZ = u 162 | } 163 | s && Array.isArray(s) && u.init(), 164 | o && 165 | o.afterEach(function () { 166 | var t = window.location.href 167 | u.pv(t) 168 | }) 169 | }), 170 | (t.usePush = function () { 171 | return { 172 | pv: function (t, e) { 173 | return i.pushCNZZ.pv(t, e) 174 | }, 175 | event: function (t, e, n, o, s) { 176 | return i.pushCNZZ.event(t, e, n, o, s) 177 | }, 178 | } 179 | }), 180 | Object.defineProperty(t, '__esModule', { value: !0 }) 181 | }) 182 | //# sourceMappingURL=vue-cnzz-analytics.min.js.map 183 | -------------------------------------------------------------------------------- /dist/vue-cnzz-analytics.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"vue-cnzz-analytics.min.js","sources":["../src/modules/cnzz.ts","../src/modules/pushCNZZ.ts","../node_modules/tslib/tslib.es6.js","../src/main.ts","../src/modules/getVueVersion.ts"],"sourcesContent":["/**\n * 定义基础配置\n * 官方文档 https://developer.umeng.com/docs/67963/detail/74517\n */\nclass CNZZ {\n siteId: number\n isDebug: boolean\n\n constructor(siteId: number = 0, isDebug: boolean = false) {\n this.siteId = siteId\n this.isDebug = isDebug\n }\n\n /**\n * 初始化\n */\n init() {\n window._czc = window._czc ? window._czc : []\n const SCRIPT = document.createElement('script')\n SCRIPT['async'] = true\n SCRIPT[\n 'src'\n ] = `https://s9.cnzz.com/z_stat.php?id=${this.siteId}&web_id=${this.siteId}`\n document.querySelector('head').appendChild(SCRIPT)\n\n if (this.isDebug) {\n console.log(\n `[vue-cnzz-analytics] siteId load done.\\nsiteId: ${this.siteId}`\n )\n }\n }\n\n /**\n * 设置要响应的站点\n */\n setAccount() {\n window._czc.push(['_setAccount', this.siteId])\n }\n\n /**\n * 提交PV、UV\n */\n trackPageview(pageUrl: string, fromUrl?: string) {\n // 如果页面链接没传或者无效链接,则默认为根域名\n if (!pageUrl || typeof pageUrl !== 'string') {\n pageUrl = '/'\n }\n\n // 如果页面链接带上了域名,则需要过滤掉\n if (pageUrl.includes('http')) {\n const PAGE_CUT = pageUrl.split('/')\n const HOST_NAME = `${PAGE_CUT[0]}//${PAGE_CUT[2]}`\n pageUrl = pageUrl.replace(HOST_NAME, '')\n }\n\n // 如果来路url异常,则设置为空\n if (!fromUrl || (fromUrl && typeof fromUrl !== 'string')) {\n fromUrl = ''\n }\n\n // 如果来路url没有带上http/https,也是设置为空\n if (typeof fromUrl === 'string' && !fromUrl.includes('http')) {\n fromUrl = ''\n }\n\n // 设置响应id并提交数据\n this.setAccount()\n\n if (fromUrl) {\n window._czc.push(['_trackPageview', pageUrl, fromUrl])\n } else {\n window._czc.push(['_trackPageview', pageUrl])\n }\n\n if (this.isDebug) {\n console.log(\n `[vue-cnzz-analytics] track pv done.\\nsiteId: ${this.siteId}\\npageUrl: ${pageUrl}\\nfromUrl: ${fromUrl}`\n )\n }\n }\n\n /**\n * 提交点击事件\n */\n trackEvent(\n category: string,\n action: string,\n label: string,\n value: number,\n nodeId: string\n ) {\n // 前两个是必填项\n if (\n typeof category !== 'string' ||\n typeof action !== 'string' ||\n !category ||\n !action\n ) {\n throw new Error(\n '[vue-cnzz-analytics] Missing necessary category and operation information, and must be of type string.'\n )\n }\n\n // 重置一些无效的默认值\n if (!label || typeof label !== 'string') {\n label = ''\n }\n\n if (!Number(value)) {\n value = 0\n }\n\n if (!nodeId || typeof nodeId !== 'string') {\n nodeId = ''\n }\n\n // 设置响应id并提交数据\n this.setAccount()\n\n if (nodeId) {\n window._czc.push(['_trackEvent', category, action, label, value, nodeId])\n } else {\n window._czc.push(['_trackEvent', category, action, label, value])\n }\n\n if (this.isDebug) {\n console.log(\n `[vue-cnzz-analytics] track event done.\\nsiteId: ${this.siteId}\\ncategory: ${category}\\naction: ${action}\\nlabel: ${label}\\nvalue: ${value}\\nnodeId: ${nodeId}`\n )\n }\n }\n}\n\nexport default CNZZ\n","import CNZZ from '@m/cnzz'\n\n/**\n * 定义推送操作\n */\nclass PushCNZZ {\n siteIdList: number[]\n isDebug: boolean\n\n constructor(siteIdList: number[], isDebug: boolean) {\n this.siteIdList = [...siteIdList]\n this.isDebug = isDebug\n }\n\n /**\n * 批量部署站点\n */\n init() {\n this.siteIdList.forEach((siteId: number) => {\n const SITE = new CNZZ(siteId, this.isDebug)\n SITE.init()\n })\n }\n\n /**\n * 批量提交pv上报\n */\n pv(pageUrl: string, fromUrl?: string) {\n this.siteIdList.forEach((siteId: number) => {\n const SITE = new CNZZ(siteId, this.isDebug)\n SITE.trackPageview(pageUrl, fromUrl)\n })\n }\n\n /**\n * 批量提交事件上报\n */\n event(\n category: string,\n action: string,\n label: string,\n value: number,\n nodeId: string\n ) {\n this.siteIdList.forEach((siteId: number) => {\n const SITE = new CNZZ(siteId, this.isDebug)\n SITE.trackEvent(category, action, label, value, nodeId)\n })\n }\n}\n\nexport default PushCNZZ\n","/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n});\r\n\r\nexport function __exportStar(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n}\r\n\r\nexport function __spreadArray(to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || from);\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nvar __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n","import PushCNZZ from '@m/pushCNZZ'\nimport getVueVersion from '@m/getVueVersion'\nimport type { Options, Vue } from '@/types'\n\n/**\n * 全局的数据\n */\nconst __GLOBAL__ = {\n pushCNZZ: {} as PushCNZZ,\n}\n\n/**\n * 暴露 Hooks\n * @description 解决 Vue 3.0 使用全局变量很麻烦的问题\n * @example\n * import { usePush } from 'vue-cnzz-analytics'\n * const cnzz = usePush();\n * cnzz.pv('/');\n */\nexport function usePush() {\n // 提交 pv\n function pv(pageUrl: string, fromUrl?: string) {\n return __GLOBAL__.pushCNZZ.pv(pageUrl, fromUrl)\n }\n\n // 提交事件\n function event(\n category: string,\n action: string,\n label: string,\n value: number,\n nodeId: string\n ) {\n return __GLOBAL__.pushCNZZ.event(category, action, label, value, nodeId)\n }\n\n return {\n pv,\n event,\n }\n}\n\n/**\n * 定义插件\n */\nexport default function install(\n Vue: Vue,\n { router, siteIdList, isDebug = false }: Partial\n) {\n /**\n * 一些环境和参数的检查\n */\n if (typeof document === 'undefined' || typeof window === 'undefined') {\n return false\n }\n\n if (!siteIdList) {\n throw new Error(\n '[vue-cnzz-analytics] Missing tracking domain ID, add at least one of cnzz analytics.'\n )\n }\n\n /**\n * 挂载推送的方法\n */\n const pushCNZZ = new PushCNZZ(siteIdList, isDebug)\n __GLOBAL__.pushCNZZ = pushCNZZ\n\n /**\n * 挂载全局变量到 Vue 上\n * 获取Vue版本(获取失败则默认为2)\n */\n const VUE_VERSION: number = getVueVersion(Vue) || 2\n switch (VUE_VERSION) {\n case 2:\n Vue.prototype.$pushCNZZ = pushCNZZ\n break\n case 3:\n Vue.config.globalProperties.$pushCNZZ = pushCNZZ\n break\n }\n\n /**\n * 部署站点并初始化\n */\n if (siteIdList && Array.isArray(siteIdList)) {\n pushCNZZ.init()\n }\n\n /**\n * 路由切换时执行PV上报\n */\n if (router) {\n router.afterEach(() => {\n // 获取要上报的链接(当前版本不需要拼接了)\n const PAGE_URL: string = window.location.href\n\n // 上报数据\n pushCNZZ.pv(PAGE_URL)\n })\n }\n}\n","import type { Vue } from '@/types'\n\n/**\n * 获取Vue的版本\n * @return 2=Vue2.x, 3=Vue3.x\n */\nconst getVueVersion = (Vue: Vue): number => {\n let version: number = 2\n\n // 获取Vue的版本号\n const VUE_VERSION: string = String(Vue.version)\n\n // Vue 2.x\n if (VUE_VERSION.slice(0, 2) === '2.') {\n version = 2\n }\n\n // Vue 3.x\n if (VUE_VERSION.slice(0, 2) === '3.') {\n version = 3\n }\n\n return version\n}\n\nexport default getVueVersion\n"],"names":["siteId","isDebug","this","CNZZ","window","_czc","SCRIPT","document","createElement","querySelector","appendChild","console","log","push","pageUrl","fromUrl","includes","PAGE_CUT","split","HOST_NAME","replace","setAccount","category","action","label","value","nodeId","Error","Number","siteIdList","to","from","pack","arguments","length","ar","i","l","Array","prototype","slice","call","concat","PushCNZZ","forEach","_this","init","trackPageview","trackEvent","__GLOBAL__","pushCNZZ","Vue","_a","router","_b","version","VUE_VERSION","String","getVueVersion","$pushCNZZ","config","globalProperties","isArray","afterEach","PAGE_URL","location","href","pv","event"],"mappings":"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"} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-cnzz-analytics", 3 | "version": "2.2.0", 4 | "description": "A data collection tool that supports reporting of single-page application data built by Vue 3.0 & 2.0 & VuePress, based on cnzz statistics.", 5 | "main": "dist/vue-cnzz-analytics.min.js", 6 | "types": "vue-cnzz-analytics.d.ts", 7 | "scripts": { 8 | "build": "rollup -c rollup.config.ts", 9 | "lint": "eslint src --ext .js,.ts", 10 | "prettier": "prettier --write src" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/analyticsjs/vue-cnzz-analytics.git" 15 | }, 16 | "keywords": [ 17 | "cnzz", 18 | "vue cnzz", 19 | "vue umeng", 20 | "vue analytics", 21 | "vuepress analytics", 22 | "vue 3.0 cnzz", 23 | "vue 3.0 umeng", 24 | "vue 3.0 analytics", 25 | "spa analytics", 26 | "cnzz统计", 27 | "umeng统计", 28 | "vuepress统计", 29 | "友盟统计" 30 | ], 31 | "author": "chengpeiquan", 32 | "homepage": "https://github.com/analyticsjs/vue-cnzz-analytics", 33 | "license": "MIT", 34 | "devDependencies": { 35 | "@babel/core": "^7.11.1", 36 | "@babel/plugin-proposal-class-properties": "^7.10.4", 37 | "@babel/preset-env": "^7.11.0", 38 | "@babel/preset-typescript": "^7.10.4", 39 | "@rollup/plugin-babel": "^5.2.0", 40 | "@rollup/plugin-commonjs": "^15.0.0", 41 | "@rollup/plugin-json": "^4.1.0", 42 | "@rollup/plugin-node-resolve": "^9.0.0", 43 | "@types/babel__core": "^7.1.9", 44 | "@typescript-eslint/eslint-plugin": "^4.20.0", 45 | "@typescript-eslint/parser": "^4.20.0", 46 | "chalk": "^4.1.1", 47 | "eslint": "^7.23.0", 48 | "eslint-config-prettier": "^8.3.0", 49 | "eslint-plugin-prettier": "^3.4.0", 50 | "husky": "4.2.3", 51 | "lint-staged": "^11.0.0", 52 | "prettier": "^2.3.1", 53 | "rollup": "^2.44.0", 54 | "rollup-plugin-banner2": "^1.2.2", 55 | "rollup-plugin-terser": "^7.0.0", 56 | "rollup-plugin-typescript2": "^0.30.0", 57 | "tslib": "^2.3.0", 58 | "typescript": "^4.0.2" 59 | }, 60 | "husky": { 61 | "hooks": { 62 | "pre-commit": "lint-staged", 63 | "commit-msg": "node scripts/verifyCommit.js" 64 | } 65 | }, 66 | "lint-staged": { 67 | "*.{js,jsx,vue,ts,tsx}": [ 68 | "prettier --write", 69 | "eslint --fix", 70 | "git add" 71 | ] 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /rollup.config.ts: -------------------------------------------------------------------------------- 1 | import resolve from '@rollup/plugin-node-resolve' 2 | import babel from '@rollup/plugin-babel' 3 | import commonjs from '@rollup/plugin-commonjs' 4 | import json from '@rollup/plugin-json' 5 | import { terser } from 'rollup-plugin-terser' 6 | import banner2 from 'rollup-plugin-banner2' 7 | import typescript from 'rollup-plugin-typescript2' 8 | import pkg from './package.json' 9 | 10 | // 输出选项 11 | const outputOptions = { 12 | format: 'umd', 13 | name: 'cnzzAnalytics', 14 | exports: 'named', 15 | sourcemap: true 16 | } 17 | 18 | export default { 19 | input: 'src/main.ts', 20 | output: [ 21 | { 22 | file: `dist/vue-cnzz-analytics.js`, 23 | ...outputOptions 24 | }, 25 | { 26 | file: `dist/vue-cnzz-analytics.min.js`, 27 | plugins: [ 28 | terser() 29 | ], 30 | ...outputOptions 31 | } 32 | ], 33 | plugins: [ 34 | resolve({ 35 | browser: true 36 | }), 37 | 38 | babel({ 39 | babelHelpers: 'bundled' 40 | }), 41 | 42 | commonjs(), 43 | 44 | json(), 45 | 46 | typescript(), 47 | 48 | banner2(() => `/*!\n * name: ${pkg.name}\n * version: v${pkg.version}\n * author: ${pkg.author}\n */\n`) 49 | ] 50 | }; 51 | -------------------------------------------------------------------------------- /scripts/verifyCommit.js: -------------------------------------------------------------------------------- 1 | // Invoked on the commit-msg git hook by yorkie. 2 | 3 | const fs = require('fs') 4 | const chalk = require('chalk') 5 | const msgPath = process.env.HUSKY_GIT_PARAMS 6 | const msg = fs.readFileSync(msgPath, 'utf-8').trim() 7 | 8 | const commitRE = 9 | /^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip|release)(\(.+\))?: .{1,50}/ 10 | 11 | if (!commitRE.test(msg)) { 12 | console.log() 13 | console.error( 14 | ` ${chalk.bgRed.white(' ERROR ')} ${chalk.red( 15 | `invalid commit message format.` 16 | )}\n\n` + 17 | chalk.red( 18 | ` Proper commit message format is required for automated changelog generation. Examples:\n\n` 19 | ) + 20 | ` ${chalk.green(`feat(compiler): add 'comments' option`)}\n` + 21 | ` ${chalk.green( 22 | `fix(v-model): handle events on blur (close #28)` 23 | )}\n\n` + 24 | chalk.red(` See .github/commit-convention.md for more details.\n`) 25 | ) 26 | process.exit(1) 27 | } 28 | -------------------------------------------------------------------------------- /src/global.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | export {} 3 | 4 | declare global { 5 | interface Window { 6 | _czc: any 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import PushCNZZ from '@m/pushCNZZ' 2 | import getVueVersion from '@m/getVueVersion' 3 | import type { Options, Vue } from '@/types' 4 | 5 | /** 6 | * 全局的数据 7 | */ 8 | const __GLOBAL__ = { 9 | pushCNZZ: {} as PushCNZZ, 10 | } 11 | 12 | /** 13 | * 暴露 Hooks 14 | * @description 解决 Vue 3.0 使用全局变量很麻烦的问题 15 | * @example 16 | * import { usePush } from 'vue-cnzz-analytics' 17 | * const cnzz = usePush(); 18 | * cnzz.pv('/'); 19 | */ 20 | export function usePush() { 21 | // 提交 pv 22 | function pv(pageUrl: string, fromUrl?: string) { 23 | return __GLOBAL__.pushCNZZ.pv(pageUrl, fromUrl) 24 | } 25 | 26 | // 提交事件 27 | function event( 28 | category: string, 29 | action: string, 30 | label: string, 31 | value: number, 32 | nodeId: string 33 | ) { 34 | return __GLOBAL__.pushCNZZ.event(category, action, label, value, nodeId) 35 | } 36 | 37 | return { 38 | pv, 39 | event, 40 | } 41 | } 42 | 43 | /** 44 | * 定义插件 45 | */ 46 | export default function install( 47 | Vue: Vue, 48 | { router, siteIdList, isDebug = false }: Partial 49 | ) { 50 | /** 51 | * 一些环境和参数的检查 52 | */ 53 | if (typeof document === 'undefined' || typeof window === 'undefined') { 54 | return false 55 | } 56 | 57 | if (!siteIdList) { 58 | throw new Error( 59 | '[vue-cnzz-analytics] Missing tracking domain ID, add at least one of cnzz analytics.' 60 | ) 61 | } 62 | 63 | /** 64 | * 挂载推送的方法 65 | */ 66 | const pushCNZZ = new PushCNZZ(siteIdList, isDebug) 67 | __GLOBAL__.pushCNZZ = pushCNZZ 68 | 69 | /** 70 | * 挂载全局变量到 Vue 上 71 | * 获取Vue版本(获取失败则默认为2) 72 | */ 73 | const VUE_VERSION: number = getVueVersion(Vue) || 2 74 | switch (VUE_VERSION) { 75 | case 2: 76 | Vue.prototype.$pushCNZZ = pushCNZZ 77 | break 78 | case 3: 79 | Vue.config.globalProperties.$pushCNZZ = pushCNZZ 80 | break 81 | } 82 | 83 | /** 84 | * 部署站点并初始化 85 | */ 86 | if (siteIdList && Array.isArray(siteIdList)) { 87 | pushCNZZ.init() 88 | } 89 | 90 | /** 91 | * 路由切换时执行PV上报 92 | */ 93 | if (router) { 94 | router.afterEach(() => { 95 | // 获取要上报的链接(当前版本不需要拼接了) 96 | const PAGE_URL: string = window.location.href 97 | 98 | // 上报数据 99 | pushCNZZ.pv(PAGE_URL) 100 | }) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/modules/cnzz.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 定义基础配置 3 | * 官方文档 https://developer.umeng.com/docs/67963/detail/74517 4 | */ 5 | class CNZZ { 6 | siteId: number 7 | isDebug: boolean 8 | 9 | constructor(siteId: number = 0, isDebug: boolean = false) { 10 | this.siteId = siteId 11 | this.isDebug = isDebug 12 | } 13 | 14 | /** 15 | * 初始化 16 | */ 17 | init() { 18 | window._czc = window._czc ? window._czc : [] 19 | const SCRIPT = document.createElement('script') 20 | SCRIPT['async'] = true 21 | SCRIPT[ 22 | 'src' 23 | ] = `https://s9.cnzz.com/z_stat.php?id=${this.siteId}&web_id=${this.siteId}` 24 | document.querySelector('head').appendChild(SCRIPT) 25 | 26 | if (this.isDebug) { 27 | console.log( 28 | `[vue-cnzz-analytics] siteId load done.\nsiteId: ${this.siteId}` 29 | ) 30 | } 31 | } 32 | 33 | /** 34 | * 设置要响应的站点 35 | */ 36 | setAccount() { 37 | window._czc.push(['_setAccount', this.siteId]) 38 | } 39 | 40 | /** 41 | * 提交PV、UV 42 | */ 43 | trackPageview(pageUrl: string, fromUrl?: string) { 44 | // 如果页面链接没传或者无效链接,则默认为根域名 45 | if (!pageUrl || typeof pageUrl !== 'string') { 46 | pageUrl = '/' 47 | } 48 | 49 | // 如果页面链接带上了域名,则需要过滤掉 50 | if (pageUrl.includes('http')) { 51 | const PAGE_CUT = pageUrl.split('/') 52 | const HOST_NAME = `${PAGE_CUT[0]}//${PAGE_CUT[2]}` 53 | pageUrl = pageUrl.replace(HOST_NAME, '') 54 | } 55 | 56 | // 如果来路url异常,则设置为空 57 | if (!fromUrl || (fromUrl && typeof fromUrl !== 'string')) { 58 | fromUrl = '' 59 | } 60 | 61 | // 如果来路url没有带上http/https,也是设置为空 62 | if (typeof fromUrl === 'string' && !fromUrl.includes('http')) { 63 | fromUrl = '' 64 | } 65 | 66 | // 设置响应id并提交数据 67 | this.setAccount() 68 | 69 | if (fromUrl) { 70 | window._czc.push(['_trackPageview', pageUrl, fromUrl]) 71 | } else { 72 | window._czc.push(['_trackPageview', pageUrl]) 73 | } 74 | 75 | if (this.isDebug) { 76 | console.log( 77 | `[vue-cnzz-analytics] track pv done.\nsiteId: ${this.siteId}\npageUrl: ${pageUrl}\nfromUrl: ${fromUrl}` 78 | ) 79 | } 80 | } 81 | 82 | /** 83 | * 提交点击事件 84 | */ 85 | trackEvent( 86 | category: string, 87 | action: string, 88 | label: string, 89 | value: number, 90 | nodeId: string 91 | ) { 92 | // 前两个是必填项 93 | if ( 94 | typeof category !== 'string' || 95 | typeof action !== 'string' || 96 | !category || 97 | !action 98 | ) { 99 | throw new Error( 100 | '[vue-cnzz-analytics] Missing necessary category and operation information, and must be of type string.' 101 | ) 102 | } 103 | 104 | // 重置一些无效的默认值 105 | if (!label || typeof label !== 'string') { 106 | label = '' 107 | } 108 | 109 | if (!Number(value)) { 110 | value = 0 111 | } 112 | 113 | if (!nodeId || typeof nodeId !== 'string') { 114 | nodeId = '' 115 | } 116 | 117 | // 设置响应id并提交数据 118 | this.setAccount() 119 | 120 | if (nodeId) { 121 | window._czc.push(['_trackEvent', category, action, label, value, nodeId]) 122 | } else { 123 | window._czc.push(['_trackEvent', category, action, label, value]) 124 | } 125 | 126 | if (this.isDebug) { 127 | console.log( 128 | `[vue-cnzz-analytics] track event done.\nsiteId: ${this.siteId}\ncategory: ${category}\naction: ${action}\nlabel: ${label}\nvalue: ${value}\nnodeId: ${nodeId}` 129 | ) 130 | } 131 | } 132 | } 133 | 134 | export default CNZZ 135 | -------------------------------------------------------------------------------- /src/modules/getVueVersion.ts: -------------------------------------------------------------------------------- 1 | import type { Vue } from '@/types' 2 | 3 | /** 4 | * 获取Vue的版本 5 | * @return 2=Vue2.x, 3=Vue3.x 6 | */ 7 | const getVueVersion = (Vue: Vue): number => { 8 | let version: number = 2 9 | 10 | // 获取Vue的版本号 11 | const VUE_VERSION: string = String(Vue.version) 12 | 13 | // Vue 2.x 14 | if (VUE_VERSION.slice(0, 2) === '2.') { 15 | version = 2 16 | } 17 | 18 | // Vue 3.x 19 | if (VUE_VERSION.slice(0, 2) === '3.') { 20 | version = 3 21 | } 22 | 23 | return version 24 | } 25 | 26 | export default getVueVersion 27 | -------------------------------------------------------------------------------- /src/modules/pushCNZZ.ts: -------------------------------------------------------------------------------- 1 | import CNZZ from '@m/cnzz' 2 | 3 | /** 4 | * 定义推送操作 5 | */ 6 | class PushCNZZ { 7 | siteIdList: number[] 8 | isDebug: boolean 9 | 10 | constructor(siteIdList: number[], isDebug: boolean) { 11 | this.siteIdList = [...siteIdList] 12 | this.isDebug = isDebug 13 | } 14 | 15 | /** 16 | * 批量部署站点 17 | */ 18 | init() { 19 | this.siteIdList.forEach((siteId: number) => { 20 | const SITE = new CNZZ(siteId, this.isDebug) 21 | SITE.init() 22 | }) 23 | } 24 | 25 | /** 26 | * 批量提交pv上报 27 | */ 28 | pv(pageUrl: string, fromUrl?: string) { 29 | this.siteIdList.forEach((siteId: number) => { 30 | const SITE = new CNZZ(siteId, this.isDebug) 31 | SITE.trackPageview(pageUrl, fromUrl) 32 | }) 33 | } 34 | 35 | /** 36 | * 批量提交事件上报 37 | */ 38 | event( 39 | category: string, 40 | action: string, 41 | label: string, 42 | value: number, 43 | nodeId: string 44 | ) { 45 | this.siteIdList.forEach((siteId: number) => { 46 | const SITE = new CNZZ(siteId, this.isDebug) 47 | SITE.trackEvent(category, action, label, value, nodeId) 48 | }) 49 | } 50 | } 51 | 52 | export default PushCNZZ 53 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import PushCNZZ from '@m/pushCNZZ' 2 | 3 | export interface Options { 4 | router: any 5 | siteIdList: number[] 6 | isDebug: boolean 7 | } 8 | 9 | export interface Vue { 10 | prototype: any 11 | $pushCNZZ: PushCNZZ 12 | version: number | string 13 | config: any 14 | } 15 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES5", 4 | "module": "ES2015", 5 | "allowSyntheticDefaultImports": true, 6 | "noImplicitAny": true, 7 | "removeComments": true, 8 | "preserveConstEnums": true, 9 | "sourceMap": true, 10 | "baseUrl": ".", 11 | "paths": { 12 | "@/*": [ 13 | "src/*" 14 | ], 15 | "@m/*": [ 16 | "src/modules/*" 17 | ] 18 | }, 19 | "declaration": true, 20 | "declarationDir": "./dist" 21 | }, 22 | "include": [ 23 | "src/**/*.ts" 24 | ], 25 | "exclude": [ 26 | "node_modules" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /vue-cnzz-analytics.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'vue-cnzz-analytics' --------------------------------------------------------------------------------