nodeOps.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. import { RendererOptions } from '@vue/runtime-core'
  2. export const svgNS = 'http://www.w3.org/2000/svg'
  3. const doc = (typeof document !== 'undefined' ? document : null) as Document
  4. const templateContainer = doc && /*#__PURE__*/ doc.createElement('template')
  5. export const nodeOps: Omit<RendererOptions<Node, Element>, 'patchProp'> = {
  6. insert: (child, parent, anchor) => {
  7. parent.insertBefore(child, anchor || null)
  8. },
  9. remove: child => {
  10. const parent = child.parentNode
  11. if (parent) {
  12. parent.removeChild(child)
  13. }
  14. },
  15. createElement: (tag, isSVG, is, props): Element => {
  16. const el = isSVG
  17. ? doc.createElementNS(svgNS, tag)
  18. : doc.createElement(tag, is ? { is } : undefined)
  19. if (tag === 'select' && props && props.multiple != null) {
  20. ;(el as HTMLSelectElement).setAttribute('multiple', props.multiple)
  21. }
  22. return el
  23. },
  24. createText: text => doc.createTextNode(text),
  25. createComment: text => doc.createComment(text),
  26. setText: (node, text) => {
  27. node.nodeValue = text
  28. },
  29. setElementText: (el, text) => {
  30. el.textContent = text
  31. },
  32. parentNode: node => node.parentNode as Element | null,
  33. nextSibling: node => node.nextSibling,
  34. querySelector: selector => doc.querySelector(selector),
  35. setScopeId(el, id) {
  36. el.setAttribute(id, '')
  37. },
  38. cloneNode(el) {
  39. const cloned = el.cloneNode(true)
  40. // #3072
  41. // - in `patchDOMProp`, we store the actual value in the `el._value` property.
  42. // - normally, elements using `:value` bindings will not be hoisted, but if
  43. // the bound value is a constant, e.g. `:value="true"` - they do get
  44. // hoisted.
  45. // - in production, hoisted nodes are cloned when subsequent inserts, but
  46. // cloneNode() does not copy the custom property we attached.
  47. // - This may need to account for other custom DOM properties we attach to
  48. // elements in addition to `_value` in the future.
  49. if (`_value` in el) {
  50. ;(cloned as any)._value = (el as any)._value
  51. }
  52. return cloned
  53. },
  54. // __UNSAFE__
  55. // Reason: innerHTML.
  56. // Static content here can only come from compiled templates.
  57. // As long as the user only uses trusted templates, this is safe.
  58. insertStaticContent(content, parent, anchor, isSVG, start, end) {
  59. // <parent> before | first ... last | anchor </parent>
  60. const before = anchor ? anchor.previousSibling : parent.lastChild
  61. // #5308 can only take cached path if:
  62. // - has a single root node
  63. // - nextSibling info is still available
  64. if (start && (start === end || start.nextSibling)) {
  65. // cached
  66. while (true) {
  67. parent.insertBefore(start!.cloneNode(true), anchor)
  68. if (start === end || !(start = start!.nextSibling)) break
  69. }
  70. } else {
  71. // fresh insert
  72. templateContainer.innerHTML = isSVG ? `<svg>${content}</svg>` : content
  73. const template = templateContainer.content
  74. if (isSVG) {
  75. // remove outer svg wrapper
  76. const wrapper = template.firstChild!
  77. while (wrapper.firstChild) {
  78. template.appendChild(wrapper.firstChild)
  79. }
  80. template.removeChild(wrapper)
  81. }
  82. parent.insertBefore(template, anchor)
  83. }
  84. return [
  85. // first
  86. before ? before.nextSibling! : parent.firstChild!,
  87. // last
  88. anchor ? anchor.previousSibling! : parent.lastChild!
  89. ]
  90. }
  91. }