一個(gè) Vue 模板可以有多個(gè)根節(jié)點(diǎn)(Fragments)?
如果我們?cè)噲D創(chuàng)建一個(gè)沒(méi)有根節(jié)點(diǎn)的Vue模板,比如這樣:
- <template>
- <div>Node 1</div>
- <div>Node 2</div>
- </template>
我們就會(huì)收到編譯或運(yùn)行時(shí)錯(cuò)誤,因?yàn)槟0灞仨毦哂袉蝹€(gè)根元素。
通常,我們通過(guò)在最外層包裹一層 div 來(lái)解決這個(gè)問(wèn)題,但這個(gè)div元素一般沒(méi)有啥使用,就是讓模板符合單根需求。
- <template>
- <div><!--只是來(lái)包裝一下-->
- <div>Node 1</div>
- <div>Node 2</div>
- </div>
- </template>
這樣的方式通常問(wèn)題不在,但是在某些情況下,擁有多根模板是必要的。在本文中,我們來(lái)探討一下何時(shí)需要以及如何解決多根的問(wèn)題。
渲染數(shù)組
某些情況下,可能需要組件渲染子節(jié)點(diǎn)數(shù)組以包含在父組件中。
例如,一些CSS特性需要非常特殊的元素層次結(jié)構(gòu)才能正確工作,比如CSS grid或flex,不能在父元素和子元素之間使用包裝器。
還有一個(gè)問(wèn)題,在組件中添加包裝元素可能會(huì)導(dǎo)致渲染無(wú)效的HTML。例如,如果要構(gòu)建table,則表行必須僅具有用于子項(xiàng)的表單元格。
簡(jiǎn)而言之,單根需求意味著在Vue中將無(wú)法返回子元素的組件的設(shè)計(jì)模式。
Fragments
這個(gè)單根限制對(duì)于React也是一個(gè)問(wèn)題,但是它在版本16中提供了一個(gè)稱為[fragments][1]的功能。要使用它,只需要將多根模板包裝在特殊的React.Fragment元素中:
這將使子組件沒(méi)有多余包裝,還有一個(gè)簡(jiǎn)潔的短語(yǔ)法<>:
Vue中的 Fragments
那么 Vue 是否也會(huì)引入 fragments?這可能不會(huì)很快,原因是虛擬DOM差異算法依賴于具有單個(gè)根的組件。根據(jù)Vue貢獻(xiàn)者Linus Borg的說(shuō)法:
“允許 fragments 需要對(duì)[diffing]算法進(jìn)行重大更改…不僅要使其能夠正常工作,而且還必須使其具有高性能。…這是一項(xiàng)非常繁重的任務(wù)” |
具有渲染功能的函數(shù)組件
函數(shù)組件沒(méi)有單根限制,因?yàn)樗鼈儾恍枰裼袪顟B(tài)組件那樣在虛擬DOM中進(jìn)行區(qū)分。這意味著,如果組件只需要返回靜態(tài)HTML,那么擁有多個(gè)根節(jié)點(diǎn)也沒(méi)什么問(wèn)題。
還有一個(gè)警告:我們需要使用渲染功能,因?yàn)関ue-loader當(dāng)前不支持多根功能([盡管對(duì)此進(jìn)行了討論][2])。
使用指令技巧
還可以使用一種簡(jiǎn)單的方法來(lái)繞過(guò)單根限制。就是使用自定義指令,首先我們先所包裹的元素刪除
之前的:
- <parent>
- <wrapper>
- <child/>
- <child/>
- </wrapper>
- </parent>
中間步驟:
- <parent>
- <wrapper/>
- <child/>
- <child/>
- </parent>
最終:
- <parent>
- <!-- 刪除 <wrapper/> -->
- <child/>
- <child/>
- </parent>
要使它正常工作有點(diǎn)棘手,這里可以使用由Julien Barbay寫的 [vue-fragments][3] 的插件。
vue-fragments
vue-fragments可以作為一個(gè)插件安裝到你的Vue項(xiàng)目中
- import { Plugin } from "vue-fragments";
- Vue.use(Plugin);
該插件注冊(cè)了一個(gè)全局VFragment組件,將其用作組件模板中的包裝器,類似于React片段的語(yǔ)法:
- <template>
- <v-fragment>
- <div>Fragment 1</div>
- <div>Fragment 2</div>
- </v-fragment>
- </template>
我不確定這個(gè)插件在所有的用例中有多健壯——它看起來(lái)可能是脆弱的——但在我做的實(shí)驗(yàn)中,它工作得很好。