# [筆記]VUE教學資料 # :memo: 前言 Vue.js 的優勢: * 容易導入: Vue 核心庫只專注在處理視圖層( view layer )的設計使其可以很輕鬆地套用在舊有的系統上。 * 完整的擴展工具: 如果你的需求是要從無到有開發的話,可以使用 Vue CLI 創建整合 Vue Core 、 Vue Router 、 Vuex 的完整前端解決方案,不用任何的設置就可以開始開發,這也是為什麼 Vue.js 自稱為是漸進式的 JavaScript 框架。 * 易學: 使開發者學習門檻降低,可以快速上手。 * 大量的中文資源: 由於作者 Evan You (尤雨溪)是中國人,因此 Vue.js 有良好的中文文件,也因為中國企業大量採用,使得 Vue.js 的技術文章絕大部分都可以找到中文資源。 * 完整的文件: 撇開中文資源這個優勢,Vue.js 的文件完整度非常的高,幾乎在開發上需要使用到的語法、功能都有詳細的介紹,也都帶有範例供開發者做演練,一路從官方文件看下來,大概就可以上戰場了。 **特性** * 撰寫良好的官方文件 * 輕量、高彈性 * 簡潔的語法 * 較低的學習曲線 * 穩定的社群成長 利用CDN載入 直接利用線上編輯器 利用vue-cli建立本地專案 #### Vue最主要的核心功能:『宣告式渲染』『元件系統』 > 備註: > 宣告式渲染:以宣告的方式在HTML上呈現JS裡的資料狀態。 > 指令式渲染:以操作DOM物件的方式更新及呈現資料狀態。 ### Vue.js 3.0新增的特性 * 引進Fragment特性,不在限制元件必須只能是單一根節點。 * 狀態的響應式偵測由Object.defineProperty改為Proxy API解決物件及陣列無法深度偵測更新的問題。 * 模板編譯:靜態節點優化。 * 內建新增"Teleport"、"Suspense"等功能元件。 * 新的Composition API 提供另一種對程式碼、邏輯甚至是狀態的共用管理方式,擺脫過去mixins的混亂。 * 新增steup、ref等語法糖。 ## :memo: 初探Vue.js ### 基本原理 ![](https://i.imgur.com/tFCbFxP.png) * View : 透過 HTML 及模板語法渲染出來的畫面。 * View Model : 使用 Vue.js 所建立起來的實體。 * Model : 後端程式中的商業邏輯。 * 圖中的綠色文字代表範例情境: 1. 使用者按下按鈕。 1. 透過 HTML 中模板語法的綁定觸發 Vue 實體中註冊的事件。 1. 事件中叫用 AJAX 向伺服器請求資料。 1. 伺服器取得資料後傳回給 Vue 實體。 1. Vue 實體修改綁定的 View Model 。 1. View Model 改變後觸發模板重新渲染。 1. 使用者看到改變後的畫面。 ## :memo: Vue實例 #### vue應用程式組成 ==透過new Vue()或是Vue.createApp()會得當一個新的物件,並將它指定給vm這個變數,此一新生成的物件便稱為vue實體物件,vue.js透過實體物件來掛在網頁上某dom節點,使我們可以控制網頁節點對應的內容。== Vue 只有一個參數: Options ,這個參數是一個物件,設定這實例的定義,在上面的例子設定了兩個屬性: el 及 data 。 el : 根實例的掛載目標,使用 CSS Selector 指到頁面上的元素,藉此將元素編譯成 Vue 的模板(template),只有在掛載目標(上面的例子是 `<div id="app">` )內才是此 Vue 實體的可用範圍。 data : 實例中所有欲做響應的目標,如果沒有設置在此屬性內的目標將不會觸發頁面的重新渲染。 Vue 是不支援巢狀的應用程式 ![](https://i.imgur.com/5MGanJY.png) #### 實體掛載至dom 最常見方式 2.X版本: 1. 透過option API的el屬性 ```javascript= const vm = new Vue({ el: '#app' }); ``` 2. 透過vue實體提供的mount方法來指定:先將實體new出來而非透過el屬性掛載,而是在適當時機透過$mount的方式指定掛載。 ```javascript= const vm = new Vue({ }); // options const el = document.createElement('div'); document.body.appendchild(el); // 新增節點,然後加入body vm.$mount(el); // 將VUE實體掛載至新生成的節點 ``` 3.x版本: 1. el屬性被mount()取代 ```javascript= const vm = Vue.createApp({ // options }); vm.mount('#app'); ``` #### 定義狀態與網頁模板的映射關係 ==vue.JS採用宣告式渲染愈MVVM模式操作網頁內容,故須將UI層(網頁畫面)會用到的資料狀態,預先定義在VUE.JS實體中,再由HTML模板輸出。== ==Vue.js會自動將data內的屬性加上getter及setter的特性,監控狀態更新(響應式更新)。== Vue實體被建立後,Vue.js就會自動為實體加上`$data`屬性,便可透過`vm.$data.xxx`操作內部狀態。 ```javascript= const vm = Vue.createApp({ data(){ return{ name:'aaa' } } }).mount('#app'); vm.$data.name = 'bbb'; ``` #### template模板屬性 綁定元素 除了直接使用HTML2當作Vue.js模板之外,也可透過Options裡的template屬性來定義 ```htmlembedded= <div id='app'></div> <script> const vm = Vue.createApp({ template: `<div>{{greeting}}</div>` data(){ return{ greeting: 'Hello Vue.js' } } }).mout('#app'); </script> ``` 整個 Vue 應用程式都會從一個根(Root) Vue 實例開始,這個 Vue 實例會用 new Vue({/* Options */}) 建立,而根實例的下面可以引入各種可以重複使用的組件(Component),每個組件都是一個 Vue 實例,因此整個應用程式會是一個以根實例為起始所展開的組件樹(component tree) 組件有以下特性: 1. 以客製的 HTML 標籤配置在頁面上: 例如 <TodoList> 。 1. 組件裡可以配置組件: 像是 <TodoList> 中有 <TodoItem> 及 <TodoListFooter> 。 1. 可以重複使用: 像是 <TodoList> 中使用 v-for 語法產生多個 <TodoItem> 組件。 Vue 設置模板的方式有三種: * 選項中有設置 template 時,使用 template 中的 html 取代原本元素上的配置: * 選項中有設置 render 函式時,使用 Render Function 配置模板: * 選項中沒有設置 template 屬性,也沒有設置 render 函式時,使用原本頁面上的元素配置 ### 改變畫面 使用前端框架的目的都是要簡化改變畫面的工作,在 JQuery 中,我們需要使用 CSS Selector 取得想要改變的元素,再改變元素中的屬性來變化頁面。 而在 Vue.js 中,我們對實例中的 data 做修改就可以使畫面產生變化。 data 可以從實例中的 $data 取得: ![](https://i.imgur.com/Ayw26H7.png) > 像是 $data 這種有前綴 $ 的屬性是 Vue 實例所配置的,有前綴是為了跟使用者定義的屬性作區別,所有的 $ 屬性可以在 API 文件中找到。 https://cn.vuejs.org/api/component-instance.html#data $屬性 Vue.js 中的 $ 属性通常表示 Vue 实例上的特殊属性或方法,以下是一些常见的 $ 属性及其用途: * $el:Vue 实例所管理的 DOM 元素。 * $data:Vue 实例中的数据对象。 * $props:组件实例接收到的属性对象。 * $options:Vue 实例创建时的选项对象。 * $emit:用于触发自定义事件。 * $on:用于监听自定义事件。 * $watch:用于监听数据的变化。 * $nextTick:用于在 DOM 更新后执行回调函数。 * $refs:用于访问组件或元素的引用。 * 需要注意的是,以 $ 开头的属性和方法通常是 Vue 内部使用的,不建议在应用代码中定义同名的属性和方法。 ### 總結 從大層面的地方看, **Vue 應用程式是由多個 Vue 實體所建立的,Root 實體( new Vue() )只能有一個**,而它的下面可以引用無數個不同但可重複的元件實體。 從小的地方來說, Vue 實體的配置都是需要經由定義選項物件來完成,透過 el 及 data 當作例子,講解選項物件中可以使用屬性及函式來定義各個不同的物件,Vue 實體就會依照這些定義掛載目標元素及改變畫面。 ## :memo:模板語法 Part 1 - Mustache 標籤 模板跟 Render Function 可以用下面的圖來說明 ![](https://i.imgur.com/iiGUmr0.png) * 模板會經由 Compiler 編譯為 Render Function 。 * Render Function 會因響應系統的觸發而重新渲染頁面 。 ### Mustache 標籤 就是以兩個大括號({{}})綁定實體資料的語法 加上 v-once 這個 directive 可以讓 Mustache 標籤只渲染一次,使用的方式如下: ![](https://i.imgur.com/SDqsoTP.png) ## :memo: 資料加工與邏輯整合 #### DATA屬性(2) 在vue實體中的data屬性有兩種寫法 ```javascript= // 方法一 data() { return { message: 'Welcome to Vue!' }; } // 方法二 data: { message: 'Welcome to Vue!' } ``` 如果你是採用線上編輯器打造的練習專案,現在一般較為常見的會是第一種寫法 如果這個回傳值跟資料來源的變化有關,那應該在來源有變化時在執行即可,否則會產生不必要的運算時間,降低效能,所以當要取得某個結果跟其他資料有關的值的話,用計算屬性才是上策。 之後說明了計算屬性會跟著來源資料變化、可以使用 arrow function 以及擁有 Setter 的特性。 #### methods方法 參考資料: https://ithelp.ithome.com.tw/articles/10191808?sc=rss.iron https://ithelp.ithome.com.tw/articles/10274622 http://jessicadin.com/vue-watch-%E5%92%8C-computed-%E5%92%8C-methods/ https://vuejs.org/guide/essentials/computed.html#computed-caching-vs-methods https://ithelp.ithome.com.tw/articles/10191808?sc=rss.iron 三次法則:將重複的部分程式碼提取出來,並包裝成函示重複使用。 ```htmlembedded= <div id='app'> <p>金額總共{{subtal()}}元</p> <!-- 中間略 --> <p>金額總共{{subtal()}}元</p> <!-- 中間略 --> <p>金額總共{{subtal()}}元</p> <!-- 中間略 --> </div> ``` ```javascript= const vm = Vue.createApp({ data(){ return{ price: 100, quantity: 10 } }, methods: { subtal: function(){ return this.price * this.quantity; } } }).mount('#app'); ``` 注意事項: 1. Vue.js實體中可透過this存取實體。data理的屬性price及quantity,到了methods裡就可透過this.price及this.quantity存取。 2. methods裡的內容為function,使用時需要被呼叫(需加入小括號),小括號內也可傳入參數。 3. 在實體中另個methods呼叫subtal,透過this.subtal()即,在模板內不須加this。 4. 如果在methods中需要存取實體資料的狀態,就不適合使用arrow function。 #### computed計算屬性 ==computed屬性會將計算後的結果暫存,若他所觀察的屬性(內部的this.xxxx)沒被更新的情況下,computed就不會重複被執行。== 注意事項:重複計算computed的效能比methods好,但computed的屬無法加入參數,若需要帶入參數仍需使用methods。 #### computed/methods的使用時機比較 範例: computed只有在資料有變化時才會重新計算 #### 監聽器 Vue 提供了監聽器,當資料變化時叫用函數,函數會有兩個傳入參數: 改變前的值、改變後的值,可以使用這個函數做跟此資料變化有關的處理。 ### 計算屬性與監聽器的比較 ##### 計算屬性適用場景 計算屬性在處理資料連動時有個很大的優勢,單個計算屬性就可以監聽多個資料變化 在實體內使用 $watch 會需要在 created 中處理,這樣的方式較 watch 繁瑣,所以一般還是使用計算屬性處理這類的需求。 ##### 監聽器適用場景 跟資料無關的處理 在一般情況下,資料連動使用計算屬性較為合適,但如果資料變化後的處理跟資料本身無關的話,例如說紀錄 Log 這樣的處理,跟資料本身無關,那就會比較適合使用監聽器: 今天介紹了計算屬性與監聽器各自合適的使用場景。 先介紹計算屬性適合使用在同步的資料連動上,而 $watch 雖然可以用函數設置多個監聽目標回傳值,但在實體中必須在 created 內使用,較 watch 來的繁瑣。 再來介紹監聽器適用於跟資料無關或是取得非同步資料的處理,在非同步資料的取得上,雖然計算屬性可以用第三方工具 vue-async-computed (opens new window)達到此需求,但會需要多引入工具庫,喜不喜歡就見仁見智了。 #### computed/watch/methods三者的比較 ==computed 最大特點是必須回傳一個值,並且會把它緩存起來,當函式裏的依賴改變時,才會重新執行和求值。但 watch 與 methods 不會強制要求回傳一個值,它們只需執行動作,不一定要回傳值。watch 會偵測單一個值,當它有變化時就執行。至於 methods,只要呼叫它,它就會執行,但 computed 和 watch 則不是透過呼叫來執行。 最大的區別為 computed 會將輸出的結果存下來,而 method 不會。 在以下例子中,頁碼是需要一直變化的,所以放在 methods 中。至於分頁需求要用來操作陣列的 pageStart, totalPage, filterRows,其結果是要存下來以供篩選和搜尋用的,所以用 computed。 methods 需要綁定事件來啟動,而 computed 是只要相關的值有變化就會重新計算。== > 參考資料:https://ithelp.ithome.com.tw/articles/10274622 ##### ==computed== * computed 的函式必須要回傳一個值。 * computed 的函式無法傳入參數。 參考資料 https://ithelp.ithome.com.tw/articles/10187537 ##### ==watch== 參考資料https://ithelp.ithome.com.tw/articles/10221281 watch 的意義? 顧名思義就是監聽某個數值的變化。因為每次執行搜尋,需要將 data 內的 currentPage 變數修改回 1,這時就可以用 watch 來監聽 filterRows 的狀況。每當 filterRows 執行時,就將 this.currentPage = 1 。 https://smlpoints.com/notes-vue-js-search-and-filter-table-through-props-data-computed-methods-watch.html ##### ==methods== * methods 函式被呼叫就一定會執行。 * methods 函式不一定要回傳一個值。 * methods 函式可傳入參數。 * 跟 computed 明顯不同,一旦 methods 被呼叫,它不管函式裏的所有依賴有沒有變化,也會照樣執行。 ## :memo: Vue實體的生命週期 Vue.js網頁應用程式是由各種元件組成,每個Vue元件從建立到被銷毀,都有它的生命週期階段。 Vue的實體物件從建立、掛載、更新到銷毀移除等過程稱為"生命週期"。 ![](https://i.imgur.com/d0JhTZd.png) > 圖片來源: [重新認識 Vue.js | Kuro Hsu](https://book.vue.tw/CH1/1-7-lifecycle.html) ### 各階段的鉤子函式 | Hooks | Hooks | 說明 | | -------- | -------- | -------- | | beforeCreate |Setup() |實例初始化立即叫用,這時還未創建實例,所以任何 Vue 實體中的設定(例如: data )都還未配置。| | created |Setup() |完成創建實例,這時 Vue 實體中的配置除了 $el 外已全部配置,而 $el 要在掛載模板後才會配置。屬性綁訂到實體上,可讀取data裡的值,但DOM元素尚未生成,$el元素也未存在。| | beforeMount |onBeforeMount|在 Vue 實體中的定義被掛載到目標元素之前叫用,這時的 $el 會是還未被 Vue 實體中的定義渲染的初始設定模板。| | mounted |onMounted|Vue 實體上的設置已經安裝上模板,這時的 $el 是已經藉由實體中的定義渲染而成的真正的頁面。| | beforeUpdate |onBeforeUpdate|當實體中的 data 產生變化後或是執行 vm.$forceUpdate() (opens new window)叫用,這時的頁面還未被重渲染為改變後的畫面。| | updated |onUpdate |在重新渲染頁面後叫用,這時的頁面已經被重渲染成改變後的畫面。| | beforeDestroy(2.x)|onBeforeUnmounted |在此實體被銷毀前時叫用,這時實體還是擁有完整的功能。| |beforeUnmount(3.x)|onBeforeUnmounted |在實體物件被銷毀| | destroyed |onBeforeUnmounted |此實體被銷毀後叫用,這時實體中的任何定義( data 、 methods...等)都已被解除綁定,代表在此做的任何操作都會失效。| | unmounted(3.x)|onUnmonted|vue實體物件被銷毀完畢。| | errorCaptured| onUnmonted|子、孫代元件的錯誤被捕獲時觸發。| | activated| |若HTML標籤中有設定keep-alive就會觸發這個階段的函數,並跳過之前的destory階段| | deactivated| |停用keep-alive時會觸發的階段。| 注意事項:Vue composition API是Vue.js 3.0提供的新特性,Vue.js 3.0針對多數2.x的語法提向下相容,所以vue.js2.x Options API的生命週期,Hooks到了3.0依然可以繼續使用。 ![](https://i.imgur.com/EIH378Y.png) > 圖片來源: [重新認識 Vue.js | Kuro Hsu](https://book.vue.tw/CH1/1-7-lifecycle.html) ![](https://i.imgur.com/Ayw26H7.png) 下面會將鉤子函數拆成四組來分析,分別是: * ==實體建立階段==beforeCreate 及 created : 創建實體。 1. beforeCreate : 在 beforeCreate 時因實體還沒創建,所以 a 跟 $el 都是 undefined 。 1. created : 到了 created 時已經創建實例,所以 a 已變為 1 ,但是 $el 因為還未掛載至目標元素,所以依然是 undefined 。 * ==實體更新階段==beforeMount 及 mounted : 掛載目標元素。 1. beforeMount : 流程圖上有提到,在叫用 beforeMount 前 Vue 已經決定模板的樣式,所以在 beforeMount 中的 $el 已經有值了,只是它還未依照 Vue 實體上的定義所渲染,只是個初始設定的模板,因此可以看到 {{a}} 、 v-on 這些模板語法都還未被轉換。 1. mounted : 在 mounted 被叫用時已經把 Vue 實體上的定義綁定到元素上,所以這裡看到的是經由 Vue 渲染後的配置。 * ==實體銷毀階段==beforeUpdate 及 updated : data 改變後的重渲染。 1. beforeUpdate : a 改變後觸發 beforeUpdate ,可以看到 a 已經變為 2 了,可是頁面上還是 1 ,表示這時雖然 data 已經改變,可是還沒有重新渲染畫面。 1. updated : 完成重新渲染的作業後觸發,這時可以看到畫面已經將 1 改為 2了。 觀察data或computed內某個狀態的時候,使用beforeUpdate又太麻煩,此時可用watch屬性處理: ```javascript= const vm = Vue.createApp({ data(){ return{ msg: 'Hello Vue.js' } }, watch: { // 當this.msg被更新觸發 msg(val, oldValue){ console.log(`新的msg: ${val}`); console.log(`舊的msg: ${oldvale}`); } } }).mount('#app'); ``` * ==實體銷毀階段==beforeDestroy 及 destroyed : 銷毀實體。 3. beforeDestroy : 叫用 beforeDestroy 表示即將執行銷毀動作,如果有些物件要釋放資源可以在這處理。 4. destroyed : 叫用 destroyed 時,實體已經銷毀。 ## :memo:指令 帶有v開頭的屬性再VUE.JS裡就稱為指令(directive)。當與指令搭配運算式(expression)的值被改變時,對應的標籤(包括節點、元件)也會隨之影響。 ==透過指令的作用與狀態的變化,即可透過改變狀態(資料)來操作整個網頁系統。== 常見的指令有以下幾種: * v-on * v-model * v-bind * v-if * v-show * v-for 功能 ##### Directives 可以使頁面渲染的方式依照相關的設置改變, 像是 v-if 決定是否渲染元素、 v-for 重複渲染相同元 素...等,也可以當作 Attributes 的值,像是 v-bind 、v- on 綁定屬性及事件 ### 屬性綁定: V-bind ==如果需要由vue.js來控制標籤的屬性,可使用v-bind的指令== 常見的標籤屬性如id、圖片的src,或是連結的fref等DOM屬性都可透過v-bind指令控制內容。 #### v-bin的縮寫為分號 例:綁定圖片 ```htmlembedded= <img :src="imgSrc"> ``` CF:Mustache Syntax data可透過{{}}將資料輸出在網頁模板,但無法被套用在HTML標籤的屬性上。 #### v-bind的style綁定 透過物件的型式接收: ```htmlembedded= <div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div> data: { activeColor: 'red', fontSize: 30 } ``` #### v-bind針對class做動態綁定 透過陣列型式接收 ```htmlembedded= <div v-bind:class="[activeClass, errorClass]"></div> data: { activeClass: 'active', errorClass: 'text-danger' } // 以上的程式碼最終會render出以下的元素 <div class="active text-danger"></div> ``` 也可以配合條件式去決定要綁定哪個class,下方的範例必定會綁定errorClass,但activeClass會依據isActive的值決定要不要綁定 ```htmlembedded= <div v-bind:class="[isActive ? activeClass : '', errorClass]"></div> ``` ### 表單綁定: V-modle 常見表單元素`<input>`、`<textarea>`及`<select>`等都可透過v-model進行資料的雙向綁定,v-model會根據不同的表單類別更新內容。 ==望在DOM中操作vue實體中的變數、同時希望在實體做的任何更動也會反應在template中,這種情況就需要v-model來協助== 備註: 由於<div>非表單元素,所以即使加上contenteditable屬性仍無法透過v-model指令處理資料雙向綁定。 參考連結:https://www.runoob.com/try/try.php?filename=tryhtml5_global_contenteditable ##### input文字框 ```htmlembedded= <template> <div id="app"> <h1 :style="{color:textColor}">{{message}}</h1> <input type="text" v-model="message"> </div> </template> <script> export default { data() { return { message: '你好 我是Danny', textColor: 'red' }; } }; </script> ``` 利用v-model綁定各種input元素,我們可以將使用者所有的輸入值都利用變數存起來,待使用者提交表單時再將整包資料一起送出。 ##### textarea文字方塊 ```htmlembedded= <p><span>Multiline message is:</span>{{ message}}</p> <textarea v-model="message" placeholder="add multiple lines"></textarea> ``` 若在<textarea>裡面使用{{}}模板語法而不是v-model時,只會控制內容的顯示,此時的更新不會寫回data內,需要用v-model指令與data內狀態綁定。 ==v-model可說是語法糖的一種,實際上vue.js是將表單元素的監聽事件與實體內容更新的動作在背後處理掉了。== ##### v-model修飾子 ### Class 的綁定 本章介紹 Class 跟一般的屬性綁定方式的不同之處,再來介紹從字串的方式綁定 Class 會需要很多的轉換,較繁瑣及不適用,接著介紹 Vue 提供的兩種綁定 Class 的特別方式: 陣列及物件,而物件也可以使用在陣列的元素中。 ### 樣式綁定 使用 Vue.js 後,可以利用實體中的資料,綁定 Style 的字串: ```javascript= var vm = new Vue({ data: { inlineStyle: "font-size:12px;font-weight:bold" } }); ``` ```HTML= <span :style="inlineStyle">Hello Style Binding</span> ``` Style 在 Vue 中有多種綁定方式,本文從字串開始介紹,依序為物件、陣列,最後在講解 Vue.js 幫我們處理掉了瀏覽器前綴字的判斷,讓我們可以更簡潔的設定 CSS 。 ### 條件渲染 #### v-else-if 及 v-else 在使用 v-else 的時候有兩點注意: v-else 沒有 Value ,它是一個單純的 Directive。 v-else 設置元素必須緊跟在 v-if 或是 v-else-if 設置元素之後,而且必須是同一層的元素。 v-else-if 有兩點在使用上需要注意: v-else-if 可以使用多次 v-else-if 跟 v-else 相同必須緊跟在 v-if 或是 v-else-if 設置元素之後,而且必須是同一層的元素。 ### 列表渲染 #### 使用 v-for 綁定陣列資料 HTML 上的 v-for 值是以特殊的語法 item in items 設定,中間以 in 分開分為: item : 每個元素的資料。 items : 原本的陣列資料。 #### 使用 of 代替 in #### 使用範圍做列表渲染 v-for 除了陣列及物件的渲染方式,它還有一個特殊的渲染方式像是 n in 10 : 10 : 範圍定義。 n : 目前所在的數字。 在這裡用一個數字替代陣列或物件,代表列表的長度, n 就是目前所在的數字。 ## :memo:元件 ![](https://i.imgur.com/hMvWMno.png) ### 組件基礎 Vue 的應用程式由多個實體所串連,形成一棵組件樹,它只會有一個根節點,就是 new Vue 的實體,底下都是稱為 Component 的組件,組件的開發方式跟 new Vue 相同,都是設定選項物件,但物件內的屬性跟 new Vue 會有些差異,現在讓我們看看如何建立及使用組件吧。 #### 甚麼是元件 元件(Component)是Vue最主要的特性之一,他提供HTML DOM元素的擴充性,也可將部分模板、程式碼封裝起來,以便開者維護及重複使用。 #### 元件的分類與切分 網頁轉換成模組區塊來管理時,會依據功能的不同進行劃分,避免元件之間耦合度高,導致日後不易維護。 > 元件耦合度: > 指的是元件之間相互依賴的程度。當元件之間緊密相連並且彼此依賴時,它們就是高度耦合的,反之則是低度耦合的。高度耦合的元件通常難以重用和維護,因為對一個元件的修改可能會影響到其他的元件。 ##### 展示型元件Presentation 以負責呈現UI為主的類型,單純將資料傳遞進去,DOM就會根據丟進去的資料生成出來,提高UI的重複使用性。 ##### 容器型元件Container 主要負責與資料端的service溝通,再將資料傳遞給展示型元件。 ##### 互動型元件Interactive 例如elementUI、Bootstrap UI library都屬於此類型,此種元件包含許多互動邏輯,也強調重複使用。例如表單、燈箱等互動元素。 ##### 功能型元件Functions 此種類型的元件本身不渲染任何內容,主要負責將元件內容做為某種應用程式的延伸,或是某種機制的封裝。例如:<router-view> #### 單一元件檔Single file components(SFC)參考書P.181 single file components是一個vue檔案,每一個vue檔案就是一個完整的組件,其中包含著三大部分 * HTML (template) * Javascript (script) * CSS (style) ##### ==template== template區塊的內容就是你在註冊全域組件時寫入的字串,它經過編譯之後會有一模一樣的結果。 一個template只能有一個根元素(root element),也就是說所有的內容都要用一個容器包起來 ##### ==script== 一個SFC內只能有一個script區塊,且最終需要輸出成一個vue實體,若你有需要引入外部的js檔案,則可以使用require或是import達成。 ##### ==style== 一個SFC內可以有著複數個style,特別注意的是預設的style是全域管理,如果你只希望在這個組件中套用指定的樣式,可以加入scoped屬性 ##### ==在single file components中使用其他組件== 在SFC內使用其他的vue組件分成幾個部分,首先你需要先透過import載入指定的組件,假設現在有兩個SFC,分別是A、B兩個組件,若我今天想在A中使用B,首先我就必須先載入該組件,就像剛剛在script區塊載入外部的js檔案一樣的寫法 > 由於SFC的.vue檔案並非標準網頁,自使用時須透過vue-loader或@vue/compiler-sfc搭配webpack等工具,先將SFC編譯成瀏覽器看得懂的JavaScipt程式碼後才可被執行。 #### 子元件的data必須是函式 在介紹Vue實體時,data的屬性總是以物件型式表示,但在紫元間的data屬性必須是以函式回傳物件的型式來表示: ![](https://i.imgur.com/4CluFLI.png) ==於JavaScript的物件型別是以傳址的方式來進行資料傳遞,若沒有透過function來回傳一個新物件,則這些子元件的data就會共用一個狀態。== 為避免資料相互汙染,Vue.js強制規定子元件內的DATA必須是以函式的型是回傳新的物件。 ### 元件之間的溝通傳遞 Vue.js每個於件的實體狀態、模板等作用範圍都應該要是獨立的,故無法在子元件的模組直接去修改父元件,我們希望這個元件可以根據外部傳入的資料來反映不同的結果。若需要從外部引進資料時,就需要透過props屬性來引用外部的狀態。 ```htmlembedded= <div id="app"> <!-- 這是外層元件的msg --> <h3>{{ msg }}</h3> <!-- 這裡的v-bind:parent-msg可簡寫為:parent-msg --> <my-component v-bind:parent="msg"></my-component> </div> ``` ```javascript= const app = Vue.createApp({ data(){ return{ msg: '這是外層元件的msg' } } }); app.component('my-component',{ template:` <div class="component"> <div>從props來的parentMsg ==>{{ parentMsg }}</div> <div>自己的Msg ==>{{ msg }}</div> </div>`, props: ["parentMsg"], data(){ return{ msg:'這是子元件的msg' } } }); ``` 我們可在內層元件透過props屬性宣告要從外部引用進來的屬性名稱。在內層元件(或稱子元件)宣告props屬性,最簡單的方式就是透過陣列的型態: ```javascript= app.component('my-component,{ props:['props1','props2','props3'...], //以下略 }'); ``` > 傳入props時一定要加v-bind:嗎? > 不一定,根據情況判斷。加的話會被當作實體的物件對待,不加的話子元件接收的就會是靜態字串(純文字字串)。 > ### 傳入靜態或動態屬性 >在屬性上我們可以將客製屬性當成一般屬性設定,沒有使用 v-bind 的屬性會將值當作靜態字串讀入,而有 v-bind 的會當作實體中的物件對待。 ### 雙向綁定?單向資料流? ![](https://i.imgur.com/4LHmXJS.png) 若從狀態(data)到畫(View)的角度來看,vue.js確實能夠做到UI的雙向綁定。但若是以元件對元件的狀態管裡來看則是以單向資料流(One-way Data Flow)的方式來管理狀態。 ![](https://i.imgur.com/s4d7vfe.png) > Vue元件之間的狀態為單向流動 #### 屬性的資料流是單向的 在之前有提到 props 屬性是父組件跟子組件溝通的方式,而 $emit 方法是子組件產生變化時通知父組件的方式,所以 props 屬性本身是單向的,也就是由父組件傳至子組件,而子組件會隨著父組件所傳的屬性值更新狀態,但子組件不能藉由 props 屬性傳資料回父組件。 vue props解釋 在 Vue.js 中,props 是指由父元件傳遞到子元件的屬性集合,用於控制子元件的行為或顯示。props 可以是任意類型的 JavaScript 值,包括原始類型、對象、陣列、函數等。 在父元件中,可以通過設置子元件的屬性來向子元件傳遞 props,例如: ```htmlembedded= <my-component :name="'John'" :age="30"></my-component> ``` 在子元件中,可以通過 props 屬性來獲取傳遞的屬性值,例如: ```javascript= Vue.component('my-component', { props: ['name', 'age'], template: '<div><p>Name: {{ name }}</p><p>Age: {{ age }}</p></div>' }); ``` 在這個例子中,my-component 父元件傳遞了兩個 props,分別是 name 和 age,子元件通過 props.name 和 props.age 獲取了這兩個屬性的值並進行顯示。 props 是 Vue.js 中實現元件之間通信的重要機制,通過 props,父元件可以控制子元件的行為和顯示,並且可以實現元件的可重用性和組合性。在使用 props 時需要注意的是,props 是單向數據流,子元件不能直接修改父元件傳遞的屬性值,只能通過觸發事件或調用父元件的方法來改變父元件的狀態。此外,使用 props 時也需要注意屬性名的大小寫和使用 kebab-case 或 camelCase 命名的區別。 ## :memo:動態元件管理 ### v-bind:is與動態元件 ### <keep-alive>保留元件狀態 `<keep-alive>`這個特殊的元件標籤可用來暫存保留當下的狀態,只樣在需要保留的元件外用`<keep-alive>`標籤包住即可。 除了跟:is搭配外也可在v-if指令上搭配使用,由於`<keep-alive>`內同時只會有一個元件會被渲染,所以也要避免`v-if`與`v-for`共同使用造成的問題。 ## :memo:編譯作用域與插槽 ### 元件的作用域 ### 插槽(Slots) slot是vue組件中用來做內容分配的的API,就像一個插槽一樣,你可以根據情況在插槽內插入想要的內容,讓你的vue組件更加的泛用。 留言 slot的部分表示要從父層插入的內容 slot 備用內容(fallback content) 命名插槽 (named slot) ### 具名插槽(Name Slots) #### 動態切換具名插槽 #### 作用域插槽(Scoped Slots) #### teleport使用方法(Vue3.0新增) 參考資料: https://ithelp.ithome.com.tw/articles/10274013 https://yachen168.github.io/article/composition-api-teleport.html 參考書P154 ==`<teleport>`的作用是可以將模板中特定的DOM移動至我們所指定的位置渲染。== 同一個網頁上可以有多個`<teleport>`指向同一個目標,實際生成的結果會依照置入的順序來渲染,不會有覆蓋的問題。 使用情境: ```htmlembedded= <teleport to='#modals'> <div>A</div> </teleport> <teleport to='#modals'> <div>B</div> </teleport> <!-- 渲染結果 --> <div id='modals'> <div>A</div> <div>B</div> </div> ``` Teleport 有兩個屬性: * to:移動的目的地,也可加上v-bind使用動態指定 `:to`。 * disabled:true(預設):元素不會被移動。false:元素會被移動到 to 指定的位置。 ## :memo:響應系統 ![](https://i.imgur.com/0DnmuQO.png) 問題:vue getter setter的解釋 Getter是一個用於獲取數據的方法。它可以返回一個計算的值或簡單地返回對象的一個屬性值。Getter在Vue中非常有用,因為它們可以幫助我們監聽數據的變化,並在必要時執行特定的操作。 Setter是一個用於設置數據的方法。它允許我們通過在數據變化時觸發setter方法來檢查並修改數據。這非常有用,因為它使我們可以在數據發生變化時自動執行某些操作,例如將數據傳遞給後端服務器或執行數據驗證等。 在Vue中,我們可以使用computed屬性來定義一個getter,這將幫助我們簡化代碼並提高可讀性。同樣,我們可以通過在對象上定義setter來創建一個自定義setter。這將幫助我們更好地控制數據並執行特定的操作。 forceUpdate 只會去強迫重新渲染而已,並不會重新設置 getter 及 setter ,因此屬性並不能被監聽器或是計算屬性所設置,在下一章我們將學會如何使用 $set 在實體上設置一個新的屬性,使用 $set 所設置的屬性就會擁有自己的 getter 及 setter ,會是一個完整的資料屬性。 ## :memo:使用 set 新增實體中的屬性 在 vue 中,建立實體後才加入的屬性因為沒有被給予 getter 及 setter ,所以不會被響應系統察覺,但使用 set 方法加入的屬性則會被賦予 getter 及 setter ,因此使用 set 加入的屬性都可以被響應在頁面上。 ### vue 無法在建立實體後增加屬性 只有一開始定義在選項物件上的屬性才會被 vue 當作響應物件,其他未在選項物件上的屬性都無法用直接加入的方式使其成為響應物件。 ### set 方法 ```javascript= var vm = new Vue( { el: "#app", data: { user: { firstName: 'Peter', // reactive }, }, created() { this.$set(this.user, 'lastName', 'Chen'); } } ); ``` 當 set 的第一個參數是陣列時,第二個參數就會變為欲修改元素的 index ## :memo:事件處理 ## :memo:客製事件-參考書117 ## :memo:動態組件-參考書133 ## :memo:Day19 - 認識vuex(上) 認識State state就像我們昨天說過的一樣,它很單純就是一個有著store內所有資料的物件,把它想為整個應用程式的資料狀態也可以! 舉個例子來說,我們可以在裡面增加一個numbers陣列,就像我們昨天做的一樣! 認識Mutations Mutations其實就是包含著一堆函數的物件,每一個mutation就是一個函數,負責接收actions並更改state的資料,其中有幾個注意事項。 mutation必定是同步函數,沒有例外 mutation是vuex中唯一可以改動state的方法 也就是說在vuex中,如果你要改變state狀態,你一定要經過以下的流程 發出一個action(dispatch an action) 接收到action後,執行對應的mutation (commit a mutation) 透過mutation更改state 認識Actions Actions就是為了呼叫Mutations而存在的東西,同樣有幾個事情你需要知道 Actions可以是非同步函數 一個Action中可以觸發多個mutation 相對起來很單純,你只要記得我們需要透過action去呼叫mutaion就好了! 我們同樣實際寫個actions來看看吧! 每一個actions包含著兩個參數 context 是一個物件,裡面可以讓你使用store中的commit、getter或是state屬性 想傳入mutation的參數,沒有要傳入則可省略 chatgpr問題 vue Methods/Watch/Computed 差異及適用的情境為何 繁體中文