# Vue.js 課程筆記(Vue - The Complete Guide) ###### tags: `線上課程` `Vue.js` # 參考 * [Udemy 課程:Vue - The Complete Guide (w/ Router, Vuex, Composition API)](http://www04.eyny.com/index.php) * [勇者鬥 Vue 龍](https://peterhpchen.github.io/VuejsQuest/basic/01_Preface.html) * [Awesome Vue.js](https://awesome-vue.js.org/) # Ch2 新增並連接 Vue 的實體 ```htmlembedded= <section id="user-goal"> <h2>My Course Goal</h2> </section> ``` ```javascript= const app = Vue.createApp() app.mount('#user-goal') ``` 在 html 插入並綁定 Vue ```htmlembedded= <p>{{ outPutGoal }}</p> ``` ```javascript= const app = Vue.createApp({ data() { return { courseGoal: 'Finish the course!' } } }) app.mount('#user-goal') ``` * `v-bind` 綁定 html 元素的屬性 * Vue App 的 `methods` * `methods` 裡的 `this` 指向 Vue Apps 中 `data` 的變數 * 用 `v-html=` 從 `data()` 中輸出 html 的語法而不是字串 ```htmlembedded= <p v-html="outPutGoal()"></p> courseGoalB: '<h2>Master Vue</h2>' ``` ## 事件綁定 * Vue 綁定事件 ``` <button v-on:click="counter++">Add</button> <button v-on:click="counter--">Remove</button> <p>Result: {{ counter }}</p> data() { return { counter: 0, }; }, ``` * 事件修飾符 (Event Modifier),下面例子等於 `event.preventDefault();` ```htmlembedded= <form v-on:submit.prevent="submitForm()"> </form> ``` * `v-once` 將元素的內容鎖定在初始值 ```htmlembedded= <p v-once>Starting Counter: {{ counter }}</p> ``` * 雙向綁定,綁定資料也會監聽表單輸入事件,常用在input、select、checkbox `v-model=name` * 當 `methods()` 作為資料綁定,如果函數被執行,Vue 也會執行 `methods()` 內的其他函數,如果使用`computed()`,則不會 >only use methods if you know that you want to recalculate a value whenever anything on the page changed. * `watch()`,監視某個`data`,當值變動時會執行函數 ```javascript= watch: { counter(value) { if (value > 50) { setTimeout(() => { this.counter = 0 }, 1000); } } } ``` * 比較 * `methods()` => event-binding * `computed()` => data-binding * `watch()` => * 縮寫: * `v-bind:url` => `:url` * `v-on:click` => `@click` * Vue 操作 CSS ```htmlembedded= <div :class="['demo', { active: boxASelected }]" @click="boxSelected('A')"></div> ``` # Ch3 * `v-if` * `v-else` * `v-show` * 比較 * `v-if`:如果沒滿足,元素就不存在 * `v-show`:元素一直存在於頁面中,只是透過`display: none` 的方式將元素隱藏起來 * `v-for` * 為了避免重複產生 DOM 元素而浪費資源,在 `v-for` 中要設定 `key` ,通常是元素的_id # Ch4 打怪小遊戲 * 玩家攻擊,並受到怪物反擊 * 玩家和怪物的血量條外觀隨著變化 => `css style` * 設置一個變數紀錄回合數,每三回合,玩家可以特殊攻擊一次 * 玩家回血,並消耗一次回合 * Game Over 功能,設置 `winner` 變數,並用 `watch()` 監視玩家和怪物的血量,產生贏家或平手 * 如果血量小於0,`style` 顯示直接歸零 * Game Over 後產生 Start New Game 按鈕,會重製所有 `data()` 中變數的值 * 設置投降事件,按下 surrender 按鈕後,直接設置 `winner`變數值為 `monster`,遊戲結束 * 設定 Log 紀錄,每個 logMessage 有`{ actionBy, actionType, actionValue }`,並根據 `actionBy` 和 `actionType` 有不同的 `style` # Ch6 Component (元件) ## Global 全域註冊 使用 Vue.component 語法來註冊一個元件,在註冊全域元件時要給予兩個參數,分別為「組件名稱」及「選項物件」,在下方範例中「組件名稱」為 `friend-contact`,「選項物件」則為其後的內容。 ```javascript= app.component('friend-contact', { template: ` <li> <h2>{{ friend.name }}</h2> <button @click="toggleDetails"> {{ isDetailVisible ? 'Hide' : 'Show' }} </button> <ul v-if="isDetailVisible"> <li><strong>Phone:</strong> {{ friend.phone }}</li> <li><strong>Email:</strong> {{ friend.email }}</li> </ul> </li> `, data() { return { isDetailVisible: false, friend: { id: 'manuel', name: 'Manuel Lorenz', phone: '01234 5678 991', email: 'manuel@localhost.com' } } }, methods: { toggleDetails() { this.isDetailVisible = !this.isDetailVisible } } }) ``` # Ch7 Vue CLI # Ch8 Component Comunication ## Props (properties) (Parent => Child) 子組件可以設定 `props` 屬性,而父組件可以將這些屬性用 DOM 客製屬性設定在子組件上,在子組件內就可以當作實體中的屬性使用。 HTML 屬性需要使用 kebab-case ,全小寫並使用分隔符號( `-` )來設定,因此雖然在 JavaScript 內可以用 camelCase 設定,但在 HTML 屬性上還是要用 kebab-case 給予屬性值。 ```javascript= // App.vue <template> <section> <header> <h1>My Friends</h1> </header> <ul> <friend-contact name="Xing" phone-number="0123 456" email-address="asd123@gmail.com" ></friend-contact> <friend-contact name="Andy" phone-number="0999 456" email-address="ccc1515@gmail.com" ></friend-contact> </ul> </section> </template> // FriendContact.vue <template> <li> <h2>{{ name }}</h2> <button @click="toggleDetails"> {{ detailsAreVisible ? "Hide" : "Show" }} Details </button> <ul v-if="detailsAreVisible"> <li> <strong>Phone:</strong> {{ phoneNumber }} </li> <li> <strong>Email:</strong> {{ emailAddress }} </li> </ul> </li> </template> <script> export default { props: ["name", "phoneNumber", "emailAddress"], data() { return { detailsAreVisible: false, friend: { id: "manuel", name: "Manuel Lorenz", phone: "0123 45678 90", email: "manuel@localhost.com", }, }; }, methods: { toggleDetails() { this.detailsAreVisible = !this.detailsAreVisible; }, }, }; </script> ``` ## Props 是不可改變的 * 不能從子組件改變 props 的值 * 改變 props 值得方法 * 從父組件改變 * 在子組件中,把 props 的初始值指派給一個新的變數 ## Props 屬性驗證 `props` 除了使用陣列宣告,也可以用物件宣告,而物件中可以定義此屬性的類型、驗證器。 使用陣列定義 ```javascript= props: ["name", "phoneNumber", "emailAddress", "isFavorite"], ``` 使用物件定義每個屬性的型別、是否必須、預設值、驗證器 ```javascript= props: { name: { type: String, required: true, }, phoneNumber: { type: String, required: true, }, emailAddress: { type: String, required: true, }, isFavorite: { type: String, required: false, default: "0", validator: function(value) { return value === "1" || value === "0"; }, }, }, ``` ## 動態組件 使用子組件時可以用 `v-bind` 綁定元素,使用相關語法 ```javascript= // APP.vue <template> <section> <header> <h1>My Friends</h1> </header> <ul> <friend-contact v-for="friend in friends" :key="friend.id" :name="friend.name" :phone-number="friend.number" :email-address="friend.email" :is-favorite="true" ></friend-contact> </ul> </section> </template> ``` ## $emit (Child => Parent) ## 定義並驗證客製事件 ```javascript= emits: ["toggle-favorite", 其他 emit...] ``` 進階的驗證,確認 $emit 函數的參數 ```javascript= emits: { "toggle-favorite": function (id) { if (id) { return true; } else { console.warn("id is missing!"); return false; } }, } ``` ## 依賴注入 provide & inject $emit 與 inject 的比較,預設應該使用 $emit,但是如果組件之間溝通要跨越很多層,就可以使用 inject。 # Ch9 元件進階 ## local 區域註冊 使用全域註冊的缺點是,不管有沒有使用到這個組件,只要使用全域註冊就一定會載入,因此使用全域註冊會將原本不需要的組件也載入進來,拖慢載入的時間。 所以針對某些特定實體設計的組件就可以用區域註冊的方式,註冊在需要它的組件中。 ```javascript= import TheHeader from "./components/TheHeader.vue"; import BadgeList from "./components/BadgeList.vue"; import UserInfo from "./components/UserInfo.vue"; export default { components: { the-header: TheHeader, badge-list: BadgeList, user-info: UserInfo, }, data() { return { } } } ``` ## CSS Style 作用域 Vue 可以很容易的將 CSS 模組化。 在每個組件中設置的 `style` 預設為全域變數,如果要設置區域範疇的 `style` ,要加上 `scope`。 ```javascript= <style scoped> h1 { ... } </style> ``` ## Slot ## Vue Fragment (根節點) 在 Vue3,組件的 template 內部要設置一個根節點 ```htmlembedded= <template> <div> <h1> ... </h1> </div> </template> ``` 在 Vue3,組件的 template 可以不用設置根節點 ```htmlembedded= <template> <h1> ... </h1> </template> ``` ## Vue 撰寫風格 [官方文件](https://cn.vuejs.org/v2/style-guide/) ## Vue 檔案結構 元件應該以不同類型來區分,例如 UI、Layout... # Ch11 Form 表單 # Ch12 Http Request # Ch13 Vue Router # Ch14 Animation & Transition # Ch15 Vuex