Skip to content
This repository was archived by the owner on Jul 19, 2025. It is now read-only.

Commit faa3e2c

Browse files
committed
fix(runtime-vapor): v-if with inherit attrs
1 parent 7a98f4b commit faa3e2c

File tree

4 files changed

+47
-15
lines changed

4 files changed

+47
-15
lines changed

packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,15 @@ export function render(_ctx) {
4545
`;
4646

4747
exports[`compiler: v-for > multi effect 1`] = `
48-
"import { renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, createFor as _createFor, template as _template } from 'vue/vapor';
48+
"import { setInheritAttrs as _setInheritAttrs, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, createFor as _createFor, template as _template } from 'vue/vapor';
4949
const t0 = _template("<div></div>")
5050
5151
export function render(_ctx) {
5252
const n0 = _createFor(() => (_ctx.items), (_ctx0) => {
5353
const n2 = t0()
54-
_renderEffect(() => _setDynamicProp(n2, "item", _ctx0[0].value))
55-
_renderEffect(() => _setDynamicProp(n2, "index", _ctx0[1].value))
54+
_setInheritAttrs(["item", "index"])
55+
_renderEffect(() => _setDynamicProp(n2, "item", _ctx0[0].value, true))
56+
_renderEffect(() => _setDynamicProp(n2, "index", _ctx0[1].value, true))
5657
return n2
5758
})
5859
return n0

packages/compiler-vapor/__tests__/transforms/transformTemplateRef.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ describe('compiler: template ref transform', () => {
9292

9393
const { positive } = ir.block.operation[0] as IfIRNode
9494
expect(positive.operation).toMatchObject([
95+
{ type: IRNodeTypes.SET_INHERIT_ATTRS },
9596
{
9697
type: IRNodeTypes.SET_TEMPLATE_REF,
9798
element: 2,
@@ -113,6 +114,7 @@ describe('compiler: template ref transform', () => {
113114

114115
const { render } = ir.block.operation[0] as ForIRNode
115116
expect(render.operation).toMatchObject([
117+
{ type: IRNodeTypes.SET_INHERIT_ATTRS },
116118
{
117119
type: IRNodeTypes.SET_TEMPLATE_REF,
118120
element: 2,

packages/compiler-vapor/src/transforms/transformElement.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,20 @@ export const transformElement: NodeTransform = (node, context) => {
6464
isDynamicComponent,
6565
)
6666

67+
let { parent } = context
68+
while (
69+
parent &&
70+
parent.parent &&
71+
parent.node.type === NodeTypes.ELEMENT &&
72+
parent.node.tagType === ElementTypes.TEMPLATE
73+
) {
74+
parent = parent.parent
75+
}
6776
const singleRoot =
68-
context.root === context.parent &&
69-
context.parent.node.children.filter(
70-
child => child.type !== NodeTypes.COMMENT,
71-
).length === 1
77+
context.root === parent &&
78+
parent.node.children.filter(child => child.type !== NodeTypes.COMMENT)
79+
.length === 1
80+
7281
;(isComponent ? transformComponentElement : transformNativeElement)(
7382
node as any,
7483
propsResult,

packages/runtime-vapor/src/componentAttrs.ts

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import { camelize, isArray, normalizeClass, normalizeStyle } from '@vue/shared'
2-
import { type ComponentInternalInstance, currentInstance } from './component'
2+
import {
3+
type ComponentInternalInstance,
4+
componentKey,
5+
currentInstance,
6+
} from './component'
37
import { isEmitListener } from './componentEmits'
48
import { type RawProps, walkRawProps } from './componentProps'
59
import { renderEffect } from './renderEffect'
610
import { mergeProp, setDynamicProp } from './dom/prop'
11+
import type { Block } from './apiRender'
712

813
export function patchAttrs(
914
instance: ComponentInternalInstance,
@@ -92,6 +97,18 @@ export function withAttrs(props: RawProps): RawProps {
9297
return [attrsGetter, props]
9398
}
9499

100+
function getFirstNode(block: Block | undefined): Node | undefined {
101+
if (!block || componentKey in block) return
102+
if (block instanceof Node) return block
103+
if (isArray(block)) {
104+
if (block.length === 1) {
105+
return getFirstNode(block[0])
106+
}
107+
} else {
108+
return getFirstNode(block.nodes)
109+
}
110+
}
111+
95112
export function fallThroughAttrs(instance: ComponentInternalInstance): void {
96113
const {
97114
block,
@@ -100,20 +117,23 @@ export function fallThroughAttrs(instance: ComponentInternalInstance): void {
100117
} = instance
101118
if (
102119
inheritAttrs === false ||
103-
!(block instanceof Element) ||
104-
// all props as dynamic
105-
dynamicAttrs === true
120+
dynamicAttrs === true || // all props as dynamic
121+
!block ||
122+
componentKey in block
106123
)
107124
return
108125

126+
const element = getFirstNode(block)
127+
if (!element || !(element instanceof Element)) return
128+
109129
const hasStaticAttrs = dynamicAttrs || dynamicAttrs === false
110130

111131
let initial: Record<string, string> | undefined
112132
if (hasStaticAttrs) {
113133
// attrs in static template
114134
initial = {}
115-
for (let i = 0; i < block.attributes.length; i++) {
116-
const attr = block.attributes[i]
135+
for (let i = 0; i < element.attributes.length; i++) {
136+
const attr = element.attributes[i]
117137
if (dynamicAttrs && dynamicAttrs.includes(attr.name)) continue
118138
initial[attr.name] = attr.value
119139
}
@@ -124,13 +144,13 @@ export function fallThroughAttrs(instance: ComponentInternalInstance): void {
124144
if (dynamicAttrs && dynamicAttrs.includes(key)) continue
125145

126146
let value: unknown
127-
if (hasStaticAttrs) {
147+
if (hasStaticAttrs && key in initial!) {
128148
value = mergeProp(key, instance.attrs[key], initial![key])
129149
} else {
130150
value = instance.attrs[key]
131151
}
132152

133-
setDynamicProp(block, key, value)
153+
setDynamicProp(element, key, value)
134154
}
135155
})
136156
}

0 commit comments

Comments
 (0)