mirror of https://github.com/vuejs/core.git
refactor(runtime-vapor): record event metadata as array
This commit is contained in:
parent
7f861441d7
commit
5a0bc110d9
|
@ -1,12 +1,12 @@
|
||||||
import { insert, normalizeBlock, prepend, remove } from '../src/dom/element'
|
import { insert, normalizeBlock, prepend, remove } from '../../src/dom/element'
|
||||||
import { fragmentKey } from '../src/render'
|
import { fragmentKey } from '../../src/render'
|
||||||
|
|
||||||
const node1 = document.createTextNode('node1')
|
const node1 = document.createTextNode('node1')
|
||||||
const node2 = document.createTextNode('node2')
|
const node2 = document.createTextNode('node2')
|
||||||
const node3 = document.createTextNode('node3')
|
const node3 = document.createTextNode('node3')
|
||||||
const anchor = document.createTextNode('anchor')
|
const anchor = document.createTextNode('anchor')
|
||||||
|
|
||||||
describe('dom', () => {
|
describe('element', () => {
|
||||||
test('normalizeBlock', () => {
|
test('normalizeBlock', () => {
|
||||||
expect(normalizeBlock([node1, node2, node3])).toEqual([node1, node2, node3])
|
expect(normalizeBlock([node1, node2, node3])).toEqual([node1, node2, node3])
|
||||||
expect(normalizeBlock([node1, [node2, [node3]]])).toEqual([
|
expect(normalizeBlock([node1, [node2, [node3]]])).toEqual([
|
|
@ -13,7 +13,7 @@ import {
|
||||||
createComponentInstance,
|
createComponentInstance,
|
||||||
setCurrentInstance,
|
setCurrentInstance,
|
||||||
} from '../../src/component'
|
} from '../../src/component'
|
||||||
import { MetadataKind, getMetadata, recordMetadata } from '../../src/metadata'
|
import { getMetadata, recordPropMetadata } from '../../src/metadata'
|
||||||
|
|
||||||
let removeComponentInstance = NOOP
|
let removeComponentInstance = NOOP
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -30,16 +30,16 @@ afterEach(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('patchProp', () => {
|
describe('patchProp', () => {
|
||||||
describe('recordMetadata', () => {
|
describe('recordPropMetadata', () => {
|
||||||
test('should record prop metadata', () => {
|
test('should record prop metadata', () => {
|
||||||
const node = {} as Node // the node is just a key
|
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()
|
expect(prev).toBeUndefined()
|
||||||
prev = recordMetadata(node, MetadataKind.prop, 'class', 'bar')
|
prev = recordPropMetadata(node, 'class', 'bar')
|
||||||
expect(prev).toBe('foo')
|
expect(prev).toBe('foo')
|
||||||
prev = recordMetadata(node, MetadataKind.prop, 'style', 'color: red')
|
prev = recordPropMetadata(node, 'style', 'color: red')
|
||||||
expect(prev).toBeUndefined()
|
expect(prev).toBeUndefined()
|
||||||
prev = recordMetadata(node, MetadataKind.prop, 'style', 'color: blue')
|
prev = recordPropMetadata(node, 'style', 'color: blue')
|
||||||
expect(prev).toBe('color: red')
|
expect(prev).toBe('color: red')
|
||||||
|
|
||||||
expect(getMetadata(node)).toEqual([
|
expect(getMetadata(node)).toEqual([
|
||||||
|
@ -51,8 +51,8 @@ describe('patchProp', () => {
|
||||||
test('should have different metadata for different nodes', () => {
|
test('should have different metadata for different nodes', () => {
|
||||||
const node1 = {} as Node
|
const node1 = {} as Node
|
||||||
const node2 = {} as Node
|
const node2 = {} as Node
|
||||||
recordMetadata(node1, MetadataKind.prop, 'class', 'foo')
|
recordPropMetadata(node1, 'class', 'foo')
|
||||||
recordMetadata(node2, MetadataKind.prop, 'class', 'bar')
|
recordPropMetadata(node2, 'class', 'bar')
|
||||||
expect(getMetadata(node1)).toEqual([{ class: 'foo' }, {}])
|
expect(getMetadata(node1)).toEqual([{ class: 'foo' }, {}])
|
||||||
expect(getMetadata(node2)).toEqual([{ class: 'bar' }, {}])
|
expect(getMetadata(node2)).toEqual([{ class: 'bar' }, {}])
|
||||||
})
|
})
|
|
@ -4,7 +4,7 @@ import {
|
||||||
onEffectCleanup,
|
onEffectCleanup,
|
||||||
onScopeDispose,
|
onScopeDispose,
|
||||||
} from '@vue/reactivity'
|
} from '@vue/reactivity'
|
||||||
import { MetadataKind, getMetadata, recordMetadata } from '../metadata'
|
import { MetadataKind, getMetadata, recordEventMetadata } from '../metadata'
|
||||||
import { withKeys, withModifiers } from '@vue/runtime-dom'
|
import { withKeys, withModifiers } from '@vue/runtime-dom'
|
||||||
|
|
||||||
export function addEventListener(
|
export function addEventListener(
|
||||||
|
@ -29,12 +29,16 @@ export function on(
|
||||||
options: AddEventListenerOptions & ModifierOptions = {},
|
options: AddEventListenerOptions & ModifierOptions = {},
|
||||||
) {
|
) {
|
||||||
const handler: DelegatedHandler = eventHandler(handlerGetter, options)
|
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 scope = getCurrentScope()
|
||||||
const effect = getCurrentEffect()
|
const effect = getCurrentEffect()
|
||||||
|
|
||||||
if (effect && effect.scope === scope) {
|
if (effect && effect.scope === scope) {
|
||||||
onEffectCleanup(cleanup)
|
onEffectCleanup(cleanup)
|
||||||
} else if (scope) {
|
} else if (scope) {
|
||||||
|
@ -55,7 +59,7 @@ export function delegate(
|
||||||
) {
|
) {
|
||||||
const handler: DelegatedHandler = eventHandler(handlerGetter, options)
|
const handler: DelegatedHandler = eventHandler(handlerGetter, options)
|
||||||
handler.delegate = true
|
handler.delegate = true
|
||||||
recordMetadata(el, MetadataKind.event, event, handler)
|
recordEventMetadata(el, event, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
function eventHandler(
|
function eventHandler(
|
||||||
|
@ -103,10 +107,14 @@ const delegatedEventHandler = (e: Event) => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
while (node !== null) {
|
while (node !== null) {
|
||||||
const handler = getMetadata(node)[MetadataKind.event][e.type]
|
const handlers = getMetadata(node)[MetadataKind.event][e.type]
|
||||||
if (handler && handler.delegate && !node.disabled) {
|
if (handlers) {
|
||||||
handler(e)
|
for (const handler of handlers) {
|
||||||
if (e.cancelBubble) return
|
if (handler.delegate && !node.disabled) {
|
||||||
|
handler(e)
|
||||||
|
if (e.cancelBubble) return
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
node =
|
node =
|
||||||
node.host && node.host !== node && node.host instanceof Node
|
node.host && node.host !== node && node.host instanceof Node
|
||||||
|
|
|
@ -11,22 +11,17 @@ import {
|
||||||
} from '@vue/shared'
|
} from '@vue/shared'
|
||||||
import { warn } from '../warning'
|
import { warn } from '../warning'
|
||||||
import { setStyle } from './style'
|
import { setStyle } from './style'
|
||||||
import { MetadataKind, getMetadata, recordMetadata } from '../metadata'
|
import { MetadataKind, getMetadata, recordPropMetadata } from '../metadata'
|
||||||
|
|
||||||
export function setClass(el: Element, value: any) {
|
export function setClass(el: Element, value: any) {
|
||||||
const prev = recordMetadata(
|
const prev = recordPropMetadata(el, 'class', (value = normalizeClass(value)))
|
||||||
el,
|
|
||||||
MetadataKind.prop,
|
|
||||||
'class',
|
|
||||||
(value = normalizeClass(value)),
|
|
||||||
)
|
|
||||||
if (value !== prev && (value || prev)) {
|
if (value !== prev && (value || prev)) {
|
||||||
el.className = value
|
el.className = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setAttr(el: Element, key: string, value: any) {
|
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 !== oldVal) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
el.setAttribute(key, value)
|
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) {
|
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 (value === oldVal) return
|
||||||
|
|
||||||
if (key === 'innerHTML' || key === 'textContent') {
|
if (key === 'innerHTML' || key === 'textContent') {
|
||||||
|
@ -184,14 +179,14 @@ function mergeProps(...args: Data[]) {
|
||||||
|
|
||||||
export function setText(el: Node, ...values: any[]) {
|
export function setText(el: Node, ...values: any[]) {
|
||||||
const text = values.map(v => toDisplayString(v)).join('')
|
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) {
|
if (text !== oldVal) {
|
||||||
el.textContent = text
|
el.textContent = text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setHtml(el: Element, value: any) {
|
export function setHtml(el: Element, value: any) {
|
||||||
const oldVal = recordMetadata(el, MetadataKind.prop, 'innerHTML', value)
|
const oldVal = recordPropMetadata(el, 'innerHTML', value)
|
||||||
if (value !== oldVal) {
|
if (value !== oldVal) {
|
||||||
el.innerHTML = value
|
el.innerHTML = value
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,15 +7,10 @@ import {
|
||||||
normalizeStyle,
|
normalizeStyle,
|
||||||
} from '@vue/shared'
|
} from '@vue/shared'
|
||||||
import { warn } from '../warning'
|
import { warn } from '../warning'
|
||||||
import { MetadataKind, recordMetadata } from '../metadata'
|
import { recordPropMetadata } from '../metadata'
|
||||||
|
|
||||||
export function setStyle(el: HTMLElement, value: any) {
|
export function setStyle(el: HTMLElement, value: any) {
|
||||||
const prev = recordMetadata(
|
const prev = recordPropMetadata(el, 'style', (value = normalizeStyle(value)))
|
||||||
el,
|
|
||||||
MetadataKind.prop,
|
|
||||||
'style',
|
|
||||||
(value = normalizeStyle(value)),
|
|
||||||
)
|
|
||||||
patchStyle(el, prev, value)
|
patchStyle(el, prev, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { Data } from '@vue/shared'
|
import { type Data, remove } from '@vue/shared'
|
||||||
import type { DelegatedHandler } from './dom/event'
|
import type { DelegatedHandler } from './dom/event'
|
||||||
|
|
||||||
export enum MetadataKind {
|
export enum MetadataKind {
|
||||||
|
@ -8,7 +8,7 @@ export enum MetadataKind {
|
||||||
|
|
||||||
export type ElementMetadata = [
|
export type ElementMetadata = [
|
||||||
props: Data,
|
props: Data,
|
||||||
events: Record<string, DelegatedHandler>,
|
events: Record<string, DelegatedHandler[]>,
|
||||||
]
|
]
|
||||||
|
|
||||||
export function getMetadata(
|
export function getMetadata(
|
||||||
|
@ -17,14 +17,16 @@ export function getMetadata(
|
||||||
return el.$$metadata || (el.$$metadata = [{}, {}])
|
return el.$$metadata || (el.$$metadata = [{}, {}])
|
||||||
}
|
}
|
||||||
|
|
||||||
export function recordMetadata(
|
export function recordPropMetadata(el: Node, key: string, value: any): any {
|
||||||
el: Node,
|
const metadata = getMetadata(el)[MetadataKind.prop]
|
||||||
kind: MetadataKind,
|
|
||||||
key: string,
|
|
||||||
value: any,
|
|
||||||
): any {
|
|
||||||
const metadata = getMetadata(el)[kind]
|
|
||||||
const prev = metadata[key]
|
const prev = metadata[key]
|
||||||
metadata[key] = value
|
metadata[key] = value
|
||||||
return prev
|
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)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue