Skip to content

Commit dcfced3

Browse files
committed
feat: 26-为什么只能有一个根元素
1 parent 3a450c4 commit dcfced3

File tree

3 files changed

+117
-1
lines changed

3 files changed

+117
-1
lines changed

public/17-only-one-root/README.md

+83-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,83 @@
1-
## Vue组件为什么只能有一个根元素?
1+
## ## Vue组件为什么只能有一个根元素?
2+
3+
这题现在有些落伍,`vue3`已经不用一个根了。因此这题目很有说头!
4+
5+
---
6+
7+
### 体验一下
8+
9+
vue2直接报错,test-v2.html
10+
11+
```js
12+
new Vue({
13+
components: {
14+
comp: {
15+
template: `
16+
<div>root1</div>
17+
<div>root2</div>
18+
`
19+
}
20+
}
21+
}).$mount('#app')
22+
```
23+
24+
<img src="https://tva1.sinaimg.cn/large/e6c9d24egy1h2tpywiwwkj20ws0hm0va.jpg" style="zoom:33%;" />
25+
26+
---
27+
28+
vue3中没有问题,test-v3.html
29+
30+
```js
31+
Vue.createApp({
32+
components: {
33+
comp: {
34+
template: `
35+
<div>root1</div>
36+
<div>root2</div>
37+
`
38+
}
39+
}
40+
}).mount('#app')
41+
```
42+
43+
<img src="https://tva1.sinaimg.cn/large/e6c9d24egy1h2tq28fsfoj20xu0biq3x.jpg" style="zoom:33%;" />
44+
45+
---
46+
47+
### 回答思路
48+
49+
- 给一条自己的结论
50+
- 解释为什么会这样
51+
- `vue3`解决方法原理
52+
53+
---
54+
55+
### 范例
56+
57+
- `vue2`中组件确实只能有一个根,但`vue3`中组件已经可以多根节点了。
58+
- 之所以需要这样是因为`vdom`是一颗单根树形结构,`patch`方法在遍历的时候从根节点开始遍历,它要求只有一个根节点。组件也会转换为一个`vdom`,自然应该满足这个要求。
59+
- `vue3`中之所以可以写多个根节点,是因为引入了`Fragment`的概念,这是一个抽象的节点,如果发现组件是多根的,就创建一个Fragment节点,把多个根节点作为它的children。将来patch的时候,如果发现是一个Fragment节点,则直接遍历children创建或更新。
60+
61+
---
62+
63+
### 知其所以然
64+
65+
- patch方法接收单根vdom:
66+
67+
https://github1s.com/vuejs/core/blob/HEAD/packages/runtime-core/src/renderer.ts#L354-L355
68+
69+
```ts
70+
// 直接获取type等,没有考虑数组的可能性
71+
const { type, ref, shapeFlag } = n2
72+
```
73+
74+
- patch方法对Fragment的处理:
75+
76+
https://github1s.com/vuejs/core/blob/HEAD/packages/runtime-core/src/renderer.ts#L1091-L1092
77+
78+
```ts
79+
// a fragment can only have array children
80+
// since they are either generated by the compiler, or implicitly created
81+
// from arrays.
82+
mountChildren(n2.children as VNodeArrayChildren, container, ...)
83+
```

public/17-only-one-root/test-v2.html

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<div id="app">
2+
<comp></comp>
3+
</div>
4+
5+
<script src="http://unpkg.com/vue@2"></script>
6+
<script>
7+
new Vue({
8+
components: {
9+
comp: {
10+
template: `
11+
<div>root1</div>
12+
<div>root2</div>
13+
`
14+
}
15+
}
16+
}).$mount('#app')
17+
</script>

public/17-only-one-root/test-v3.html

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<div id="app">
2+
<comp></comp>
3+
</div>
4+
5+
<script src="http://unpkg.com/vue@3"></script>
6+
<script>
7+
Vue.createApp({
8+
components: {
9+
comp: {
10+
template: `
11+
<div>root1</div>
12+
<div>root2</div>
13+
`
14+
}
15+
}
16+
}).mount('#app')
17+
</script>

0 commit comments

Comments
 (0)