]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(runtime-vapor): `v-if` with inherit attrs
author三咲智子 Kevin Deng <sxzz@sxzz.moe>
Thu, 14 Nov 2024 16:42:54 +0000 (00:42 +0800)
committer三咲智子 Kevin Deng <sxzz@sxzz.moe>
Thu, 14 Nov 2024 16:42:54 +0000 (00:42 +0800)
packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/transformTemplateRef.spec.ts
packages/compiler-vapor/src/transforms/transformElement.ts
packages/runtime-vapor/src/componentAttrs.ts

index 6780439eca0f35473d0aab85cbc0d7c5a954935b..55354aec574e4eda8940bd7869fcaf02a3d07253 100644 (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
index b9adeb51e41c4130086a9dbdd8e9e954679ad847..f95ca7338cb69af6957c256db2c255f8f14b4560 100644 (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,
index c894c724b6c2f37485720f4d93c8fcfe35bd4d20..3356a1d772ae06a961da1557a50edbf4faeec5d0 100644 (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,
index 7f646546fee5b123a54b6e041d62a80f4ec3672c..7807063fbaace1e839c0cf7901cfba6e5e719d2a 100644 (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)
     }
   })
 }