props.ts 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // __UNSAFE__
  2. // Reason: potentially setting innerHTML.
  3. // This can come from explicit usage of v-html or innerHTML as a prop in render
  4. import { warn, DeprecationTypes, compatUtils } from '@vue/runtime-core'
  5. import { includeBooleanAttr } from '@vue/shared'
  6. // functions. The user is responsible for using them with only trusted content.
  7. export function patchDOMProp(
  8. el: any,
  9. key: string,
  10. value: any,
  11. // the following args are passed only due to potential innerHTML/textContent
  12. // overriding existing VNodes, in which case the old tree must be properly
  13. // unmounted.
  14. prevChildren: any,
  15. parentComponent: any,
  16. parentSuspense: any,
  17. unmountChildren: any
  18. ) {
  19. if (key === 'innerHTML' || key === 'textContent') {
  20. if (prevChildren) {
  21. unmountChildren(prevChildren, parentComponent, parentSuspense)
  22. }
  23. el[key] = value == null ? '' : value
  24. return
  25. }
  26. if (key === 'value' && el.tagName !== 'PROGRESS') {
  27. // store value as _value as well since
  28. // non-string values will be stringified.
  29. el._value = value
  30. const newValue = value == null ? '' : value
  31. if (el.value !== newValue) {
  32. el.value = newValue
  33. }
  34. if (value == null) {
  35. el.removeAttribute(key)
  36. }
  37. return
  38. }
  39. if (value === '' || value == null) {
  40. const type = typeof el[key]
  41. if (type === 'boolean') {
  42. // e.g. <select multiple> compiles to { multiple: '' }
  43. el[key] = includeBooleanAttr(value)
  44. return
  45. } else if (value == null && type === 'string') {
  46. // e.g. <div :id="null">
  47. el[key] = ''
  48. el.removeAttribute(key)
  49. return
  50. } else if (type === 'number') {
  51. // e.g. <img :width="null">
  52. // the value of some IDL attr must be greater than 0, e.g. input.size = 0 -> error
  53. try {
  54. el[key] = 0
  55. } catch {}
  56. el.removeAttribute(key)
  57. return
  58. }
  59. }
  60. if (
  61. __COMPAT__ &&
  62. value === false &&
  63. compatUtils.isCompatEnabled(
  64. DeprecationTypes.ATTR_FALSE_VALUE,
  65. parentComponent
  66. )
  67. ) {
  68. const type = typeof el[key]
  69. if (type === 'string' || type === 'number') {
  70. __DEV__ &&
  71. compatUtils.warnDeprecation(
  72. DeprecationTypes.ATTR_FALSE_VALUE,
  73. parentComponent,
  74. key
  75. )
  76. el[key] = type === 'number' ? 0 : ''
  77. el.removeAttribute(key)
  78. return
  79. }
  80. }
  81. // some properties perform value validation and throw
  82. try {
  83. el[key] = value
  84. } catch (e: any) {
  85. if (__DEV__) {
  86. warn(
  87. `Failed setting prop "${key}" on <${el.tagName.toLowerCase()}>: ` +
  88. `value ${value} is invalid.`,
  89. e
  90. )
  91. }
  92. }
  93. }