web-tracing-core 2.1.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/{dist/README.md → README.md} +8 -0
  2. package/{dist/index.cjs → index.cjs} +24 -5
  3. package/{dist/index.iife.js → index.iife.js} +24 -5
  4. package/{dist/index.iife.min.js → index.iife.min.js} +9 -9
  5. package/{dist/index.mjs → index.mjs} +24 -5
  6. package/package.json +9 -9
  7. package/__test__/css/performance.css +0 -3
  8. package/__test__/err-batch.spec.ts +0 -47
  9. package/__test__/err.spec.ts +0 -82
  10. package/__test__/event.spec.ts +0 -62
  11. package/__test__/html/performance.html +0 -57
  12. package/__test__/html/recordscreen.html +0 -39
  13. package/__test__/http.spec.ts +0 -143
  14. package/__test__/img/performance.png +0 -0
  15. package/__test__/js/performance.js +0 -3
  16. package/__test__/performance.spec.ts +0 -112
  17. package/__test__/recordscreen.spec.ts +0 -50
  18. package/__test__/utils/index.ts +0 -99
  19. package/__test__/utils/pollify.ts +0 -14
  20. package/__test__/utils.spec.ts +0 -18
  21. package/dist/package.json +0 -49
  22. package/index.ts +0 -75
  23. package/src/common/config.ts +0 -13
  24. package/src/common/constant.ts +0 -57
  25. package/src/common/index.ts +0 -2
  26. package/src/lib/base.ts +0 -129
  27. package/src/lib/err-batch.ts +0 -134
  28. package/src/lib/err.ts +0 -323
  29. package/src/lib/event-dwell.ts +0 -63
  30. package/src/lib/event.ts +0 -252
  31. package/src/lib/eventBus.ts +0 -97
  32. package/src/lib/exportMethods.ts +0 -208
  33. package/src/lib/http.ts +0 -197
  34. package/src/lib/intersectionObserver.ts +0 -164
  35. package/src/lib/line-status.ts +0 -45
  36. package/src/lib/options.ts +0 -325
  37. package/src/lib/performance.ts +0 -302
  38. package/src/lib/pv.ts +0 -199
  39. package/src/lib/recordscreen.ts +0 -169
  40. package/src/lib/replace.ts +0 -371
  41. package/src/lib/sendData.ts +0 -264
  42. package/src/observer/computed.ts +0 -52
  43. package/src/observer/config.ts +0 -1
  44. package/src/observer/dep.ts +0 -21
  45. package/src/observer/index.ts +0 -91
  46. package/src/observer/ref.ts +0 -80
  47. package/src/observer/types.ts +0 -22
  48. package/src/observer/watch.ts +0 -19
  49. package/src/observer/watcher.ts +0 -88
  50. package/src/types/index.ts +0 -126
  51. package/src/utils/debug.ts +0 -17
  52. package/src/utils/element.ts +0 -47
  53. package/src/utils/fingerprintjs.ts +0 -2132
  54. package/src/utils/getIps.ts +0 -127
  55. package/src/utils/global.ts +0 -49
  56. package/src/utils/index.ts +0 -551
  57. package/src/utils/is.ts +0 -78
  58. package/src/utils/localStorage.ts +0 -70
  59. package/src/utils/session.ts +0 -27
  60. /package/{dist/LICENSE → LICENSE} +0 -0
  61. /package/{dist/index.d.ts → index.d.ts} +0 -0
package/src/lib/err.ts DELETED
@@ -1,323 +0,0 @@
1
- import { EVENTTYPES, SEDNEVENTTYPES, SENDID } from '../common'
2
- import { map, filter, getLocationHref, getTimestamp } from '../utils'
3
- import { _global } from '../utils/global'
4
- import { sendData } from './sendData'
5
- import { eventBus } from './eventBus'
6
- import { isArray, isRegExp } from '../utils/is'
7
- import { options } from './options'
8
- import { zip, getEventList } from './recordscreen'
9
- import { debug } from '../utils/debug'
10
- import { initBatchError, batchError } from './err-batch'
11
- import { RecordEventScope } from '../types'
12
-
13
- /**
14
- * 序列化console.error的参数
15
- * 处理各种类型的参数,包括对象、函数、Error等
16
- */
17
- function serializeConsoleArgs(args: any[]): string {
18
- const serializedArgs = args.map((arg: any) => {
19
- if (arg === null) return 'null'
20
- if (arg === undefined) return 'undefined'
21
- if (typeof arg === 'string') return arg
22
- if (typeof arg === 'number' || typeof arg === 'boolean') return String(arg)
23
- if (typeof arg === 'function')
24
- return `[Function: ${arg.name || 'anonymous'}]`
25
- if (arg instanceof Error) {
26
- return `${arg.name}: ${arg.message}${arg.stack ? '\n' + arg.stack : ''}`
27
- }
28
- if (typeof arg === 'object') {
29
- try {
30
- // 尝试JSON序列化对象,保持缩进格式
31
- return JSON.stringify(arg, null, 2)
32
- } catch (error) {
33
- // 如果JSON序列化失败(如循环引用),使用toString
34
- return arg.toString()
35
- }
36
- }
37
- return String(arg)
38
- })
39
- return serializedArgs.join(' | ')
40
- }
41
-
42
- interface ErrorStack {
43
- errMessage: string
44
- errStack: string
45
- }
46
-
47
- type InstabilityNature = {
48
- lineNumber: string
49
- fileName: string
50
- columnNumber: string
51
- }
52
-
53
- /**
54
- * 格式化错误对象信息
55
- * @param err Error 错误对象
56
- */
57
- function parseStack(err: Error): ErrorStack {
58
- const { stack = '', message = '' } = err
59
- const result = { eventId: SENDID.CODE, errMessage: message, errStack: stack }
60
-
61
- if (stack) {
62
- const rChromeCallStack = /^\s*at\s*([^(]+)\s*\((.+?):(\d+):(\d+)\)$/
63
- const rMozlliaCallStack = /^\s*([^@]*)@(.+?):(\d+):(\d+)$/
64
- // chrome中包含了message信息,将其去除,并去除后面的换行符
65
- const callStackStr = stack.replace(
66
- new RegExp(`^[\\w\\s:]*${message}\n`),
67
- ''
68
- )
69
- const callStackFrameList = map(
70
- filter(callStackStr.split('\n'), (item: string) => item),
71
- (str: string) => {
72
- const chromeErrResult = str.match(rChromeCallStack)
73
- if (chromeErrResult) {
74
- return {
75
- triggerPageUrl: chromeErrResult[2],
76
- line: chromeErrResult[3], // 错误发生位置的行数
77
- col: chromeErrResult[4] // 错误发生位置的列数
78
- }
79
- }
80
-
81
- const mozlliaErrResult = str.match(rMozlliaCallStack)
82
- if (mozlliaErrResult) {
83
- return {
84
- triggerPageUrl: mozlliaErrResult[2],
85
- line: mozlliaErrResult[3],
86
- col: mozlliaErrResult[4]
87
- }
88
- }
89
- return {}
90
- }
91
- )
92
- const item = callStackFrameList[0] || {}
93
- return { ...result, ...item }
94
- }
95
- return result
96
- }
97
-
98
- /**
99
- * 分析错误信息
100
- * @param e 错误源信息
101
- * @returns 相对标准格式的错误信息
102
- */
103
- function parseError(e: any) {
104
- if (e instanceof Error) {
105
- // fileName: 引发此错误的文件的路径 (此属性为非标准,所以下面得区分)
106
- const { message, stack, lineNumber, fileName, columnNumber } = e as Error &
107
- InstabilityNature
108
- if (fileName) {
109
- return {
110
- errMessage: message,
111
- errStack: stack,
112
- eventId: SENDID.CODE,
113
- line: lineNumber, // 不稳定属性 - 在某些浏览器可能是undefined,被废弃了
114
- col: columnNumber, // 不稳定属性 - 非标准,有些浏览器可能不支持
115
- triggerPageUrl: fileName // 不稳定属性 - 非标准,有些浏览器可能不支持
116
- }
117
- }
118
- return parseStack(e)
119
- }
120
- if (e.message) return parseStack(e)
121
-
122
- // reject 错误
123
- if (typeof e === 'string') return { eventId: SENDID.REJECT, errMessage: e }
124
-
125
- // console.error 暴露的错误
126
- if (isArray(e)) {
127
- return { eventId: SENDID.CONSOLEERROR, errMessage: serializeConsoleArgs(e) }
128
- }
129
-
130
- return {}
131
- }
132
-
133
- /**
134
- * 判断是否为 promise-reject 错误类型
135
- */
136
- function isPromiseRejectedResult(
137
- event: ErrorEvent | PromiseRejectedResult
138
- ): event is PromiseRejectedResult {
139
- return (event as PromiseRejectedResult).reason !== undefined
140
- }
141
-
142
- function parseErrorEvent(event: ErrorEvent | PromiseRejectedResult) {
143
- // promise reject 错误
144
- if (isPromiseRejectedResult(event)) {
145
- return { eventId: SENDID.CODE, ...parseError(event.reason) }
146
- }
147
-
148
- // html元素上发生的异常错误
149
- const { target } = event
150
- if (target instanceof HTMLElement) {
151
- // 为1代表节点是元素节点
152
- if (target.nodeType === 1) {
153
- const result = {
154
- initiatorType: target.nodeName.toLowerCase(),
155
- eventId: SENDID.RESOURCE,
156
- requestUrl: ''
157
- }
158
- switch (target.nodeName.toLowerCase()) {
159
- case 'link':
160
- result.requestUrl = (target as HTMLLinkElement).href
161
- break
162
- default:
163
- result.requestUrl =
164
- (target as HTMLImageElement).currentSrc ||
165
- (target as HTMLScriptElement).src
166
- }
167
- return result
168
- }
169
- }
170
-
171
- // 代码异常
172
- if (event.error) {
173
- // chrome中的error对象没有fileName等属性,将event中的补充给error对象
174
- const e = event.error
175
- e.fileName = e.filename || event.filename
176
- e.columnNumber = e.colno || event.colno
177
- e.lineNumber = e.lineno || event.lineno
178
- return { eventId: SENDID.CODE, ...parseError(e) }
179
- }
180
-
181
- // 兜底
182
- // ie9版本,从全局的event对象中获取错误信息
183
- return {
184
- eventId: SENDID.CODE,
185
- line: (_global as any).event.errorLine,
186
- col: (_global as any).event.errorCharacter,
187
- errMessage: (_global as any).event.errorMessage,
188
- triggerPageUrl: (_global as any).event.errorUrl
189
- }
190
- }
191
-
192
- /**
193
- * 判断错误源信息是否为需要拦截的
194
- * @param error 错误源信息
195
- */
196
- function isIgnoreErrors(error: any): boolean {
197
- if (!options.value.ignoreErrors.length) return false
198
- let errMessage = error.errMessage || error.message
199
- if (!errMessage) return false
200
- errMessage = String(errMessage)
201
-
202
- return options.value.ignoreErrors.some(item => {
203
- if (isRegExp(item)) {
204
- if ((item as RegExp).test(errMessage)) {
205
- debug(`ignoreErrors拦截成功 - 截条件:${item} 错误信息:${errMessage}`)
206
- return true
207
- } else {
208
- return false
209
- }
210
- } else {
211
- if (errMessage === item) {
212
- debug(`ignoreErrors拦截成功 - 截条件:${item} 错误信息:${errMessage}`)
213
- return true
214
- } else {
215
- return false
216
- }
217
- }
218
- })
219
- }
220
-
221
- /**
222
- * 获取错误录屏数据
223
- */
224
- function getRecordEvent(): RecordEventScope[] {
225
- const _recordscreenList: RecordEventScope[] = JSON.parse(
226
- JSON.stringify(getEventList())
227
- )
228
- return _recordscreenList
229
- .slice(-2)
230
- .map(item => item.eventList)
231
- .flat()
232
- }
233
-
234
- /**
235
- * 发送错误事件信息
236
- * @param errorInfo 信息源
237
- */
238
- function emit(errorInfo: any, flush = false): void {
239
- const info = {
240
- ...errorInfo,
241
- eventType: SEDNEVENTTYPES.ERROR,
242
- recordscreen: options.value.recordScreen ? zip(getRecordEvent()) : null,
243
- triggerPageUrl: getLocationHref(),
244
- triggerTime: getTimestamp()
245
- }
246
-
247
- options.value.scopeError
248
- ? batchError.pushCacheErrorA(info)
249
- : sendData.emit(info, flush)
250
- }
251
-
252
- /**
253
- * 初始化错误监听
254
- */
255
- function initError(): void {
256
- if (!options.value.error.core) return
257
-
258
- if (options.value.scopeError) {
259
- initBatchError()
260
- // 如果开启了检测批量错误 则要挂载卸载事件以防缓存池内的错误丢失
261
- eventBus.addEvent({
262
- type: EVENTTYPES.BEFOREUNLOAD,
263
- callback: () => {
264
- batchError.sendAllCacheError()
265
- }
266
- })
267
- }
268
-
269
- // 捕获阶段可以获取资源加载错误,script.onError link.onError img.onError,无法知道具体状态
270
- eventBus.addEvent({
271
- type: EVENTTYPES.ERROR,
272
- callback: (e: ErrorEvent) => {
273
- const errorInfo = parseErrorEvent(e)
274
- if (isIgnoreErrors(errorInfo)) return
275
- emit(errorInfo)
276
- }
277
- })
278
-
279
- // promise调用链未捕获异常
280
- // 只捕获未处理的 reject的错误,如果对reject进行了回调处理这边不进行捕获
281
- eventBus.addEvent({
282
- type: EVENTTYPES.UNHANDLEDREJECTION,
283
- callback: (e: PromiseRejectedResult) => {
284
- const errorInfo = parseErrorEvent(e)
285
- if (isIgnoreErrors(errorInfo)) return
286
- emit(errorInfo)
287
- }
288
- })
289
-
290
- // 劫持console.error
291
- eventBus.addEvent({
292
- type: EVENTTYPES.CONSOLEERROR,
293
- callback: e => {
294
- const errorInfo = parseError(e)
295
- if (isIgnoreErrors(errorInfo)) return
296
- emit({ eventId: SENDID.CODE, ...errorInfo })
297
- }
298
- })
299
- }
300
-
301
- /**
302
- * 主动触发错误上报
303
- * @param eventId 事件ID
304
- * @param message 错误信息
305
- * @param options 自定义配置信息
306
- */
307
- function handleSendError(options = {}, flush = false): void {
308
- emit(options, flush)
309
- }
310
-
311
- /**
312
- * 卸载所有错误监听
313
- */
314
- export function destroyError() {
315
- // 清除错误相关的事件类型
316
- eventBus.removeEvents([
317
- EVENTTYPES.ERROR,
318
- EVENTTYPES.UNHANDLEDREJECTION,
319
- EVENTTYPES.CONSOLEERROR
320
- ])
321
- }
322
-
323
- export { initError, handleSendError, parseError }
@@ -1,63 +0,0 @@
1
- /**
2
- * 这部分功能移植到 pv 中,并且默认开启
3
- */
4
- import { EVENTTYPES, SEDNEVENTTYPES, WEBPAGELOAD } from '../common'
5
- import { uuid, isValidKey, getTimestamp, getLocationHref } from '../utils'
6
- import { eventBus } from './eventBus'
7
- import { sendData } from './sendData'
8
- // import { options } from './options'
9
-
10
- class DwellRequestTemplate {
11
- eventId = '' // 事件ID
12
- eventType = '' // 事件类型
13
- triggerPageUrl = '' // 当前页面URL
14
- referer = '' // 上级页面URL
15
- entryTime = -1 // 加载完成时间
16
- triggerTime = -1 // 卸载时间
17
- millisecond = -1 // 页面停留时间
18
- operateAction = '' // 页面加载来源
19
- constructor(config = {}) {
20
- Object.keys(config).forEach(key => {
21
- if (isValidKey(key, config)) {
22
- this[key] = config[key] || null
23
- }
24
- })
25
- }
26
- }
27
-
28
- /**
29
- * 加载 & 卸载事件
30
- */
31
- function dwellCollector() {
32
- const _config = new DwellRequestTemplate({ eventType: SEDNEVENTTYPES.DWELL })
33
-
34
- // 加载完成事件
35
- eventBus.addEvent({
36
- type: EVENTTYPES.LOAD,
37
- callback: () => {
38
- _config.entryTime = getTimestamp()
39
- }
40
- })
41
-
42
- // 卸载事件
43
- eventBus.addEvent({
44
- type: EVENTTYPES.BEFOREUNLOAD,
45
- callback: () => {
46
- _config.eventId = uuid()
47
- _config.triggerPageUrl = getLocationHref() // 当前页面 url
48
- _config.referer = document.referrer // 上级页面 url(从哪个页面跳过来的就是上级页面)
49
- _config.triggerTime = getTimestamp() // 卸载时间
50
- _config.millisecond = getTimestamp() - _config.entryTime // 停留多久
51
- const { type } = performance.navigation // 表示加载来源, type为 0,1,2,255
52
- _config.operateAction = WEBPAGELOAD[type] || ''
53
- sendData.emit(_config, true)
54
- }
55
- })
56
- }
57
-
58
- function initEventDwell() {
59
- // options.value.event.unload && dwellCollector() // 放弃此方法
60
- dwellCollector()
61
- }
62
-
63
- export { initEventDwell }
package/src/lib/event.ts DELETED
@@ -1,252 +0,0 @@
1
- import { isValidKey, getLocationHref, getTimestamp } from '../utils'
2
- import { getElByAttr, isSimpleEl, getNodeXPath } from '../utils/element'
3
- import { sendData } from './sendData'
4
- import { eventBus } from './eventBus'
5
- import { EVENTTYPES, SEDNEVENTTYPES } from '../common'
6
- import { options } from './options'
7
-
8
- class RequestTemplateClick {
9
- eventId = '' // 事件ID
10
- eventType = '' // 事件类型
11
- title = '' // 事件名
12
- triggerPageUrl = '' // 当前页面URL
13
- x = -1 // 被点击元素与屏幕左边距离
14
- y = -1 // 被点击元素与屏幕上边距离
15
- params = {} // 事件参数
16
- elementPath = '' // 被点击元素的层级
17
- triggerTime = -1 // 事件发生时间
18
- constructor(config = {}) {
19
- Object.keys(config).forEach(key => {
20
- if (isValidKey(key, config)) {
21
- this[key] = config[key] || null
22
- }
23
- })
24
- }
25
- }
26
-
27
- /**
28
- * 监听 - 点击事件
29
- */
30
- function clickCollection() {
31
- eventBus.addEvent({
32
- type: EVENTTYPES.CLICK,
33
- callback: (e: MouseEvent) => {
34
- const _config = new RequestTemplateClick({
35
- eventType: SEDNEVENTTYPES.CLICK
36
- })
37
-
38
- // 获取被点击的元素到最外层元素组成的数组
39
- const path: HTMLElement[] = e.composedPath()
40
- ? (e.composedPath() as HTMLElement[])
41
- : e.target
42
- ? getNodePath(e.target as HTMLElement)
43
- : []
44
-
45
- // 检查被点击的元素以及其父级元素是否有这些属性(从内到外)
46
- const target = path.find(
47
- el =>
48
- el.hasAttribute &&
49
- (el.hasAttribute('data-warden-container') ||
50
- el.hasAttribute('data-warden-event-id') ||
51
- el.hasAttribute('data-warden-title'))
52
- )
53
-
54
- if (!target) return
55
-
56
- const { scrollTop, scrollLeft } = document.documentElement // html距离上和左侧的距离(一般都是0)
57
- const { top, left } = (e.target as HTMLElement).getBoundingClientRect() // 元素距离html的距离
58
- _config.x = left + scrollLeft
59
- _config.y = top + scrollTop
60
- _config.triggerTime = getTimestamp() // 点击时间
61
- _config.triggerPageUrl = getLocationHref() // 当前页面的url
62
- _config.title = extractTitleByTarget(target) // 获取title属性
63
- _config.eventId = extractDataByPath(path) // 提取数据事件ID
64
- _config.params = extractParamsByPath(path) // 提取数据参数
65
- _config.elementPath = getNodeXPath(target).slice(-128) // 长度限制128字符
66
- sendData.emit(_config)
67
- }
68
- })
69
- }
70
-
71
- /**
72
- * 获取目标元素到最外层元素组成的数组
73
- */
74
- function getNodePath(
75
- node: HTMLElement,
76
- options = { includeSelf: true, order: 'asc' }
77
- ) {
78
- if (!node) return []
79
- const { includeSelf, order } = options
80
- let parent = includeSelf ? node : node.parentElement
81
- let result: HTMLElement[] = []
82
- while (parent) {
83
- result = order === 'asc' ? result.concat(parent) : [parent].concat(result)
84
- parent = parent.parentElement
85
- }
86
- return result
87
- }
88
-
89
- /**
90
- * 获取title属性(data-warden-title 或者 title)
91
- */
92
- function extractTitleByTarget(target: HTMLElement) {
93
- const selfTitle = getNodeTitle(target)
94
- if (selfTitle) return selfTitle
95
-
96
- // 向上找其父节点
97
- let container = target.parentElement
98
-
99
- while (container && container !== document.body) {
100
- if (container.hasAttribute('data-warden-container')) break
101
- container = container.parentElement
102
- }
103
- const superTitle = getNodeTitle(container)
104
- if (superTitle) return superTitle
105
-
106
- // 自身以及父级都没有拿到 title 值的情况下
107
- const { tagName } = target
108
- return !target.hasChildNodes() || tagName.toLowerCase() === 'svg'
109
- ? handleLeafNode(target)
110
- : handleNoLeafNode(target)
111
- }
112
- /**
113
- * 获取元素的 data-warden-title 属性或者 title属性
114
- */
115
- function getNodeTitle(node: HTMLElement | null) {
116
- if (node) {
117
- return node.hasAttribute('data-warden-title')
118
- ? node.getAttribute('data-warden-title')
119
- : node.title
120
- }
121
- return ''
122
- }
123
- /**
124
- * 获取 title - 叶子元素的情况下,取其特殊值
125
- * 叶子元素(也就是不包含其他HTML元素,也不能有文本内容)
126
- */
127
- function handleLeafNode(target: any) {
128
- const { tagName, textContent } = target
129
- if (tagName === 'IMG') return target.getAttribute('alt') || null
130
- if (tagName === 'svg') {
131
- const a = [...Array(target.children)].find(item => item.tagName === 'use')
132
- if (a) return a.getAttribute('xlink:href') || null
133
- }
134
- return textContent
135
- }
136
- /**
137
- * 获取 title - 非叶子元素的情况
138
- */
139
- function handleNoLeafNode(target: Element) {
140
- const { tagName, textContent } = target
141
- if (tagName === 'A') {
142
- const res = isSimpleEl([...Array.from(target.children)])
143
- return res ? textContent : target.getAttribute('href') || null
144
- }
145
- if (tagName === 'BUTTON') {
146
- const name = target.getAttribute('name')
147
- const res = isSimpleEl([...Array.from(target.children)])
148
- return name || res ? textContent : target.getAttribute('href') || null
149
- }
150
- const { length } = [...Array.from(target.children)].filter(() =>
151
- target.hasChildNodes()
152
- )
153
- return length > 0 ? null : textContent
154
- }
155
-
156
- /**
157
- * 提取数据事件ID
158
- */
159
- function extractDataByPath(list: HTMLElement[] = []) {
160
- // data-warden-event-id
161
- const hasIdEl = getElByAttr(list, 'data-warden-event-id')
162
- if (hasIdEl) return hasIdEl.getAttribute('data-warden-event-id')!
163
-
164
- // title
165
- const hasTitleEl = getElByAttr(list, 'title')
166
- if (hasTitleEl) return hasTitleEl.getAttribute('title')!
167
-
168
- // container
169
- const container = getElByAttr(list, 'data-warden-container')
170
- if (container) {
171
- if (container.getAttribute('data-warden-event-id')) {
172
- return container.getAttribute('data-warden-event-id')!
173
- }
174
- if (container.getAttribute('title')) {
175
- return container.getAttribute('title')!
176
- }
177
- const id2 = container.getAttribute('data-warden-container')!
178
- if (typeof id2 === 'string' && id2) return id2
179
- }
180
-
181
- // 都没有则以 tagname 去当做ID
182
- return list[0].tagName.toLowerCase()
183
- }
184
-
185
- /**
186
- * 提取数据参数
187
- * 如果本身节点没有埋点属性的话会用父级埋点属性
188
- */
189
- function extractParamsByPath(list: HTMLElement[] = []) {
190
- const regex = /^data-warden-/
191
- let target
192
- let targetIndex = -1
193
-
194
- // 遍历从子节点到body下最大的节点,遍历他们的属性,直到某个节点的属性能通过校验的节点
195
- for (let index = 0; index < list.length; index++) {
196
- const el = list[index]
197
- const attributes = (el && el.attributes && Array.from(el.attributes)) || []
198
- target = attributes.find(item =>
199
- item.nodeName.match(regex)
200
- ? item.nodeName.match(regex)
201
- : item.nodeName.indexOf('data-warden-container') !== -1
202
- )
203
- if (target) {
204
- targetIndex = index
205
- break
206
- }
207
- }
208
- if (targetIndex < 0) return {}
209
-
210
- const container = list[targetIndex]
211
- const attrList = Array.from(container.attributes) || []
212
- const params: Record<string, string | null> = {}
213
- const defaultKey = ['container', 'title', 'event-id']
214
- attrList.forEach(item => {
215
- if (item.nodeName.indexOf('data-warden') < 0) return // 过滤非标准命名 如 data-v-fbcf7454
216
- const key = item.nodeName.replace(regex, '')
217
- if (defaultKey.includes(key)) return // 过滤sdk自定义属性
218
- params[key] = item.nodeValue
219
- })
220
-
221
- return params
222
- }
223
-
224
- function initEvent() {
225
- options.value.event.core && clickCollection()
226
- }
227
-
228
- /**
229
- * 主动触发事件上报
230
- * @param options 自定义配置信息
231
- */
232
- function handleSendEvent(options = {}, flush = false) {
233
- sendData.emit(
234
- {
235
- ...options,
236
- eventType: SEDNEVENTTYPES.CUSTOM,
237
- triggerTime: getTimestamp(),
238
- triggerPageUrl: getLocationHref()
239
- },
240
- flush
241
- )
242
- }
243
-
244
- /**
245
- * 卸载所有事件监听
246
- */
247
- export function destroyEvent() {
248
- // 清除事件相关的事件类型
249
- eventBus.removeEvents([EVENTTYPES.CLICK, EVENTTYPES.LOAD])
250
- }
251
-
252
- export { initEvent, handleSendEvent }