# 前端學習札記 #
> 此篇文章為個人的學習小小紀錄,主要是方便複習及紀錄成長
> 如果有錯誤,或有想要討論的內容都十分歡迎找我討論
> 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,可以在開啟瀏覽頁後的分頁上看到

>表頭中除了導入資源,還有就是拿來宣吿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

>在這邊引用別人的圖來說明,為什麼會說是類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)

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,如官方文件說明

* 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...)

default就基本的babel & eslint
也可以選Manually select features來自行選擇需要安裝那些工具

這邊就視情況看自己的專案需要那些工具,這邊我選了babel、Router、Vuex、CSS預處理器、ESLint

如果有選router的話,會跳出來詢問你router的mode要使用history還是hash
> History V.S Hash 可以到下面的vue-router查看差異

有選CSS預處理器的話,這邊會讓你選擇你要使用哪種預處理器

有選ESLint的話,這邊會讓你選擇你想要的linter

接著詢問檢查的時機點
* 存檔時檢查
* commit時檢查

詢問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..等等

可以切成多個部分作呈現
```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管理