-
-
Notifications
You must be signed in to change notification settings - Fork 8.4k
/
props.ts
102 lines (96 loc) · 2.83 KB
/
props.ts
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
// __UNSAFE__
// Reason: potentially setting innerHTML.
// This can come from explicit usage of v-html or innerHTML as a prop in render
import { DeprecationTypes, compatUtils, warn } from '@vue/runtime-core'
import { includeBooleanAttr } from '@vue/shared'
// functions. The user is responsible for using them with only trusted content.
export function patchDOMProp(
el: any,
key: string,
value: any,
parentComponent: any,
): void {
if (key === 'innerHTML' || key === 'textContent') {
// null value case is handled in renderer patchElement before patching
// children
if (value == null) return
el[key] = value
return
}
const tag = el.tagName
if (
key === 'value' &&
tag !== 'PROGRESS' &&
// custom elements may use _value internally
!tag.includes('-')
) {
// #4956: <option> value will fallback to its text content so we need to
// compare against its attribute value instead.
const oldValue =
tag === 'OPTION' ? el.getAttribute('value') || '' : el.value
const newValue = value == null ? '' : String(value)
if (oldValue !== newValue || !('_value' in el)) {
el.value = newValue
}
if (value == null) {
el.removeAttribute(key)
}
// store value as _value as well since
// non-string values will be stringified.
el._value = value
return
}
let needRemove = false
if (value === '' || value == null) {
const type = typeof el[key]
if (type === 'boolean') {
// e.g. <select multiple> compiles to { multiple: '' }
value = includeBooleanAttr(value)
} else if (value == null && type === 'string') {
// e.g. <div :id="null">
value = ''
needRemove = true
} else if (type === 'number') {
// e.g. <img :width="null">
value = 0
needRemove = true
}
} else {
if (
__COMPAT__ &&
value === false &&
compatUtils.isCompatEnabled(
DeprecationTypes.ATTR_FALSE_VALUE,
parentComponent,
)
) {
const type = typeof el[key]
if (type === 'string' || type === 'number') {
__DEV__ &&
compatUtils.warnDeprecation(
DeprecationTypes.ATTR_FALSE_VALUE,
parentComponent,
key,
)
value = type === 'number' ? 0 : ''
needRemove = true
}
}
}
// some properties perform value validation and throw,
// some properties has getter, no setter, will error in 'use strict'
// eg. <select :type="null"></select> <select :willValidate="null"></select>
try {
el[key] = value
} catch (e: any) {
// do not warn if value is auto-coerced from nullish values
if (__DEV__ && !needRemove) {
warn(
`Failed setting prop "${key}" on <${tag.toLowerCase()}>: ` +
`value ${value} is invalid.`,
e,
)
}
}
needRemove && el.removeAttribute(key)
}