页面交互行为跟踪

从 1.5.0 版本开始,amis 内置了跟踪用户交互行为采集功能。

使用方法

amis 只负责采集,对行为的存储和分析都需要外部实现。

在 amis 渲染时的第三个参数 env 可以传递 tracker 函数,下面以 sdk 作为示例,具体实现可以根据实际需求修改,比如可以收集一段时间后再批量提交等。

  1. amis.embed(
  2. '#root',
  3. {
  4. // amis schema
  5. },
  6. {
  7. // 这里是初始 props
  8. },
  9. {
  10. tracker: (eventTrack, props) => {
  11. const blob = new Blob([JSON.stringify(eventTrack)], {
  12. type: 'application/json'
  13. });
  14. navigator.sendBeacon('/tracker', blob);
  15. }
  16. }
  17. );

参数类型

eventTrack 的类型定义是

  1. interface EventTrack {
  2. // 后面会详细介绍
  3. eventType:
  4. | 'api'
  5. | 'url'
  6. | 'link'
  7. | 'dialog'
  8. | 'drawer'
  9. | 'copy'
  10. | 'reload'
  11. | 'email'
  12. | 'prev'
  13. | 'next'
  14. | 'cancel'
  15. | 'close'
  16. | 'submit'
  17. | 'confirm'
  18. | 'reset'
  19. | 'reset-and-submit'
  20. | 'formItemChange'
  21. | 'tabChange'
  22. | 'pageHidden'
  23. | 'pageVisible';
  24. /**
  25. * 事件数据,根据不同事件有不同结构,下面会详细说明
  26. */
  27. eventData: ActionSchema | Api;
  28. }

有时候无法通过 eventData 区分点击行为,比如有个两个提交按钮

  1. [
  2. {
  3. "label": "提交",
  4. "primary": true
  5. },
  6. {
  7. "label": "提交",
  8. "primary": true
  9. }
  10. ]

当它触发事件的时 EventTrack 内容是一样的

  1. {
  2. "eventType": "submit",
  3. "eventData": {
  4. "primary": true,
  5. "label": "提交"
  6. }
  7. }

如何区分究竟是哪个事件?可以通过增加 id 属性,比如

  1. [
  2. {
  3. "id": "button1",
  4. "label": "提交",
  5. "primary": true
  6. },
  7. {
  8. "id": "button2",
  9. "label": "提交",
  10. "primary": true
  11. }
  12. ]

这样触发事件中就会包含 id 字段来方便区分,比如

  1. {
  2. "eventType": "submit",
  3. "eventData": {
  4. "id": "button1",
  5. "primary": true,
  6. "label": "提交"
  7. }
  8. }

另一个方法是通过 tracker 的第二个参数 props 来判断,它可以拿到这个组件的所有属性配置

事件示例

除了下面的文档,还可以打开浏览器的控制台,在 debug 分类下可以看到实际操作时的例子

api

api 的来源有两方面,一个是各种组件的 api 及 source 配置,另一个是 action 里的 ajax 类型请求

以 crud 为例

  1. {
  2. "eventType": "api",
  3. "eventData": {
  4. "method": "get",
  5. "url": "/api/mock2/sample?page=1&perPage=10",
  6. "query": {
  7. "page": 1,
  8. "perPage": 10
  9. }
  10. }
  11. }

如果是 post 则类似下面的数据

  1. {
  2. "eventType": "api",
  3. "eventData": {
  4. "method": "post",
  5. "url": "/api/mock2/form/saveForm"
  6. }
  7. }

为了避免信息泄露在 eventData 里没有包含提交数据,要获取提交数据详情需要通过第二个参数,参考下面的例子

  1. {
  2. tracker: (eventTrack, data) => {
  3. console.log('提交数据详情', data);
  4. const blob = new Blob([JSON.stringify(eventTrack)], {
  5. type: 'application/json'
  6. });
  7. navigator.sendBeacon('/tracker', blob);
  8. };
  9. }

url

这是打开外部链接事件,注意不要和 link 混淆,link 一般用来做应用内相对地址无刷新跳转

示例

  1. {
  2. "eventType": "url",
  3. "eventData": {
  4. "url": "https://www.baidu.com",
  5. "blank": true,
  6. "label": "百度一下,你就知道"
  7. }
  8. }

这个事件有可能是 Link 组件触发,也有可能是 Action 组件触发,如果是 Action 这是类似下面的参数

  1. {
  2. "eventType": "url",
  3. "eventData": {
  4. "url": "http://www.baidu.com",
  5. "level": "success",
  6. "blank": true,
  7. "label": "打开 Baidu"
  8. }
  9. }

Action 组件会多些数据

link

触发这个事件主要是 Action 和 Nav 组件

如果是 Action,数据将会是

  1. {
  2. "eventType": "link",
  3. "eventData": {
  4. "label": "进入介绍页",
  5. "level": "info",
  6. "link": "../index"
  7. }
  8. }

如果是 Nav,数据将会是

  1. {
  2. "eventType": "link",
  3. "eventData": {
  4. "label": "Nav 2-2",
  5. "link": "?cat=2-2"
  6. }
  7. }

它们都有 label 及 link 字段

dialog

这个事件主要由 action 触发,示例

  1. {
  2. "eventType": "dialog",
  3. "eventData": {
  4. "dialog": {
  5. "title": "提示",
  6. "closeOnEsc": true,
  7. "body": "这是个简单的弹框"
  8. },
  9. "label": "打开弹框"
  10. }
  11. }

需要注意 dialog 里会包含所有弹框的 schema 配置,可能会导致提交数据太大,建议根据需求裁剪。

drawer

这个事件主要由 action 触发,示例

  1. {
  2. "eventType": "drawer",
  3. "eventData": {
  4. "drawer": {
  5. "position": "left",
  6. "size": "xs",
  7. "title": "提示",
  8. "body": "这是个简单的弹框"
  9. },
  10. "label": "左侧弹出-极小框"
  11. }
  12. }

和前面的 dialog 示例,它的数据中会包含所有 drawer 配置,可能会内容过大,需要根据需求过滤

copy

由 action 触发,示例如下

  1. {
  2. "eventType": "copy",
  3. "eventData": {
  4. "content": "http://www.baidu.com",
  5. "label": "复制一段文本"
  6. }
  7. }

reload

由 action 触发,示例

  1. {
  2. "eventType": "reload",
  3. "eventData": {
  4. "label": "搜索",
  5. "target": "my_form.select"
  6. }
  7. }

email

由 action 触发,示例

  1. {
  2. "eventType": "email",
  3. "eventData": {
  4. "to": "amis@baidu.com",
  5. "cc": "baidu@baidu.com",
  6. "subject": "这是邮件主题",
  7. "body": "这是邮件正文",
  8. "label": "发送邮件"
  9. }
  10. }

prev/next

可能有两个地方,一个是 Wizard 里的上一步下一步,还有可能是 Dialog 里的上一个下一个,示例

  1. {
  2. "eventType": "next",
  3. "eventData": {
  4. "level": "info",
  5. "label": "下一个"
  6. }
  7. }

cancel

action 里的取消事件,示例

  1. {
  2. "eventType": "cancel",
  3. "eventData": {
  4. "label": "关闭"
  5. }
  6. }

close

action 里的关闭事件,主要用于关闭弹框,示例

  1. {
  2. "eventType": "close",
  3. "eventData": {
  4. "label": "算了"
  5. }
  6. }

submit

点击提交按钮的事件,这个事件可能还会同时触发 api 事件,比如表单的提交按钮。

  1. {
  2. "eventType": "submit",
  3. "eventData": {
  4. "primary": true,
  5. "label": "提交"
  6. }
  7. }

confirm

action 中的事件,主要用于关闭弹框

  1. {
  2. "eventType": "confirm",
  3. "eventData": {
  4. "primary": true,
  5. "label": "确认"
  6. }
  7. }

reset

由 action 触发,主要用于重置表单数据,示例

  1. {
  2. "eventType": "reset",
  3. "eventData": {
  4. "label": "重置"
  5. }
  6. }

reset-and-submit

由 action 触发,会重置表单并提交数据

  1. {
  2. "eventType": "reset-and-submit",
  3. "eventData": {
  4. "label": "重置并提交"
  5. }
  6. }

formItemChange

表单项数据变化时,也就是用户在表单里输入和修改任何数据时触发,比如

有一个特例是 input-password 类型的字段不会触发这个事件,避免隐私风险 但在 api 中还是有可能包含隐私信息,因此建议前面 api 类的事件不记录数据提交内容

  1. {
  2. "eventType": "formItemChange",
  3. "eventData": {
  4. "name": "name",
  5. "label": "用户名",
  6. "type": "input-text",
  7. "value": "amis"
  8. }
  9. }

事件数据里主要是 name typevalue

需要注意这个事件非常频繁,只要修改内容就会触发。

和 action 类似,如果给表单项加上 id 字段也会透传到这里,方便用于区分同名输入框,比如

  1. {
  2. "eventType": "formItemChange",
  3. "eventData": {
  4. "id": "name1",
  5. "name": "name",
  6. "label": "用户名",
  7. "type": "input-text",
  8. "value": "amis"
  9. }
  10. }

tabChange

tab 切换事件,示例

  1. {
  2. "eventType": "tabChange",
  3. "eventData": {
  4. "key": "tab2"
  5. }
  6. }

默认情况下 key 的值从 0 开始,如果 tab 上设置了 hash 值就会用这个值。

同样,如果 tabs 设置了 id,也会输出这个 id 值方便区分

pageHidden

当 tab 切换或者页面关闭时触发,可以当成用户离开页面的时间。

pageVisible

当用户又切换回当前页面的时间,可以当做是用户重新访问的开始时间。

由于 amis 可能被嵌入到页面中,所以 amis 无法知晓页面首次打开的时间,需要自行处理。