File tree 3 files changed +117
-1
lines changed
3 files changed +117
-1
lines changed Original file line number Diff line number Diff line change 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
+ ```
Original file line number Diff line number Diff line change
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 >
Original file line number Diff line number Diff line change
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 >
You can’t perform that action at this time.
0 commit comments