From 1ace71648620576a5e244aefa3255e692028e1c7 Mon Sep 17 00:00:00 2001 From: chenli Date: Thu, 25 Aug 2022 22:47:05 +0800 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20=E6=8F=90=E4=BA=A4=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/HelloWorld.vue | 101 +++++++++++++++++++++++----------- tests/unit/example.spec.js | 2 +- 2 files changed, 71 insertions(+), 32 deletions(-) diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue index 5e4ce20..1fb8062 100644 --- a/src/components/HelloWorld.vue +++ b/src/components/HelloWorld.vue @@ -1,44 +1,83 @@ diff --git a/tests/unit/example.spec.js b/tests/unit/example.spec.js index d0bae58..28a6363 100644 --- a/tests/unit/example.spec.js +++ b/tests/unit/example.spec.js @@ -16,4 +16,4 @@ describe('HelloWorld.vue', () => { button[1].trigger('click') expect(wrapper.vm.spmText).toMatch('aa.dd.ff') }) -}) \ No newline at end of file +}) From 9b46f9e7cb0d9e95291957208ceb78e6bb74b862 Mon Sep 17 00:00:00 2001 From: chenli Date: Fri, 26 Aug 2022 13:24:21 +0800 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E9=80=BB=E8=BE=91=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/HelloWorld.vue | 79 +++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue index 1fb8062..7bbd1d7 100644 --- a/src/components/HelloWorld.vue +++ b/src/components/HelloWorld.vue @@ -41,6 +41,85 @@ if (target === currentTarget) { this.spmText = arr.reverse().join('.') return + /* +为什么使用arr.push再arr.reverse().join('.')? +一、实际测试了以下几段代码: + + +1. 使用arr.unshift,再arr.join('.') + +console.time('array unshift') +let arr = [] + +for (let i = 0; i < 100000000; i++) { + arr.unshift('aa') +} + +let str = arr.join('.') +console.timeEnd('array unshift') + +循环100W次 +耗时: 1:55.289 (m:ss.mmm) + +2. 使用arr.push再arr.reverse().join('.') + +console.time('array push') +let arr = [] + +for (let i = 0; i < 100000000; i++) { + arr.push('aa') +} + +let str = arr.reverse().join('.') +console.timeEnd('array push') + +测试环境:Node.js v16.14.1 +循环100W次 +耗时: 61.79ms +循环1000W次 +耗时: 672.56ms +循环1亿次 +耗时: 8.396s + +测试环境:Chrome 104.0.5112.101(正式版本) (arm64) +循环100W次 +耗时: 52.5791015625 ms +循环1000W次 +耗时: 392.364990234375 ms +循环1亿次 +耗时: 3324.813232421875 ms + +3. 使用String + +console.time('string') +let str = '' + +for (let i = 0; i < 100000000; i++) { + str = 'aa' + '.' + str +} +console.timeEnd('string') + +测试环境:Node.js v16.14.1 +循环100W次 +耗时: 84.646ms +循环1000W次 +耗时: 790.097ms +循环1亿次 +耗时: 12.251s + +测试环境:Chrome 104.0.5112.101(正式版本) (arm64) +循环100W次 +耗时: 72.958984375 ms +循环1000W次 +耗时: 751.48486328125 ms +循环1亿次 +耗时: 6852.30615234375 ms + +二、选用Array的原因 +1. 从实际效果来看使用arr.push再arr.reverse().join('.'),和直接用字符串拼接性能差异不大。 +2. 但考虑到用Array性能较高 +3. 使用Array代码逻辑简单,不需要处理字符串拼接结果为aa.bb.cc. ,最后会多一个'.'的问题 + */ } this.getSpmText(target.parentNode, currentTarget, arr) From c6b6b55391412c9e643289f8068e7d05317029d4 Mon Sep 17 00:00:00 2001 From: chenli Date: Sun, 28 Aug 2022 16:18:11 +0800 Subject: [PATCH 3/6] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E6=88=90?= =?UTF-8?q?=E9=80=9A=E7=94=A8=E6=96=B9=E6=B3=95,=E5=B9=B6=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E5=9C=A8=E5=AD=90=E7=BB=84=E4=BB=B6=E4=B8=AD=E8=A7=A6?= =?UTF-8?q?=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/HelloWorld.vue | 136 ++++++-------------------------- src/components/InnerButton.vue | 24 ++++++ src/utils/spm.js | 140 +++++++++++++++++++++++++++++++++ tests/unit/example.spec.js | 24 ++++-- 4 files changed, 204 insertions(+), 120 deletions(-) create mode 100644 src/components/InnerButton.vue create mode 100644 src/utils/spm.js diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue index 7bbd1d7..858de1a 100644 --- a/src/components/HelloWorld.vue +++ b/src/components/HelloWorld.vue @@ -1,141 +1,51 @@ diff --git a/src/components/InnerButton.vue b/src/components/InnerButton.vue new file mode 100644 index 0000000..2147400 --- /dev/null +++ b/src/components/InnerButton.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/utils/spm.js b/src/utils/spm.js new file mode 100644 index 0000000..ac261cd --- /dev/null +++ b/src/utils/spm.js @@ -0,0 +1,140 @@ +// 缓存所有hook,并在click事件触发时依次运行 +let hooks = [] + +// 为document.body绑定事件,获取spm值 +export function init(hookArray = []) { + // 初始化时存储所有hook + hooks.push(...hookArray) + + document.body.addEventListener('click', function (event) { + let spmTextArray = [] // 存储每个元素的spm值 + getSpmText(event.target, event.currentTarget, spmTextArray) + // 生成spm字符串 + const spmText = spmTextArray.reverse().join('.') + + // 依次运行hook,并将spm字符串传入 + hooks.forEach(callback => { + callback(spmText) + }) + }) +} + +// 添加hook +export function addHook(hook) { + hooks.push(hook) +} + +// 移除hook +export function removeHook(callback) { + const removeIndex = hooks.findIndex(cb => cb === callback) + hooks.splice(removeIndex, 1) +} + +// 不断向父级元素查找,直到查找到绑定事件的元素 +function getSpmText(target, currentTarget, arr) { + // 早点当前元素的spm + const targetSpmText = findSpmText(target) + + // 如果有spm则存入数组 + if (targetSpmText) { + arr.push(targetSpmText) + } + + // 如果查找到绑定事件的元素,就将结果存储并退出循环 + if (target === currentTarget) { + return + /* +为什么使用arr.push再arr.reverse().join('.')? +一、实际测试了以下几段代码: + + +1. 使用arr.unshift,再arr.join('.') + +console.time('array unshift') +let arr = [] + +for (let i = 0; i < 100000000; i++) { +arr.unshift('aa') +} + +let str = arr.join('.') +console.timeEnd('array unshift') + +循环100W次 +耗时: 1:55.289 (m:ss.mmm) + +2. 使用arr.push再arr.reverse().join('.') + +console.time('array push') +let arr = [] + +for (let i = 0; i < 100000000; i++) { +arr.push('aa') +} + +let str = arr.reverse().join('.') +console.timeEnd('array push') + +测试环境:Node.js v16.14.1 +循环100W次 +耗时: 61.79ms +循环1000W次 +耗时: 672.56ms +循环1亿次 +耗时: 8.396s + +测试环境:Chrome 104.0.5112.101(正式版本) (arm64) +循环100W次 +耗时: 52.5791015625 ms +循环1000W次 +耗时: 392.364990234375 ms +循环1亿次 +耗时: 3324.813232421875 ms + +3. 使用String + +console.time('string') +let str = '' + +for (let i = 0; i < 100000000; i++) { +str = 'aa' + '.' + str +} +console.timeEnd('string') + +测试环境:Node.js v16.14.1 +循环100W次 +耗时: 84.646ms +循环1000W次 +耗时: 790.097ms +循环1亿次 +耗时: 12.251s + +测试环境:Chrome 104.0.5112.101(正式版本) (arm64) +循环100W次 +耗时: 72.958984375 ms +循环1000W次 +耗时: 751.48486328125 ms +循环1亿次 +耗时: 6852.30615234375 ms + +二、选用Array的原因 +1. 从实际效果来看使用arr.push再arr.reverse().join('.'),和直接用字符串拼接性能差异不大。 +2. 但考虑到用Array性能较高 +3. 使用Array代码逻辑简单,不需要处理字符串拼接结果为aa.bb.cc. ,最后会多一个'.'的问题 +*/ + } + + getSpmText(target.parentNode, currentTarget, arr) +} +// 查找当前元素是否有data-spmx属性,并且其有值 +// 将data-spmx属性的值返回,无值返回'' +function findSpmText(target) { + const dataset = target.dataset + const spmKey = Object.keys(dataset).find(key => key.startsWith('spm')) + + if (spmKey && dataset[spmKey]) { + return dataset[spmKey] + } + + return '' +} diff --git a/tests/unit/example.spec.js b/tests/unit/example.spec.js index 50061c1..c889b2c 100644 --- a/tests/unit/example.spec.js +++ b/tests/unit/example.spec.js @@ -1,21 +1,31 @@ import { shallowMount, mount } from '@vue/test-utils' -import HelloWorld from '@/components/HelloWorld.vue'; -import { warn } from 'vue'; +import HelloWorld from '@/components/HelloWorld.vue' jest.setTimeout(10000) describe('HelloWorld.vue', () => { it('校验第一个按钮的spm是否为aa.bb.cc', async () => { - const wrapper = shallowMount(HelloWorld, { attachTo: document.body }); - const button = wrapper.findAll('button'); - await button[0].trigger('click'); - expect(wrapper.vm.spmText).toMatch('aa.bb.cc'); + const wrapper = shallowMount(HelloWorld, { attachTo: document.body }) + const button = wrapper.findAll('button') + await button[0].trigger('click') + expect(wrapper.vm.spmText).toMatch('aa.bb.cc') }) }) describe('HelloWorld.vue', () => { - it('校验第一个按钮的spm是否为aa.dd.ff', async () => { + it('校验第二个按钮的spm是否为aa.dd.ff', async () => { const wrapper = shallowMount(HelloWorld, { attachTo: document.body }) const button = wrapper.findAll('button') await button[1].trigger('click') expect(wrapper.vm.spmText).toMatch('aa.dd.ff') }) }) +describe('InnerButton.vue', () => { + it('校验第三个按钮的spm是否为aa.dd.gg', async () => { + const wrapper = mount(HelloWorld, { attachTo: document.body }) + const button = wrapper.findAll('button') + + // 触发InnerButton组件中button的click事件 + // HelloWorld组件能监听到变化,并同步修改spmText的值 + await button[2].trigger('click') + expect(wrapper.vm.spmText).toMatch('aa.dd.gg') + }) +}) From f5d3817c981ad0339ec9e322926a4412e4e898b1 Mon Sep 17 00:00:00 2001 From: chenli Date: Sun, 28 Aug 2022 16:22:18 +0800 Subject: [PATCH 4/6] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/HelloWorld.vue | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue index 858de1a..5d38572 100644 --- a/src/components/HelloWorld.vue +++ b/src/components/HelloWorld.vue @@ -39,10 +39,12 @@ hook ]) + // 可以移除hook,这样点击就无效 setTimeout(() => { removeHook(hook) }, 3000); + // 可以添加hook,让点击重新生效 setTimeout(() => { addHook(hook) }, 5000); From 595d29055fb55ab2e0cddda51fef71502c8f9e6c Mon Sep 17 00:00:00 2001 From: chenli Date: Sun, 28 Aug 2022 16:34:40 +0800 Subject: [PATCH 5/6] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/HelloWorld.vue | 4 +++- src/utils/spm.js | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue index 5d38572..ec86022 100644 --- a/src/components/HelloWorld.vue +++ b/src/components/HelloWorld.vue @@ -34,7 +34,9 @@ this.spmText = spmText } - // 为组件添加 + // 初始化信息收集,并传入hook进行数据处理 + // 建议在入口JS文件或入口组件进行初始化 + // 此处为通过用例,在组件中初始化 init([ hook ]) diff --git a/src/utils/spm.js b/src/utils/spm.js index ac261cd..19149a8 100644 --- a/src/utils/spm.js +++ b/src/utils/spm.js @@ -13,8 +13,8 @@ export function init(hookArray = []) { const spmText = spmTextArray.reverse().join('.') // 依次运行hook,并将spm字符串传入 - hooks.forEach(callback => { - callback(spmText) + hooks.forEach(hook => { + hook(spmText) }) }) } @@ -25,8 +25,8 @@ export function addHook(hook) { } // 移除hook -export function removeHook(callback) { - const removeIndex = hooks.findIndex(cb => cb === callback) +export function removeHook(removeHookItem) { + const removeIndex = hooks.findIndex(hook => hook === removeHookItem) hooks.splice(removeIndex, 1) } From 9e1277eeab8053bece656b002f71f63c7cd8f464 Mon Sep 17 00:00:00 2001 From: chenli Date: Sun, 28 Aug 2022 17:00:24 +0800 Subject: [PATCH 6/6] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/HelloWorld.vue | 14 +++++++------- src/utils/spm.js | 8 ++++++-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue index ec86022..f952339 100644 --- a/src/components/HelloWorld.vue +++ b/src/components/HelloWorld.vue @@ -29,27 +29,27 @@ spmText: 'xx.xx.xx' } }, - mounted () { - const hook = (spmText) => { + mounted() { + const hook = spmText => { this.spmText = spmText } // 初始化信息收集,并传入hook进行数据处理 // 建议在入口JS文件或入口组件进行初始化 // 此处为通过用例,在组件中初始化 - init([ - hook - ]) + init({ + hooks: [hook] + }) // 可以移除hook,这样点击就无效 setTimeout(() => { removeHook(hook) - }, 3000); + }, 3000) // 可以添加hook,让点击重新生效 setTimeout(() => { addHook(hook) - }, 5000); + }, 5000) } } diff --git a/src/utils/spm.js b/src/utils/spm.js index 19149a8..25a19f8 100644 --- a/src/utils/spm.js +++ b/src/utils/spm.js @@ -2,11 +2,15 @@ let hooks = [] // 为document.body绑定事件,获取spm值 -export function init(hookArray = []) { +export function init(params) { + // 支持自定义监听点击的元素 + const element = params.element ?? document.body + // 初始化传入的hook + const hookArray = params.hooks ?? [] // 初始化时存储所有hook hooks.push(...hookArray) - document.body.addEventListener('click', function (event) { + element.addEventListener('click', function (event) { let spmTextArray = [] // 存储每个元素的spm值 getSpmText(event.target, event.currentTarget, spmTextArray) // 生成spm字符串