HanC's Blog

使用很夯的Vue Vine實現多元件於一身

Posted:15th January 2025
7 Minutes
1284 Words

序言

於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的模板與邏輯分離特色,如下:

IDComponents.vine.ts
1
export function AddIDBtn() {
2
function addId(){
3
const id = uuidv4();
4
sharedIDs.value.push(id);
5
}
6
7
return vine`
8
<IDBtn
9
title="新增"
10
@action="addId"
11
/>
12
`;
13
}

需注意的點

  • 只支援 Vue 3.0+Vite
  • 只支援 TypeScript
  • 製作多元件時,需使用 vine 標籤回傳元件字串
  • 元件需使用 .vine.ts 作為副檔名
  • 使用 ${} 表達式於模板字串中會報錯,因Vine會將其傳遞給 @vue/compiler-dom ,進行編譯,所以一樣記得使用{{}}表達式

了解vue-vine的原由及其特色後,就可以開始入門著手寫元件了!

搭建Vue Vine環境

Installation

Terminal window
1
pnpm i -D vue-vine

配置Vite

於vite的配置檔案中,加入以下內容:

vite.config.ts
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檔

IDComponents.vine.ts
1
/**
2
* 此為按鈕父元件
3
*/
4
export 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
*/
18
import { v4 as uuidv4 } from "uuid"; // $pnpm install uuid,安裝後再引用
19
import { sharedIDs } from "../store/sharedState"; // 另一個檔案,存放共用變數
20
21
/**
22
* 列表元件
23
*/
24
export 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
*/
38
export function AddIDBtn() {
39
function addId(){
40
const id = uuidv4();
41
sharedIDs.value.push(id);
42
}
43
44
return vine`
45
<IDBtn
46
title="新增"
47
@action="addId"
48
/>
49
`;
50
}
51
52
/**
53
* 刪除ID按鈕
54
*/
55
export function DeleteIDBtn() {
56
function deleteId(){
57
sharedIDs.value.pop();
58
}
59
60
return vine`
61
<IDBtn
62
title="刪除"
63
@action="deleteId"/>
64
`;
65
}
sharedState.ts
1
import { ref } from 'vue';
2
3
export 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檔元件

App.vue
1
<script setup lang="ts">
2
import { 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 + TypeScriptVue-Vine

另一個坑是,雖然有React的精神在裡面,但還是需要提醒自己這仍是vue專案,因為在寫IDList()元件時,一度卡住,想說是不是應該使用for in + return來實現,而寫出這樣的code:

1
export function IDList() {
2
return vine`
3
<ul>
4
{{ sharedIDs.map(id => `<li>${id}</li>`) }}
5
</ul>
6
`;
7
}

直接又踩了vue-vine的規則,不能使用 ${},後來才想到,它就是vue,幹嘛寫複雜呢!

非常感謝有各路大神們,不斷創造新工具,讓大家嘗鮮又能滿足各種開發願望,希望此篇開箱 & 小踩坑的vue vine入門文可以幫助到想將多元件寫於同一檔案作管理的讀者。

Article title:使用很夯的Vue Vine實現多元件於一身
Article author:HanC
Release time:15th January 2025