]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(runtime-vapor): scope id for `v-if`
author三咲智子 Kevin Deng <sxzz@sxzz.moe>
Thu, 14 Nov 2024 17:21:30 +0000 (01:21 +0800)
committer三咲智子 Kevin Deng <sxzz@sxzz.moe>
Thu, 14 Nov 2024 17:21:30 +0000 (01:21 +0800)
packages/runtime-vapor/src/apiCreateComponent.ts
packages/runtime-vapor/src/apiRender.ts
packages/runtime-vapor/src/component.ts
packages/runtime-vapor/src/componentAttrs.ts

index 581a86079ac5e7926e46b14fd9c54089b8bb88ea..df67f173600fcd8fc7a5aadd67e9aad744a7132e 100644 (file)
@@ -38,6 +38,11 @@ export function createComponent(
     slots,
     once,
   )
+
+  instance.scopeIds = [...current.scopeIds]
+  const scopeId = current.type.__scopeId
+  if (scopeId) instance.scopeIds.push(scopeId)
+
   setupComponent(instance)
 
   // register sub-component with current component for lifecycle management
index 26a9b98cb742b79677530ff528cdf55adac5d87d..f173964ba8d63fa39c0afd04606fe8aba7f081ec 100644 (file)
@@ -91,8 +91,17 @@ export function setupComponent(instance: ComponentInternalInstance): void {
       block = []
     }
     instance.block = block
-    fallThroughAttrs(instance)
-    attachScopeId(instance)
+
+    const rootElement = findFirstRootElement(instance)
+    if (rootElement) {
+      fallThroughAttrs(instance, rootElement)
+
+      // attach scopeId
+      for (const id of instance.scopeIds) {
+        rootElement.setAttribute(id, '')
+      }
+    }
+
     return block
   })
   reset()
@@ -168,15 +177,19 @@ export function unmountComponent(instance: ComponentInternalInstance): void {
   flushPostFlushCbs()
 }
 
-export function attachScopeId(instance: ComponentInternalInstance): void {
-  const scopeId = instance.type.__scopeId
-  if (scopeId) {
-    let blk: Block | null = instance.block
-    while (blk && componentKey in blk) {
-      blk = blk.block
-      if (blk instanceof Element) {
-        blk.setAttribute(scopeId, '')
-      }
+function findFirstRootElement(instance: ComponentInternalInstance) {
+  const element = getFirstNode(instance.block)
+  return element instanceof Element ? element : undefined
+}
+
+function getFirstNode(block: Block | null): 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)
   }
 }
index fdfcd55f06c530d336632196f1c0ac9d2c088e16..9c36c84f538d7c3b12e20222ea434e29ce81cf4d 100644 (file)
@@ -162,6 +162,7 @@ export interface ComponentInternalInstance {
   provides: Data
   scope: EffectScope
   comps: Set<ComponentInternalInstance>
+  scopeIds: string[]
 
   rawProps: NormalizedRawProps
   propsOptions: NormalizedPropsOptions
@@ -293,6 +294,7 @@ export function createComponentInstance(
     provides: parent ? parent.provides : Object.create(_appContext.provides),
     type: component,
     comps: new Set(),
+    scopeIds: [],
 
     // resolved props and emits options
     rawProps: null!, // set later
index 7807063fbaace1e839c0cf7901cfba6e5e719d2a..635b45a7a490fab39932de8f15d9b78e26c295fb 100644 (file)
@@ -1,14 +1,9 @@
 import { camelize, isArray, normalizeClass, normalizeStyle } from '@vue/shared'
-import {
-  type ComponentInternalInstance,
-  componentKey,
-  currentInstance,
-} from './component'
+import { type ComponentInternalInstance, 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,
@@ -97,35 +92,20 @@ 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 {
+export function fallThroughAttrs(
+  instance: ComponentInternalInstance,
+  element: Element,
+): void {
   const {
-    block,
     type: { inheritAttrs },
     dynamicAttrs,
   } = instance
   if (
     inheritAttrs === false ||
-    dynamicAttrs === true || // all props as dynamic
-    !block ||
-    componentKey in block
+    dynamicAttrs === true // all props as dynamic
   )
     return
 
-  const element = getFirstNode(block)
-  if (!element || !(element instanceof Element)) return
-
   const hasStaticAttrs = dynamicAttrs || dynamicAttrs === false
 
   let initial: Record<string, string> | undefined