筆記 - Vue.js Intro (1)

透過 Vue.js 官網 tutorial 學習的筆記。學習標的為 Vue 3, using composition API.

Introduction

.vue 一個檔案可以包含 HTML (template), CSS (styles), and JavaScript (component’s logic). 稱 Single-File Components (SFC).

Key words of Vue: 宣告式 declarative, component-based programming model

Two core features of Vue:

  • Declarative Rendering: Vue extends standard HTML with a template syntax that allows us to declaratively describe HTML output based on JavaScript state.
  • Reactivity: Vue automatically tracks JavaScript state changes and efficiently updates the DOM when changes happen.

兩種 API Styles

  • Options API: define a component’s logic using and object of options such as data, methods, and mounted. Properties defined by options are exposed on this inside functions, which points to the component instance. 感覺像是 JavaScript 物件宣告
  • Composition API: define a component’s logic using imported API functions. In SFCs, used with <script setup>. The setup attribute is a hint that makes Vue perform compile-time transforms that allow us to use Composition API with less boilerplate 模板.
    1
    2
    3
    <script setup>
    import { ref, onMounted } from 'vue'
    ...

Reactivity Fundamentals

Declaring Reactive State: reactive()

Create a reactive object or array with reactive():

1
2
import { reactive } from 'vue'
const state = reactive({ count: 0 })

Reactive objects are JavaScript Proxies and behave just like normal objects. The difference is that Vue is able to track the property access and mutations of a reactive object.
之後再讀:Reactivity in Depth

To use reactive state in a component’s template, declare and return them from a component’s setup() function:

實作發現 <script setup> 下面不能 export,就直接寫裡面的東西就好了 (2022/12/24)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { reactive } from 'vue'

export default {
// `setup` is a special hook dedicated for composition API.
setup() {
const state = reactive({ count: 0 })

function increment() {
state.count++
}
// expose the state to the template
return {
state,
increment
}
}
}
1
2
3
4
5
<div>
<button @click="increment">
{{ state.count }}
</button>
</div>

<script setup>

待補

Template syntax: v- directives

A directive is a special attribute that starts with the v- prefix. They are part of Vue’s template syntax. Similar to text interpolations, directive values are JavaScript expressions that have access to the component’s state.
See Template Syntax.

Attribute Binding: v-bind

Use v-bind to bind an attribute to a dynamic value.

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

The part after the colon (:id) is the “argument” of the directive.
dynamicId is the property from the component’s state.

1
<h1 v-bind:class="titleClass"> or <h1 :class="titleClass">

with

1
2
3
4
5
<style>
.title {
color: red;
}
</style>

Event Listeners: v-on

Listen to DOM events using the v-on directive. Argument: native DOM event.

1
2
<button v-on:click="increment">{{ count }}</button> or
<button @click="increment">{{ count }}</button>

while increment is referencing a function declared in <script setup>.

1
2
3
4
5
6
7
8
<script setup>
import { ref } from 'vue'
const count = ref(0)
function increment() {
// update component state
count.value++
}
</script>

See Event Handling.

Form Bindings v-model: bind v-bind and v-on

Using v-bind and v-on together, create two-way bindings on form input elements.

1
<input :value="text" @input="onInput">
1
2
3
4
function onInput(e) {
// a v-on handler receives the native DOM event as the argument.
text.value = e.target.value
}

To simplify two-ways bindings, Vue provide v-model which is a syntax sugar. v-model automatically syncs the <input>‘s value with the bound state, so we no longer need to use an event handler for that. 連function onInput都不用了

1
<input v-model="text">

Applicable on inputs: text inputs, checkboxes, radio buttons, select dropdowns.

See Form Input Bindings.

Conditional Rendering v-if

Use v-if to conditionally render an element. Use v-else and v-else-if to denote other branches of the condition.

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

The <h1> will be rendered only if awesome.value is truthy.

See Conditional Rendering.

List Rendering v-for

Use v-for to render a list of elements based on a source array.

1
2
3
4
5
<ul>
<li v-for="todo in todos" :key="todo.id">
{{ todo.text }}
</li>
</ul>

Note:

  1. todo is a local variable and only accessible on or inside the v-for element.
  2. We are also giving each todo object an unique id, and binding it as the special key attribute for each <li> to match the position of its corresponding object in the array.

Two ways to update the list:

  1. Call mutating methods on the source array
    1
    todos.value.push(newTodo)
  2. Replace the array with a new one:
    1
    todos.value = todos.value.filter(/*...*/)
    See List Rendering.

Computed Property computed()

Create a computed ref that computes its .value based on other reactive data sources by introducing computed().

會依據其他 ref 來源會連動自動更新值

To render different list items based on the state, with a button that toggles the hideCompleted state.

1
2
3
4
5
6
7
8
9
10
11
import { ref, computed } from 'vue'

const hideCompleted = ref(false)
const todos = ref([
/* ... */
])

const filteredTodos = computed(() => {
// return filtered todos based on `todos.value` & `hideCompleted.value`
return hideCompleted.value ? todos.value.filter(t => !t.done) : todos.value
})
1
2
- <li v-for="todo in todos">
+ <li v-for="todo in filteredTodos">

See Computed Properties.