Vue3多組件的N種編寫方式
Vue 本身以及周邊生態(tài)在設(shè)計(jì)語法糖上幾乎沒讓我失望過,包括本次在 VueConf 2024 深圳盛會(huì)上正式亮相的 Vue Vine。
它的出現(xiàn)引起了我對(duì) Vue3 組件編寫方式的好奇,以及哪一種方式更接近「最佳實(shí)踐」?
那么 Vue Vine 究竟是一個(gè)什么有意思的工具?以及與這個(gè)工具類似的其他工具都有哪些?它們分別對(duì)應(yīng)的場(chǎng)景是什么?該如何選擇?
下面讓我來為大家一一道來:
SFC 單文件組件
我們?cè)谟镁帉懘a時(shí),經(jīng)常是會(huì)出現(xiàn)重復(fù)的代碼,就比如:
<template> <dialog v-if="showInDialog"> <!-- 代碼片段 --> </dialog> <div v-else> <!-- 代碼片段 --> </div> </template>
如果我們不想將「代碼片段」這部分重復(fù)的寫兩遍該怎么辦?
這時(shí)候,我們往往會(huì)將這個(gè)代碼片段拎出來放在一個(gè)新建的 .vue
子組件中:
<!-- 父組件 --> <template> <dialog v-if="showInDialog"> <Content /> </dialog> <div v-else> <Content /> </div> </template> <!-- 子組件 Content.vue --> <template> <!-- 代碼片段 --> </template>
這本身是 Vue 官方默認(rèn)的一種組件化開發(fā)方式,也就是 SFC 單文件組件。
但是在某些情況下,我們可能并不想將這部分「代碼片段」拆分成獨(dú)立的單文件,比如「代碼片段」非常的簡(jiǎn)單的時(shí)候,又或者父組件代碼量并不多的時(shí)候...
并且強(qiáng)行拆分帶來的一系列繁瑣操作有時(shí)也挺煩人,這時(shí)候我們就得找一些方案來解決這種單文件組件解決不了的情況。
多模板方案
多模板方案強(qiáng)調(diào)的是在一個(gè)單文件組件中提取出能復(fù)用的模板代碼,換句話說就是提取出公共的 HTML 代??。
createReusableTemplate
VueUse 是一個(gè)提供了非常多實(shí)用的 Vue3 組合式函數(shù)(Composables)的工具庫,其中便提供了一個(gè)創(chuàng)建可重用模板的 createReusableTemplate
方法,文檔鏈接是https://vueuse.org/core/createReusableTemplate
使用方式非常簡(jiǎn)單:
<script setup> import { createReusableTemplate } from '@vueuse/core' const [DefineTemplate, ReuseTemplate] = createReusableTemplate() </script> <template> <DefineTemplate> <!-- 代碼片段 --> </DefineTemplate> <dialog v-if="showInDialog"> <ReuseTemplate /> </dialog> <div v-else> <ReuseTemplate /> </div> </template>
用導(dǎo)入的 DefineTemplate
組件注冊(cè)模板(注意此時(shí)不會(huì)渲染內(nèi)容),然后再用 ReuseTemplate
組件來渲染剛才注冊(cè)的模板(注意 DefineTemplate 必須在 ReuseTemplate 之前使用)即可。
namedTemplate
Vue Macros 像魔法一樣,能讓你在 Vue3 項(xiàng)目中體驗(yàn)到更多超前的語法糖。并且它還是一塊 Vue 語法的試驗(yàn)田,里面諸多的語法都有機(jī)會(huì)被 Vue 官方收錄!
它提供了一個(gè)命名模板 namedTemplate
特性,文檔鏈接是 https://vue-macros.dev/zh-CN/features/named-template.html
使用方式如下:
<script setup> const showInDialog = ref(false) </script> <template name="reusable"> <!-- 代碼片段 --> </template> <template> <template v-if="showInDialog"> <dialog> <template is="reusable" /> </dialog> </template> <template v-else> <div> <template is="reusable" /> </div> </template> </template>
多組件(無狀態(tài))方案
多組件(無狀態(tài))方案強(qiáng)調(diào)的是在一個(gè)文件中定義單個(gè)有狀態(tài)組件 + 多個(gè)無狀態(tài)組件
JSX
JSX 是多組件實(shí)踐中最常見的一個(gè)方案,霸榜了「多組件(無狀態(tài))方案」,并且 JSX 方案中寫法非常多,涉及到有狀態(tài)的「組件」和無狀態(tài)的「函數(shù)組件」的知識(shí)。
我這里挑選三個(gè)常見的方案:defineComponent render
、defineRender
、setupSFC
,其他寫法并不主流,我們就不在這里提及了。
defineComponent render
這是 Vue3 中最樸實(shí)無華的使用 JSX 的方式!屬于 Vue3 + JSX 夢(mèng)開始的地方
import { defineComponent, ref } from "vue" export default defineComponent({ setup() { // 使用 ref 創(chuàng)建一個(gè)響應(yīng)式變量來控制顯示狀態(tài) const showInDialog = ref(false) // 聲明一個(gè)無狀態(tài)函數(shù)組件 Content 用于渲染代碼片段 function Content() { return <div>代碼片段</div> } // 返回 render 函數(shù) return () => ( <div> {showInDialog.value ? ( <dialog> <Content /> </dialog> ) : ( <div> <Content /> </div> )} </div> ) } })
defineComponent
方法用于定義組件,在 setup
方法內(nèi)部我們可以利用「函數(shù)組件」來定義一些需要復(fù)用的「無狀態(tài)組件」,最后直接返回 render 函數(shù)即可。
本質(zhì)上就是「defineComponent + render + 無狀態(tài)函數(shù)組件 + JSX」的配合使用
defineRender
而 defineRender 則可以看作是 defineComponent render
的升級(jí)版,它也是 Vue Macros 提供的方法。
使用 defineRender
可以直接在 <script setup>
中定義渲染函數(shù):
<script setup lang="jsx"> // 使用 ref 創(chuàng)建一個(gè)響應(yīng)式變量來控制顯示狀態(tài) const showInDialog = ref(false) // 聲明一個(gè)無狀態(tài)函數(shù)組件 Content 用于渲染代碼片段 function Content() { return <div>代碼片段</div> } defineRender( <div> {showInDialog.value ? ( <dialog> <Content /> </dialog> ) : ( <div> <Content /> </div> )} </div> ) </script>
這種方式雖然告別了 defineComponent
和 Options API
使得代碼更加輕量,但是在 .vue
中寫 jsx
還是不夠優(yōu)雅。
于是又有了關(guān)于它的升級(jí)版 setupSFC
!
setupSFC
setupSFC 是我比較喜歡的在 Vue3 中編寫 JSX 組件的方案之一(它依舊是 Vue Macros 提供的方法)。
我們開發(fā)時(shí)需要定義后綴為 .setup.tsx / .setup.jsx
的文件:
// 使用 ref 創(chuàng)建一個(gè)響應(yīng)式變量來控制顯示狀態(tài) const showInDialog = ref(false) // 聲明一個(gè)無狀態(tài)函數(shù)組件 Content 用于渲染代碼片段 function Content() { return <div>代碼片段</div> } export default () => ( <div> {showInDialog.value ? ( <dialog> <Content /> </dialog> ) : ( <div> <Content /> </div> )} </div> )
告別了 defineComponent
和 Options API
,將 setup
和 jsx
完美的融合。
多組件(有狀態(tài))方案
多組件(有狀態(tài))方案強(qiáng)調(diào)的是在一個(gè)文件中定義多個(gè)有狀態(tài)組件
JSX
沒錯(cuò),JSX 霸榜了「多組件(無狀態(tài))方案」后,也活躍在「多組件(有狀態(tài))方案」中!
defineComponent render
其實(shí),我們把前文提到的「defineComponent render」多定義幾遍,也就是本方案了。
import { defineComponent, ref } from "vue" // 子組件 const Content = defineComponent({ setup() { return () => <div>代碼片段</div> } }) // 父組件 const App = defineComponent({ setup() { const showInDialog = ref(false) return () => ( <div> {showInDialog.value ? ( <dialog> <Content /> </dialog> ) : ( <div> <Content /> </div> )} </div> ) } }) export default App
在一個(gè)文件中堆砌 defineComponent
即可,這個(gè)形式類似于 React 中的 “類組件”
setupComponent
既然 “類組件” 有了,那么有沒有 “有狀態(tài)的函數(shù)組件” 呢?
于是 Vue Macros 它又又又提供了一個(gè)非??岬恼Z法 setupComponent,可以在 .jsx
文件中書寫多個(gè) “有狀態(tài)函數(shù)組件”,這也是我最喜歡的在 Vue3 中編寫 JSX 組件的方案。
// 子組件 const Content = defineSetupComponent(() => { return <div>代碼片段</div> }) // 父組件 const App = defineSetupComponent(() => { const showInDialog = ref(false) return ( <div> {showInDialog.value ? ( <dialog> <Content /> </dialog> ) : ( <div> <Content /> </div> )} </div> ) }) export default App
Vue Vine
有沒有發(fā)現(xiàn),文章到目前為止的多組件方案中,全是基于 JSX 的。那有沒有一種既用模板又能支持多組件的方案呢?
那就得說說 Vue Vine 了。
值得注意的是 Vine 僅支持 Vue3 + Vite + TS
,然后我們建立一個(gè) .vine.ts
文件:
// 子組件 function Content() { return vine`<div>代碼片段</div>` } // 父組件 function App() { const showInDialog = ref(false) return vine` <div> <template v-if="showInDialog"> <dialog> <Content /> </dialog> </template> <template v-else> <div> <Content /> </div> </template> </div> ` } export default App
一個(gè)函數(shù)就是一個(gè)組件,然后用 vine
標(biāo)記的模板字符串聲明組件模板。
這種書寫方式和剛剛提到的 setupComponent
非常相似,都屬于 “有狀態(tài)的函數(shù)組件”,但區(qū)別就是一個(gè)返回 JSX,一個(gè)返回模板,模板的優(yōu)勢(shì)就在于 Vue 對(duì)其有編譯時(shí)優(yōu)化。
總結(jié)
- 大多數(shù)情況下,依舊首選
SFC 單文件組件
方案就行 - 針對(duì)模板的復(fù)用,我雖然更喜歡 Vue Macros 提供的
namedTemplate
方案,但是鑒于目前的穩(wěn)定性,還是建議采用 VueUse 提供的createReusableTemplate
方案 - 針對(duì)多組件情景,現(xiàn)階段還是建議首選 JSX 方案下穩(wěn)妥的
defineComponent render
方案。喜歡嘗鮮的開發(fā)者可以大膽嘗試 Vue Macros 提供的setupComponent
或選擇Vue Vine
End
以上就是Vue3多組件的N種編寫方式的詳細(xì)內(nèi)容,更多關(guān)于Vue3多組件編寫方式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue權(quán)限路由實(shí)現(xiàn)的方法示例總結(jié)
這篇文章主要給大家介紹了關(guān)于vue權(quán)限路由實(shí)現(xiàn)方法的相關(guān)資料,文中通過示例代碼介紹地方非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用vue具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-07-07vue路由傳參接收以及傳參對(duì)象為對(duì)象時(shí)的問題及解決
這篇文章主要介紹了vue路由傳參接收以及傳參對(duì)象為對(duì)象時(shí)的問題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09vue2.0 better-scroll 實(shí)現(xiàn)移動(dòng)端滑動(dòng)的示例代碼
本篇文章主要介紹了vue2.0 better-scroll 實(shí)現(xiàn)移動(dòng)端滑動(dòng)的示例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2018-01-01Vue-cli proxyTable 解決開發(fā)環(huán)境的跨域問題詳解
本篇文章主要介紹了Vue-cli proxyTable 解決開發(fā)環(huán)境的跨域問題詳解,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-05-05vue在App.vue文件中監(jiān)聽路由變化刷新頁面操作
這篇文章主要介紹了vue在App.vue文件中監(jiān)聽路由變化刷新頁面操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-08-08vue-router之nuxt動(dòng)態(tài)路由設(shè)置的兩種方法小結(jié)
今天小編就為大家分享一篇vue-router之nuxt動(dòng)態(tài)路由設(shè)置的兩種方法小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-09-09vue的diff算法知識(shí)點(diǎn)總結(jié)
本篇文章給大家分享了關(guān)于vue的diff算法的相關(guān)知識(shí)點(diǎn)總結(jié),有興趣的朋友參考學(xué)習(xí)下。2018-03-03