2
0
Эх сурвалжийг харах

fix(v-model): handle mutations of v-model bound array/sets

fix #4096
Evan You 4 жил өмнө
parent
commit
2937530bef

+ 6 - 6
packages/runtime-core/src/apiWatch.ts

@@ -390,12 +390,12 @@ export function createPathGetter(ctx: any, path: string) {
   }
 }
 
-function traverse(value: unknown, seen: Set<unknown> = new Set()) {
-  if (
-    !isObject(value) ||
-    seen.has(value) ||
-    (value as any)[ReactiveFlags.SKIP]
-  ) {
+export function traverse(value: unknown, seen: Set<unknown> = new Set()) {
+  if (!isObject(value) || (value as any)[ReactiveFlags.SKIP]) {
+    return value
+  }
+  seen = seen || new Set()
+  if (seen.has(value)) {
     return value
   }
   seen.add(value)

+ 5 - 0
packages/runtime-core/src/directives.ts

@@ -20,6 +20,7 @@ import { callWithAsyncErrorHandling, ErrorCodes } from './errorHandling'
 import { ComponentPublicInstance } from './componentPublicInstance'
 import { mapCompatDirectiveHook } from './compat/customDirective'
 import { pauseTracking, resetTracking } from '@vue/reactivity'
+import { traverse } from './apiWatch'
 
 export interface DirectiveBinding<V = any> {
   instance: ComponentPublicInstance | null
@@ -51,6 +52,7 @@ export interface ObjectDirective<T = any, V = any> {
   beforeUnmount?: DirectiveHook<T, null, V>
   unmounted?: DirectiveHook<T, null, V>
   getSSRProps?: SSRDirectiveHook
+  deep?: boolean
 }
 
 export type FunctionDirective<T = any, V = any> = DirectiveHook<T, any, V>
@@ -101,6 +103,9 @@ export function withDirectives<T extends VNode>(
         updated: dir
       } as ObjectDirective
     }
+    if (dir.deep) {
+      traverse(value)
+    }
     bindings.push({
       dir,
       instance,

+ 4 - 0
packages/runtime-dom/src/directives/vModel.ts

@@ -99,6 +99,8 @@ export const vModelText: ModelDirective<
 }
 
 export const vModelCheckbox: ModelDirective<HTMLInputElement> = {
+  // #4096 array checkboxes need to be deep traversed
+  deep: true,
   created(el, _, vnode) {
     el._assign = getModelAssigner(vnode)
     addEventListener(el, 'change', () => {
@@ -171,6 +173,8 @@ export const vModelRadio: ModelDirective<HTMLInputElement> = {
 }
 
 export const vModelSelect: ModelDirective<HTMLSelectElement> = {
+  // <select multiple> value need to be deep traversed
+  deep: true,
   created(el, { value, modifiers: { number } }, vnode) {
     const isSetModel = isSet(value)
     addEventListener(el, 'change', () => {