From 5a0bc110d9e9c7a826b4111e31f9f2be24fd85aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E6=99=BA=E5=AD=90=20Kevin=20Deng?= Date: Fri, 1 Mar 2024 18:15:00 +0800 Subject: [PATCH] refactor(runtime-vapor): record event metadata as array --- .../{dom.spec.ts => dom/element.spec.ts} | 6 ++--- .../dom/{patchProp.spec.ts => prop.spec.ts} | 16 ++++++------ packages/runtime-vapor/src/dom/event.ts | 26 ++++++++++++------- packages/runtime-vapor/src/dom/prop.ts | 17 +++++------- packages/runtime-vapor/src/dom/style.ts | 9 ++----- packages/runtime-vapor/src/metadata.ts | 20 +++++++------- 6 files changed, 47 insertions(+), 47 deletions(-) rename packages/runtime-vapor/__tests__/{dom.spec.ts => dom/element.spec.ts} (91%) rename packages/runtime-vapor/__tests__/dom/{patchProp.spec.ts => prop.spec.ts} (96%) diff --git a/packages/runtime-vapor/__tests__/dom.spec.ts b/packages/runtime-vapor/__tests__/dom/element.spec.ts similarity index 91% rename from packages/runtime-vapor/__tests__/dom.spec.ts rename to packages/runtime-vapor/__tests__/dom/element.spec.ts index f094f37cc..43b9ab02b 100644 --- a/packages/runtime-vapor/__tests__/dom.spec.ts +++ b/packages/runtime-vapor/__tests__/dom/element.spec.ts @@ -1,12 +1,12 @@ -import { insert, normalizeBlock, prepend, remove } from '../src/dom/element' -import { fragmentKey } from '../src/render' +import { insert, normalizeBlock, prepend, remove } from '../../src/dom/element' +import { fragmentKey } from '../../src/render' const node1 = document.createTextNode('node1') const node2 = document.createTextNode('node2') const node3 = document.createTextNode('node3') const anchor = document.createTextNode('anchor') -describe('dom', () => { +describe('element', () => { test('normalizeBlock', () => { expect(normalizeBlock([node1, node2, node3])).toEqual([node1, node2, node3]) expect(normalizeBlock([node1, [node2, [node3]]])).toEqual([ diff --git a/packages/runtime-vapor/__tests__/dom/patchProp.spec.ts b/packages/runtime-vapor/__tests__/dom/prop.spec.ts similarity index 96% rename from packages/runtime-vapor/__tests__/dom/patchProp.spec.ts rename to packages/runtime-vapor/__tests__/dom/prop.spec.ts index 355d99891..f701910d5 100644 --- a/packages/runtime-vapor/__tests__/dom/patchProp.spec.ts +++ b/packages/runtime-vapor/__tests__/dom/prop.spec.ts @@ -13,7 +13,7 @@ import { createComponentInstance, setCurrentInstance, } from '../../src/component' -import { MetadataKind, getMetadata, recordMetadata } from '../../src/metadata' +import { getMetadata, recordPropMetadata } from '../../src/metadata' let removeComponentInstance = NOOP beforeEach(() => { @@ -30,16 +30,16 @@ afterEach(() => { }) describe('patchProp', () => { - describe('recordMetadata', () => { + describe('recordPropMetadata', () => { test('should record prop metadata', () => { const node = {} as Node // the node is just a key - let prev = recordMetadata(node, MetadataKind.prop, 'class', 'foo') + let prev = recordPropMetadata(node, 'class', 'foo') expect(prev).toBeUndefined() - prev = recordMetadata(node, MetadataKind.prop, 'class', 'bar') + prev = recordPropMetadata(node, 'class', 'bar') expect(prev).toBe('foo') - prev = recordMetadata(node, MetadataKind.prop, 'style', 'color: red') + prev = recordPropMetadata(node, 'style', 'color: red') expect(prev).toBeUndefined() - prev = recordMetadata(node, MetadataKind.prop, 'style', 'color: blue') + prev = recordPropMetadata(node, 'style', 'color: blue') expect(prev).toBe('color: red') expect(getMetadata(node)).toEqual([ @@ -51,8 +51,8 @@ describe('patchProp', () => { test('should have different metadata for different nodes', () => { const node1 = {} as Node const node2 = {} as Node - recordMetadata(node1, MetadataKind.prop, 'class', 'foo') - recordMetadata(node2, MetadataKind.prop, 'class', 'bar') + recordPropMetadata(node1, 'class', 'foo') + recordPropMetadata(node2, 'class', 'bar') expect(getMetadata(node1)).toEqual([{ class: 'foo' }, {}]) expect(getMetadata(node2)).toEqual([{ class: 'bar' }, {}]) }) diff --git a/packages/runtime-vapor/src/dom/event.ts b/packages/runtime-vapor/src/dom/event.ts index 60858341f..2370147ca 100644 --- a/packages/runtime-vapor/src/dom/event.ts +++ b/packages/runtime-vapor/src/dom/event.ts @@ -4,7 +4,7 @@ import { onEffectCleanup, onScopeDispose, } from '@vue/reactivity' -import { MetadataKind, getMetadata, recordMetadata } from '../metadata' +import { MetadataKind, getMetadata, recordEventMetadata } from '../metadata' import { withKeys, withModifiers } from '@vue/runtime-dom' export function addEventListener( @@ -29,12 +29,16 @@ export function on( options: AddEventListenerOptions & ModifierOptions = {}, ) { const handler: DelegatedHandler = eventHandler(handlerGetter, options) - recordMetadata(el, MetadataKind.event, event, handler) + const cleanupMetadata = recordEventMetadata(el, event, handler) + const cleanupEvent = addEventListener(el, event, handler, options) + + function cleanup() { + cleanupMetadata() + cleanupEvent() + } - const cleanup = addEventListener(el, event, handler, options) const scope = getCurrentScope() const effect = getCurrentEffect() - if (effect && effect.scope === scope) { onEffectCleanup(cleanup) } else if (scope) { @@ -55,7 +59,7 @@ export function delegate( ) { const handler: DelegatedHandler = eventHandler(handlerGetter, options) handler.delegate = true - recordMetadata(el, MetadataKind.event, event, handler) + recordEventMetadata(el, event, handler) } function eventHandler( @@ -103,10 +107,14 @@ const delegatedEventHandler = (e: Event) => { }, }) while (node !== null) { - const handler = getMetadata(node)[MetadataKind.event][e.type] - if (handler && handler.delegate && !node.disabled) { - handler(e) - if (e.cancelBubble) return + const handlers = getMetadata(node)[MetadataKind.event][e.type] + if (handlers) { + for (const handler of handlers) { + if (handler.delegate && !node.disabled) { + handler(e) + if (e.cancelBubble) return + } + } } node = node.host && node.host !== node && node.host instanceof Node diff --git a/packages/runtime-vapor/src/dom/prop.ts b/packages/runtime-vapor/src/dom/prop.ts index 49a450463..3f5d6c128 100644 --- a/packages/runtime-vapor/src/dom/prop.ts +++ b/packages/runtime-vapor/src/dom/prop.ts @@ -11,22 +11,17 @@ import { } from '@vue/shared' import { warn } from '../warning' import { setStyle } from './style' -import { MetadataKind, getMetadata, recordMetadata } from '../metadata' +import { MetadataKind, getMetadata, recordPropMetadata } from '../metadata' export function setClass(el: Element, value: any) { - const prev = recordMetadata( - el, - MetadataKind.prop, - 'class', - (value = normalizeClass(value)), - ) + const prev = recordPropMetadata(el, 'class', (value = normalizeClass(value))) if (value !== prev && (value || prev)) { el.className = value } } export function setAttr(el: Element, key: string, value: any) { - const oldVal = recordMetadata(el, MetadataKind.prop, key, value) + const oldVal = recordPropMetadata(el, key, value) if (value !== oldVal) { if (value != null) { el.setAttribute(key, value) @@ -37,7 +32,7 @@ export function setAttr(el: Element, key: string, value: any) { } export function setDOMProp(el: any, key: string, value: any) { - const oldVal = recordMetadata(el, MetadataKind.prop, key, value) + const oldVal = recordPropMetadata(el, key, value) if (value === oldVal) return if (key === 'innerHTML' || key === 'textContent') { @@ -184,14 +179,14 @@ function mergeProps(...args: Data[]) { export function setText(el: Node, ...values: any[]) { const text = values.map(v => toDisplayString(v)).join('') - const oldVal = recordMetadata(el, MetadataKind.prop, 'textContent', text) + const oldVal = recordPropMetadata(el, 'textContent', text) if (text !== oldVal) { el.textContent = text } } export function setHtml(el: Element, value: any) { - const oldVal = recordMetadata(el, MetadataKind.prop, 'innerHTML', value) + const oldVal = recordPropMetadata(el, 'innerHTML', value) if (value !== oldVal) { el.innerHTML = value } diff --git a/packages/runtime-vapor/src/dom/style.ts b/packages/runtime-vapor/src/dom/style.ts index e6cde09bf..a6dd74fa3 100644 --- a/packages/runtime-vapor/src/dom/style.ts +++ b/packages/runtime-vapor/src/dom/style.ts @@ -7,15 +7,10 @@ import { normalizeStyle, } from '@vue/shared' import { warn } from '../warning' -import { MetadataKind, recordMetadata } from '../metadata' +import { recordPropMetadata } from '../metadata' export function setStyle(el: HTMLElement, value: any) { - const prev = recordMetadata( - el, - MetadataKind.prop, - 'style', - (value = normalizeStyle(value)), - ) + const prev = recordPropMetadata(el, 'style', (value = normalizeStyle(value))) patchStyle(el, prev, value) } diff --git a/packages/runtime-vapor/src/metadata.ts b/packages/runtime-vapor/src/metadata.ts index 4dfbe5208..f2835d0be 100644 --- a/packages/runtime-vapor/src/metadata.ts +++ b/packages/runtime-vapor/src/metadata.ts @@ -1,4 +1,4 @@ -import type { Data } from '@vue/shared' +import { type Data, remove } from '@vue/shared' import type { DelegatedHandler } from './dom/event' export enum MetadataKind { @@ -8,7 +8,7 @@ export enum MetadataKind { export type ElementMetadata = [ props: Data, - events: Record, + events: Record, ] export function getMetadata( @@ -17,14 +17,16 @@ export function getMetadata( return el.$$metadata || (el.$$metadata = [{}, {}]) } -export function recordMetadata( - el: Node, - kind: MetadataKind, - key: string, - value: any, -): any { - const metadata = getMetadata(el)[kind] +export function recordPropMetadata(el: Node, key: string, value: any): any { + const metadata = getMetadata(el)[MetadataKind.prop] const prev = metadata[key] metadata[key] = value return prev } + +export function recordEventMetadata(el: Node, key: string, value: any) { + const metadata = getMetadata(el)[MetadataKind.event] + const handlers = (metadata[key] ||= []) + handlers.push(value) + return () => remove(handlers, value) +}