---
# System prepended metadata

title: VUE.js練習筆記
tags: [vue.js, js]

---

# 建立資料夾
在VScode用terminal命令，建立一個vue.js資料夾
```
npm init vue@latest
```

會問一系列的問題，本次練習單頁面，所以node router點選y即可
然後取名字，本次取為"vue-training"
:::success
這樣就建立好vue.js專案了
:::

## 打開vue並執行測試
####  首先安裝第三方套件
```
npm install
```
這會根據電腦去下載可能會需要的套件
全部都安裝到新增的"**node_modules**"資料夾裡面

#### 執行測試看看這個專案是否能正常運作
```
npm run dev
```
運行後長這樣
![image](https://hackmd.io/_uploads/Bkr2Djoi6.png)
點擊連結後
![image](https://hackmd.io/_uploads/Byve_sijp.png)
:::success
這樣運行成功了！！ :tada: 
:::

若是要暫停此測試
在terminal上**ctrl+C**即可暫停

---

# VUE專案結構

- package.json 基礎專案描述檔
- vite.config.js 專案建置工具設定檔
- 子資料夾：
- - .vscode 開發環境設定
- - node_modules 第三方套件安裝位置
- - src 主要的程式原始碼資料夾
- - public 靜態檔案資料夾(ex. image、icon...)
- - dist 專案建置後存放的位置(> npm run build)

## 用命令做專案的建置

#### 成品輸出
打包原始程式碼(src)，輸出後檔案接到特定資料夾(dist)
通常用於**最後**輸出成果
```
npm run build
```

#### 開發測試 
啟動內建伺服器，不輸出檔案，直接在記憶體中建置專案
隨時反映原始碼的更新！！
```
npm run dev
```

---

# 試著建立第一個Vue App!(理論)
一個以Vue開發的網頁應用包含一到多個組件
下方是建立一個Vue App會做的事情：
- 建立最基礎的HTML ==index.html==
- 建立一個**根組件**==App.vue==(組件中最頂層的那個)
- 建立一個主程式檔案==main.js==(一般的javascript程式)
- 在主程式==main.js==中建立Vue App(寫一點程式碼)：
- - 載入、設定根組件
- - 設定掛載的HTML標籤(我們的APP要掛載在哪個html標籤底下)

## 建立Vue App 
使用**createApp**函式
使用方式：
- 載入createApp函式
```
import {createApp} from "vue"
```
- 載入、設定根組件(在主程式中)
```
import 根組件名稱 from "組件檔案路徑"
const app="createApp(根組件名稱)"
```
- 設定掛載的HTML標籤
```
app.mount("CSS選擇器")
```

## 什麼是Vue 組件？(Single File Component)
使用單一一個程式檔案代表一個組件。

#### 組件的概念
將網頁的HTML、CSS、JavaScript包裹在一個vue程式檔案中
示意：
```
#組件名稱.vue

<script setup>
 //javascript程式碼
</script>

<template>
<!---HTML樣板結構--->
</template>

<style scoped>
/*CSS設定*/
</style>
```
![image](https://hackmd.io/_uploads/B1ZPxnoip.png)

---

# 試著建立第一個Vue App!(實操)
因為要從頭開始實際操作，所以原始的src裡面的資料全都要清空，從0開始

## 建立一個基礎的HTML程式(index.html)
裡面有個關鍵，body的`<div id="app"></div>`其中id設定為"app"
而vue的應用程式就是要掛載在這個id底下！
底下`<script type="module" src="/src/main.js"></script>`為了要引入我們的主程式
![image](https://hackmd.io/_uploads/rysFz3jsa.png)

## 建立main.js
#### 載入createApp函式
```
import { createApp } from "vue";
```
#### 載入根組件
尚未有組件，所以立刻在src底下建立一個file
```
import App from "./App.vue";
```
#### 建立Vue App物件
```
const app = createApp(App);
```

#### 掛載到HTML標籤底下
```
app.mount("#app");
```
![image](https://hackmd.io/_uploads/rkLVSnoja.png)
## 關於App.vue
東西都用好了，缺根組件。
在裡面寫下規則上的程式碼。
```
<script setup>
    console.log("我的第一個組件");
</script>

<template>
    <nav>導覽列</nav>
    <main>基本主內容</main>
</template>

<style scoped
    main{background-color: #dddddd;}
</style>
```

---

# Vue 的樣板語法！標籤內文與屬性
回顧組件的基本組成： 完整涵蓋HTML、CSS、JavaScript
![image](https://hackmd.io/_uploads/B1ZPxnoip.png)

## 樣板的用途
程式、與HTML之間的關係。
==可以根據程式中的(變數)資料，產生最終的畫面。==
舉個栗子：

![image](https://hackmd.io/_uploads/rJHeQF2sa.png)

## 樣板語法：內文
#### 如何在HTML中嵌入純文字？
==標籤內使用{{**嵌入的變數**}}語法==
栗子：
![image](https://hackmd.io/_uploads/SkXJVtnip.png)

#### 如何嵌入HTML語法？
==標籤屬性設定v-html="嵌入的變數"==
栗子：
![image](https://hackmd.io/_uploads/SkBDEY2ia.png)

## 樣板語法：屬性
樣板的標籤屬性，如何綁定一個變數？綁定程式中的變數名稱？
#### 如何嵌入屬性值？
標籤屬性設定
==v-bind:屬性名稱="嵌入的變數"==
![image](https://hackmd.io/_uploads/Sy4QwYhoa.png)
#### 嵌入屬性值-簡寫 :+1: 較為常用
:屬性名稱="嵌入的變數"
![image](https://hackmd.io/_uploads/rylavFnoa.png)

## 樣板語法：程式語句
使用JavaScript的程式語句。
### 透過程式語句產生標籤內文
標籤內使用 =={{程式語句}}== 語法
舉個栗子：
![image](https://hackmd.io/_uploads/H11aOthjp.png)
### 透過程式語句產生標籤屬性值
標籤屬性設定
==:屬性名聲="程式語句"==
![image](https://hackmd.io/_uploads/HJ0WH92sp.png)

---

# Vue 的樣板語法！流程控制
樣板裡面的判斷式&迴圈
## 判斷式
### if判斷式
使用==v-if="布林值"==
![image](https://hackmd.io/_uploads/SJDjI4l2p.png)
### if...else判斷式
使用==v-else==語法，需搭配==v-if==使用
![image](https://hackmd.io/_uploads/BkO-P4g3p.png)
>  :bookmark: 小提醒 
>  boolean值若是要實作的話
>  在執行if else 某值=3000時
>  ==等號==要這樣寫：
```
<div v-if="level===3">大神</div>
```
### if...else if...else
![image](https://hackmd.io/_uploads/SkamvVehT.png)
## 迴圈
### for 迴圈 - 陣列
使用 ==v-for="變數 in 陣列"== 語法
![image](https://hackmd.io/_uploads/HkDnDEl2p.png)
### for 迴圈 - 陣列索引
==v-for="(變數,變數) in 陣列"==
![image](https://hackmd.io/_uploads/S1dM_Neh6.png)
通常前者是"資料"，第二個"變數"是「索引」
```
<script setup>
 let data=["A", "B", "C"];

</script>
<template>
    <div v-for="(text, index) in data">
     {{index}} - {{text}}
    </div>
</template>

# print出來的結果是：
0 - A
1 - B
2 - C
```
### for 迴圈 - 物件
針對「物件」做迴圈
==v-for="(變數,變數) in 物件"==
![image](https://hackmd.io/_uploads/Syi8FNeha.png)
```
<script setup>
    #dictionary物件 
    # {"key": value,...}
    let data={"x":3, "y":4};
</script>
<template>
    <div v-for="(value, key) in data">
     物件屬性{{key}} 為 {{value}}
    </div>
</template>

# print出來的結果是：
x 為 3
y 為 4
```

---

# Vue 的樣板語法！事件處裡
## 基本事件處裡
使用 ==v-on:事件名稱="函式名稱"== 語法

![image](https://hackmd.io/_uploads/HyrWW8g3p.png)
- click: 點擊事件
- handler: 函式名稱(在上方script創建的函式)
- :+1: 這樣就可以在span標籤上加上「點擊」處理

### 基本事件處裡 - 簡寫
==@事件名稱="函式名稱"== 語法
![image](https://hackmd.io/_uploads/SkOxfLxhT.png)
- mouseover: 事件名稱，滑鼠移動
- 這樣此程式碼的span有兩個事件，一個是click，一個是mouseover

## 使用修飾字
### 使用**once**：表達事件只觸發一次
==v-on:事件名稱.once="函式名稱"==
==@事件名稱.once="函式名稱"==
:heavy_check_mark: 表達此事件只觸發 **「一次」**
![image](https://hackmd.io/_uploads/rytKrOlnT.png)
### 使用**prevent**：表達停止預設行為
==v-on:事件名稱.prevent="函式名稱"==
==@事件名稱.prevent="函式名稱"==
![image](https://hackmd.io/_uploads/HyUZDdxna.png)
- 預設，此a超連結預設到此連結對應的網址
- 利用**prevent**，停止"超連結"這個預設行為，這樣再點擊一次就不會連到另一個網頁了
- 轉而執行函式 **"handler"**

---

# Vue 響應式狀態
## 何謂 「非響應式的狀態」？
資料和畫面沒有連動。
![image](https://hackmd.io/_uploads/HyPAHYg3a.png)
比如上圖。
原先的div 的變數 content 是 "網站的內容"
下方button 設定上click後，觸發handler函式，變數content應該要變為"新的網站內容"
但是在目前的狀況下畫面是不會更動的。
變數的資料已被更改，但是畫面並不會和變數資料作連動，仍保持原來的內容。
這就是所問 ==「非響應式狀態」==，之前所做的練習都是這個狀態
:::warning
:exclamation:這樣無法在使用者作練習時，變數跟畫面連動，看不清效果
 
無法在使用者點擊按鈕時，看不到改變內容，也沒辦法繼續做更多的事情。

所以要做出應對措施。
:::
## 響應式狀態
==資料和畫面連動。==
### 建立響應式狀態之步驟
:::spoiler **點選看在哪邊施作**
:exclamation: 下方步驟皆在App.vue根組件上完成！！
:::
vue提供了響應式狀態的相關資源：
- 載入 Vue 的 **ref** 函式
```
import {ref} from "vue";
```
- 呼叫 ref 函式並建立響應式狀態
```
let content = ref(資料);

#這個content是變數，儲存響應式資料的變數
```
- 在樣板中使用，顯示資料
```
<div>{{content}}</div>

# content是變數名稱
```
- 更新響應式壯代的資料
```
content.value=新的資料

# content得到原來的響應式狀態之參考，*.value*代表它內部的資料
# 新的資料就要放在他value的屬性中。
```
:::success
這樣資料更新完後，畫面也跟著做連動。

這就是響應式狀態的做法了:tada:
:::

### 響應式狀態-範例(1)
![image](https://hackmd.io/_uploads/r14-f5x2T.png)
### 響應式狀態-範例(2)
![image](https://hackmd.io/_uploads/HyPKz5gna.png)

:label:**補充**
- 此範例動到css
- 原先給的響應式資料為"title"，為class命名
- 後透過button執行handler函式，class改名為title highlight
- css有兩個設定分別為title和highlight，響應式變動後div的class新增了hightlight，所以也會吃到此css選擇器的設定
- 可以用到，畫面中「白天黑夜」一鍵切換的那種場景
### 響應式狀態-實作(1)
資料用物件的方式整理，template的div要怎麼擷所需的資料？
```
<script setup>
    import {ref} from "vue";
    let state = ref({
        title:"網站標題",
        className:"title"
    });
    
    let handler = function(){
        state.value.title="新的網站標題";
        state.value.className="title highlight";
    }
    
    # state.value 是代表state的狀態
    # 要修正裡面的值就用state.value.title等等
</script>

<template>
    <main>
        <div :class="state.className">{{ state.title }}</div>
        <button @click="handler">按鈕</button>
    </main>
</template>

<style scoped>
    .title{font-weight:bold}
    .highlight{color: red;}
</style>
```
:::success
:tada:這樣基本完成把狀態套用在樣板中
:::

---

# Vue 響應式狀態-表單輸入元件
接收使用者輸入的HTML元件，在Vue有特別的處理方式
## 表單輸入元件
- 單行、多行輸入框
```htmlembedded!
<!--- 單行--->
<input type="text">

<!--- 多行--->
<textarea></textarea>
```
- 多選方框、單選圓框
```htmlembedded!
<!--- 多選--->
<input type="checkbox" />

<!--- 單選--->
<input type="radio" />
```
- 下拉式選單
```htmlembedded!
<select>
    <option>1</option>
    <option>2</option>
</select>
```

## 輸入元件&響應式狀態之綁定
### 綁定響應式狀態
使用==v-model="響應式狀態名稱"==
輸入的資料和響應式狀態連動
![image](https://hackmd.io/_uploads/rk3Pjt-na.png)
```
<script setup>
    import {ref} from "vue";
    let text = ref("預設的文字")
</script>

<template>
    #下方 *v-model="text"* 是script內的text，其內容為"預設文字"
    <input type="text" v-model="text" />
    
    # 輸入文字的{{text}}連動上方的v-model，使用者改什麼，下方div區塊的內文也會跟著變動
    <div>輸入文字：{{text}}</div>
</template>
```
### 單選框的範例
多個選擇框綁定 ==同一個響應式狀態== 資料和標籤的value屬性對應
![image](https://hackmd.io/_uploads/SJDOat-np.png)
- 此響應式資料設定為 **gender**
- **gender** 設定時為null，沒有東西，他的變動來自於我們賦予他什麼值
- 若是選擇了radio 男，**gender**會取得此radio的value="male"，==gender="male"==
- 若是女性，以此類推，==gender="female"==
:::success
最終下方的 **{{gender}}** 會跟著所選擇的對象作連動顯示
:::
### 多選框範例
綁定的響應式狀態使用==陣列資料==
資料和標籤的 **value** 屬性相應
![image](https://hackmd.io/_uploads/r1TYZc-2a.png)
- 當選到某個checkbox，裡面的value就會存進**friut陣列**裡面
### 下拉式選單範例
綁定**select標籤**，==資料和option標籤的value屬性對應==
![image](https://hackmd.io/_uploads/By8w6kQ3T.png)
- 這個gender是空字串

---

# Vue 組件結構：基本觀念&語法
前些練習，得知單一組件來完成
可使當網頁越來越複雜時，所有程式碼放在單一組件會難以維護
:::info
若是把網頁分割成一塊塊，就能讓許多工程師各自做自己的區塊，合力建立一個網站。
:::
## 組件的切割
將網頁根據實際的畫面區塊，切割成多個組件。
```
# App.vue

<script setup>
    console.log("導覽列相關程式碼");
    console.log("主區塊相關程式碼");
</script>

<template>
    # 分成 nav 和 main 兩塊部分
    <nav>
        網頁導覽列
    </nav>
    <main>
        <div>區塊 01</div>
        <div>區塊 02</div>
    </main>
</template>

<style scoped>
    nav{font-weight: bold}
    main{padding:30px 0px}
</style>
```

為了分別兩個區塊的差別，給他做了切割
```
# Nav.vue

<script setup>
    console.log("導覽列相關程式碼");
</script>

<template>
    <nav>
        網頁導覽列
    </nav>
</template>

<style scoped>
    nav{font-weight: bold}
</style>
```

```
# Main.vue

<script setup>
    console.log("主區塊相關程式碼");
</script>

<template>
    <main>
        <div>區塊 01</div>
        <div>區塊 02</div>
    </main>
</template>

<style scoped>
    main{padding:30px 0px}
</style>
```

App.vue根組件做了切割後，就不需要將所有的東西寫在根組件裡面，只需要做出引入的動作就好。
因此App.vue改寫成這樣：
```
# App.vue

<script setup>
    import Nav from "./Nav.vue";
    import Main from "./Main.vue";
</script>

<template>
    <Nav></Nav>
    <Main></Main>
</template>

<style scoped>
</style>
```
![image](https://hackmd.io/_uploads/SJs5D4Xhp.png)
## 組件結構：基本語法
### 載入組件
在程式中載入其他的組件
語法： ==import 組件名稱 from "組件檔案路徑"==
栗子：
```
<script setup>
    import NavComp from "./Nav.vue";
</script>
```
> 組件名稱可隨意自取
### 使用載入的組件
組件就像自定義的HTML標籤
若是要在樣板中使用已載入的組件
==<組件名稱></組件名稱>==
栗子：
```
<script setup>
    import NavComp from "./Nav.vue";
</script>
<template>
    <NavComp></NavComp>
</template>
```