跳至主要内容

17 篇文章 含有標籤「vue.js」

檢視所有標籤

Vue.js 3 官方入門語法教學筆記 [6] - List Rendering 表單綁定 | 學習筆記

· 閱讀時間約 2 分鐘
kdchang

List Rendering 列表渲染
我們可以使用 v-for 指令根據一個來源陣列來渲染元素列表:

<template>
<ul>
<li v-for="todo in todos" :key="todo.id">
{{ todo.text }}
</li>
</ul>
</template>

在這裡,todo 是一個局部變數,代表目前被迭代的陣列元素。它的作用域僅限於 v-for 元素內部,類似於函式的作用域。


請注意,我們為每個 todo 對象指定了一個唯一的 id,並將其綁定為每個 <li> 的特殊 key 屬性。key 允許 Vue 精準地移動每個 <li>,以匹配陣列中對應對象的位置。


有兩種方式可以更新列表:

  1. 對來源陣列調用可變方法:

    todos.value.push(newTodo)
  2. 使用新的陣列替換:

    todos.value = todos.value.filter(/* ... */)

以下是一個簡單的待辦事項列表範例,您可以試著實現 addTodo()removeTodo() 方法,使其正常運作!

範例程式碼:

<template>
<div>
<ul>
<li v-for="todo in todos" :key="todo.id">
{{ todo.text }}
<button @click="removeTodo(todo.id)">Remove</button>
</li>
</ul>
<input v-model="newTodoText" placeholder="Add a new todo" />
<button @click="addTodo">Add Todo</button>
</div>
</template>

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

// 定義待辦事項列表和新增的文字
const todos = ref([
{ id: 1, text: 'Learn Vue.js' },
{ id: 2, text: 'Build a project' }
])

const newTodoText = ref('')

// 新增待辦事項
function addTodo() {
if (newTodoText.value.trim()) {
todos.value.push({
id: Date.now(), // 使用當前時間作為唯一 ID
text: newTodoText.value.trim()
})
newTodoText.value = '' // 清空輸入框
}
}

// 移除待辦事項
function removeTodo(id) {
todos.value = todos.value.filter(todo => todo.id !== id)
}
</script>

更多關於 v-for 的詳細內容,請參閱官方指南 - 列表渲染

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

// give each todo a unique id
let id = 0

const newTodo = ref('')
const todos = ref([
{ id: id++, text: 'Learn HTML' },
{ id: id++, text: 'Learn JavaScript' },
{ id: id++, text: 'Learn Vue' }
])

function addTodo() {
todos.value.push({ id: id++, text: newTodo.value })
newTodo.value = ''
}

function removeTodo(todo) {
todos.value = todos.value.filter((t) => t !== todo)
}
</script>

<template>
<form @submit.prevent="addTodo">
<input v-model="newTodo" required placeholder="new todo">
<button>Add Todo</button>
</form>
<ul>
<li v-for="todo in todos" :key="todo.id">
{{ todo.text }}
<button @click="removeTodo(todo)">X</button>
</li>
</ul>
</template>

Vue.js 3 官方入門語法教學筆記 [5] - Conditional Rendering 表單綁定 | 學習筆記

· 閱讀時間約 2 分鐘
kdchang

Conditional Rendering 條件渲染
在 Vue 中,我們可以使用 v-if 指令來條件式渲染元素:

<template>
<h1 v-if="awesome">Vue is awesome!</h1>
</template>

這個 <h1> 只有在 awesome 的值為真值時才會被渲染。如果 awesome 的值變為假值,它將從 DOM 中被移除。


我們還可以使用 v-elsev-else-if 表示條件的其他分支:

<template>
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
</template>

目前的範例同時顯示了兩個 <h1>,按鈕也沒有作用。請嘗試為 <h1> 添加 v-ifv-else 指令,並實作一個 toggle() 方法,使我們可以透過按鈕來切換顯示的內容。


示例程式碼範例:

<template>
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
<button @click="toggle">Toggle</button>
</template>

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

const awesome = ref(true)

function toggle() {
awesome.value = !awesome.value
}
</script>

更多關於 v-if 的詳細內容請參閱官方指南 - 條件渲染

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

const awesome = ref(true)

function toggle() {
awesome.value = !awesome.value
}
</script>

<template>
<button @click="toggle">Toggle</button>
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
</template>

Vue.js 3 官方入門語法教學筆記 [4] - Form Bindings 表單綁定 | 學習筆記

· 閱讀時間約 2 分鐘
kdchang

Form Bindings 表單綁定
使用 v-bindv-on 結合,我們可以對表單輸入元素創建雙向綁定:

<template>
<input :value="text" @input="onInput">
<p>{{ text }}</p>
</template>

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

const text = ref('')

function onInput(e) {
// v-on 處理器接收原生 DOM 事件作為參數
text.value = e.target.value
}
</script>

當您在輸入框中輸入時,您應該會看到 <p> 中的文字隨之更新。


為了簡化雙向綁定,Vue 提供了 v-model 指令,它本質上是上述代碼的語法糖:

<template>
<input v-model="text">
<p>{{ text }}</p>
</template>

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

const text = ref('')
</script>

v-model 會自動同步 <input> 的值與綁定的狀態,因此我們不再需要為此使用事件處理器。


v-model 不僅適用於文本輸入,還適用於其他輸入類型,如復選框 (checkbox)、單選按鈕 (radio button) 和下拉選單 (select dropdown)。有關更多細節,請參閱官方指南 - 表單綁定


現在,我們試著將代碼重構為使用 v-model

SFC/Composition 版本:

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

const text = ref('')
</script>

<template>
<input v-model="text" placeholder="Type here">
<p>{{ text }}</p>
</template>

SFC/Options 版本:

<script>
export default {
data() {
return {
text: ''
}
},
methods: {
onInput(e) {
this.text = e.target.value
}
}
}
</script>

<template>
<input :value="text" @input="onInput" placeholder="Type here">
<p>{{ text }}</p>
</template>

HTML/Options 版本:

<script type="module">
import { createApp } from 'vue'

createApp({
data() {
return {
text: ''
}
},
methods: {
onInput(e) {
this.text = e.target.value
}
}
}).mount('#app')
</script>

<div id="app">
<input :value="text" @input="onInput" placeholder="Type here">
<p>{{ text }}</p>
</div>

HTML/Composition 版本:

<script type="module">
import { createApp, ref } from 'vue'

createApp({
setup() {
const text = ref('')

function onInput(e) {
text.value = e.target.value
}

return {
text,
onInput
}
}
}).mount('#app')
</script>

<div id="app">
<input :value="text" @input="onInput" placeholder="Type here">
<p>{{ text }}</p>
</div>

Vue.js 3 官方入門語法教學筆記 [3] - Event Listeners 事件監聽器 | 學習筆記

· 閱讀時間約 1 分鐘
kdchang

Event Listeners 事件監聽器
在 Vue 中,我們可以使用 v-on 指令監聽 DOM 事件:

<template>
<button v-on:click="increment">{{ count }}</button>
</template>

由於 v-on 的使用頻率很高,Vue 提供了一個簡寫語法:

<template>
<button @click="increment">{{ count }}</button>
</template>

在這裡,increment 是在 <script setup> 中定義的一個函式:

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

// 定義響應式狀態
const count = ref(0)

// 定義函式來更新狀態
function increment() {
// 更新組件的狀態
count.value++
}
</script>

在函式內,我們可以透過修改 ref 的值來更新組件的狀態。


事件處理器也可以使用內聯表達式,並透過修飾符簡化常見任務。這些細節在指南 - 事件處理中有詳細說明。


現在,我們可以試著自己實作 increment 函式,並使用 v-on 將它綁定到按鈕。

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

const count = ref(0)

function increment() {
count.value++
}
</script>

<template>
<button @click="increment">Count is: {{ count }}</button>
</template>

Vue.js 3 官方入門語法教學筆記 [2] - Attribute Bindings 屬性綁定 | 學習筆記

· 閱讀時間約 1 分鐘
kdchang

Attribute Bindings 屬性綁定
在 Vue 中,Mustache 語法只能用於文字插值。要將屬性綁定到動態值,我們需要使用 v-bind 指令:

<template>
<div v-bind:id="dynamicId"></div>
</template>

指令是一種特殊的屬性,以 v- 前綴開頭,屬於 Vue 的模板語法的一部分。與文字插值類似,指令的值是 JavaScript 表達式,可以訪問組件的狀態。有關 v-bind 和指令語法的完整細節,請參閱官方說明指南 - 模板語法

冒號之後的部分(:id)是指令的「參數」。在這裡,元素的 id 屬性將與組件狀態中的 dynamicId 屬性同步。

由於 v-bind 的使用頻率很高,Vue 提供了專用的簡寫語法:

<template>
<div :id="dynamicId"></div>
</template>

我們可以試著將動態類名綁定到 <h1>,使用 titleClassref 作為值。如果綁定正確,文字應該會變成紅色!

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

const titleClass = ref('title')
</script>

<template>
<h1 :class="titleClass">Make me red</h1> <!-- add dynamic class binding here -->
</template>

<style>
.title {
color: red;
}
</style>

Vue.js 3 官方入門語法教學筆記 [1] - Declarative Rendering 聲明式渲染 | 學習筆記

· 閱讀時間約 3 分鐘
kdchang

在 Vue3 我們常看到的是 Vue 單文件元件 (SFC)。SFC 是一個可重用的、獨立的程式碼區塊,它將相關的 HTML、CSS 和 JavaScript 封裝在一起,並寫在一個 .vue 文件中。

Vue 的核心特性是聲明式渲染:使用擴展 HTML 的模板語法,我們可以根據 JavaScript 的狀態描述 HTML 應該如何呈現。當狀態發生變化時,HTML 會自動更新。

可以在狀態變化時觸發更新的狀態被認為是響應式的。我們可以使用 Vue 的 reactive() API 來聲明響應式狀態。通過 reactive() 創建的對象是 JavaScript 的 Proxy,它們的行為與普通物件相同:

SFC 版本:

import { reactive } from 'vue'

const counter = reactive({
count: 0
})

console.log(counter.count) // 0
counter.count++

html 版本:

<script type="module">
import { createApp, ref } from 'vue'

createApp({
setup() {
// component logic
// declare some reactive state here.

return {
// exposed to template
}
}
}).mount('#app')
</script>

<div id="app">
<h1>Make me dynamic!</h1>
</div>

reactive() 只能作用於物件(包括陣列和內建類型如 Map 和 Set)。另一方面,ref() 可以接受任何類型的值並創建一物件,其內部值通過 .value 屬性暴露出來:

import { ref } from 'vue'

const message = ref('Hello World!')

console.log(message.value) // "Hello World!"
message.value = 'Changed'

有關 reactive()ref() 的更多細節,可以參考官方教學指南 - 響應式基礎

在組件的 <script setup> 區塊中聲明的響應式狀態可以直接在模板中使用。我們可以基於 counter 對象和 message 的值,使用 Mustache 語法渲染動態文字:

<template>
<h1>{{ message }}</h1>
<p>Count is: {{ counter.count }}</p>
</template>

注意,當在模板中訪問 messageref 值時,我們不需要使用 .value:它會自動取值,以提供更簡潔的用法。

Mustache {{ }} 中的內容不限於標識符或路徑 —— 我們可以使用任何有效的 JavaScript 表達式:

<template>
<h1>{{ message.split('').reverse().join('') }}</h1>
</template>

現在,試著自己創建一些響應式狀態,並使用它來為模板中的 <h1> 渲染動態文本內容吧!

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

const counter = reactive({ count: 0 })
const message = ref('Hello World!')
</script>

<template>
<h1>{{ message }}</h1>
<p>Count is: {{ counter.count }}</p>
</template>

總結

Vue.js 3 提供了更好的性能、更靈活的 API 和更簡潔的開發體驗。無論是使用 Composition API 還是 Options API,都能快速上手並構建強大的前端應用。

Vue3 Options API 和 Composition API 風格差異教學筆記 | 學習筆記

· 閱讀時間約 3 分鐘
kdchang

根據官方文件的說明,一般來說 Vue 元件可以用兩種不同的 API 風格來撰寫:Options APIComposition API


Options API

使用 Options API 時,我們透過一個包含 datamethodsmounted 等選項的物件來定義元件邏輯。選項中定義的屬性會在函式內透過 this 曝露,this 指向的是元件實例。

<script>
export default {
// 從 data() 返回的屬性成為響應式狀態,
// 並會透過 `this` 曝露。
data() {
return {
count: 0
}
},

// Methods 是變更狀態並觸發更新的函式,
// 可作為模板中的事件處理程序綁定。
methods: {
increment() {
this.count++
}
},

// 生命週期鉤子會在組件的不同階段被調用。
// 此函式會在組件掛載時調用。
mounted() {
console.log(`初始計數值為 ${this.count}`)
}
}
</script>

<template>
<button @click="increment">Count is: {{ count }}</button>
</template>

Composition API

使用 Composition API 時,我們透過導入的 API 函式來定義組件邏輯。在單文件組件 (SFC) 中,Composition API 通常搭配 <script setup> 使用。setup 屬性是一個提示,它讓 Vue 執行編譯時轉換,從而減少樣板代碼。舉例來說,在 <script setup> 中宣告的導入、第一層變數和函式可直接用於模板中。

以下是相同的組件,模板保持不變,但改用 Composition API 和 <script setup>

<script setup>
import { ref, onMounted } from 'vue'

// 響應式狀態
const count = ref(0)

// 改變狀態並觸發更新的函式
function increment() {
count.value++
}

// 生命週期鉤子
onMounted(() => {
console.log(`初始計數值為 ${count.value}`)
})
</script>

<template>
<button @click="increment">Count is: {{ count }}</button>
</template>

該選擇哪種風格?

這兩種 API 風格都能滿足常見的使用場景。它們是基於相同底層系統的不同介面。實際上,Options API 是基於 Composition API 實現的!Vue 的核心概念和知識在兩種風格中是共通的。

  1. Options API

    • 圍繞「組件實例」(如範例中的 this)進行設計,對於來自 OOP 語言背景的使用者,這種風格通常更符合以類為基礎的思維模型。
    • 初學者友好,通過選項分組的方式隱藏了響應式細節,簡化程式碼組織。
  2. Composition API

    • 在函式作用域中直接宣告響應式狀態變數,並透過組合多個函式來管理複雜性。
    • 更加靈活,但需要對 Vue 的響應式機制有深入理解才能有效使用。
    • 適合組織和重用邏輯的更強大模式。

學習上的建議

  • 新手學習:選擇對您來說更容易理解的風格。大多數核心概念在兩種風格中是共通的,您之後可以再學習另一種風格。
  • 生產使用
    • 如果不使用建構工具,或計畫主要用於低複雜度場景(如漸進式增強),建議使用 Options API
    • 如果計畫使用 Vue 構建完整應用,建議使用 Composition API + 單文件組件

在學習階段,我們也不需要僅限於某一種風格。可以根據適合的情境使用適合的 API 風格。