|
|
@@ -6,7 +6,6 @@ import {
|
|
|
looseIndexOf,
|
|
|
looseToNumber,
|
|
|
} from '@vue/shared'
|
|
|
-import type { ComponentInternalInstance } from '../component'
|
|
|
import type {
|
|
|
DirectiveBinding,
|
|
|
DirectiveHook,
|
|
|
@@ -16,13 +15,11 @@ import type {
|
|
|
import { addEventListener } from '../dom/event'
|
|
|
import { nextTick } from '../scheduler'
|
|
|
import { warn } from '../warning'
|
|
|
+import { getMetadata } from '../metadata'
|
|
|
|
|
|
type AssignerFn = (value: any) => void
|
|
|
-function getModelAssigner(
|
|
|
- el: Element,
|
|
|
- instance: ComponentInternalInstance,
|
|
|
-): AssignerFn {
|
|
|
- const metadata = instance.metadata.get(el)!
|
|
|
+function getModelAssigner(el: Element): AssignerFn {
|
|
|
+ const metadata = getMetadata(el)
|
|
|
const fn: any = metadata.props['onUpdate:modelValue']
|
|
|
return isArray(fn) ? value => invokeArrayFns(fn, value) : fn
|
|
|
}
|
|
|
@@ -49,8 +46,8 @@ export const vModelText: ObjectDirective<
|
|
|
any,
|
|
|
'lazy' | 'trim' | 'number'
|
|
|
> = {
|
|
|
- beforeMount(el, { instance, modifiers: { lazy, trim, number } = {} }) {
|
|
|
- const assigner = getModelAssigner(el, instance)
|
|
|
+ beforeMount(el, { modifiers: { lazy, trim, number } = {} }) {
|
|
|
+ const assigner = getModelAssigner(el)
|
|
|
assignFnMap.set(el, assigner)
|
|
|
|
|
|
const castToNumber = number // || (vnode.props && vnode.props.type === 'number')
|
|
|
@@ -84,11 +81,8 @@ export const vModelText: ObjectDirective<
|
|
|
mounted(el, { value }) {
|
|
|
el.value = value == null ? '' : value
|
|
|
},
|
|
|
- beforeUpdate(
|
|
|
- el,
|
|
|
- { instance, value, modifiers: { lazy, trim, number } = {} },
|
|
|
- ) {
|
|
|
- assignFnMap.set(el, getModelAssigner(el, instance))
|
|
|
+ beforeUpdate(el, { value, modifiers: { lazy, trim, number } = {} }) {
|
|
|
+ assignFnMap.set(el, getModelAssigner(el))
|
|
|
|
|
|
// avoid clearing unresolved text. #2302
|
|
|
if ((el as any).composing) return
|
|
|
@@ -116,17 +110,17 @@ export const vModelText: ObjectDirective<
|
|
|
}
|
|
|
|
|
|
export const vModelRadio: ObjectDirective<HTMLInputElement> = {
|
|
|
- beforeMount(el, { value, instance }) {
|
|
|
- el.checked = looseEqual(value, getValue(el, instance))
|
|
|
- assignFnMap.set(el, getModelAssigner(el, instance))
|
|
|
+ beforeMount(el, { value }) {
|
|
|
+ el.checked = looseEqual(value, getValue(el))
|
|
|
+ assignFnMap.set(el, getModelAssigner(el))
|
|
|
addEventListener(el, 'change', () => {
|
|
|
- assignFnMap.get(el)!(getValue(el, instance))
|
|
|
+ assignFnMap.get(el)!(getValue(el))
|
|
|
})
|
|
|
},
|
|
|
- beforeUpdate(el, { value, oldValue, instance }) {
|
|
|
- assignFnMap.set(el, getModelAssigner(el, instance))
|
|
|
+ beforeUpdate(el, { value, oldValue }) {
|
|
|
+ assignFnMap.set(el, getModelAssigner(el))
|
|
|
if (value !== oldValue) {
|
|
|
- el.checked = looseEqual(value, getValue(el, instance))
|
|
|
+ el.checked = looseEqual(value, getValue(el))
|
|
|
}
|
|
|
},
|
|
|
}
|
|
|
@@ -134,13 +128,13 @@ export const vModelRadio: ObjectDirective<HTMLInputElement> = {
|
|
|
export const vModelSelect: ObjectDirective<HTMLSelectElement, any, 'number'> = {
|
|
|
// <select multiple> value need to be deep traversed
|
|
|
deep: true,
|
|
|
- beforeMount(el, { value, instance, modifiers: { number = false } = {} }) {
|
|
|
+ beforeMount(el, { value, modifiers: { number = false } = {} }) {
|
|
|
const isSetModel = isSet(value)
|
|
|
addEventListener(el, 'change', () => {
|
|
|
const selectedVal = Array.prototype.filter
|
|
|
.call(el.options, (o: HTMLOptionElement) => o.selected)
|
|
|
.map((o: HTMLOptionElement) =>
|
|
|
- number ? looseToNumber(getValue(o, instance)) : getValue(o, instance),
|
|
|
+ number ? looseToNumber(getValue(o)) : getValue(o),
|
|
|
)
|
|
|
assignFnMap.get(el)!(
|
|
|
el.multiple
|
|
|
@@ -155,28 +149,20 @@ export const vModelSelect: ObjectDirective<HTMLSelectElement, any, 'number'> = {
|
|
|
assigningMap.set(el, false)
|
|
|
})
|
|
|
})
|
|
|
- assignFnMap.set(el, getModelAssigner(el, instance))
|
|
|
- setSelected(el, instance, value, number)
|
|
|
+ assignFnMap.set(el, getModelAssigner(el))
|
|
|
+ setSelected(el, value, number)
|
|
|
},
|
|
|
- beforeUpdate(el, { instance }) {
|
|
|
- assignFnMap.set(el, getModelAssigner(el, instance))
|
|
|
+ beforeUpdate(el) {
|
|
|
+ assignFnMap.set(el, getModelAssigner(el))
|
|
|
},
|
|
|
- updated(
|
|
|
- el,
|
|
|
- { value, oldValue, instance, modifiers: { number = false } = {} },
|
|
|
- ) {
|
|
|
+ updated(el, { value, modifiers: { number = false } = {} }) {
|
|
|
if (!assigningMap.get(el)) {
|
|
|
- setSelected(el, instance, value, number)
|
|
|
+ setSelected(el, value, number)
|
|
|
}
|
|
|
},
|
|
|
}
|
|
|
|
|
|
-function setSelected(
|
|
|
- el: HTMLSelectElement,
|
|
|
- instance: ComponentInternalInstance,
|
|
|
- value: any,
|
|
|
- number: boolean,
|
|
|
-) {
|
|
|
+function setSelected(el: HTMLSelectElement, value: any, number: boolean) {
|
|
|
const isMultiple = el.multiple
|
|
|
const isArrayValue = isArray(value)
|
|
|
if (isMultiple && !isArrayValue && !isSet(value)) {
|
|
|
@@ -190,7 +176,7 @@ function setSelected(
|
|
|
|
|
|
for (let i = 0, l = el.options.length; i < l; i++) {
|
|
|
const option = el.options[i]
|
|
|
- const optionValue = getValue(option, instance)
|
|
|
+ const optionValue = getValue(option)
|
|
|
if (isMultiple) {
|
|
|
if (isArrayValue) {
|
|
|
const optionType = typeof optionValue
|
|
|
@@ -206,7 +192,7 @@ function setSelected(
|
|
|
option.selected = value.has(optionValue)
|
|
|
}
|
|
|
} else {
|
|
|
- if (looseEqual(getValue(option, instance), value)) {
|
|
|
+ if (looseEqual(getValue(option), value)) {
|
|
|
if (el.selectedIndex !== i) el.selectedIndex = i
|
|
|
return
|
|
|
}
|
|
|
@@ -218,21 +204,14 @@ function setSelected(
|
|
|
}
|
|
|
|
|
|
// retrieve raw value set via :value bindings
|
|
|
-function getValue(
|
|
|
- el: HTMLOptionElement | HTMLInputElement,
|
|
|
- instance: ComponentInternalInstance,
|
|
|
-) {
|
|
|
- const metadata = instance.metadata.get(el)
|
|
|
+function getValue(el: HTMLOptionElement | HTMLInputElement) {
|
|
|
+ const metadata = getMetadata(el)
|
|
|
return (metadata && metadata.props.value) || el.value
|
|
|
}
|
|
|
|
|
|
// retrieve raw value for true-value and false-value set via :true-value or :false-value bindings
|
|
|
-function getCheckboxValue(
|
|
|
- el: HTMLInputElement,
|
|
|
- instance: ComponentInternalInstance,
|
|
|
- checked: boolean,
|
|
|
-) {
|
|
|
- const metadata = instance.metadata.get(el)
|
|
|
+function getCheckboxValue(el: HTMLInputElement, checked: boolean) {
|
|
|
+ const metadata = getMetadata(el)
|
|
|
const props = metadata && metadata.props
|
|
|
const key = checked ? 'true-value' : 'false-value'
|
|
|
if (props && key in props) {
|
|
|
@@ -246,14 +225,14 @@ function getCheckboxValue(
|
|
|
|
|
|
const setChecked: DirectiveHook<HTMLInputElement> = (
|
|
|
el,
|
|
|
- { value, oldValue, instance },
|
|
|
+ { value, oldValue },
|
|
|
) => {
|
|
|
if (isArray(value)) {
|
|
|
- el.checked = looseIndexOf(value, getValue(el, instance)) > -1
|
|
|
+ el.checked = looseIndexOf(value, getValue(el)) > -1
|
|
|
} else if (isSet(value)) {
|
|
|
- el.checked = value.has(getValue(el, instance))
|
|
|
+ el.checked = value.has(getValue(el))
|
|
|
} else if (value !== oldValue) {
|
|
|
- el.checked = looseEqual(value, getCheckboxValue(el, instance, true))
|
|
|
+ el.checked = looseEqual(value, getCheckboxValue(el, true))
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -261,12 +240,11 @@ export const vModelCheckbox: ObjectDirective<HTMLInputElement> = {
|
|
|
// #4096 array checkboxes need to be deep traversed
|
|
|
deep: true,
|
|
|
beforeMount(el, binding) {
|
|
|
- const { instance } = binding
|
|
|
- assignFnMap.set(el, getModelAssigner(el, binding.instance))
|
|
|
+ assignFnMap.set(el, getModelAssigner(el))
|
|
|
|
|
|
addEventListener(el, 'change', () => {
|
|
|
const modelValue = binding.value
|
|
|
- const elementValue = getValue(el, instance)
|
|
|
+ const elementValue = getValue(el)
|
|
|
const checked = el.checked
|
|
|
const assigner = assignFnMap.get(el)!
|
|
|
if (isArray(modelValue)) {
|
|
|
@@ -288,14 +266,14 @@ export const vModelCheckbox: ObjectDirective<HTMLInputElement> = {
|
|
|
}
|
|
|
assigner(cloned)
|
|
|
} else {
|
|
|
- assigner(getCheckboxValue(el, instance, checked))
|
|
|
+ assigner(getCheckboxValue(el, checked))
|
|
|
}
|
|
|
})
|
|
|
},
|
|
|
// set initial checked on mount to wait for true-value/false-value
|
|
|
mounted: setChecked,
|
|
|
beforeUpdate(el, binding) {
|
|
|
- assignFnMap.set(el, getModelAssigner(el, binding.instance))
|
|
|
+ assignFnMap.set(el, getModelAssigner(el))
|
|
|
setChecked(el, binding)
|
|
|
},
|
|
|
}
|