6e62932ddbbecf28c1ff38c46dea437403b527c1fa980223d275c258c7ed0990bf164f17b624c96b9d8d7f9a57890010a869105d24684fee43832bda3f8f3a 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. /* @flow */
  2. import { isDef, isUndef, extend, toNumber } from 'shared/util'
  3. import { isSVG } from 'web/util/index'
  4. let svgContainer
  5. function updateDOMProps (oldVnode: VNodeWithData, vnode: VNodeWithData) {
  6. if (isUndef(oldVnode.data.domProps) && isUndef(vnode.data.domProps)) {
  7. return
  8. }
  9. let key, cur
  10. const elm: any = vnode.elm
  11. const oldProps = oldVnode.data.domProps || {}
  12. let props = vnode.data.domProps || {}
  13. // clone observed objects, as the user probably wants to mutate it
  14. if (isDef(props.__ob__)) {
  15. props = vnode.data.domProps = extend({}, props)
  16. }
  17. for (key in oldProps) {
  18. if (!(key in props)) {
  19. elm[key] = ''
  20. }
  21. }
  22. for (key in props) {
  23. cur = props[key]
  24. // ignore children if the node has textContent or innerHTML,
  25. // as these will throw away existing DOM nodes and cause removal errors
  26. // on subsequent patches (#3360)
  27. if (key === 'textContent' || key === 'innerHTML') {
  28. if (vnode.children) vnode.children.length = 0
  29. if (cur === oldProps[key]) continue
  30. // #6601 work around Chrome version <= 55 bug where single textNode
  31. // replaced by innerHTML/textContent retains its parentNode property
  32. if (elm.childNodes.length === 1) {
  33. elm.removeChild(elm.childNodes[0])
  34. }
  35. }
  36. if (key === 'value' && elm.tagName !== 'PROGRESS') {
  37. // store value as _value as well since
  38. // non-string values will be stringified
  39. elm._value = cur
  40. // avoid resetting cursor position when value is the same
  41. const strCur = isUndef(cur) ? '' : String(cur)
  42. if (shouldUpdateValue(elm, strCur)) {
  43. elm.value = strCur
  44. }
  45. } else if (key === 'innerHTML' && isSVG(elm.tagName) && isUndef(elm.innerHTML)) {
  46. // IE doesn't support innerHTML for SVG elements
  47. svgContainer = svgContainer || document.createElement('div')
  48. svgContainer.innerHTML = `<svg>${cur}</svg>`
  49. const svg = svgContainer.firstChild
  50. while (elm.firstChild) {
  51. elm.removeChild(elm.firstChild)
  52. }
  53. while (svg.firstChild) {
  54. elm.appendChild(svg.firstChild)
  55. }
  56. } else if (
  57. // skip the update if old and new VDOM state is the same.
  58. // `value` is handled separately because the DOM value may be temporarily
  59. // out of sync with VDOM state due to focus, composition and modifiers.
  60. // This #4521 by skipping the unnecessary `checked` update.
  61. cur !== oldProps[key]
  62. ) {
  63. // some property updates can throw
  64. // e.g. `value` on <progress> w/ non-finite value
  65. try {
  66. elm[key] = cur
  67. } catch (e) {}
  68. }
  69. }
  70. }
  71. // check platforms/web/util/attrs.js acceptValue
  72. type acceptValueElm = HTMLInputElement | HTMLSelectElement | HTMLOptionElement;
  73. function shouldUpdateValue (elm: acceptValueElm, checkVal: string): boolean {
  74. return (!elm.composing && (
  75. elm.tagName === 'OPTION' ||
  76. isNotInFocusAndDirty(elm, checkVal) ||
  77. isDirtyWithModifiers(elm, checkVal)
  78. ))
  79. }
  80. function isNotInFocusAndDirty (elm: acceptValueElm, checkVal: string): boolean {
  81. // return true when textbox (.number and .trim) loses focus and its value is
  82. // not equal to the updated value
  83. let notInFocus = true
  84. // #6157
  85. // work around IE bug when accessing document.activeElement in an iframe
  86. try { notInFocus = document.activeElement !== elm } catch (e) {}
  87. return notInFocus && elm.value !== checkVal
  88. }
  89. function isDirtyWithModifiers (elm: any, newVal: string): boolean {
  90. const value = elm.value
  91. const modifiers = elm._vModifiers // injected by v-model runtime
  92. if (isDef(modifiers)) {
  93. if (modifiers.number) {
  94. return toNumber(value) !== toNumber(newVal)
  95. }
  96. if (modifiers.trim) {
  97. return value.trim() !== newVal.trim()
  98. }
  99. }
  100. return value !== newVal
  101. }
  102. export default {
  103. create: updateDOMProps,
  104. update: updateDOMProps
  105. }