Vue3多組件的N種編寫方式
Vue 本身以及周邊生態(tài)在設(shè)計(jì)語法糖上幾乎沒讓我失望過,包括本次在 VueConf 2024 深圳盛會(huì)上正式亮相的 Vue Vine。
它的出現(xiàn)引起了我對(duì) Vue3 組件編寫方式的好奇,以及哪一種方式更接近「最佳實(shí)踐」?
那么 Vue Vine 究竟是一個(gè)什么有意思的工具?以及與這個(gè)工具類似的其他工具都有哪些?它們分別對(duì)應(yī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ú)立的單文件,比如「代碼片段」非常的簡單的時(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
使用方式非常簡單:
<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è)非常酷的語法 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)勢就在于 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-07
vue路由傳參接收以及傳參對(duì)象為對(duì)象時(shí)的問題及解決
這篇文章主要介紹了vue路由傳參接收以及傳參對(duì)象為對(duì)象時(shí)的問題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
vue2.0 better-scroll 實(shí)現(xiàn)移動(dòng)端滑動(dòng)的示例代碼
本篇文章主要介紹了vue2.0 better-scroll 實(shí)現(xiàn)移動(dòng)端滑動(dòng)的示例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2018-01-01
Vue-cli proxyTable 解決開發(fā)環(huán)境的跨域問題詳解
本篇文章主要介紹了Vue-cli proxyTable 解決開發(fā)環(huán)境的跨域問題詳解,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-05-05
vue在App.vue文件中監(jiān)聽路由變化刷新頁面操作
這篇文章主要介紹了vue在App.vue文件中監(jiān)聽路由變化刷新頁面操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-08-08
vue-router之nuxt動(dòng)態(tài)路由設(shè)置的兩種方法小結(jié)
今天小編就為大家分享一篇vue-router之nuxt動(dòng)態(tài)路由設(shè)置的兩種方法小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-09-09
vue的diff算法知識(shí)點(diǎn)總結(jié)
本篇文章給大家分享了關(guān)于vue的diff算法的相關(guān)知識(shí)點(diǎn)總結(jié),有興趣的朋友參考學(xué)習(xí)下。2018-03-03

