mirror of https://github.com/vuejs/core.git
refactor(runtime-vapor): split props & event metadata
This commit is contained in:
parent
88123e56d0
commit
23653cc447
|
@ -13,7 +13,7 @@ import {
|
||||||
createComponentInstance,
|
createComponentInstance,
|
||||||
setCurrentInstance,
|
setCurrentInstance,
|
||||||
} from '../../src/component'
|
} from '../../src/component'
|
||||||
import { getMetadata, recordPropMetadata } from '../../src/metadata'
|
import { getMetadata, recordMetadata } from '../../src/metadata'
|
||||||
|
|
||||||
let removeComponentInstance = NOOP
|
let removeComponentInstance = NOOP
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -30,33 +30,36 @@ afterEach(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('patchProp', () => {
|
describe('patchProp', () => {
|
||||||
describe('recordPropMetadata', () => {
|
describe('recordMetadata', () => {
|
||||||
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 = recordPropMetadata(node, 'class', 'foo')
|
let prev = recordMetadata(node, 'props', 'class', 'foo')
|
||||||
expect(prev).toBeUndefined()
|
expect(prev).toBeUndefined()
|
||||||
prev = recordPropMetadata(node, 'class', 'bar')
|
prev = recordMetadata(node, 'props', 'class', 'bar')
|
||||||
expect(prev).toBe('foo')
|
expect(prev).toBe('foo')
|
||||||
prev = recordPropMetadata(node, 'style', 'color: red')
|
prev = recordMetadata(node, 'props', 'style', 'color: red')
|
||||||
expect(prev).toBeUndefined()
|
expect(prev).toBeUndefined()
|
||||||
prev = recordPropMetadata(node, 'style', 'color: blue')
|
prev = recordMetadata(node, 'props', 'style', 'color: blue')
|
||||||
expect(prev).toBe('color: red')
|
expect(prev).toBe('color: red')
|
||||||
|
|
||||||
expect(getMetadata(node)).toEqual({
|
expect(getMetadata(node)).toEqual({
|
||||||
props: { class: 'bar', style: 'color: blue' },
|
props: { class: 'bar', style: 'color: blue' },
|
||||||
|
events: {},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
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
|
||||||
recordPropMetadata(node1, 'class', 'foo')
|
recordMetadata(node1, 'props', 'class', 'foo')
|
||||||
recordPropMetadata(node2, 'class', 'bar')
|
recordMetadata(node2, 'props', 'class', 'bar')
|
||||||
expect(getMetadata(node1)).toEqual({
|
expect(getMetadata(node1)).toEqual({
|
||||||
props: { class: 'foo' },
|
props: { class: 'foo' },
|
||||||
|
events: {},
|
||||||
})
|
})
|
||||||
expect(getMetadata(node2)).toEqual({
|
expect(getMetadata(node2)).toEqual({
|
||||||
props: { class: 'bar' },
|
props: { class: 'bar' },
|
||||||
|
events: {},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -20,7 +20,7 @@ import { getMetadata } from '../metadata'
|
||||||
type AssignerFn = (value: any) => void
|
type AssignerFn = (value: any) => void
|
||||||
function getModelAssigner(el: Element): AssignerFn {
|
function getModelAssigner(el: Element): AssignerFn {
|
||||||
const metadata = getMetadata(el)
|
const metadata = getMetadata(el)
|
||||||
const fn: any = metadata.props['onUpdate:modelValue']
|
const fn: any = metadata.events['update:modelValue']
|
||||||
return isArray(fn) ? value => invokeArrayFns(fn, value) : fn
|
return isArray(fn) ? value => invokeArrayFns(fn, value) : fn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,7 @@ import {
|
||||||
onEffectCleanup,
|
onEffectCleanup,
|
||||||
onScopeDispose,
|
onScopeDispose,
|
||||||
} from '@vue/reactivity'
|
} from '@vue/reactivity'
|
||||||
import { recordPropMetadata } from '../metadata'
|
import { recordMetadata } from '../metadata'
|
||||||
import { toHandlerKey } from '@vue/shared'
|
|
||||||
import { withKeys, withModifiers } from '@vue/runtime-dom'
|
import { withKeys, withModifiers } from '@vue/runtime-dom'
|
||||||
|
|
||||||
export function addEventListener(
|
export function addEventListener(
|
||||||
|
@ -25,11 +24,7 @@ export function on(
|
||||||
options?: AddEventListenerOptions,
|
options?: AddEventListenerOptions,
|
||||||
{ modifiers, keys }: { modifiers?: string[]; keys?: string[] } = {},
|
{ modifiers, keys }: { modifiers?: string[]; keys?: string[] } = {},
|
||||||
) {
|
) {
|
||||||
recordPropMetadata(el, toHandlerKey(event), handlerGetter)
|
const handler = (...args: any[]) => {
|
||||||
const cleanup = addEventListener(
|
|
||||||
el,
|
|
||||||
event,
|
|
||||||
(...args: any[]) => {
|
|
||||||
let handler = handlerGetter()
|
let handler = handlerGetter()
|
||||||
if (!handler) return
|
if (!handler) return
|
||||||
|
|
||||||
|
@ -40,9 +35,9 @@ export function on(
|
||||||
handler = withKeys(handler, keys)
|
handler = withKeys(handler, keys)
|
||||||
}
|
}
|
||||||
handler && handler(...args)
|
handler && handler(...args)
|
||||||
},
|
}
|
||||||
options,
|
recordMetadata(el, 'events', event, handler)
|
||||||
)
|
const cleanup = addEventListener(el, event, handler, options)
|
||||||
|
|
||||||
const scope = getCurrentScope()
|
const scope = getCurrentScope()
|
||||||
const effect = getCurrentEffect()
|
const effect = getCurrentEffect()
|
||||||
|
|
|
@ -11,17 +11,22 @@ import {
|
||||||
} from '@vue/shared'
|
} from '@vue/shared'
|
||||||
import { warn } from '../warning'
|
import { warn } from '../warning'
|
||||||
import { setStyle } from './style'
|
import { setStyle } from './style'
|
||||||
import { getMetadata, recordPropMetadata } from '../metadata'
|
import { getMetadata, recordMetadata } from '../metadata'
|
||||||
|
|
||||||
export function setClass(el: Element, value: any) {
|
export function setClass(el: Element, value: any) {
|
||||||
const prev = recordPropMetadata(el, 'class', (value = normalizeClass(value)))
|
const prev = recordMetadata(
|
||||||
|
el,
|
||||||
|
'props',
|
||||||
|
'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 = recordPropMetadata(el, key, value)
|
const oldVal = recordMetadata(el, 'props', key, value)
|
||||||
if (value !== oldVal) {
|
if (value !== oldVal) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
el.setAttribute(key, value)
|
el.setAttribute(key, value)
|
||||||
|
@ -32,7 +37,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 = recordPropMetadata(el, key, value)
|
const oldVal = recordMetadata(el, 'props', key, value)
|
||||||
if (value === oldVal) return
|
if (value === oldVal) return
|
||||||
|
|
||||||
if (key === 'innerHTML' || key === 'textContent') {
|
if (key === 'innerHTML' || key === 'textContent') {
|
||||||
|
@ -179,14 +184,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 = recordPropMetadata(el, 'textContent', text)
|
const oldVal = recordMetadata(el, 'props', '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 = recordPropMetadata(el, 'innerHTML', value)
|
const oldVal = recordMetadata(el, 'props', 'innerHTML', value)
|
||||||
if (value !== oldVal) {
|
if (value !== oldVal) {
|
||||||
el.innerHTML = value
|
el.innerHTML = value
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,15 @@ import {
|
||||||
normalizeStyle,
|
normalizeStyle,
|
||||||
} from '@vue/shared'
|
} from '@vue/shared'
|
||||||
import { warn } from '../warning'
|
import { warn } from '../warning'
|
||||||
import { recordPropMetadata } from '../metadata'
|
import { recordMetadata } from '../metadata'
|
||||||
|
|
||||||
export function setStyle(el: HTMLElement, value: any) {
|
export function setStyle(el: HTMLElement, value: any) {
|
||||||
const prev = recordPropMetadata(el, 'style', (value = normalizeStyle(value)))
|
const prev = recordMetadata(
|
||||||
|
el,
|
||||||
|
'props',
|
||||||
|
'style',
|
||||||
|
(value = normalizeStyle(value)),
|
||||||
|
)
|
||||||
patchStyle(el, prev, value)
|
patchStyle(el, prev, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,29 @@ import type { Data } from '@vue/shared'
|
||||||
|
|
||||||
export interface ElementMetadata {
|
export interface ElementMetadata {
|
||||||
props: Data
|
props: Data
|
||||||
|
events: Data
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMetadata(
|
export function getMetadata(
|
||||||
el: Node & { $$metadata?: ElementMetadata },
|
el: Node & { $$metadata?: ElementMetadata },
|
||||||
): ElementMetadata {
|
): ElementMetadata {
|
||||||
return el.$$metadata || (el.$$metadata = { props: {} })
|
return (
|
||||||
|
el.$$metadata ||
|
||||||
|
(el.$$metadata = {
|
||||||
|
props: {},
|
||||||
|
events: {},
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function recordPropMetadata(el: Node, key: string, value: any): any {
|
export function recordMetadata(
|
||||||
const metadata = getMetadata(el)
|
el: Node,
|
||||||
const prev = metadata.props[key]
|
kind: 'props' | 'events',
|
||||||
metadata.props[key] = value
|
key: string,
|
||||||
|
value: any,
|
||||||
|
): any {
|
||||||
|
const metadata = getMetadata(el)[kind]
|
||||||
|
const prev = metadata[key]
|
||||||
|
metadata[key] = value
|
||||||
return prev
|
return prev
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue