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`] = ` 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>") const t0 = _template("<div></div>")
export function render(_ctx) { export function render(_ctx) {
const n0 = _createFor(() => (_ctx.items), (_ctx0) => { const n0 = _createFor(() => (_ctx.items), (_ctx0) => {
const n2 = t0() const n2 = t0()
_renderEffect(() => _setDynamicProp(n2, "item", _ctx0[0].value)) _setInheritAttrs(["item", "index"])
_renderEffect(() => _setDynamicProp(n2, "index", _ctx0[1].value)) _renderEffect(() => _setDynamicProp(n2, "item", _ctx0[0].value, true))
_renderEffect(() => _setDynamicProp(n2, "index", _ctx0[1].value, true))
return n2 return n2
}) })
return n0 return n0

View File

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

View File

@ -64,11 +64,20 @@ export const transformElement: NodeTransform = (node, context) => {
isDynamicComponent, isDynamicComponent,
) )
let { parent } = context
while (
parent &&
parent.parent &&
parent.node.type === NodeTypes.ELEMENT &&
parent.node.tagType === ElementTypes.TEMPLATE
) {
parent = parent.parent
}
const singleRoot = const singleRoot =
context.root === context.parent && context.root === parent &&
context.parent.node.children.filter( parent.node.children.filter(child => child.type !== NodeTypes.COMMENT)
child => child.type !== NodeTypes.COMMENT, .length === 1
).length === 1
;(isComponent ? transformComponentElement : transformNativeElement)( ;(isComponent ? transformComponentElement : transformNativeElement)(
node as any, node as any,
propsResult, propsResult,

View File

@ -1,9 +1,14 @@
import { camelize, isArray, normalizeClass, normalizeStyle } from '@vue/shared' 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 { isEmitListener } from './componentEmits'
import { type RawProps, walkRawProps } from './componentProps' import { type RawProps, walkRawProps } from './componentProps'
import { renderEffect } from './renderEffect' import { renderEffect } from './renderEffect'
import { mergeProp, setDynamicProp } from './dom/prop' import { mergeProp, setDynamicProp } from './dom/prop'
import type { Block } from './apiRender'
export function patchAttrs( export function patchAttrs(
instance: ComponentInternalInstance, instance: ComponentInternalInstance,
@ -92,6 +97,18 @@ export function withAttrs(props: RawProps): RawProps {
return [attrsGetter, props] 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 { export function fallThroughAttrs(instance: ComponentInternalInstance): void {
const { const {
block, block,
@ -100,20 +117,23 @@ export function fallThroughAttrs(instance: ComponentInternalInstance): void {
} = instance } = instance
if ( if (
inheritAttrs === false || inheritAttrs === false ||
!(block instanceof Element) || dynamicAttrs === true || // all props as dynamic
// all props as dynamic !block ||
dynamicAttrs === true componentKey in block
) )
return return
const element = getFirstNode(block)
if (!element || !(element instanceof Element)) return
const hasStaticAttrs = dynamicAttrs || dynamicAttrs === false const hasStaticAttrs = dynamicAttrs || dynamicAttrs === false
let initial: Record<string, string> | undefined let initial: Record<string, string> | undefined
if (hasStaticAttrs) { if (hasStaticAttrs) {
// attrs in static template // attrs in static template
initial = {} initial = {}
for (let i = 0; i < block.attributes.length; i++) { for (let i = 0; i < element.attributes.length; i++) {
const attr = block.attributes[i] const attr = element.attributes[i]
if (dynamicAttrs && dynamicAttrs.includes(attr.name)) continue if (dynamicAttrs && dynamicAttrs.includes(attr.name)) continue
initial[attr.name] = attr.value initial[attr.name] = attr.value
} }
@ -124,13 +144,13 @@ export function fallThroughAttrs(instance: ComponentInternalInstance): void {
if (dynamicAttrs && dynamicAttrs.includes(key)) continue if (dynamicAttrs && dynamicAttrs.includes(key)) continue
let value: unknown let value: unknown
if (hasStaticAttrs) { if (hasStaticAttrs && key in initial!) {
value = mergeProp(key, instance.attrs[key], initial![key]) value = mergeProp(key, instance.attrs[key], initial![key])
} else { } else {
value = instance.attrs[key] value = instance.attrs[key]
} }
setDynamicProp(block, key, value) setDynamicProp(element, key, value)
} }
}) })
} }