superfine.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. var SSR_NODE = 1
  2. var TEXT_NODE = 3
  3. var EMPTY_OBJ = {}
  4. var EMPTY_ARR = []
  5. var SVG_NS = "http://www.w3.org/2000/svg"
  6. var getKey = (vdom) => (vdom == null ? vdom : vdom.key)
  7. var listener = function (event) {
  8. this.tag[event.type](event)
  9. }
  10. var patchProp = (dom, key, oldVal, newVal, isSvg) => {
  11. if (key === "key") {
  12. } else if (key[0] === "o" && key[1] === "n") {
  13. if (!((dom.tag || (dom.tag = {}))[(key = key.slice(2))] = newVal)) {
  14. dom.removeEventListener(key, listener)
  15. } else if (!oldVal) {
  16. dom.addEventListener(key, listener)
  17. }
  18. } else if (!isSvg && key !== "list" && key !== "form" && key in dom) {
  19. dom[key] = newVal == null ? "" : newVal
  20. } else if (newVal == null || newVal === false) {
  21. dom.removeAttribute(key)
  22. } else {
  23. dom.setAttribute(key, newVal)
  24. }
  25. }
  26. var createNode = (vdom, isSvg) => {
  27. var props = vdom.props
  28. var dom =
  29. vdom.tag === TEXT_NODE
  30. ? document.createTextNode(vdom.type)
  31. : (isSvg = isSvg || vdom.type === "svg")
  32. ? document.createElementNS(SVG_NS, vdom.type, { is: props.is })
  33. : document.createElement(vdom.type, { is: props.is })
  34. for (var k in props) patchProp(dom, k, null, props[k], isSvg)
  35. vdom.children.map((kid) =>
  36. dom.appendChild(createNode((kid = vdomify(kid)), isSvg))
  37. )
  38. return (vdom.dom = dom)
  39. }
  40. var patchDom = (parent, dom, oldVdom, newVdom, isSvg) => {
  41. if (oldVdom === newVdom) {
  42. } else if (
  43. oldVdom != null &&
  44. oldVdom.tag === TEXT_NODE &&
  45. newVdom.tag === TEXT_NODE
  46. ) {
  47. if (oldVdom.type !== newVdom.type) dom.nodeValue = newVdom.type
  48. } else if (oldVdom == null || oldVdom.type !== newVdom.type) {
  49. dom = parent.insertBefore(
  50. createNode((newVdom = vdomify(newVdom)), isSvg),
  51. dom
  52. )
  53. if (oldVdom != null) {
  54. parent.removeChild(oldVdom.dom)
  55. }
  56. } else {
  57. var tmpVKid,
  58. oldVKid,
  59. oldKey,
  60. newKey,
  61. oldProps = oldVdom.props,
  62. newProps = newVdom.props,
  63. oldVKids = oldVdom.children,
  64. newVKids = newVdom.children,
  65. oldHead = 0,
  66. newHead = 0,
  67. oldTail = oldVKids.length - 1,
  68. newTail = newVKids.length - 1
  69. isSvg = isSvg || newVdom.type === "svg"
  70. for (var i in { ...oldProps, ...newProps }) {
  71. if (
  72. (i === "value" || i === "selected" || i === "checked"
  73. ? dom[i]
  74. : oldProps[i]) !== newProps[i]
  75. ) {
  76. patchProp(dom, i, oldProps[i], newProps[i], isSvg)
  77. }
  78. }
  79. while (newHead <= newTail && oldHead <= oldTail) {
  80. if (
  81. (oldKey = getKey(oldVKids[oldHead])) == null ||
  82. oldKey !== getKey(newVKids[newHead])
  83. ) {
  84. break
  85. }
  86. patchDom(
  87. dom,
  88. oldVKids[oldHead].dom,
  89. oldVKids[oldHead++],
  90. (newVKids[newHead] = vdomify(newVKids[newHead++])),
  91. isSvg
  92. )
  93. }
  94. while (newHead <= newTail && oldHead <= oldTail) {
  95. if (
  96. (oldKey = getKey(oldVKids[oldTail])) == null ||
  97. oldKey !== getKey(newVKids[newTail])
  98. ) {
  99. break
  100. }
  101. patchDom(
  102. dom,
  103. oldVKids[oldTail].dom,
  104. oldVKids[oldTail--],
  105. (newVKids[newTail] = vdomify(newVKids[newTail--])),
  106. isSvg
  107. )
  108. }
  109. if (oldHead > oldTail) {
  110. while (newHead <= newTail) {
  111. dom.insertBefore(
  112. createNode((newVKids[newHead] = vdomify(newVKids[newHead++])), isSvg),
  113. (oldVKid = oldVKids[oldHead]) && oldVKid.dom
  114. )
  115. }
  116. } else if (newHead > newTail) {
  117. while (oldHead <= oldTail) {
  118. dom.removeChild(oldVKids[oldHead++].dom)
  119. }
  120. } else {
  121. for (var keyed = {}, newKeyed = {}, i = oldHead; i <= oldTail; i++) {
  122. if ((oldKey = oldVKids[i].key) != null) {
  123. keyed[oldKey] = oldVKids[i]
  124. }
  125. }
  126. while (newHead <= newTail) {
  127. oldKey = getKey((oldVKid = oldVKids[oldHead]))
  128. newKey = getKey((newVKids[newHead] = vdomify(newVKids[newHead])))
  129. if (
  130. newKeyed[oldKey] ||
  131. (newKey != null && newKey === getKey(oldVKids[oldHead + 1]))
  132. ) {
  133. if (oldKey == null) {
  134. dom.removeChild(oldVKid.dom)
  135. }
  136. oldHead++
  137. continue
  138. }
  139. if (newKey == null || oldVdom.tag === SSR_NODE) {
  140. if (oldKey == null) {
  141. patchDom(
  142. dom,
  143. oldVKid && oldVKid.dom,
  144. oldVKid,
  145. newVKids[newHead],
  146. isSvg
  147. )
  148. newHead++
  149. }
  150. oldHead++
  151. } else {
  152. if (oldKey === newKey) {
  153. patchDom(dom, oldVKid.dom, oldVKid, newVKids[newHead], isSvg)
  154. newKeyed[newKey] = true
  155. oldHead++
  156. } else {
  157. if ((tmpVKid = keyed[newKey]) != null) {
  158. patchDom(
  159. dom,
  160. dom.insertBefore(tmpVKid.dom, oldVKid && oldVKid.dom),
  161. tmpVKid,
  162. newVKids[newHead],
  163. isSvg
  164. )
  165. newKeyed[newKey] = true
  166. } else {
  167. patchDom(
  168. dom,
  169. oldVKid && oldVKid.dom,
  170. null,
  171. newVKids[newHead],
  172. isSvg
  173. )
  174. }
  175. }
  176. newHead++
  177. }
  178. }
  179. while (oldHead <= oldTail) {
  180. if (getKey((oldVKid = oldVKids[oldHead++])) == null) {
  181. dom.removeChild(oldVKid.dom)
  182. }
  183. }
  184. for (var i in keyed) {
  185. if (newKeyed[i] == null) {
  186. dom.removeChild(keyed[i].dom)
  187. }
  188. }
  189. }
  190. }
  191. return (newVdom.dom = dom)
  192. }
  193. var vdomify = (vdom) =>
  194. vdom !== true && vdom !== false && vdom ? vdom : text("")
  195. var recycleNode = (dom) =>
  196. dom.nodeType === TEXT_NODE
  197. ? text(dom.nodeValue, dom)
  198. : createVdom(
  199. dom.nodeName.toLowerCase(),
  200. EMPTY_OBJ,
  201. EMPTY_ARR.map.call(dom.childNodes, recycleNode),
  202. dom,
  203. null,
  204. SSR_NODE
  205. )
  206. var createVdom = (type, props, children, dom, key, tag) => ({
  207. type,
  208. props,
  209. children,
  210. dom,
  211. key,
  212. tag,
  213. })
  214. export var text = (value, dom) =>
  215. createVdom(value, EMPTY_OBJ, EMPTY_ARR, dom, null, TEXT_NODE)
  216. export var h = (type, props, ch) =>
  217. createVdom(
  218. type,
  219. props,
  220. Array.isArray(ch) ? ch : ch == null ? EMPTY_ARR : [ch],
  221. null,
  222. props.key
  223. )
  224. export var patch = (dom, vdom) => (
  225. ((dom = patchDom(
  226. dom.parentNode,
  227. dom,
  228. dom.v || recycleNode(dom),
  229. vdom
  230. )).v = vdom),
  231. dom
  232. )