
序言
於2024/07/06的Vue Conf上,沈青川大大介紹了新專案 - Vue Vine,其中 “於一個檔寫入多組元件”,就是它最核心的功能。有寫過React是否就會立馬聯想到Function Components,當時看到這一專案時,眼睛為之一亮,可能以前受React影響,有時在寫Vue專案,就想把一些相關元件直接寫在同一檔案,但受於Vue本身SFC限制,只能乖乖地 cmd+n
一個個新的Vue檔。
Vine component 是以Function所組成,全名為 ‘Vine Component Function’(官方稱為”VCF”),結合了SFC & JSX優點,讓一個檔案可以寫入多元件外,同時繼續享受Vue的模板語法,將相關元件集中於同一檔案,減少於不同元件中來回切換的痛苦,是不是讓各方面都滿足了呢~
而為什麼為說它是Function Component呢?
因為你可以將template
& setup script
寫在一塊,像極了React,但仍保有Vue的模板與邏輯分離特色,如下:
1export function AddIDBtn() {2 function addId(){3 const id = uuidv4();4 sharedIDs.value.push(id);5 }6
7 return vine`8 <IDBtn9 title="新增"10 @action="addId"11 />12 `;13}
需注意的點
- 只支援 Vue 3.0+ 及 Vite
- 只支援 TypeScript
- 製作多元件時,需使用
vine
標籤回傳元件字串 - 元件需使用
.vine.ts
作為副檔名 - 使用
${}
表達式於模板字串中會報錯,因Vine會將其傳遞給@vue/compiler-dom
,進行編譯,所以一樣記得使用{{}}
表達式
了解vue-vine的原由及其特色後,就可以開始入門著手寫元件了!
搭建Vue Vine環境
Installation
1 pnpm i -D vue-vine
配置Vite
於vite的配置檔案中,加入以下內容:
1 import { VineVitePlugin } from 'vue-vine/vite'2
3 export default defineConfig({4 plugins: [5 // ...其他插件6 VineVitePlugin()7 ],8 })
安裝vue-vine的VS Code插件
建議可以安裝,因為它會將語法高亮,以免開發時看到的都是字串格式,最後會寫得眼花撩亂。

實作新增與刪除ID的vue-vine元件
先來看實作出來效果

創建多組元件共用的vine檔
1/**2 * 此為按鈕父元件3 */4export function IDBtn() {5 const title = vineProp<string>();6 const emit = vineEmits(["action"]);7
8 return vine`9 <button @click="emit('action')">10 {{title}}11 </button>12 `;13}52 collapsed lines
14
15/**16 * 此兩組引用,用於下方ID列表顯示與操作17 */18import { v4 as uuidv4 } from "uuid"; // $pnpm install uuid,安裝後再引用19import { sharedIDs } from "../store/sharedState"; // 另一個檔案,存放共用變數20
21/**22 * 列表元件23 */24export function IDList() {25 return vine`26 <span v-if="sharedIDs.length === 0">請點選'新增',創建ID</span>27 <ul v-else>28 <li v-for="id in sharedIDs" :key="id">29 {{ id }}30 </li>31 </ul>32 `;33}34
35/**36 * 新增ID按鈕37 */38export function AddIDBtn() {39 function addId(){40 const id = uuidv4();41 sharedIDs.value.push(id);42 }43
44 return vine`45 <IDBtn46 title="新增"47 @action="addId"48 />49 `;50}51
52/**53 * 刪除ID按鈕54 */55export function DeleteIDBtn() {56 function deleteId(){57 sharedIDs.value.pop();58 }59
60 return vine`61 <IDBtn62 title="刪除"63 @action="deleteId"/>64 `;65}
1import { ref } from 'vue';2
3export const sharedIDs = ref<string[]>([]);
從上述代碼可以看到,真實將操作ID相關的’模板’ & ‘操作邏輯’,全都寫在同一個ts檔中。
於IDList()
中更是將vue原有的習慣寫法都保留,v-if
& v-for
…等關鍵字都是可正常運作。
而於export的function component,也可將所需的function放於自身定義中,一個function component就像我們在寫SFC一樣。
vineProp
& vineEmits
,即是於vine中欲傳遞參數給子元件時的關鍵字,使用方式與Vue幾乎一樣,只要在腦中覺得應該是這樣的寫法,照著自己的想法走,就能與vine融於一塊了!
引用vine檔元件
1<script setup lang="ts">2import { AddIDBtn, DeleteIDBtn, IDList } from './components/IDComponents.vine';3</script>4
5<template>6 <div class="action-block">7 <AddIDBtn />8 <DeleteIDBtn />9 </div>10 <hr />11 <IDList />12</template>13
14<style scoped>7 collapsed lines
15.action-block {16 display: flex;17 gap: 16px;18 justify-content: center;19 align-items: start;20}21</style>
vine中每一function即是一組元件,因此於vue中如何引用元件,在此如法炮製地引用,學習曲線平緩得很。
後話
在寫vue-vine時,其實寫到後來有一點暢快,因為可以參有React彈性寫於Vue之中,滿足我什麼都要的欲望。 但在一開始,還是踩了一點點的坑,在此跟大家分享一下。
建議可以直接使用vite創建專案,而後再選擇vue + ts,因很習慣直接使用vue create
,所以在建置時,想說怎麼一直跑不起來,結果…是忘了vue-vine也要使用vite才會運作。現在會記得Vue
+ Vite
+ TypeScript
→ Vue-Vine
。
另一個坑是,雖然有React的精神在裡面,但還是需要提醒自己這仍是vue專案,因為在寫IDList()
元件時,一度卡住,想說是不是應該使用for in
+ return
來實現,而寫出這樣的code:
1export function IDList() {2 return vine`3 <ul>4 {{ sharedIDs.map(id => `<li>${id}</li>`) }}5 </ul>6 `;7}
直接又踩了vue-vine的規則,不能使用 ${},後來才想到,它就是vue,幹嘛寫複雜呢!
非常感謝有各路大神們,不斷創造新工具,讓大家嘗鮮又能滿足各種開發願望,希望此篇開箱 & 小踩坑的vue vine入門文可以幫助到想將多元件寫於同一檔案作管理的讀者。