2018-09-19 15:35:38 +00:00
|
|
|
import { patchClass } from './modules/class'
|
|
|
|
import { patchStyle } from './modules/style'
|
|
|
|
import { patchAttr } from './modules/attrs'
|
|
|
|
import { patchDOMProp } from './modules/props'
|
|
|
|
import { patchEvent } from './modules/events'
|
2021-02-24 20:06:51 +00:00
|
|
|
import { isOn, isString, isFunction, isModelListener } from '@vue/shared'
|
2020-02-12 16:56:42 +00:00
|
|
|
import { RendererOptions } from '@vue/runtime-core'
|
2018-10-12 21:42:08 +00:00
|
|
|
|
2020-04-10 15:57:07 +00:00
|
|
|
const nativeOnRE = /^on[a-z]/
|
|
|
|
|
2020-06-30 15:23:09 +00:00
|
|
|
type DOMRendererOptions = RendererOptions<Node, Element>
|
|
|
|
|
|
|
|
export const forcePatchProp: DOMRendererOptions['forcePatchProp'] = (_, key) =>
|
|
|
|
key === 'value'
|
|
|
|
|
|
|
|
export const patchProp: DOMRendererOptions['patchProp'] = (
|
2020-02-12 16:56:42 +00:00
|
|
|
el,
|
|
|
|
key,
|
|
|
|
prevValue,
|
2020-03-09 20:15:49 +00:00
|
|
|
nextValue,
|
2020-02-12 16:56:42 +00:00
|
|
|
isSVG = false,
|
|
|
|
prevChildren,
|
|
|
|
parentComponent,
|
|
|
|
parentSuspense,
|
|
|
|
unmountChildren
|
|
|
|
) => {
|
2018-09-19 15:35:38 +00:00
|
|
|
switch (key) {
|
|
|
|
// special
|
|
|
|
case 'class':
|
|
|
|
patchClass(el, nextValue, isSVG)
|
|
|
|
break
|
|
|
|
case 'style':
|
2019-05-26 07:19:44 +00:00
|
|
|
patchStyle(el, prevValue, nextValue)
|
2018-09-19 15:35:38 +00:00
|
|
|
break
|
|
|
|
default:
|
2018-10-17 16:20:54 +00:00
|
|
|
if (isOn(key)) {
|
2020-03-16 21:51:56 +00:00
|
|
|
// ignore v-model listeners
|
2020-07-21 18:17:48 +00:00
|
|
|
if (!isModelListener(key)) {
|
2020-04-07 15:34:54 +00:00
|
|
|
patchEvent(el, key, prevValue, nextValue, parentComponent)
|
2020-03-16 21:51:56 +00:00
|
|
|
}
|
2020-07-06 23:00:53 +00:00
|
|
|
} else if (shouldSetAsProp(el, key, nextValue, isSVG)) {
|
2019-08-19 22:06:20 +00:00
|
|
|
patchDOMProp(
|
|
|
|
el,
|
|
|
|
key,
|
|
|
|
nextValue,
|
|
|
|
prevChildren,
|
|
|
|
parentComponent,
|
2019-09-10 16:11:08 +00:00
|
|
|
parentSuspense,
|
2019-08-19 22:06:20 +00:00
|
|
|
unmountChildren
|
|
|
|
)
|
2018-09-19 15:35:38 +00:00
|
|
|
} else {
|
2019-11-12 21:24:39 +00:00
|
|
|
// special case for <input v-model type="checkbox"> with
|
|
|
|
// :true-value & :false-value
|
|
|
|
// store value as dom properties since non-string values will be
|
|
|
|
// stringified.
|
|
|
|
if (key === 'true-value') {
|
|
|
|
;(el as any)._trueValue = nextValue
|
|
|
|
} else if (key === 'false-value') {
|
|
|
|
;(el as any)._falseValue = nextValue
|
|
|
|
}
|
2021-04-29 18:45:22 +00:00
|
|
|
patchAttr(el, key, nextValue, isSVG, parentComponent)
|
2018-09-19 15:35:38 +00:00
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2020-07-06 23:00:53 +00:00
|
|
|
|
|
|
|
function shouldSetAsProp(
|
|
|
|
el: Element,
|
|
|
|
key: string,
|
|
|
|
value: unknown,
|
|
|
|
isSVG: boolean
|
|
|
|
) {
|
|
|
|
if (isSVG) {
|
|
|
|
// most keys must be set as attribute on svg elements to work
|
|
|
|
// ...except innerHTML
|
|
|
|
if (key === 'innerHTML') {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
// or native onclick with function values
|
|
|
|
if (key in el && nativeOnRE.test(key) && isFunction(value)) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// spellcheck and draggable are numerated attrs, however their
|
|
|
|
// corresponding DOM properties are actually booleans - this leads to
|
|
|
|
// setting it with a string "false" value leading it to be coerced to
|
|
|
|
// `true`, so we need to always treat them as attributes.
|
|
|
|
// Note that `contentEditable` doesn't have this problem: its DOM
|
|
|
|
// property is also enumerated string values.
|
|
|
|
if (key === 'spellcheck' || key === 'draggable') {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2021-02-24 20:06:51 +00:00
|
|
|
// #1787, #2840 form property on form elements is readonly and must be set as
|
|
|
|
// attribute.
|
|
|
|
if (key === 'form') {
|
2020-08-06 13:32:28 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-07-06 23:00:53 +00:00
|
|
|
// #1526 <input list> must be set as attribute
|
|
|
|
if (key === 'list' && el.tagName === 'INPUT') {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2021-02-24 20:06:51 +00:00
|
|
|
// #2766 <textarea type> must be set as attribute
|
|
|
|
if (key === 'type' && el.tagName === 'TEXTAREA') {
|
2020-07-06 23:00:53 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2021-02-24 20:06:51 +00:00
|
|
|
// native onclick with string value, must be set as attribute
|
|
|
|
if (nativeOnRE.test(key) && isString(value)) {
|
2021-02-24 19:51:19 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-07-06 23:00:53 +00:00
|
|
|
return key in el
|
|
|
|
}
|