Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | 2x 2x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 15x 28x 28x 27x 27x 27x 15x 15x 15x 58x 58x 58x 15x 24x 24x 24x 3x 24x 1x 1x 23x 23x 23x 23x 22x 2x 2x 20x 2x 1x 24x 4x 4x 4x 23x 23x 23x 7x 5x 24x 1x 1x 23x 23x 24x 15x 15x 15x 2x 2x 2x 4x 4x 4x 4x 2x 2x 15x 15x 2x 54x 54x 54x 54x 13x 41x 30x 29x 54x | 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 { warn } from '../warning' import type { NormalizedProps } from '../componentProps' import { watchSyncEffect } from '../apiWatch' export function useModel< M extends PropertyKey, T extends Record<string, any>, K extends keyof T, G = T[K], S = T[K], >( props: T, name: K, options?: DefineModelOptions<T[K], G, S>, ): ModelRef<T[K], M, G, S> export function useModel( props: Record<string, any>, name: string, options: DefineModelOptions = EMPTY_OBJ, ): Ref { const i = getCurrentInstance()! 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]) { warn(`useModel() called with prop "${name}" which is not declared.`) return ref() as any } const hyphenatedName = hyphenate(name) const modifiers = getModelModifiers(props, camelizedName) const res = customRef((track, trigger) => { let localValue: any let prevSetValue: any = EMPTY_OBJ let prevEmittedValue: any watchSyncEffect(() => { const propValue = props[camelizedName] if (hasChanged(localValue, propValue)) { localValue = propValue trigger() } }) return { get() { track() return options.get ? options.get(localValue) : localValue }, set(value) { const emittedValue = options.set ? options.set(value) : value if ( !hasChanged(emittedValue, localValue) && !(prevSetValue !== EMPTY_OBJ && hasChanged(value, prevSetValue)) ) { 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) ) ) { // no v-model, local update localValue = value trigger() } i.emit(`update:${name}`, emittedValue) // #10279: if the local value is converted via a setter but the value // emitted to parent was the same, the parent will not trigger any // updates and there will be no prop sync. However the local input state // may be out of sync, so we need to force an update here. if ( hasChanged(value, emittedValue) && hasChanged(value, prevSetValue) && !hasChanged(emittedValue, prevEmittedValue) ) { trigger() } prevSetValue = value prevEmittedValue = emittedValue }, } }) // @ts-expect-error res[Symbol.iterator] = () => { let i = 0 return { next() { if (i < 2) { return { value: i++ ? modifiers || EMPTY_OBJ : res, done: false } } else { return { done: true } } }, } } return res } export const getModelModifiers = ( props: Record<string, any>, modelName: string, ): Record<string, boolean> | undefined => { return modelName === 'modelValue' || modelName === 'model-value' ? props.modelModifiers : props[`${modelName}Modifiers`] || props[`${camelize(modelName)}Modifiers`] || props[`${hyphenate(modelName)}Modifiers`] } |