ranuts 0.1.0-alpha.1 → 0.1.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/dist/src/file/fileInfo.d.ts +0 -7
- package/dist/src/file/fs.d.ts +0 -2
- package/dist/src/file/readDir.d.ts +0 -6
- package/dist/src/file/readFile.d.ts +0 -8
- package/dist/src/file/watchFile.d.ts +0 -8
- package/dist/src/file/writeFile.d.ts +0 -8
- package/dist/src/mode/subscribe.d.ts +0 -16
- package/dist/src/ranlog/behavior.d.ts +0 -1
- package/dist/src/ranlog/env.d.ts +0 -5
- package/dist/src/ranlog/error.d.ts +0 -2
- package/dist/src/ranlog/index.d.ts +0 -26
- package/dist/src/ranlog/performance.d.ts +0 -21
- package/dist/src/ranlog/report.d.ts +0 -7
- package/dist/src/ranlog/request.d.ts +0 -18
- package/dist/src/ranlog/utils.d.ts +0 -19
- package/dist/src/utils/filterObj.d.ts +0 -8
- package/dist/src/utils/str2Xml.d.ts +0 -8
- package/dist/src/vnode/h.d.ts +0 -6
- package/dist/src/vnode/hooks.d.ts +0 -23
- package/dist/src/vnode/htmlDomApi.d.ts +0 -33
- package/dist/src/vnode/init.d.ts +0 -2
- package/dist/src/vnode/is.d.ts +0 -5
- package/dist/src/vnode/modules/attributes.d.ts +0 -8
- package/dist/src/vnode/modules/class.d.ts +0 -8
- package/dist/src/vnode/modules/index.d.ts +0 -7
- package/dist/src/vnode/modules/listeners.d.ts +0 -14
- package/dist/src/vnode/modules/props.d.ts +0 -8
- package/dist/src/vnode/modules/style.d.ts +0 -14
- package/dist/src/vnode/vnode.d.ts +0 -31
- package/src/astParser/Parser.ts +0 -654
- package/src/astParser/Tokenizer.ts +0 -447
- package/src/astParser/nodeTypes.ts +0 -194
- package/src/astParser/utils.ts +0 -27
- package/src/babel/parser.ts +0 -10
- package/src/colors/fmt.ts +0 -29
- package/src/colors/isColorSupported.ts +0 -13
- package/src/file/appendFile.ts +0 -29
- package/src/file/fileInfo.ts +0 -22
- package/src/file/fs.ts +0 -9
- package/src/file/readDir.ts +0 -18
- package/src/file/readFile.ts +0 -26
- package/src/file/watchFile.ts +0 -31
- package/src/file/writeFile.ts +0 -38
- package/src/mode/subscribe.ts +0 -89
- package/src/ran/commit.ts +0 -0
- package/src/ran/dom.ts +0 -0
- package/src/ran/hooks.ts +0 -0
- package/src/ran/reconcile.ts +0 -0
- package/src/ran/schedule.ts +0 -0
- package/src/ranlog/behavior.ts +0 -5
- package/src/ranlog/console.ts +0 -16
- package/src/ranlog/env.ts +0 -29
- package/src/ranlog/error.ts +0 -11
- package/src/ranlog/performance.ts +0 -65
- package/src/ranlog/report.ts +0 -33
- package/src/ranlog/request.ts +0 -60
- package/src/ranlog/utils.ts +0 -92
- package/src/ranpack/ast/Declaration.ts +0 -120
- package/src/ranpack/ast/Node.ts +0 -7
- package/src/ranpack/ast/Reference.ts +0 -32
- package/src/ranpack/ast/Scope.ts +0 -80
- package/src/ranpack/bundle.ts +0 -50
- package/src/ranpack/graph.ts +0 -143
- package/src/ranpack/module.ts +0 -431
- package/src/ranpack/moduleLoader.ts +0 -73
- package/src/ranpack/plugins.ts +0 -70
- package/src/ranpack/statement.ts +0 -66
- package/src/ranpack/utils/buildScope.ts +0 -77
- package/src/ranpack/utils/findReference.ts +0 -36
- package/src/ranpack/utils/isFunctionDeclaration.ts +0 -41
- package/src/ranpack/utils/makeLegalIdentifier.ts +0 -18
- package/src/ranpack/utils/object.ts +0 -8
- package/src/ranpack/utils/resolve.ts +0 -32
- package/src/ranpack/utils/walk.ts +0 -66
- package/src/ranpack/ws.ts +0 -269
- package/src/server/connectType.ts +0 -9
- package/src/server/encodeUrl.ts +0 -46
- package/src/server/escapeHtml.ts +0 -46
- package/src/server/get.ts +0 -36
- package/src/server/jitter.ts +0 -77
- package/src/server/mimeType.ts +0 -858
- package/src/server/paresUrl.ts +0 -40
- package/src/server/send.ts +0 -89
- package/src/server/server.ts +0 -67
- package/src/server/status.ts +0 -191
- package/src/server/traverse.ts +0 -54
- package/src/server/websocket.ts +0 -200
- package/src/sort/bubble.ts +0 -21
- package/src/sort/bucket.ts +0 -11
- package/src/sort/count.ts +0 -10
- package/src/sort/heap.ts +0 -10
- package/src/sort/insert.ts +0 -20
- package/src/sort/merge.ts +0 -35
- package/src/sort/quick.ts +0 -50
- package/src/sort/radix.ts +0 -11
- package/src/sort/randomArray.ts +0 -21
- package/src/sort/select.ts +0 -23
- package/src/sort/shell.ts +0 -22
- package/src/utils/compose.ts +0 -37
- package/src/utils/filterObj.ts +0 -21
- package/src/utils/mergeObj.ts +0 -12
- package/src/utils/startTask.ts +0 -15
- package/src/utils/str2Xml.ts +0 -26
- package/src/utils/taskEnd.ts +0 -14
- package/src/vnode/h.ts +0 -108
- package/src/vnode/hooks.ts +0 -25
- package/src/vnode/htmlDomApi.ts +0 -199
- package/src/vnode/init.ts +0 -429
- package/src/vnode/is.ts +0 -17
- package/src/vnode/modules/attributes.ts +0 -70
- package/src/vnode/modules/class.ts +0 -46
- package/src/vnode/modules/listeners.ts +0 -123
- package/src/vnode/modules/props.ts +0 -41
- package/src/vnode/modules/style.ts +0 -118
- package/src/vnode/vnode.ts +0 -65
package/src/vnode/init.ts
DELETED
|
@@ -1,429 +0,0 @@
|
|
|
1
|
-
// 虚拟dom
|
|
2
|
-
import type { VNode } from './vnode'
|
|
3
|
-
import { vnode } from './vnode'
|
|
4
|
-
// 引入操作的dom api的相关方法
|
|
5
|
-
import type { DOMAPI } from './htmlDomApi'
|
|
6
|
-
import { htmlDomApi } from './htmlDomApi'
|
|
7
|
-
// 类型判断
|
|
8
|
-
import * as is from './is'
|
|
9
|
-
// 导入模块
|
|
10
|
-
import type { ModuleHook } from './modules';
|
|
11
|
-
import { modules } from './modules'
|
|
12
|
-
|
|
13
|
-
type NonUndefined<T> = T extends undefined ? never : T
|
|
14
|
-
|
|
15
|
-
type KeyToIndexMap = { [key: string]: number }
|
|
16
|
-
|
|
17
|
-
interface Cbs {
|
|
18
|
-
[key: string]: ModuleHook[]
|
|
19
|
-
create: Array<ModuleHook>
|
|
20
|
-
update: Array<ModuleHook>
|
|
21
|
-
destroy: Array<(oldVnode: VNode, vnode?: VNode) => void>
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// 如果2个VNode节点的key和sel属性都相同,我们就认为它们是相同的VNode节点
|
|
25
|
-
function sameVnode(vnode1: VNode, vnode2: VNode): boolean {
|
|
26
|
-
return vnode1.key === vnode2.key && vnode1.sel === vnode2.sel
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// 判断是否为Vnode
|
|
30
|
-
function isVnode(vnode: any): vnode is VNode {
|
|
31
|
-
return vnode.sel !== undefined
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// 根据children item的key属性,创建Key Map
|
|
35
|
-
function createKeyToOldIdx(
|
|
36
|
-
children: VNode[],
|
|
37
|
-
beginIdx: number,
|
|
38
|
-
endIdx: number,
|
|
39
|
-
): KeyToIndexMap {
|
|
40
|
-
const map: KeyToIndexMap = {}
|
|
41
|
-
for (let i = beginIdx; i <= endIdx; ++i) {
|
|
42
|
-
const key = children[i]?.key
|
|
43
|
-
if (key !== undefined) {
|
|
44
|
-
map[key] = i
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return map
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// 创建一个空白VNode,用于createElm中触发create钩子函数时调用
|
|
51
|
-
const emptyNode = vnode('', {}, [], undefined, undefined)
|
|
52
|
-
|
|
53
|
-
export function init(): (oldVnode: VNode | Element, vnode: VNode) => VNode {
|
|
54
|
-
// 获取操作html dom的api
|
|
55
|
-
const api: DOMAPI = htmlDomApi
|
|
56
|
-
|
|
57
|
-
// 用于缓存各个模块的钩子函数
|
|
58
|
-
const cbs: Cbs = {
|
|
59
|
-
create: [],
|
|
60
|
-
update: [],
|
|
61
|
-
destroy: [],
|
|
62
|
-
}
|
|
63
|
-
// 遍历cbs
|
|
64
|
-
for (const key of Object.keys(cbs)) {
|
|
65
|
-
// 初始化为数组
|
|
66
|
-
cbs[key] = []
|
|
67
|
-
// 遍历modules
|
|
68
|
-
for (const module of Object.keys(modules)) {
|
|
69
|
-
// 获取模块中对应的生命周期
|
|
70
|
-
const hook = modules[module][key]
|
|
71
|
-
// 如果生命周期有值
|
|
72
|
-
if (hook !== undefined) {
|
|
73
|
-
// 将其加入cbs对应的属性中
|
|
74
|
-
cbs[key].push(hook)
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// 创建一个只有标签名和选择器的空白VNode
|
|
80
|
-
function emptyNodeAt(elm: Element) {
|
|
81
|
-
const id = elm.id ? '#' + elm.id : ''
|
|
82
|
-
const c = elm.className ? '.' + elm.className.split(' ').join('.') : ''
|
|
83
|
-
return vnode(
|
|
84
|
-
api.tagName(elm).toLowerCase() + id + c,
|
|
85
|
-
{},
|
|
86
|
-
[],
|
|
87
|
-
undefined,
|
|
88
|
-
elm,
|
|
89
|
-
)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// 判断是否为undefined
|
|
93
|
-
function isUndef(s: unknown): boolean {
|
|
94
|
-
return s === undefined
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// 判断是否为defined
|
|
98
|
-
function isDef<A>(s: A): s is NonUndefined<A> {
|
|
99
|
-
return s !== undefined
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// 根据VNode创建dom
|
|
103
|
-
function createElm(vnode: VNode): Node {
|
|
104
|
-
// 缓存循环children中的index
|
|
105
|
-
let i: number
|
|
106
|
-
// 缓存VNode的children
|
|
107
|
-
const children = vnode.children
|
|
108
|
-
// 缓存VNode的选择器
|
|
109
|
-
const sel = vnode.sel
|
|
110
|
-
// 把 vnode 转化成真实DOM对象(没有渲染到页面)
|
|
111
|
-
if (sel === '!') {
|
|
112
|
-
// 如果选择器是!,创建注释节点
|
|
113
|
-
if (isUndef(vnode.text)) {
|
|
114
|
-
vnode.text = ''
|
|
115
|
-
}
|
|
116
|
-
vnode.elm = api.createComment(`${vnode.text!}`)
|
|
117
|
-
} else if (sel !== undefined) {
|
|
118
|
-
// 如果选择器不为空,解析选择器
|
|
119
|
-
// 缓存id
|
|
120
|
-
const hashIdx = sel.indexOf('#')
|
|
121
|
-
// 缓存class
|
|
122
|
-
const dotIdx = sel.indexOf('.', hashIdx)
|
|
123
|
-
// 缓存 # 的位置
|
|
124
|
-
const hash = hashIdx > 0 ? hashIdx : sel.length
|
|
125
|
-
// 缓存 . 的位置
|
|
126
|
-
const dot = dotIdx > 0 ? dotIdx : sel.length
|
|
127
|
-
// 缓存标签
|
|
128
|
-
const tag =
|
|
129
|
-
hashIdx !== -1 || dotIdx !== -1
|
|
130
|
-
? sel.slice(0, Math.min(hash, dot))
|
|
131
|
-
: sel
|
|
132
|
-
// 创建dom
|
|
133
|
-
const elm = (vnode.elm = api.createElement(tag))
|
|
134
|
-
// dom设置id
|
|
135
|
-
if (hash < dot) elm.setAttribute('id', sel.slice(hash + 1, dot))
|
|
136
|
-
// dom设置class
|
|
137
|
-
if (dotIdx > 0)
|
|
138
|
-
elm.setAttribute('class', sel.slice(dot + 1).replace(/\./g, ' '))
|
|
139
|
-
// 触发各个模块的create钩子函数
|
|
140
|
-
for (i = 0; i < cbs.create.length; ++i) {
|
|
141
|
-
cbs.create[i](emptyNode, vnode)
|
|
142
|
-
}
|
|
143
|
-
// 如果vnode中有子节点,创建子vnode对应的DOM元素并追加到DOM树上
|
|
144
|
-
if (is.array(children)) {
|
|
145
|
-
for (i = 0; i < children.length; ++i) {
|
|
146
|
-
const ch = children[i]
|
|
147
|
-
if (ch != null) {
|
|
148
|
-
api.appendChild(elm, createElm(ch as VNode))
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
} else if (is.primitive(vnode.text)) {
|
|
152
|
-
// 如果有子文本节点,也创建并追加到DOM树上
|
|
153
|
-
api.appendChild(elm, api.createTextNode(`${vnode.text!}`))
|
|
154
|
-
}
|
|
155
|
-
} else {
|
|
156
|
-
// 如果选择器为空,创建文本节点
|
|
157
|
-
vnode.elm = api.createTextNode(`${vnode.text!}`)
|
|
158
|
-
}
|
|
159
|
-
// 返回新创建的DOM
|
|
160
|
-
return vnode.elm
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// 根据VNode新增dom
|
|
164
|
-
function addVnodes(
|
|
165
|
-
parentElm: Node,
|
|
166
|
-
before: Node | null,
|
|
167
|
-
vnodes: VNode[],
|
|
168
|
-
startIdx: number,
|
|
169
|
-
endIdx: number,
|
|
170
|
-
) {
|
|
171
|
-
// 遍历传入的VNode数组,创建对应的dom,再将dom插入到指定的dom元素之前
|
|
172
|
-
for (; startIdx <= endIdx; ++startIdx) {
|
|
173
|
-
const ch = vnodes[startIdx]
|
|
174
|
-
if (ch != null) {
|
|
175
|
-
api.insertBefore(parentElm, createElm(ch), before)
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// 触发destroy钩子函数
|
|
181
|
-
function invokeDestroyHook(vnode: VNode) {
|
|
182
|
-
// 获取VNode的data属性
|
|
183
|
-
const data = vnode.data
|
|
184
|
-
// 当data不为空时
|
|
185
|
-
if (data !== undefined) {
|
|
186
|
-
// 触发各个模块的destroy钩子函数
|
|
187
|
-
for (let i = 0; i < cbs.destroy.length; ++i) cbs.destroy[i](vnode)
|
|
188
|
-
// 当VNode有子节点,且子节点不为字符串或数字,触发子节点VNode的destroy钩子函数
|
|
189
|
-
if (vnode.children !== undefined) {
|
|
190
|
-
for (let j = 0; j < vnode.children.length; ++j) {
|
|
191
|
-
const child = vnode.children[j]
|
|
192
|
-
if (
|
|
193
|
-
child != null &&
|
|
194
|
-
typeof child !== 'string' &&
|
|
195
|
-
typeof child !== 'number'
|
|
196
|
-
) {
|
|
197
|
-
invokeDestroyHook(child)
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// 创建删除子节点dom的方法
|
|
205
|
-
function createRmCb(childElm: Node) {
|
|
206
|
-
return function rmCb() {
|
|
207
|
-
// 这里是一个闭包将需要删除的dom节点缓存起来,方便之后调用rmCb方法删除
|
|
208
|
-
const parent = api.parentNode(childElm) as Node
|
|
209
|
-
api.removeChild(parent, childElm)
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// 删除VNode对应dom
|
|
214
|
-
function removeVnodes(
|
|
215
|
-
parentElm: Node,
|
|
216
|
-
vnodes: VNode[],
|
|
217
|
-
startIdx: number,
|
|
218
|
-
endIdx: number,
|
|
219
|
-
): void {
|
|
220
|
-
for (; startIdx <= endIdx; ++startIdx) {
|
|
221
|
-
// 用于缓存删除dom的方法
|
|
222
|
-
let rm: () => void
|
|
223
|
-
// 获取当前要删除节点
|
|
224
|
-
const ch = vnodes[startIdx]
|
|
225
|
-
if (ch != null) {
|
|
226
|
-
if (isDef(ch.sel)) {
|
|
227
|
-
// 触发destroy钩子函数
|
|
228
|
-
invokeDestroyHook(ch)
|
|
229
|
-
/*
|
|
230
|
-
* 在dom中这里需要判断remove钩子函数是否全部调用,而我们dom没有remove钩子函数,所以
|
|
231
|
-
* 不需要判断
|
|
232
|
-
*/
|
|
233
|
-
rm = createRmCb(ch.elm!)
|
|
234
|
-
// 删除子节点
|
|
235
|
-
rm()
|
|
236
|
-
} else {
|
|
237
|
-
// 删除文本节点
|
|
238
|
-
api.removeChild(parentElm, ch.elm!)
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// 更新children
|
|
245
|
-
function updateChildren(parentElm: Node, oldCh: VNode[], newCh: VNode[]) {
|
|
246
|
-
// 旧VNode的children头索引
|
|
247
|
-
let oldStartIdx = 0
|
|
248
|
-
// 新VNode的children头索引
|
|
249
|
-
let newStartIdx = 0
|
|
250
|
-
// 旧VNode的children尾索引
|
|
251
|
-
let oldEndIdx = oldCh.length - 1
|
|
252
|
-
// 新VNode的children尾索引
|
|
253
|
-
let newEndIdx = newCh.length - 1
|
|
254
|
-
// 旧VNode的children的头VNode
|
|
255
|
-
let oldStartVnode = oldCh[0]
|
|
256
|
-
// 旧VNode的children的尾VNode
|
|
257
|
-
let oldEndVnode = oldCh[oldEndIdx]
|
|
258
|
-
// 新VNode的children的头VNode
|
|
259
|
-
let newStartVnode = newCh[0]
|
|
260
|
-
// 新VNode的children的尾VNode
|
|
261
|
-
let newEndVnode = newCh[newEndIdx]
|
|
262
|
-
// 旧VNode的children的Key Map
|
|
263
|
-
let oldKeyToIdx: KeyToIndexMap | undefined
|
|
264
|
-
// 用于缓存key相同的新旧VNode
|
|
265
|
-
let idxInOld: number
|
|
266
|
-
// 用于缓存将要移动的旧VNode
|
|
267
|
-
let elmToMove: VNode
|
|
268
|
-
// 用于缓存将要插入新增VNode的位置之前的VNode
|
|
269
|
-
let before: any
|
|
270
|
-
|
|
271
|
-
// 遍历新旧children数组,直到其中之一遍历完
|
|
272
|
-
while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
|
|
273
|
-
// 我们之后可能会对oldStartVnode、oldEndVnode、newStartVnode、newEndVnode重新赋值,可能会出现等于null的情况
|
|
274
|
-
if (oldStartVnode == null) {
|
|
275
|
-
oldStartVnode = oldCh[++oldStartIdx]
|
|
276
|
-
} else if (oldEndVnode == null) {
|
|
277
|
-
oldEndVnode = oldCh[--oldEndIdx]
|
|
278
|
-
} else if (newStartVnode == null) {
|
|
279
|
-
newStartVnode = newCh[++newStartIdx]
|
|
280
|
-
} else if (newEndVnode == null) {
|
|
281
|
-
newEndVnode = newCh[--newEndIdx]
|
|
282
|
-
// key 和 sel 相同,则就是相同节点
|
|
283
|
-
} else if (sameVnode(oldStartVnode, newStartVnode)) {
|
|
284
|
-
// 当旧头VNode和新头VNode是相同VNode时,将新头VNode差异更新到旧头VNode上,同时将新旧头索引后移
|
|
285
|
-
// 对比两个节点,如果newVnode有vnodeData,
|
|
286
|
-
// 执行update钩子,更新oldNode上的模块的内容
|
|
287
|
-
// 更新加载过的模块里的内容
|
|
288
|
-
// 判断节点的类型,文本节点直接替换,如果不是文本节点
|
|
289
|
-
// 判断是否有子元素,更新子元素
|
|
290
|
-
patchVnode(oldStartVnode, newStartVnode)
|
|
291
|
-
oldStartVnode = oldCh[++oldStartIdx]
|
|
292
|
-
newStartVnode = newCh[++newStartIdx]
|
|
293
|
-
} else if (sameVnode(oldEndVnode, newEndVnode)) {
|
|
294
|
-
// 当旧尾VNode和新尾VNode是相同VNode时,将新尾VNode差异更新到旧尾VNode上,同时将新旧尾索引前移
|
|
295
|
-
patchVnode(oldEndVnode, newEndVnode)
|
|
296
|
-
oldEndVnode = oldCh[--oldEndIdx]
|
|
297
|
-
newEndVnode = newCh[--newEndIdx]
|
|
298
|
-
} else if (sameVnode(oldStartVnode, newEndVnode)) {
|
|
299
|
-
/**
|
|
300
|
-
* 当旧头VNode和新尾VNode是相同节点时,将新尾VNode差异更新到旧头VNode上,然后将旧头VNode插入到旧尾VNode后
|
|
301
|
-
* 最后将旧头索引后移,新尾索引前移
|
|
302
|
-
*/
|
|
303
|
-
patchVnode(oldStartVnode, newEndVnode)
|
|
304
|
-
api.insertBefore(parentElm,oldStartVnode.elm!,api.nextSibling(oldEndVnode.elm!))
|
|
305
|
-
oldStartVnode = oldCh[++oldStartIdx]
|
|
306
|
-
newEndVnode = newCh[--newEndIdx]
|
|
307
|
-
} else if (sameVnode(oldEndVnode, newStartVnode)) {
|
|
308
|
-
/**
|
|
309
|
-
* 当旧尾VNode和新头VNode是相同节点时,将新头VNode差异更新到旧尾VNode上,然后将旧尾VNode插入到旧头VNode前
|
|
310
|
-
* 最后将旧尾索引前移,新头索引后移
|
|
311
|
-
*/
|
|
312
|
-
patchVnode(oldEndVnode, newStartVnode)
|
|
313
|
-
api.insertBefore(parentElm, oldEndVnode.elm!, oldStartVnode.elm!)
|
|
314
|
-
oldEndVnode = oldCh[--oldEndIdx]
|
|
315
|
-
newStartVnode = newCh[++newStartIdx]
|
|
316
|
-
} else {
|
|
317
|
-
// 如果没有Key Map则创建Key Map,用于根据key来更新VNode
|
|
318
|
-
if (oldKeyToIdx === undefined) {
|
|
319
|
-
oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
|
|
320
|
-
}
|
|
321
|
-
// 根据Key Map获取当前新头VNode的对应的旧VNode的index
|
|
322
|
-
idxInOld = oldKeyToIdx[newStartVnode.key as string]
|
|
323
|
-
|
|
324
|
-
if (isUndef(idxInOld)) {
|
|
325
|
-
// 如果没有设置key属性,直接根据新头VNode创建dom元素,插入到旧头VNode对应dom之前
|
|
326
|
-
api.insertBefore(
|
|
327
|
-
parentElm,
|
|
328
|
-
createElm(newStartVnode),
|
|
329
|
-
oldStartVnode.elm!,
|
|
330
|
-
)
|
|
331
|
-
} else {
|
|
332
|
-
// 如果设置key属性,获取到key对应的旧VNode
|
|
333
|
-
elmToMove = oldCh[idxInOld]
|
|
334
|
-
if (elmToMove.sel !== newStartVnode.sel) {
|
|
335
|
-
// 如果旧VNode和新VNode的sel属性不同,则直接创建新VNode对应的dom,插入到旧头VNode对应dom之前
|
|
336
|
-
api.insertBefore(
|
|
337
|
-
parentElm,
|
|
338
|
-
createElm(newStartVnode),
|
|
339
|
-
oldStartVnode.elm!,
|
|
340
|
-
)
|
|
341
|
-
} else {
|
|
342
|
-
// 如果sel属性相同,则将新VNode数据更新到旧VNode上
|
|
343
|
-
patchVnode(elmToMove, newStartVnode)
|
|
344
|
-
// 删除旧children对应的VNode,代表已经更新过
|
|
345
|
-
oldCh[idxInOld] = undefined as any
|
|
346
|
-
// 创建VNode对应的dom,插入到旧头VNode对应dom之前
|
|
347
|
-
api.insertBefore(parentElm, elmToMove.elm!, oldStartVnode.elm!)
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
// 将新头VNode设置为新children数组中新头索引后一位
|
|
351
|
-
newStartVnode = newCh[++newStartIdx]
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
// 循环完成后,当旧头索引小于等于旧尾索引,或新头索引大于等于新尾索引时,说明新旧children其中之一已经遍历完成
|
|
355
|
-
if (oldStartIdx <= oldEndIdx || newStartIdx <= newEndIdx) {
|
|
356
|
-
// 如果存在旧头索引大于旧尾索引情况,说明新children中新增了VNode
|
|
357
|
-
if (oldStartIdx > oldEndIdx) {
|
|
358
|
-
// 获取新增VNode后一位的VNode对应的dom
|
|
359
|
-
before = newCh[newEndIdx + 1] == null ? null : newCh[newEndIdx + 1].elm
|
|
360
|
-
// 将新增VNode对应dom插入对应dom树位置
|
|
361
|
-
addVnodes(parentElm, before, newCh, newStartIdx, newEndIdx)
|
|
362
|
-
} else {
|
|
363
|
-
// 删除多余dom节点
|
|
364
|
-
removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx)
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
// 对比新旧vnode差异,将差异更新到旧VNode上。
|
|
370
|
-
function patchVnode(oldVnode: VNode, vnode: VNode) {
|
|
371
|
-
// 当VNode的data属性存在时,触发update钩子函数
|
|
372
|
-
if (vnode.data !== undefined) {
|
|
373
|
-
for (let i = 0; i < cbs.update.length; ++i) {
|
|
374
|
-
cbs.update[i](oldVnode, vnode)
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// 由于是相同的VNode节点,使用新旧VNode的真实dom元素相同
|
|
379
|
-
const elm = (vnode.elm = oldVnode.elm!)
|
|
380
|
-
// 获取旧VNode的children
|
|
381
|
-
const oldCh = oldVnode.children as VNode[]
|
|
382
|
-
// 获取新VNode的children
|
|
383
|
-
const ch = vnode.children as VNode[]
|
|
384
|
-
|
|
385
|
-
// 如果新旧节点完全相同,直接返回
|
|
386
|
-
if (oldVnode === vnode) return
|
|
387
|
-
// 判断VNode是否为文本节点
|
|
388
|
-
if (isUndef(vnode.text)) {
|
|
389
|
-
// 如果不是文本节点,判断新旧VNode是否同时有children
|
|
390
|
-
if (isDef(oldCh) && isDef(ch)) {
|
|
391
|
-
// 如果同时有children属性,且children属性不相同就更新children
|
|
392
|
-
if (oldCh !== ch) {
|
|
393
|
-
updateChildren(elm, oldCh, ch)
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
return function patch(oldVnode: VNode | Element, vnode: VNode): VNode {
|
|
400
|
-
// 缓存dom节点和父dom节点
|
|
401
|
-
let elm: Node, parent: Node
|
|
402
|
-
|
|
403
|
-
// 当oldVnode不是VNode时,说明是初次加载,创建一个空白VNode
|
|
404
|
-
if (!isVnode(oldVnode)) {
|
|
405
|
-
oldVnode = emptyNodeAt(oldVnode)
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
// 判断是否为相同VNode节点
|
|
409
|
-
if (sameVnode(oldVnode, vnode)) {
|
|
410
|
-
// 更新VNode节点差异
|
|
411
|
-
patchVnode(oldVnode, vnode)
|
|
412
|
-
} else {
|
|
413
|
-
// 获取旧VNode的dom
|
|
414
|
-
elm = oldVnode.elm!
|
|
415
|
-
// 获取父节点dom
|
|
416
|
-
parent = api.parentNode(elm) as Node
|
|
417
|
-
// 创建dom元素
|
|
418
|
-
createElm(vnode)
|
|
419
|
-
// 当父节点不为空时
|
|
420
|
-
if (parent != null) {
|
|
421
|
-
// 将新创建的dom插入dom树
|
|
422
|
-
api.insertBefore(parent, vnode.elm!, api.nextSibling(elm))
|
|
423
|
-
// 删除旧VNode节点
|
|
424
|
-
removeVnodes(parent, [oldVnode], 0, 0)
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
return vnode
|
|
428
|
-
}
|
|
429
|
-
}
|
package/src/vnode/is.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { VNode } from './vnode'
|
|
2
|
-
|
|
3
|
-
// 判断是否为数组
|
|
4
|
-
export const array = Array.isArray
|
|
5
|
-
|
|
6
|
-
export const isStr = (str: unknown): str is string => {
|
|
7
|
-
return typeof str === 'string'
|
|
8
|
-
}
|
|
9
|
-
// 判断是否为字符串或数字
|
|
10
|
-
export function primitive(s: unknown): s is string | number {
|
|
11
|
-
return typeof s === 'string' || typeof s === 'number'
|
|
12
|
-
}
|
|
13
|
-
// 判断是否为vnode
|
|
14
|
-
export function isVnode(s: any): s is VNode {
|
|
15
|
-
return !!s?.sel
|
|
16
|
-
}
|
|
17
|
-
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import type { VNode, VNodeData } from '../vnode'
|
|
2
|
-
|
|
3
|
-
export type Attrs = Record<string, string | number | boolean>
|
|
4
|
-
|
|
5
|
-
const xlinkNS = 'http://www.w3.org/1999/xlink'
|
|
6
|
-
const xmlNS = 'http://www.w3.org/XML/1998/namespace'
|
|
7
|
-
const colonChar = 58
|
|
8
|
-
const xChar = 120
|
|
9
|
-
|
|
10
|
-
function updateAttrs(oldVnode: VNode, vnode: VNode): void {
|
|
11
|
-
// 用于缓存attrs的name
|
|
12
|
-
let key: string
|
|
13
|
-
// 用于缓存Vnode的dom
|
|
14
|
-
const elm: Element = vnode.elm as Element
|
|
15
|
-
// 用于缓存旧VNode的attrs
|
|
16
|
-
let oldAttrs = oldVnode.data && oldVnode.data.attrs
|
|
17
|
-
// 用于缓存新VNode的attrs
|
|
18
|
-
let attrs = vnode.data && vnode.data.attrs
|
|
19
|
-
|
|
20
|
-
// 如果新旧VNode都没有attrs属性,直接返回
|
|
21
|
-
if (!oldAttrs && !attrs) return
|
|
22
|
-
// 如果新旧VNode的attrs属性相同,直接返回
|
|
23
|
-
if (oldAttrs === attrs) return
|
|
24
|
-
// 如果旧VNode没有attrs,将其设置为空对象
|
|
25
|
-
oldAttrs = oldAttrs || {}
|
|
26
|
-
// 如果新VNode没有attrs,将其设置为空对象
|
|
27
|
-
attrs = attrs || {}
|
|
28
|
-
|
|
29
|
-
// 遍历新VNode的attrs
|
|
30
|
-
for (key in attrs) {
|
|
31
|
-
// 获取当前attrs的值
|
|
32
|
-
const cur = attrs[key]
|
|
33
|
-
// 获取旧VNode对应的attrs的值
|
|
34
|
-
const old = oldAttrs[key]
|
|
35
|
-
// 如果新旧VNode的attrs值不相同
|
|
36
|
-
if (old !== cur) {
|
|
37
|
-
// 如果新VNode的attrs值为true
|
|
38
|
-
if (cur === true) {
|
|
39
|
-
// 通过setAttribute设置为空字符串
|
|
40
|
-
elm.setAttribute(key, '')
|
|
41
|
-
} else if (cur === false) {
|
|
42
|
-
// 如果新VNode的attrs值为false,则删除key
|
|
43
|
-
elm.removeAttribute(key)
|
|
44
|
-
} else {
|
|
45
|
-
// 设置svg的属性
|
|
46
|
-
if (key.charCodeAt(0) !== xChar) {
|
|
47
|
-
elm.setAttribute(key, cur as any)
|
|
48
|
-
} else if (key.charCodeAt(3) === colonChar) {
|
|
49
|
-
// Assume xml namespace
|
|
50
|
-
elm.setAttributeNS(xmlNS, key, cur as any)
|
|
51
|
-
} else if (key.charCodeAt(5) === colonChar) {
|
|
52
|
-
// Assume xlink namespace
|
|
53
|
-
elm.setAttributeNS(xlinkNS, key, cur as any)
|
|
54
|
-
} else {
|
|
55
|
-
// 通过setAttribute设置值
|
|
56
|
-
elm.setAttribute(key, `${cur}`)
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
// 遍历旧VNode的attrs
|
|
62
|
-
for (key in oldAttrs) {
|
|
63
|
-
// 如果新VNode的attrs中没有相同的key,则直接删除该attrs属性
|
|
64
|
-
if (!(key in attrs)) {
|
|
65
|
-
elm.removeAttribute(key)
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export const attributesModule = { create: updateAttrs, update: updateAttrs }
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import type { VNode, VNodeData } from '../vnode'
|
|
2
|
-
|
|
3
|
-
export type Classes = Record<string, boolean>
|
|
4
|
-
|
|
5
|
-
function updateClass(oldVnode: VNode, vnode: VNode): void {
|
|
6
|
-
// 用于缓存遍历中当前class属性的值
|
|
7
|
-
let cur: any
|
|
8
|
-
// 用于缓存遍历中当前class的name
|
|
9
|
-
let name: string
|
|
10
|
-
// 获取新VNode的dom元素
|
|
11
|
-
const elm: Element = vnode.elm as Element
|
|
12
|
-
// 获取旧VNode的class数据
|
|
13
|
-
let oldClass = oldVnode.data && oldVnode.data.class
|
|
14
|
-
// 获取新VNode的class数据
|
|
15
|
-
let className = vnode.data && vnode.data.class
|
|
16
|
-
|
|
17
|
-
// 如果新旧VNode都没有class,直接返回
|
|
18
|
-
if (!oldClass && !className) return
|
|
19
|
-
// 如果新旧VNode完全相同,直接返回
|
|
20
|
-
if (oldClass === className) return
|
|
21
|
-
// 如果旧VNode没有class,将其设置为空对象
|
|
22
|
-
oldClass = oldClass || {}
|
|
23
|
-
// 如果新VNode没有class,将其设置为空对象
|
|
24
|
-
className = className || {}
|
|
25
|
-
|
|
26
|
-
// 遍历旧VNode的class
|
|
27
|
-
for (name in oldClass) {
|
|
28
|
-
// 如果当前class旧VNode上有但新VNode没有,则删除该VNode
|
|
29
|
-
if (
|
|
30
|
-
oldClass[name] &&
|
|
31
|
-
!Object.prototype.hasOwnProperty.call(className, name)
|
|
32
|
-
) {
|
|
33
|
-
elm.classList.remove(name)
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
// 遍历新Vnodde的class
|
|
37
|
-
for (name in className) {
|
|
38
|
-
// 如果新旧VNode的class值不同,则根据新VNode的class值是true or false来判断是新增还是删除class
|
|
39
|
-
cur = className[name]
|
|
40
|
-
if (cur !== oldClass[name]) {
|
|
41
|
-
(elm.classList as any)[cur ? 'add' : 'remove'](name)
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export const classModule = { create: updateClass, update: updateClass }
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import type { VNode, VNodeData } from '../vnode'
|
|
2
|
-
|
|
3
|
-
const isFunction = (handler: unknown): handler is Function => {
|
|
4
|
-
return typeof handler === 'function'
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
type Listener<T> = (this: VNode, ev: T, vnode: VNode) => void
|
|
8
|
-
|
|
9
|
-
export type On = {
|
|
10
|
-
[N in keyof HTMLElementEventMap]?:
|
|
11
|
-
| Listener<HTMLElementEventMap[N]>
|
|
12
|
-
| Array<Listener<HTMLElementEventMap[N]>>
|
|
13
|
-
} & {
|
|
14
|
-
[event: string]: Listener<any> | Array<Listener<any>>
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
type SomeListener<N extends keyof HTMLElementEventMap> =
|
|
18
|
-
| Listener<HTMLElementEventMap[N]>
|
|
19
|
-
| Listener<any>
|
|
20
|
-
|
|
21
|
-
function invokeHandler<N extends keyof HTMLElementEventMap>(
|
|
22
|
-
handler: SomeListener<N> | Array<SomeListener<N>>,
|
|
23
|
-
vnode: VNode,
|
|
24
|
-
event?: Event,
|
|
25
|
-
): void {
|
|
26
|
-
if (isFunction(handler)) {
|
|
27
|
-
// 如果类型是function,说明只有一个事件监听,将this指向vnode调用
|
|
28
|
-
(handler as Function).call(vnode, event, vnode)
|
|
29
|
-
} else if (typeof handler === 'object') {
|
|
30
|
-
// 如果类型是对象,说明有多个事件监听,遍历依次调用
|
|
31
|
-
for (let i = 0; i < handler.length; i++) {
|
|
32
|
-
invokeHandler(handler[i], vnode, event)
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function handleEvent(event: Event, vnode: VNode) {
|
|
38
|
-
const name = event.type
|
|
39
|
-
const on = vnode.data && vnode.data.on
|
|
40
|
-
|
|
41
|
-
// 如果on中存在事件监听,则进行运行
|
|
42
|
-
if (on && on[name]) {
|
|
43
|
-
invokeHandler(on[name], vnode, event)
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// 创建一个事件监听的闭包,这样可以确保每次创建的都是一个独立的事件监听
|
|
48
|
-
function createListener() {
|
|
49
|
-
return function handler(event: Event) {
|
|
50
|
-
handleEvent(event, (handler as any).vnode)
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function updateEventListeners(oldVnode: VNode, vnode?: VNode): void {
|
|
55
|
-
// 获取旧VNode中监听的事件
|
|
56
|
-
const oldOn = oldVnode?.data?.on
|
|
57
|
-
// 获取旧VNode中已经创建的监听事件
|
|
58
|
-
const oldListener = oldVnode?.listener
|
|
59
|
-
// 获取旧VNode的dom
|
|
60
|
-
const oldElm: Element = oldVnode.elm as Element
|
|
61
|
-
// 获取新VNode中监听的事件
|
|
62
|
-
const on = vnode?.data?.on
|
|
63
|
-
// 获取新VNode中已经创建的监听事件
|
|
64
|
-
const elm: Element = (vnode && vnode.elm) as Element
|
|
65
|
-
// 缓存遍历中当前事件的名称
|
|
66
|
-
let name: string
|
|
67
|
-
|
|
68
|
-
// 如果新旧VNode监听事件完全一样,直接返回
|
|
69
|
-
if (oldOn === on) {
|
|
70
|
-
return
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// 如果旧VNode中有已经创建的事件监听
|
|
74
|
-
if (oldOn && oldListener) {
|
|
75
|
-
// 如果新VNode中没有事件监听
|
|
76
|
-
if (!on) {
|
|
77
|
-
for (name in oldOn) {
|
|
78
|
-
// 删除旧VNode中的事件监听
|
|
79
|
-
oldElm.removeEventListener(name, oldListener, false)
|
|
80
|
-
}
|
|
81
|
-
} else {
|
|
82
|
-
// 如果新VNode中有事件监听,则遍历旧VNode
|
|
83
|
-
for (name in oldOn) {
|
|
84
|
-
// 如果新VNode中没有当前的事件监听,则删除该事件监听
|
|
85
|
-
if (!on[name]) {
|
|
86
|
-
oldElm.removeEventListener(name, oldListener, false)
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// 如果新VNode有事件监听
|
|
93
|
-
if (on) {
|
|
94
|
-
// 如果新VNode上已经存在事件监听,则直接继承,如果没有则创建一个新事件监听
|
|
95
|
-
const listener = vnode.listener = oldVnode.listener || createListener()
|
|
96
|
-
// 更新listener上的vnode
|
|
97
|
-
// listener.vnode = vnode
|
|
98
|
-
|
|
99
|
-
// 如果旧VNode没有事件监听
|
|
100
|
-
if (!oldOn) {
|
|
101
|
-
// 遍历新VNode上的事件监听
|
|
102
|
-
for (name in on) {
|
|
103
|
-
// 将其添加到dom上
|
|
104
|
-
elm.addEventListener(name, listener, false)
|
|
105
|
-
}
|
|
106
|
-
} else {
|
|
107
|
-
// 如果旧VNode有事件监听
|
|
108
|
-
// 遍历新VNode上的事件监听
|
|
109
|
-
for (name in on) {
|
|
110
|
-
// 将旧VNode上没有的事件监听添加到dom上
|
|
111
|
-
if (!oldOn[name]) {
|
|
112
|
-
elm.addEventListener(name, listener, false)
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export const eventListenersModule = {
|
|
120
|
-
create: updateEventListeners,
|
|
121
|
-
update: updateEventListeners,
|
|
122
|
-
destroy: updateEventListeners,
|
|
123
|
-
}
|