fix(runtime-vapor): `v-if` with inherit attrs

This commit is contained in:
三咲智子 Kevin Deng 2024-11-15 00:42:54 +08:00
parent 7a98f4b565
commit faa3e2c0d2
No known key found for this signature in database
4 changed files with 47 additions and 15 deletions

View File

@ -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("<div></div>")
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

View File

@ -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,

View File

@ -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,

View File

@ -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<string, string> | 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)
}
})
}