# 前端學習札記 # > 此篇文章為個人的學習小小紀錄,主要是方便複習及紀錄成長 > 如果有錯誤,或有想要討論的內容都十分歡迎找我討論 > https://github.com/xdkillyou --- ### 目錄 ### * Web * HTML * CSS * 網頁運作 * JS & JQ * 前端框架 * Vue * API管理 --- ## Web ## Web,即是我們正在看的網頁,呈現、互動、動畫、功能,網頁的演進到現在,不再只是純文字或資料取向,更多的是操作與使用者的互動。 > 網頁發展: http://www.evolutionoftheweb.com/?hl=zh-tw #### 網頁的組成分成三大項目 #### * 骨架 ( HTML ) * 皮膚 ( CSS ) * 大腦 ( Javascript ) > 有了骨架才能抹上皮膚,有了身體才能帶入大腦 ## HTML ## HTML並不是程式語言,而是一種==標記語言==,又稱做超文本標記語言(**H**yper**T**ext **M**arkup **L**anguage),HTML透過tag來表達語意,而網頁由一個個的元素(DOM)所組成,最終形成一個網頁架構,來表達網頁的呈現內容 > 人(網頁)由骨頭(DOM)所組成,骨頭有不同種類及形式(tag的語意),分別代表不同部位(作用) 網頁必須透過HTML這種語言來表達文字及畫面的語意 >將網頁語意話最重要的是要讓機器也能讀懂網頁的內容,優化SEO,也可以讓開發者更快理解網站結構 >介紹SEO(缺) #### tag認識及介紹 ```htmlmixed= <tag> ... </tag> <!-- tag透過<>包裹起來,有起始標籤及結束標籤 --> <!-- 組合成一個元素(DOM element) --> ``` 當然也是有單個標籤的,稱為**空元素** ```htmlmixed <img> html寫法 <img/> XHTML寫法 <img /> XHTML兼容html寫法 -> 最嚴謹的寫法 而html5兼容XHTML ``` > 空元素有哪些: https://developer.mozilla.org/zh-TW/docs/Glossary/Empty_element >之後再補充XHTML、XML(缺) 可以為巢狀結構 ```htmlmixed <div> <p>我是內文</p> </div> ``` #### HTML的架構 ```htmlmixed= <!DOCTYPE html> <!-- 此處為文件類型聲明 --> <html lang="en"> <head> <!-----------此範圍為表頭----------------> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <!------------------------------------> <body> <!-----------此範圍為畫面呈現-------------> <h1>大標題</h1> <p>內文</p> </body> <!------------------------------------> </html> ``` * 文件類型聲明 聲明html的類型、版本,但已經是時代的眼淚,只需要形式上的引入即可 * `<html></html>` 包住頁面的所有內容,又被稱為根元素 * `<head></head>` 表頭拿來宣告、引入資源及連結等,內容不會顯示在網頁上 `<title>Document</title>`指的是page title,可以在開啟瀏覽頁後的分頁上看到 ![](https://i.imgur.com/T4PoRO3.png) >表頭中除了導入資源,還有就是拿來宣吿meta,提高網頁SEO及網站的介紹、描述,在這邊先大致知道即可 > * `<body></body>` 這邊就是網頁呈現的畫面及內容 #### tag的屬性 ```htmlmixed= <p class="name">contain<p> <!-- class屬性 --> <p id="name">contain<p> <!-- id屬性 --> ``` >"name"皆為自定義,id與class屬性的差異為 >id 只能為獨一無二 >class 能夠有多個 >id的權重高於class 其餘的Tag及Attribute介紹皆可以到[W3Schools](https://www.w3schools.com/html/default.asp)及[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML)查找 #### Atteribute >補 ## CSS ## ## 網頁運作 ## ## JS & JQ ## ## 前端框架 ## ## Vue ## Vue為前端(2020)三大框架(Angular,React,Vue)之一,主打==輕量好入門==,官方已經宣布Vue3.0 release版本,這邊還先以2.x為主 ### 特性 * 類MVVM ![](https://i.imgur.com/FFkgQXr.png) >在這邊引用別人的圖來說明,為什麼會說是類MVVM,因為尤雨溪大大是參考MVVM架構做的 >>**View**是我們看到的前端畫面 >>**Model**是我們的資料(data) >>**ViewModel**是連繫View & Model的橋樑 > >這也是Vue資料驅動畫面的關鍵,透過綁定將View及Model繫在一起 * 漸進式 >漸進式意味著你可以只選用部分Vue提供的功能(vue-cli/vur-router/vuex...等)來實作專案,挑選你所需的功能來用即可,而不用將一大包資源一次引入 >除了上面說明以外,Vue其實也可以與其他如JQuery & JavaScript合併著使用,但在使用上要格外注意,一個功能就用單一一種語法寫就好(this指向問題) * 聲明式渲染 > **聲明式渲染 V.S 命令式渲染** > 白話一點的說明他們兩個之間的差異的話,以商店來舉例 > >聲明式 : 這枝筆我要調整價錢(老闆語氣),服務生就自己乖乖的把架上的價錢改掉(好員工 :100: > > >命令式 : 這枝筆我要調整價錢,你!就你這個服務生,你現在準備好調整後的價錢,然後去找筆這個商品在哪個架上,接著價錢換掉,換成調整後的價錢(順道一提JQuery就是命令式) > >感受到其中的差異了嗎? Vue更動畫面只需要==修改資料==,不像JQuery要去瘋狂的==操作DOM== 這邊不是一昧的指JQuery不好,JQuery非常方便,還是要看專案來考慮自己需要什麼,但BootStrap5要砍掉與JQuery的相依關係,不知道會不會使JQuery用戶變少就是了 > Object.defineProperty() ### 生命週期、生命週期鉤子(Hook) ![](https://i.imgur.com/PhUR9Zt.jpg) Vue的生命週期,即意味著從他出生(建立instance)到他死掉(destroyed)的過程,生命週期主要還以Hook為主,我們可以透過Hook在各個階段去執行我們想要的事 >這邊分成**創建階段**與**運行階段**,顧名思義,創建階段只會跑過一次,而運行階段會一直執行直到destroyed > el(element) - el為Vue實例掛載範圍(DOM element) #### Hook --- 創建階段 --- * beforeCreate: 初始化instance,el尚未建立,options尚未初始化(methods、computed..等),data尚未被定義,DOM尚未生成 * created: el尚未建立,options & data定義完成,可以調用data資料與options定義好的方法,DOM尚未生成,尚未綁定至el >這邊開始已經可以開始調用宣告在data中的資料及options的方法,意謂這邊就可以開始處理資料 * beforeMount: el掛載前,DOM已經載入完成,樣板語法尚未被賦予值 >這階段的網頁呈現,DOM已經被載入了,但樣板語法尚未被賦予值,所以有透過 {{ data }} 綁定在DOM元素裡的data,還尚未被放值進去,都還是文字的呈現 * mounted: el建立完成並掛載成功,樣板語法被賦予值 >創建階段的最後一個Hook了,創建階段結束 --- 運行階段 --- * beforeUpdate: 當綁定的資料改變時,畫面要被重新re-render前觸發 >值得注意的事,當我綁定的資料沒放到畫面時,畫面不會被重新re-render >補充: Vue還有個特性就是會複用相同的DOM元素,以便加速DOM的繪製(**[Virtual DOM](https://medium.com/%E6%89%8B%E5%AF%AB%E7%AD%86%E8%A8%98/build-a-simple-virtual-dom-5cf12ccf379f)**) * updated: 資料改變後且畫面已經被re-render完畢後觸發 --- 銷毀階段 --- >製作SPA時,其實在切換router時,當下資料的綁定就會被destroy掉,如果要主動destroy掉要透過指令```vm.$destroy```,但不建議主動去destroy,如官方文件說明 ![](https://i.imgur.com/L9Hw2Dn.png) * beforeDestroy: Vue instance銷毀前,此階段Vue instance中data還有options還可以被使用 >**!重要!在這個階段,可以拿來remove掉純JavaScript的監聽事件** * destroyed: Vue instance已經被銷毀完畢,與資料的綁定被銷毀 >透過測試發現,如果destroy後還停留在當下的頁面,已經渲染在DOM上的畫面依舊會保留,且事件監聽依舊會存在,事件依舊會運行,資料依舊會變化,只是畫面與資料的綁定(ViewModel?)會銷毀,不會re-render > codepen: https://codepen.io/xdcodetxt/pen/dyMRWLK?editors=1011 ### 模板語法 #### v-on 綁定事件 ```htmlmixed= <button v-on:event="functionName">Click</button> ``` >v-on:觸發事件 = "執行函式" ```htmlmixed= <button @event="functionName">Click</button> <!-- 可以將v-on縮寫成@ --> ``` 事件修飾符可以參考: https://vuejs.org/v2/api/#v-on #### v-for 迴圈 <ul> <li>pen</li> <li>book</li> </ul> ```htmlmixed= <ul> <li v-for="item in Array" :key="item.id">{{ item.name }}</li> </ul> ``` > <ul> <li>0. pen</li> <li>1. book</li> </ul> ```htmlmixed= <ul> <li v-for="(item,index) in Array" :key="item.id"> {{ index }}: {{ item.name }} </li> </ul> ``` ```javascript= data: { Array: [ { name: "pen", id: 1 }, { name: "book", id: 2 } ] } ``` >v-for中的==key==功用是什麼?? >要先了解Virtual DOM的目的,盡可能減少DOM的變化,提升效能,所以Vue會有複用DOM的特性 >key的目的就是用來判斷此項目是否要re-render,所以key不可重複,因此key的值盡量不要使用index,否則在陣列變化時,效能變差(如果是在陣列最前面插入內容,陣列中的index全會變化,變成全部re-render) >參考說明: https://juejin.im/post/6844903577215827982 #### v-bind 綁定屬性(Attribute) ```htmlmixed= <p v-bind:title="cool">mouse moves over on me</p> ``` ```htmlmixed= <p :title="cool">mouse moves over on me</p> <!-- 可以將v-bind縮寫成: --> ``` > prop就是利用v-bind丟資料 #### v-model 雙向綁定 View變化後透過ViewModel監聽與Model做雙向溝通(主要用在input/select/textarea..等等form element上) [form element參考](https://www.w3schools.com/html/html_form_elements.asp) <form> <input type="text"> </form> ```htmlmixed= <input v-model="account" /> ``` ```javascript= data: { account: "" } ``` v-model比較像是語法糖,原理其實就是v-bind綁value屬性 & v-on監聽變化後把資料帶回去 ```htmlmixed= <input v-bind:value="data" v-on:input="data = $event.target.value" /> ``` 修飾符可以參考: https://vuejs.org/v2/api/#v-model #### v-if / v-else-if / v-else 畫面渲染 判斷是否渲染畫面,可以寫表達式 ```htmlmixed= <div v-if="boolean"> <p>contant</p> </div> <div v-else-if="boolean"> <p>contant</p> </div> <div v-else> <p>contant</p> </div> ``` ```htmlmixed= <div v-if="text === 'cool'"> <p>contant</p> </div> <div v-else> <p>contant</p> </div> ``` >v-else-if & v-else必須緊接著v-if後面使用(同一層),否則會跳出錯誤 #### v-show 畫面渲染 判斷是否渲染畫面,可以寫表達式 ```htmlmixed= <div v-show="boolean"> <p>contant</p> </div> ``` ```htmlmixed= <div v-show="text === 'cool'"> <p>contant</p> </div> ``` >**v-if V.S v-show** >你可能會想兩者都是畫面渲染,那其中的差異在哪?我該在什麼情況下使用? >v-if的處理連DOM元素都不會被畫出來,而v-show的處理則是畫出了DOM並display:none >兩者最大的差異在於性能上的選擇 > >如果是頻繁操作(顯示、隱藏)使用**v-show - 初始成本高**(載入時DOM都畫好並加上display:none) >如果是操作並不這麼頻繁、希望第一次載入速度越快越好使用**v-if - 切換成本高**(re-render) 以上是最常用、最基本的Vue提供的模板語法,當然Vue提供的不只這些 如果好奇的話可以到Vue官網翻閱: https://vuejs.org/v2/guide/installation.html ### Options #### data 你可以把data理解為變數宣告的區域,我要宣告一個變數初始值是0 ```javascript= data: { num: 0 } ``` 要在html結構中使用(文字插值)的話,透過Moustache模板引擎 ```htmlmixed= <p> 共 {{ num }} 元</p> ``` #### methods 可以直接把methods先理解為宣告function的區域,使用者行為觸發methods ```javascript= methods: { functionName: function(){ ... } } ``` 也可以縮寫成 ```javascript= methods: { functionName: { ... } } ``` 要在methods中使用data的值的話,要加上this ```javascript= methods: { functionName: { this.num = this.num + 100; } } ``` #### computed 可以把computed理解成資料的處理(資料產生資料),寫法十分像methods,不過一定要加return,當data變化時,computed裡的值才會進行變化,且有cache機制,在處理資料更有優勢 >computed只會與vue中的data進行連動,不是vue的data則不會更新 ```javascript= data: { num: 100 }, computed: { numPlus: { return this.num*2; } } ``` 要插值的話,一樣使用Moustache ```htmlmixed= <p> 共 {{ numPlus }} 元</p> ``` #### watch 監聽資料(data),資料改變時去執行什麼事(methods、function..等) ```javascript= data: { school: { students: { name: "Chris" }, teachers: { name: "Cook" } } } ``` ```javascript= watch: { // 監聽school這個data,變化時觸發下列的事 school: function(val){ // val為變化後代入的值 } } ``` 可以縮寫為 ```javascript= watch: { // 監聽school這個data,變化時觸發下列的事 school(val) { // val為變化後代入的值 } } ``` ```javascript= watch: { // 監聽data,變化時觸發method,這邊的method指的是vue裡methods中的function school : 'method' } ``` 如果監聽的data是巢狀的物件時,如school中有student,student中有name,你使用上述的方法去監聽的話,無法監聽到school內物件的變化,只能監聽school這個資料的變化 如果需要監聽到整個物件,可以使用 ```javascript= watch: { school : { handler: 'method', // handler為觸發function deep: true // 加上deep: true,可以監聽整個物件,不管層級多深 } } ``` >上述方法當然也有缺點,就是資源耗費大,效能差,因為監聽了整個物件,包含物件裡所有物件的變化 ```javascript= watch: { // 監聽的物件 : 觸發funciton 'school.students': 'method' } ``` >如果希望能監聽到物件內的物件變化,又不希望全部監聽可以像上面那樣寫,只針對其中一個變化去監聽 ```javascript= watch: { school : { handler: 'method', immediate: true // 加上immediate: true,在監聽前先觸發綁定的function } } ``` 當然也可以去監聽vuex內的變數 ```javascript= watch: { "$store.state.item" : funtion{ // do some thing... } } ``` >如果是這樣寫"xxx",記得不能用縮寫!! #### component ### Prop & $emit ### SPA SPA,單頁式應用,全名為single-page application 與傳統MPA(多頁式應用multi-page application)差別在於當切換頁面時(補...) ### Vue-cli v4(與v3目錄結構不同,其他參照v3學習即可) vue-cli為官方提供的開發工具,可以**快速建置開發環境** #### 安裝 * node版本要求Node.js 8.9以上 ```javascript= node -v // 檢查當前node.js版本 ``` >node版本管理 : https://www.jianshu.com/p/c641dcc47b48 * 如果你先前有使用過vue-cli2的記得要先移除 ```javascript= npm uninstall vue-cli -g ``` >vue-cli -> v2 >@vue/cli -> v3 * 安裝vue-cli ```javascript= npm install -g @vue/cli ``` * 確認Vue-cli版本 ```javascript= vue -V ``` #### 建立新專案 ```javascript= vue create projectName ``` 第一個為以前使用過的紀錄,可以看到當使用了那些工具(babel、router、vuex...) ![](https://i.imgur.com/5TVVHXL.png) default就基本的babel & eslint 也可以選Manually select features來自行選擇需要安裝那些工具 ![](https://i.imgur.com/hrSUnB9.png) 這邊就視情況看自己的專案需要那些工具,這邊我選了babel、Router、Vuex、CSS預處理器、ESLint ![](https://i.imgur.com/hgttnko.png) 如果有選router的話,會跳出來詢問你router的mode要使用history還是hash > History V.S Hash 可以到下面的vue-router查看差異 ![](https://i.imgur.com/8W9bjkU.png) 有選CSS預處理器的話,這邊會讓你選擇你要使用哪種預處理器 ![](https://i.imgur.com/zGHA7Fc.png) 有選ESLint的話,這邊會讓你選擇你想要的linter ![](https://i.imgur.com/HbOenni.png) 接著詢問檢查的時機點 * 存檔時檢查 * commit時檢查 ![](https://i.imgur.com/wYZZRJD.png) 詢問babel、ESLint...等設定檔放哪 ### Vue-Router 使用vue-router建構SPA的router系統,區分為**History mode** & **Hash mode** >**History mode** : >使用history mode會使網址更為美觀(...bookstore/book),但要使用history mode必須要與後端(server)配合,否則當重新整理或使用路徑進入網頁時,會出現error >**Hash mode** >使用hash mode網址會比較醜(...bookstore/#book),但不會有路徑上的問題 #### 設定router source 在目錄結構中找到router,進入index.js捨定,引入Vue & Vue-router,這兩個在create project時就會幫你用到好 我們只需要引入我們要呈現的頁面(紅線區塊),並且設定好path、name..等等 ![](https://i.imgur.com/Gtsgjb8.png) 可以切成多個部分作呈現 ```javascript= { path: "/path", // 設定router路徑 name: "pathName", // 此路徑下顯示在router-view的內容,router-view要設定name判斷顯示 components: { default: home, nav: Nav, sidebar: Sidebar } } ``` >也可以切成多個子組件(補 #### 設定router-link 有了資源在來要新增router-link在畫面上,點擊時切換router ```htmlmixed= <router-link to="/path"> link Name </router-link> ``` #### 設定router-view 有了source、切換router的link,剩下的就剩應該在哪裡呈現切換的畫面 ```htmlmixed= <div id="app"> <router-view /> </div> ``` 將畫面切成多個部分作呈現 ```htmlmixed= <div id="app"> <router-view id="nav" name="nav" /> <router-view id="nav" name="language" /> <router-view id="sidebar" name="sidebar" /> <router-view id="frame"/> </div> ``` #### 其他轉跳方式 除了可以將link寫在tag中透過path進行轉跳以外還可以透過 1. 透過name進行轉跳 ```htmlmixed= <router-link :to={ name: pathName }></router-link> ``` 2. 透過Js轉跳 ```javascript= this.$router.push("/path"); ``` ```javascript= this.$router.push({ name: pathName }); ``` #### router rule 在透過router進行轉跳時,可以在裡面寫些規則或檢查,檢查是否要否要給使用者進行轉跳 ```javascript= router.beforeEach((to,from,next)) => { ... } ``` > to.path -> 要去哪個path > from.path -> 從哪個path來 > next(/path) -> 執行轉跳這個動作 ```javascript= router.beforeEach((to,from,next)) => { // 在轉跳前檢查path要轉跳到哪 // 如果要轉跳到path 且 是登入狀態的話 if(to.path === "/path" && signIn === true){ // 轉跳到/path next("/path"); }else{ // 如果不符合上述條件轉跳到/signIn next("/signIn"); } } ``` >注意不要寫成無窮迴圈 #### router 網址列大小寫 除了透過點擊link、透過Js進行轉跳以外,其實還是可以透過修改網址列來進行轉跳 但透過修改網址列進行轉跳時要注意使用者在網址列輸入的內容,可能會打破router rule ```javascript= router.beforeEach((to,from,next)) => { if(to.path === "/path"){ next("/path"); }else{ next("/signIn"); } } ``` 以上述rule為例子 當我在網址列輸入 https:.../path時,正常情形會進rule判斷,接著轉跳進/path **問題:可是當我在網址列輸入 https:.../PatH時,會轉跳到哪??** >答案一樣是轉跳進/path,就算你是用=== >**解決辦法: if(to.path.toLowerCase() === "/path") 一律用小寫或大寫來判斷** 備註: 上述方式都是使用history mode進行測試 ### Vuex ### set & $set ### Vue-i18n ## API管理