|
|
@@ -65,18 +65,17 @@ 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)
|
|
|
- )
|
|
|
- ) {
|
|
|
+ const hasVModel = !!(
|
|
|
+ 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)
|
|
|
+ )
|
|
|
+ if (!hasVModel) {
|
|
|
// no v-model, local update
|
|
|
localValue = value
|
|
|
trigger()
|
|
|
@@ -88,9 +87,18 @@ export function useModel(
|
|
|
// 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)
|
|
|
+ ((hasChanged(value, emittedValue) &&
|
|
|
+ !hasChanged(emittedValue, prevEmittedValue)) ||
|
|
|
+ // #13524: browsers differ in when they flush microtasks between
|
|
|
+ // event listeners. If a v-model listener emits an intermediate value
|
|
|
+ // and a following listener restores the model to its previous prop
|
|
|
+ // value before parent updates are flushed, the parent render can be
|
|
|
+ // deduped as having no prop change. Force a local update so DOM state
|
|
|
+ // such as an input's value is synchronized back to the current model.
|
|
|
+ (hasVModel &&
|
|
|
+ prevSetValue !== EMPTY_OBJ &&
|
|
|
+ !hasChanged(emittedValue, localValue)))
|
|
|
) {
|
|
|
trigger()
|
|
|
}
|