Vue3 筆記 | 專案建立與響應式

更新 發佈閱讀 15 分鐘

當初在找工作的時候在 104 上就發現台灣的公司貌似比較常用 Vue 來開發前端專案,React 和 Angular 的職缺較少,而且 Angular 也逐漸被 Vue 和 React 給甩到後面去了。

現在開始逐步學習 Vue、Pinia、Nuxt,我會把學習筆記以部落格的方式放出來分享給大家,與有興趣的各位一同學習。



專案建立

Vue3 釋出之後改變了許多 Vue 原本的生態,包括 Vue2 的選項式 API 寫法改成推薦使用組合式 API 寫法,在專案的建立上也不再使用舊版的 CLI 而是直接使用 Vite。

網路上查詢用 Vite 建立專案會有複數種寫法,但最簡便的方式其實是 Vue 官網上開宗明義使用的 :

npm create vue@latest

這串打下去就直接默認用 Vite 來幫忙建立 Vue 專案了,可以說是非常的迅速。接下來r進到專案後按照下列步驟:

npm install
npm run dev

當你在瀏覽器看到類似下面這張圖時,就代表成功建立一個 Vue 專案了。

raw-image



語法

講語法前,先來說一下 Vue3 的結構。Vue3 推薦的架構跟 Vue2 不太一樣,當然還是可以用 Vue2 的那種架構寫法,但 Vue3 的架構會更方便易懂,尤其如果你是像我一樣先寫 React 才來學 Vue 的。Vue3 的架構會像下面這樣:

<script setup>
/** 你的變數、方法通通都在這裡,如果想用 Vue2 寫法,可以不在 script 處加 setup **/
</script>

<template>
/** 你的 HTML 架構 **/
</template>

<style scoped>
/** 你的樣式,添加 scope 讓這個樣式只生效於此元件下 **/
</style>

接下來講語法。與 React 使用 JSX 語法不同,Vue 使用模板語法進行開發,使用上會更像 Express + Handlebars。

使用上有兩個重點:

  1. {{…}} 包裹變數:如 <span>Message: {{ msg }}</span> 中,msg 代表的可能是個響應式變數,當他變動時渲染也會跟著更新。
  2. v-html 包裹 HTML 語法:因為 {{…}} 會把數據解釋為純文本,如果你的變數代表的是一段 HTML,那必須為你的 tag 添加 v-html 屬性並掛上的 HTML 變數,這裡我直接放官網範例:
raw-image

v-bind

如果今天變數擺放的區域是在 HTML tag 上,比如說屬性要依照某變數來決定是否掛上 tag,那在這時不能使用 {{…}},而是要改用 v-bind

<h1 v-bind:class="{addColor: changed}">I will change my color</h1>

比如這裡可以假定為當 changed 為 true 時掛上一個 class 叫 addColor,false 時就把 class 移除。

因為 v-bind 很常用,所以可以簡寫成下列方式,用 : 代替 v-bind

 <h1 :class="{addColor: changed}">I will change my color</h1>

動態參數

還有一個神奇的玩意兒叫動態參數,長這樣:

<a :[attributeName]="url"> ... </a>

他的意思是,比如今天attributeName 被更動為 href,那這串就等同 v-bindhref 這個屬性。



響應式基礎 (Vue 中的狀態管理)

在 React 中,我們會學到最基本的響應資料型態是用 useState 這個 hook 做管理。但 Vue 不一樣,他靠 ref reactive 以及 computed 做狀態儲存與計算。

關於 ref reactive 真的會讓初學者一開始很難摸清楚到底在幹嘛,為什麼就不能像 useState那樣一個東西決所有問題呢?

ref

ref 可以存取的所有型態的資料,但通常不會把物件和陣列的資料交給它存。

而且 ref 的操作稍微沒那麼直觀,為何這樣說呢?那是因為如果是在<script setup>或調用 ref 的值,會需要添加 refItem.value,但如果只是單純 HTML 模板,直接 {{refItem}} 就可以取到值了。

比方說,我定義一個變數 num ref 並且預設 0,然後我寫了一個方法來使每次點擊都把它的值加 1,來看看 code 和畫面渲染吧:

<script setup>
import { ref } from 'vue';

const num = ref(0)

const changeNum = () => num.value += 1
</script>

<template>
<h1>{{ num }}</h1>
<button @click="changeNum">Add one</button>
</template>


實際上我把按鈕改成 <button @click="num++">Add one</button> 也是做一樣的事,但在<script setup>中定義的方法取值必須用.value

提醒一下,定義 ref 請使用 const 宣告為常數,不然用 let 可能會一不小心被覆蓋掉。

reactive

他只能存陣列或物件,跟 ref 不同的地方,他無論在哪裡取值都不需要添加 .value

我們來創個玩玩:

<script setup>
import { reactive } from 'vue';

const people2 = reactive({
name: 'Jeremy',
gender: 'Male',
age: 20
})

const changePeople2 = () => {
people2.name = 'Lucy'
console.log('people2 changed')
}
</script>

<template>
<h1>{{ people2.name }} / {{ people2.gender }}</h1>
<button @click="changePeople2">Change!</button>
</template>

可以很清楚看到名字改變了!這樣就可以輕輕鬆鬆修改值啦!

ref 和 reactive 差異

所以 ref reactive 差在哪裡?

除了儲存類型的主要差異,和 ref 貌似被一大包東西包起來的感覺 (還需要 .value 取值),實際上操作好像就只差在要不要用 .value 取值誒。

實際上這兩個的差異在於監聽上。當有用到 watch 去監聽響應式數值是否變動時,如果 ref 今天存的是個物件,而我們變動了其中一部分的值,watch 是監聽不到的,因為這個變動太深層了!但反之 reactive所儲存的物件內部若有變動卻是監聽得到的。我們實際來看看:

<script setup>
import { ref, reactive, watch } from 'vue';

// 用 ref 創個物件​
const people1 = ref({
name: 'Mike',
gender: 'Female',
age: 30
})
//​ 用 reactive 創個物件
const people2 = reactive({
name: 'Jeremy',
gender: 'Male',
age: 20
})

const changePeople1 = () => {
people1.value.name = 'Leo'
}

const changePeople2 = () => {
people2.name = 'Lucy'
}

// 監聽響應式的改變​
watch(people1, () => {
console.log('people1 changed')
})

watch(people2, () => {
console.log('people2 changed')
})

</script>

<template>
<div class="main-area">
<div>
<h1>Here is ref Object. Name: {{ people1.name }}. Gender: {{ people1.gender }}. Age: {{ people1.age }}</h1>
<button @click="changePeople1">click</button>
</div>
<div>
<h1>Here is reactive object Name: {{ people2.name }}. Gender: {{ people2.gender }}. Age: {{ people2.age }}</h1>
<button @click="changePeople2">click</button>
</div>
</div>
</template>

我們會發現畫面上 people1 的名字的確被更動成 Leo 了,但 watch 裡的console.log 並不會被觸發,但 people2 的 watch中的 console.log 會被觸發。

但如果現在把 watch 掛上第三個參數讓它可以執行深層監聽呢?讓我們調整一下 people1 的 watch 監聽器:

watch(people1, () => {
console.log('people1 changed')
}, {deep : true})
raw-image

嘿,可以看到 people1 的 watch中的 console.log 也被執行了,表示變動被監聽到了!

根據 Mike Chen 老師說的,其實 reactive 中包的每個項目其實都是單獨一個 ref 項目,具備這個想法後對於 Vue 官方文件的解讀,無論是這裡監聽的差異還是解構都會清楚很多。

computed

computed 顧名思義是拿來做計算的,計算什麼?計算響應式資料的變動然後來幫助畫面渲染。什麼意思?我們來看這個例子:

<script setup>
import { ref } from 'vue';
const num1 = ref(1)
const num2 = ref(2)

</script>

<template>
<h1>Num1: {{ num1 }}</h1>
<h1>Num2: {{ num2 }}</h1>
<h1>Num1 + Num2 = {{ num1 + num2 }}</h1>
</template>
raw-image

So?就是在 HTML template 中添加了一個式子嘛,計算正確啊!

對,我們可以在 HTML template 中寫各種判斷式或各式式子,實際上我之前在 React 的撰寫中也幹過這樣把邏輯寫在 HTML 架構中的事 (突然想起我還有被助教提醒...),但這樣其實程式碼結構一大會很難維護。所以 Vue 的 computed 出現了!它可以為我們做到監聽響應式變化並即時做出反應。

<script setup>
import { ref, computed } from 'vue';
const num1 = ref(1)
const num2 = ref(2)

const numPlus = computed(()=>{
return num1.value + num2.value
})
</script>

<template>
<h1>Num1: {{ num1 }}</h1>
<h1>Num2: {{ num2 }}</h1>
<h1>Num1 + Num2 = {{ numPlus }}</h1>
</template>

這樣我們可以得到跟第一段一樣的結果,但邏輯被我們抽出去了。

在學習 computed 時會有一個疑惑,所以它跟 method 差在哪裡?主要差在兩個地方:

  1. computed 只有當響應式資料變動時才會執行。
  2. computed 默認不能傳參數進去。

關於第二點,在 Vue 官方文件裡有說,computed 的使用默認只有 getter,所以你只能拿到由響應式資料計算出的回應結果,但無法透過 computed 去更動響應式資料。

但如果今天你說,我就是想在計算的時候也順便把我的資料做更動啊!好吧,可以,的確可以為 computed 加上 setter 。而至於具體操作和應用情境等我搞懂再來更新 www



參考資料

  1. Vue.js 官方網站
  2. Vue3 + Vite 快速上手 Get Startrd EP1 - 初探 Vite 專案 / Vue3 初學者應該要先知道的東西 / 剛開始寫 Composition API 會犯的錯誤 !
  3. Vue3 + Vite 快速上手 Get Startrd EP2 - 定義資料 ref、reactive、computed 深度探討
留言
avatar-img
Jeremy Ho的沙龍
20會員
37內容數
這個專題用來存放我在學習網頁開發時的心得及知識。
Jeremy Ho的沙龍的其他內容
2023/11/22
用 vue3-openlayers 畫張地圖吧
Thumbnail
2023/11/22
用 vue3-openlayers 畫張地圖吧
Thumbnail
2023/11/13
Vue3 筆記,指令進階篇
Thumbnail
2023/11/13
Vue3 筆記,指令進階篇
Thumbnail
2023/11/12
Vue3 學習筆記,vue-router 篇。
Thumbnail
2023/11/12
Vue3 學習筆記,vue-router 篇。
Thumbnail
看更多
你可能也想看
Thumbnail
在 vocus 與你一起探索內容、發掘靈感的路上,我們又將啟動新的冒險——vocus App 正式推出! 現在起,你可以在 iOS App Store 下載全新上架的 vocus App。 無論是在通勤路上、日常空檔,或一天結束後的放鬆時刻,都能自在沈浸在內容宇宙中。
Thumbnail
在 vocus 與你一起探索內容、發掘靈感的路上,我們又將啟動新的冒險——vocus App 正式推出! 現在起,你可以在 iOS App Store 下載全新上架的 vocus App。 無論是在通勤路上、日常空檔,或一天結束後的放鬆時刻,都能自在沈浸在內容宇宙中。
Thumbnail
vocus 慶祝推出 App,舉辦 2026 全站慶。推出精選內容與數位商品折扣,訂單免費與紅包抽獎、新註冊會員專屬活動、Boba Boost 贊助抽紅包,以及全站徵文,並邀請你一起來回顧過去的一年, vocus 與創作者共同留下了哪些精彩創作。
Thumbnail
vocus 慶祝推出 App,舉辦 2026 全站慶。推出精選內容與數位商品折扣,訂單免費與紅包抽獎、新註冊會員專屬活動、Boba Boost 贊助抽紅包,以及全站徵文,並邀請你一起來回顧過去的一年, vocus 與創作者共同留下了哪些精彩創作。
Thumbnail
Vue 筆記,Nuxt 簡介
Thumbnail
Vue 筆記,Nuxt 簡介
Thumbnail
Vue3 筆記,指令進階篇
Thumbnail
Vue3 筆記,指令進階篇
Thumbnail
Vue3 學習筆記,vue-router 篇。
Thumbnail
Vue3 學習筆記,vue-router 篇。
Thumbnail
Vue3 學習筆記,元件與資料傳遞篇
Thumbnail
Vue3 學習筆記,元件與資料傳遞篇
Thumbnail
Vue3 學習筆記,專案建立與基礎響應式篇
Thumbnail
Vue3 學習筆記,專案建立與基礎響應式篇
Thumbnail
在寫頁面之前,先來介紹 Vue 頁面結構。 首先先在 src/components 底下建立一個 home.vue 跟寫一個 html 頁面很像,一樣是分成 寫網頁內容、script、style,三個部分,只是 html 標籤換成了 template。 template 就是相當於原生 html 檔
Thumbnail
在寫頁面之前,先來介紹 Vue 頁面結構。 首先先在 src/components 底下建立一個 home.vue 跟寫一個 html 頁面很像,一樣是分成 寫網頁內容、script、style,三個部分,只是 html 標籤換成了 template。 template 就是相當於原生 html 檔
Thumbnail
專案建好了,那先來講 Vue 的專案架構 詳細內容很多,所以我挑重點講 public index.html public/index.html 是 Vue 頁面的 entry point,進入一個 Vue 頁面會先進 public/index.html,再套用 App.vue,最後才是進入你寫的 .
Thumbnail
專案建好了,那先來講 Vue 的專案架構 詳細內容很多,所以我挑重點講 public index.html public/index.html 是 Vue 頁面的 entry point,進入一個 Vue 頁面會先進 public/index.html,再套用 App.vue,最後才是進入你寫的 .
Thumbnail
前言 Vue 在過去的一兩年內快速發展,寫法也一直改變,我在過去一年多也更改了兩次寫法,在這個系列中我將以最新的 composition api + typescript 寫法進行教學。 javascript 有兩大痛點,一個是異步問題,另一個是弱型別。要渲染畫面一定要多線程同時異步處理,不然真的一
Thumbnail
前言 Vue 在過去的一兩年內快速發展,寫法也一直改變,我在過去一年多也更改了兩次寫法,在這個系列中我將以最新的 composition api + typescript 寫法進行教學。 javascript 有兩大痛點,一個是異步問題,另一個是弱型別。要渲染畫面一定要多線程同時異步處理,不然真的一
Thumbnail
Create project 裝好 vue CLI 之後,只要在終端輸入 vue create 想取的專案名稱 就可以開始創建 vue 專案囉 1. Pick a preset 2. Select the features 3. Choose the version of vue 選擇 vue3
Thumbnail
Create project 裝好 vue CLI 之後,只要在終端輸入 vue create 想取的專案名稱 就可以開始創建 vue 專案囉 1. Pick a preset 2. Select the features 3. Choose the version of vue 選擇 vue3
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News