From faa3e2c0d2deb467dbc00cb82ddf63b64d3c37d7 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, 15 Nov 2024 00:42:54 +0800 Subject: [PATCH] fix(runtime-vapor): `v-if` with inherit attrs --- .../__snapshots__/vFor.spec.ts.snap | 7 ++-- .../transforms/transformTemplateRef.spec.ts | 2 ++ .../src/transforms/transformElement.ts | 17 ++++++--- packages/runtime-vapor/src/componentAttrs.ts | 36 ++++++++++++++----- 4 files changed, 47 insertions(+), 15 deletions(-) diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap index 6780439ec..55354aec5 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap @@ -45,14 +45,15 @@ export function render(_ctx) { `; exports[`compiler: v-for > multi effect 1`] = ` -"import { renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, createFor as _createFor, template as _template } from 'vue/vapor'; +"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, createFor as _createFor, template as _template } from 'vue/vapor'; const t0 = _template("
") export function render(_ctx) { const n0 = _createFor(() => (_ctx.items), (_ctx0) => { const n2 = t0() - _renderEffect(() => _setDynamicProp(n2, "item", _ctx0[0].value)) - _renderEffect(() => _setDynamicProp(n2, "index", _ctx0[1].value)) + _setInheritAttrs(["item", "index"]) + _renderEffect(() => _setDynamicProp(n2, "item", _ctx0[0].value, true)) + _renderEffect(() => _setDynamicProp(n2, "index", _ctx0[1].value, true)) return n2 }) return n0 diff --git a/packages/compiler-vapor/__tests__/transforms/transformTemplateRef.spec.ts b/packages/compiler-vapor/__tests__/transforms/transformTemplateRef.spec.ts index b9adeb51e..f95ca7338 100644 --- a/packages/compiler-vapor/__tests__/transforms/transformTemplateRef.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/transformTemplateRef.spec.ts @@ -92,6 +92,7 @@ describe('compiler: template ref transform', () => { const { positive } = ir.block.operation[0] as IfIRNode expect(positive.operation).toMatchObject([ + { type: IRNodeTypes.SET_INHERIT_ATTRS }, { type: IRNodeTypes.SET_TEMPLATE_REF, element: 2, @@ -113,6 +114,7 @@ describe('compiler: template ref transform', () => { const { render } = ir.block.operation[0] as ForIRNode expect(render.operation).toMatchObject([ + { type: IRNodeTypes.SET_INHERIT_ATTRS }, { type: IRNodeTypes.SET_TEMPLATE_REF, element: 2, diff --git a/packages/compiler-vapor/src/transforms/transformElement.ts b/packages/compiler-vapor/src/transforms/transformElement.ts index c894c724b..3356a1d77 100644 --- a/packages/compiler-vapor/src/transforms/transformElement.ts +++ b/packages/compiler-vapor/src/transforms/transformElement.ts @@ -64,11 +64,20 @@ export const transformElement: NodeTransform = (node, context) => { isDynamicComponent, ) + let { parent } = context + while ( + parent && + parent.parent && + parent.node.type === NodeTypes.ELEMENT && + parent.node.tagType === ElementTypes.TEMPLATE + ) { + parent = parent.parent + } const singleRoot = - context.root === context.parent && - context.parent.node.children.filter( - child => child.type !== NodeTypes.COMMENT, - ).length === 1 + context.root === parent && + parent.node.children.filter(child => child.type !== NodeTypes.COMMENT) + .length === 1 + ;(isComponent ? transformComponentElement : transformNativeElement)( node as any, propsResult, diff --git a/packages/runtime-vapor/src/componentAttrs.ts b/packages/runtime-vapor/src/componentAttrs.ts index 7f646546f..7807063fb 100644 --- a/packages/runtime-vapor/src/componentAttrs.ts +++ b/packages/runtime-vapor/src/componentAttrs.ts @@ -1,9 +1,14 @@ import { camelize, isArray, normalizeClass, normalizeStyle } from '@vue/shared' -import { type ComponentInternalInstance, currentInstance } from './component' +import { + type ComponentInternalInstance, + componentKey, + currentInstance, +} from './component' import { isEmitListener } from './componentEmits' import { type RawProps, walkRawProps } from './componentProps' import { renderEffect } from './renderEffect' import { mergeProp, setDynamicProp } from './dom/prop' +import type { Block } from './apiRender' export function patchAttrs( instance: ComponentInternalInstance, @@ -92,6 +97,18 @@ export function withAttrs(props: RawProps): RawProps { return [attrsGetter, props] } +function getFirstNode(block: Block | undefined): Node | undefined { + if (!block || componentKey in block) return + if (block instanceof Node) return block + if (isArray(block)) { + if (block.length === 1) { + return getFirstNode(block[0]) + } + } else { + return getFirstNode(block.nodes) + } +} + export function fallThroughAttrs(instance: ComponentInternalInstance): void { const { block, @@ -100,20 +117,23 @@ export function fallThroughAttrs(instance: ComponentInternalInstance): void { } = instance if ( inheritAttrs === false || - !(block instanceof Element) || - // all props as dynamic - dynamicAttrs === true + dynamicAttrs === true || // all props as dynamic + !block || + componentKey in block ) return + const element = getFirstNode(block) + if (!element || !(element instanceof Element)) return + const hasStaticAttrs = dynamicAttrs || dynamicAttrs === false let initial: Record | undefined if (hasStaticAttrs) { // attrs in static template initial = {} - for (let i = 0; i < block.attributes.length; i++) { - const attr = block.attributes[i] + for (let i = 0; i < element.attributes.length; i++) { + const attr = element.attributes[i] if (dynamicAttrs && dynamicAttrs.includes(attr.name)) continue initial[attr.name] = attr.value } @@ -124,13 +144,13 @@ export function fallThroughAttrs(instance: ComponentInternalInstance): void { if (dynamicAttrs && dynamicAttrs.includes(key)) continue let value: unknown - if (hasStaticAttrs) { + if (hasStaticAttrs && key in initial!) { value = mergeProp(key, instance.attrs[key], initial![key]) } else { value = instance.attrs[key] } - setDynamicProp(block, key, value) + setDynamicProp(element, key, value) } }) }