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