From: daiwei Date: Thu, 9 Oct 2025 03:44:25 +0000 (+0800) Subject: wip: force hydrate v-bind with .prop modifiers X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5e29c98e5003de36dc645823873ee148c8f13691;p=thirdparty%2Fvuejs%2Fcore.git wip: force hydrate v-bind with .prop modifiers --- diff --git a/packages/runtime-vapor/__tests__/hydration.spec.ts b/packages/runtime-vapor/__tests__/hydration.spec.ts index 3068a3fc75..eeda18af30 100644 --- a/packages/runtime-vapor/__tests__/hydration.spec.ts +++ b/packages/runtime-vapor/__tests__/hydration.spec.ts @@ -2983,7 +2983,7 @@ describe('Vapor Mode hydration', () => { expect((container.firstChild as any)._trueValue).toBe(true) }) - test.todo('force hydrate checkbox with indeterminate', async () => { + test('force hydrate checkbox with indeterminate', async () => { const { container } = await mountWithHydration( '', ``, @@ -2991,11 +2991,24 @@ describe('Vapor Mode hydration', () => { expect((container.firstChild! as any).indeterminate).toBe(true) }) - test.todo( - 'force hydrate select option with non-string value bindings', - () => {}, - ) + test('force hydrate select option with non-string value bindings', async () => { + const { container } = await mountWithHydration( + '', + ``, + ) + expect((container.firstChild!.firstChild as any)._value).toBe(true) + }) + + test('force hydrate v-bind with .prop modifiers', async () => { + const { container } = await mountWithHydration( + '
', + `
`, + ref({ '.foo': true }), + ) + expect((container.firstChild! as any).foo).toBe(true) + }) + // vapor custom element not implemented yet test.todo('force hydrate custom element with dynamic props', () => {}) }) diff --git a/packages/runtime-vapor/src/dom/prop.ts b/packages/runtime-vapor/src/dom/prop.ts index eb48cdef96..899d7f0caa 100644 --- a/packages/runtime-vapor/src/dom/prop.ts +++ b/packages/runtime-vapor/src/dom/prop.ts @@ -89,7 +89,12 @@ export function setAttr(el: any, key: string, value: any): void { } } -export function setDOMProp(el: any, key: string, value: any): void { +export function setDOMProp( + el: any, + key: string, + value: any, + forceHydrate: boolean = false, +): void { if (!isApplyingFallthroughProps && el.$root && hasFallthroughKey(key)) { return } @@ -98,7 +103,8 @@ export function setDOMProp(el: any, key: string, value: any): void { (__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) && isHydrating && !attributeHasMismatch(el, key, value) && - !shouldForcePatch(el, key) + !shouldForceHydrate(el, key) && + !forceHydrate ) { return } @@ -225,7 +231,11 @@ function setStyleIncremental(el: any, value: any): NormalizedStyle | undefined { patchStyle(el, el[cacheKey], (el[cacheKey] = normalizedValue)) } -export function setValue(el: TargetElement, value: any): void { +export function setValue( + el: TargetElement, + value: any, + forceHydrate: boolean = false, +): void { if (!isApplyingFallthroughProps && el.$root && hasFallthroughKey('value')) { return } @@ -237,7 +247,9 @@ export function setValue(el: TargetElement, value: any): void { if ( (__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) && isHydrating && - !attributeHasMismatch(el, 'value', getClientText(el, value)) + !attributeHasMismatch(el, 'value', getClientText(el, value)) && + !shouldForceHydrate(el, 'value') && + !forceHydrate ) { return } @@ -350,6 +362,7 @@ export function setDynamicProp( ): void { // TODO const isSVG = false + let forceHydrate = false if (key === 'class') { setClass(el, value) } else if (key === 'style') { @@ -357,7 +370,8 @@ export function setDynamicProp( } else if (isOn(key)) { on(el, key[2].toLowerCase() + key.slice(3), value, { effect: true }) } else if ( - key[0] === '.' + // force hydrate v-bind with .prop modifiers + (forceHydrate = key[0] === '.') ? ((key = key.slice(1)), true) : key[0] === '^' ? ((key = key.slice(1)), false) @@ -368,12 +382,11 @@ export function setDynamicProp( } else if (key === 'textContent') { setElementText(el, value) } else if (key === 'value' && canSetValueDirectly(el.tagName)) { - setValue(el, value) + setValue(el, value, forceHydrate) } else { - setDOMProp(el, key, value) + setDOMProp(el, key, value, forceHydrate) } } else { - // TODO special case for setAttr(el, key, value) } return value @@ -491,8 +504,12 @@ function getClientText(el: Node, value: string): string { return value } -function shouldForcePatch(el: Element, key: string): boolean { +function shouldForceHydrate(el: Element, key: string): boolean { const { tagName } = el - const forcePatch = tagName === 'INPUT' || tagName === 'OPTION' - return forcePatch && (key.endsWith('value') || key === 'indeterminate') + return ( + ((tagName === 'INPUT' || tagName === 'OPTION') && + (key.endsWith('value') || key === 'indeterminate')) || + // force hydrate custom element dynamic props + tagName.includes('-') + ) }