| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- 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'
- import { isOn, isString, isFunction, isModelListener } from '@vue/shared'
- import { RendererOptions } from '@vue/runtime-core'
- const nativeOnRE = /^on[a-z]/
- type DOMRendererOptions = RendererOptions<Node, Element>
- export const patchProp: DOMRendererOptions['patchProp'] = (
- el,
- key,
- prevValue,
- nextValue,
- isSVG = false,
- prevChildren,
- parentComponent,
- parentSuspense,
- unmountChildren
- ) => {
- if (key === 'class') {
- patchClass(el, nextValue, isSVG)
- } else if (key === 'style') {
- patchStyle(el, prevValue, nextValue)
- } else if (isOn(key)) {
- // ignore v-model listeners
- if (!isModelListener(key)) {
- patchEvent(el, key, prevValue, nextValue, parentComponent)
- }
- } else if (
- key[0] === '.'
- ? ((key = key.slice(1)), true)
- : key[0] === '^'
- ? ((key = key.slice(1)), false)
- : shouldSetAsProp(el, key, nextValue, isSVG)
- ) {
- patchDOMProp(
- el,
- key,
- nextValue,
- prevChildren,
- parentComponent,
- parentSuspense,
- unmountChildren
- )
- } else {
- // 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
- }
- patchAttr(el, key, nextValue, isSVG, parentComponent)
- }
- }
- 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 & textContent
- if (key === 'innerHTML' || key === 'textContent') {
- 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
- }
- // #1787, #2840 form property on form elements is readonly and must be set as
- // attribute.
- if (key === 'form') {
- return false
- }
- // #1526 <input list> must be set as attribute
- if (key === 'list' && el.tagName === 'INPUT') {
- return false
- }
- // #2766 <textarea type> must be set as attribute
- if (key === 'type' && el.tagName === 'TEXTAREA') {
- return false
- }
- // native onclick with string value, must be set as attribute
- if (nativeOnRE.test(key) && isString(value)) {
- return false
- }
- return key in el
- }
|