1 |
|
2 | var KEBAB = /[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g;
|
3 |
|
4 | function toKebabCase (data) {
|
5 | return data.replace(this.KEBAB, function (match) {
|
6 | return '-' + match.toLowerCase();
|
7 | });
|
8 | }
|
9 |
|
10 | function n (type, attributes, children) {
|
11 | var attributes = (arguments[1].constructor === Object ? arguments[1] : ) || undefined;
|
12 | var node = document.createElement(type);
|
13 |
|
14 | for (var attribute in attributes) {
|
15 | node.setAttribute(toKebabCase(attribute), attributes[attribute]);
|
16 | }
|
17 |
|
18 | for (var i = 0, l = children.length; i < l; i++) {
|
19 | if (typeof children[i] === 'string') {
|
20 | children[i] = document.createTextNode(children[i]);
|
21 | }
|
22 | node.appendChild(children[i]);
|
23 | }
|
24 |
|
25 | return node;
|
26 | }
|
27 |
|
28 | function createElement (data) {
|
29 | if (typeof data === 'string') {
|
30 | return document.createTextNode(data);
|
31 | } else {
|
32 | var node = document.createElement(data.type);
|
33 |
|
34 | var attributes = data.attributes;
|
35 | for (var attribute in attributes) {
|
36 | node.setAttribute(toKebabCase(attribute), attributes[attribute]);
|
37 | }
|
38 |
|
39 |
|
40 |
|
41 | var children = data.children;
|
42 | for (var i = 0, l = children.length; i < l; i++) {
|
43 | node.appendChild(createElement(children[i]));
|
44 | }
|
45 |
|
46 |
|
47 |
|
48 | return node;
|
49 | }
|
50 | }
|
51 |
|
52 | function changed (node1, node2) {
|
53 | return typeof node1 !== typeof node2
|
54 | || typeof node1 === 'string'
|
55 | && node1 !== node2
|
56 | || node1.type !== node2.type;
|
57 | }
|
58 |
|
59 | function updateElement (parent, newNode, oldNode, index) {
|
60 | index = index || 0;
|
61 | if (!oldNode) {
|
62 | parent.appendChild(
|
63 | n(newNode)
|
64 | );
|
65 | } else if (!newNode) {
|
66 | parent.removeChild(
|
67 | parent.childNodes[index]
|
68 | );
|
69 | } else if (changed(newNode, oldNode)) {
|
70 | parent.replaceChild(
|
71 | n(newNode),
|
72 | parent.childNodes[index]
|
73 | );
|
74 | } else if (newNode.type) {
|
75 | var newLength = newNode.children.length;
|
76 | var oldLength = oldNode.children.length;
|
77 | for (var i = 0; i < newLength || i < oldLength; i++) {
|
78 | updateElement(
|
79 | parent.childNodes[index],
|
80 | newNode.children[i],
|
81 | oldNode.children[i],
|
82 | i
|
83 | );
|
84 | }
|
85 | }
|
86 | }
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 | var b = {
|
105 | type: 'ul',
|
106 | children: [
|
107 | {
|
108 | type: 'li',
|
109 | children: ['bar']
|
110 | },
|
111 | {
|
112 | type: 'li',
|
113 | children: ['bar']
|
114 | }
|
115 | ]
|
116 | };
|
117 |
|
118 | var a = n('ul', [
|
119 | n('li', ['bar']),
|
120 | n('li', ['bar'])
|
121 | ]);
|
122 |
|
123 | var b = n('ul', [
|
124 | n('li', ['foo']),
|
125 | n('li', ['foo'])
|
126 | ]);
|
127 |
|
128 | var root = document.getElementById('root');
|
129 | var reload = document.getElementById('reload');
|
130 |
|
131 | updateElement(root, a);
|
132 |
|
133 | reload.addEventListener('click', () => {
|
134 | updateElement(root, b, a);
|
135 | });
|