]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor(runtime-core): useModel work with vapor mode (#12666)
authoredison <daiwei521@126.com>
Wed, 29 Jan 2025 04:12:44 +0000 (12:12 +0800)
committerGitHub <noreply@github.com>
Wed, 29 Jan 2025 04:12:44 +0000 (12:12 +0800)
packages/runtime-core/src/component.ts
packages/runtime-core/src/helpers/useModel.ts
packages/runtime-vapor/src/component.ts

index f91af6c73996315955ff34e2b5b9d1736549628c..493d08b5a0529f015cbe78afec9006917cc7fcc7 100644 (file)
@@ -366,6 +366,7 @@ export interface GenericComponentInstance {
    * @internal
    */
   refs: Data
+  emit: EmitFn
   /**
    * used for keeping track of .once event handlers on components
    * @internal
@@ -377,6 +378,11 @@ export interface GenericComponentInstance {
    * @internal
    */
   propsDefaults: Data | null
+  /**
+   * used for getting the keys of a component's raw props, vapor only
+   * @internal
+   */
+  rawKeys?: () => string[]
 
   // exposed properties via expose()
   exposed: Record<string, any> | null
index befe7627747565dba124590402f63ca248db8fdf..e85edc6e9a7b7c2bee08490aeba5b928a606fba8 100644 (file)
@@ -1,7 +1,10 @@
 import { type Ref, customRef, ref } from '@vue/reactivity'
 import { EMPTY_OBJ, camelize, hasChanged, hyphenate } from '@vue/shared'
 import type { DefineModelOptions, ModelRef } from '../apiSetupHelpers'
-import { getCurrentInstance } from '../component'
+import {
+  type ComponentInternalInstance,
+  getCurrentGenericInstance,
+} from '../component'
 import { warn } from '../warning'
 import type { NormalizedProps } from '../componentProps'
 import { watchSyncEffect } from '../apiWatch'
@@ -23,14 +26,14 @@ export function useModel(
   name: string,
   options: DefineModelOptions = EMPTY_OBJ,
 ): Ref {
-  const i = getCurrentInstance()!
+  const i = getCurrentGenericInstance()!
   if (__DEV__ && !i) {
     warn(`useModel() called without active instance.`)
     return ref() as any
   }
 
   const camelizedName = camelize(name)
-  if (__DEV__ && !(i.propsOptions[0] as NormalizedProps)[camelizedName]) {
+  if (__DEV__ && !(i.propsOptions![0] as NormalizedProps)[camelizedName]) {
     warn(`useModel() called with prop "${name}" which is not declared.`)
     return ref() as any
   }
@@ -65,19 +68,38 @@ export function useModel(
         ) {
           return
         }
-        const rawProps = i.vnode!.props
-        if (
-          !(
-            rawProps &&
-            // check if parent has passed v-model
-            (name in rawProps ||
-              camelizedName in rawProps ||
-              hyphenatedName in rawProps) &&
-            (`onUpdate:${name}` in rawProps ||
-              `onUpdate:${camelizedName}` in rawProps ||
-              `onUpdate:${hyphenatedName}` in rawProps)
-          )
-        ) {
+
+        let rawPropKeys
+        let parentPassedModelValue = false
+        let parentPassedModelUpdater = false
+
+        if (i.rawKeys) {
+          // vapor instance
+          rawPropKeys = i.rawKeys()
+        } else {
+          const rawProps = (i as ComponentInternalInstance).vnode!.props
+          rawPropKeys = rawProps && Object.keys(rawProps)
+        }
+
+        if (rawPropKeys) {
+          for (const key of rawPropKeys) {
+            if (
+              key === name ||
+              key === camelizedName ||
+              key === hyphenatedName
+            ) {
+              parentPassedModelValue = true
+            } else if (
+              key === `onUpdate:${name}` ||
+              key === `onUpdate:${camelizedName}` ||
+              key === `onUpdate:${hyphenatedName}`
+            ) {
+              parentPassedModelUpdater = true
+            }
+          }
+        }
+
+        if (!parentPassedModelValue || !parentPassedModelUpdater) {
           // no v-model, local update
           localValue = value
           trigger()
index 61476a098c91548e177ef898d6f0c7f04630a1f8..abe72e79cfe78b48eb1a0b616245531f30387a8d 100644 (file)
@@ -50,6 +50,7 @@ import {
 import {
   type DynamicPropsSource,
   type RawProps,
+  getKeysFromRawProps,
   getPropsProxyHandlers,
   hasFallthroughAttrs,
   normalizePropsOptions,
@@ -410,6 +411,14 @@ export class VaporComponentInstance implements GenericComponentInstance {
       this.emitsOptions = normalizeEmitsOptions(comp)
     }
   }
+
+  /**
+   * Expose `getKeysFromRawProps` on the instance so it can be used in code
+   * paths where it's needed, e.g. `useModel`
+   */
+  rawKeys(): string[] {
+    return getKeysFromRawProps(this.rawProps)
+  }
 }
 
 export function isVaporComponent(