# Vue 3
## 壹、重新認識 ES6
### 一、Let 與 const
#### let
與 var 不同,就算在 if 內使用 let 宣告同變數。
也不會改變變數的值。
```javascript=
var a = 'aa'
console.log(a) // 'aa'
if(true) {
var a = 'bb';
}
console.log(a) // 'bb'
```
```javascript=
let a = 'aa'
console.log(a) // 'aa'
if(true) {
let a = 'bb';
}
console.log(a) // 'aa'
```
#### const
- 一但使用 const 宣告的變數,就不可再改變他的值
- 陣列和物件有例外,雖然不可改變原有的陣列或物件,但可以作增加。
```javascript=
const a = {name: "peter"}
a["age"] = 12
// {name: "Peter", age: 12}
const b = ['a']
b.push('b')
// ["a", "b"]
```
### 二、解構
- 可直接用解構的特性直接將物件內的拿出來
- 如果要在物件中加入另一個陣列,可以直接放入變數名稱,ES6的特性會直接將裡層物件解構出來
```javascript=
const user = {
name: 'Peter',
age: 12,
address: 'Nantou'
}
const {name, age, address} = user;
console.log(name, age, address); // Peter 12 Nantou
const data = {
user,
salary: 100000,
}
console.log(data)
/*
{
salary: 100000
user: {name: "Peter", age: 12, address: "Nantou"}
}
*/
```
### 三、箭頭函式
- 透過函式運算式來使用箭頭函式,函式宣告則不適用
```javascript=
const add = () => {
console.log('add')
}
```
- 如果返回的程式碼只有一行,可簡化箭頭函式,不用加上 return,箭頭韓式會自動補上
```
const Add = (a, b) => a + b
```
### 四、function default
- 給函式變數加上預設值,就算帶入的值是空陣列也不會噴錯
```javascript=
const arrToString = (arr = []) => {
const mapStr = arr.map((item) => item + "");
return mapStr;
}
console.log(arrToString([1,2,3]))
```
### 五、ES module
將 js 檔的 function 或變數引用至實際執行的網頁
tool.js檔案
```javascript=
const Add = (a, b) => a + b;
export const name = 'Peter';
export const age = 30;
expoet const remove = () = {
...
}
export default Add;
```
.執行網頁檔案
```javascript=
<script type="module">
import Add, {name, age, remove} from './js/tool.js'
console.log(Add(1,2))
</script>
```
## 貳、Vue3 基礎入門
### 一、step()函數 - 起手式
- 和 vue 有關的資料元件都要寫在 step 裡面,用 return 回傳出來
```htmlmixed=
<div id="app"></div>
const app = {
step() {
return {};
}
}
vue.createApp(App).mount("#app");
```
### 二、透過 ref 和 reactive 綁定資料
- ref 綁定資料,能帶全型別的資料
- 要操作 ref 值的時候,要使用 text.value 選取物件中的值
```javascript=
const {ref} = vue; // 將 ref 解構出來
const App = {
const text = ref("hello world!");
return { text }
}
vue.createApp(App).mount("#app");
```
- reactive 綁定資料,只能帶物件或陣列
- reactive 不需要使用 value 去取值
```htmlmixed=
<div id="app">
<h1>{{ message.text }}</h1>
</div>
```
```javascript=
const {reactive} = vue; // 將 reactive 解構出來
const App = {
const message = reactive({test: "hello"});
return { message }
}
vue.createApp(App).mount("#app");
```
- 使用時機:除了物件和陣列使用 reactive,其他型別可使用 ref

### 三、click 事件
```htmlmixed=
<div id="app">
<h1>{{idx}}</h1>
<button @click="addFn">Add</button>
<button @click="removeFn">Remove</button>
</div>
<script>
const { ref } = Vue;
const App = {
setup() {
const idx = ref(0);
const addFn = () => {
idx.value++;
};
const removeFn = () => {
idx.value--;
};
return {
idx,
addFn,
removeFn,
};
},
};
Vue.createApp(App).mount("#app");
</script>
```
### 四、readOnly
避免資料被修改
- 從 vue 取出 readonly 的值
- 不論是 reactive 或 ref,只要使用了 readOnly 就不能被修改。
```htmlmixed=
<div id="app">
<h1>{{num.idx}}</h1>
<button v-on:click="addNum">Add</button>
<button v-on:click="addCopyNumFn">Add copy</button>
</div>
<script src="./js/vue.js"></script>
<script>
const { reactive, readonly } = Vue;
const App = {
setup() {
const num = reactive({ idx: 0 }); // 不論是 reactive
// const num = ref(0) 或是使用 ref,只要使用了 readOnly 就不能被修改。
/*
readonly 就是讓你的 ref 或是 reactive 的資料只可以讀取不可以被修改
非常適合用在參數傳遞的時候避免不小心被修改資料
*/
const copyNum = readonly(num);
const addNum = () => {
num.idx++;
console.log("1 num=>", num);
console.log("1 copyNum=>", copyNum);
};
// warning -> Set operation on key "idx" failed: target is readonly.
const addCopyNumFn = () => {
copyNum.idx++;
console.log("2 num=>", num);
console.log("2 copyNum=>", copyNum);
};
return {
num,
addNum,
addCopyNumFn,
};
},
};
Vue.createApp(App).mount("#app");
</script>
```
### 四、computed
自動計算值
```javascript=
// computed
const BoxHeight = computed(() => {
return isOpen.value ? `${ItemArr.value.length * 40}px` : "0px";
});
// function
const domFn = () => {
return isOpen.value ? `${ItemArr.value.length * 40}px` : "0px";
}
```
#### 1. 比較 function 與 computed 的不同

#### 2. 透過 computed 過濾資料
Vue 不建議 v-if 與 v-for 同時使用,因為 v-if 會先起作用,v-for 才會開始渲染。
因此這邊可以透過 computed 先過濾一次資料,再讓 v-for 渲染出來,這樣就能避免 v-if 與 v-for 同時使用了
```javascript=
<ul class="box" :style="{height: BoxHeight}">
<li v-for="(list, idx) in ItemArr" :key="list">
{{idx + 1}}. {{list.name}} => ${{list.money}}
</li>
</ul>
const listArr = reactive([
{ name: "2020 Vue3 專業職人 | 入門篇", money: 3200 },
{ name: "2020 Vue3 專業職人 | 加值篇", money: 100 },
{ name: "2020 Vue3 專業職人 | 進階篇", money: 500 },
{ name: "現代 JavaScript 職人之路|入門篇", money: 300 },
{ name: "現代 JavaScript 職人之路|中階實戰篇", money: 1600 },
{ name: "職人必修的RWD 網頁入門班", money: 900 },
{ name: "HTML5+Animate CC 網頁動畫與遊戲互動", money: 2000 },
{ name: "現代 JavaScript 職人之路|面試篇", money: 1800 },
]);
const ItemArr = computed(() => {
const filter = listArr.filter((item) => item.money > 1300);
return filter;
});
```
### 五、watch 監控
#### 1. watch 會回傳兩個值,變動前與變動後的值
```javascript=
setup() {
const num = ref(0);
watch(num, (num, prevNum) => {
console.log({ num });
});
// watch(監控的值, (新的值, 舊的值) => {})
timer = setInterval(() => {
num.value++;
}, 1000);
return {};
},
};
```
#### 2. 監控 ref 與監控 reactive 的不同
- watch 只能監控被讀取的值。
- 如果監控的值非只能被讀取的值,會跳以下錯誤

- ref 的監控
```javascript=
setup() {
const num = ref(0);
// num <= readOnly
// num.value <= 可被改變值
// ===> 因此只要監控 num 就好
watch(num, (num, prevNum) => {
console.log({ num });
});
timer = setInterval(() => {
num.value++;
}, 1000);
return {};
},
```
- reactive 的監控
- 必須對物件中的 key 做監控
- 監控的值必須會 readOnly
```javascript=
setup() {
const numData = reactive({ idx: 0 });
let timer = null;
watch(
() => numData.idx, // 透過 function 回傳一個 readOnly 的值
(idx, prevIdx) => {
console.log({ idx });
}
);
timer = setInterval(() => {
numData.idx++;
if (num.value > 4) {
clearInterval(timer);
}
}, 1000);
return {};
},
```
- ref 與 reactive 對物件的監控
- watch 無法對 red 對深層的監控,但可以對 ref 的物件中的值做單一監控
- watch 可以對 reactive 對整個物件的深層監控,物件中值有變化,就會做出相對應的改變
```javascript=
setup() {
const refObj = ref({ idx: 0 });
const reactiveObj = reactive({ idx: 0 });
watch(refObj, (idx, prevIdx) => {
console.log("ref:", refObj);
});
// ===> ref 無法對物件作深層的監控
// 不過 ref 可以單一監控物件中的值
watch(() => refObj.value.idx, (idx, prevIdx) => {
console.log("ref:", refObj);
});
// ===> OK
watch(reactiveObj, (idx, prevIdx) => {
console.log("reactive:", idx);
});
// ===> reactive OK
setTimeout(() => {
refObj.value.idx = 1;
reactiveObj.idx = 1;
}, 1000);
return { refObj, reactiveObj };
},
```
#### 3. watch Option => deep
如果不得已只能使用 ref 定義物件,watch 也有提供另一個方式做深層的監控。
但 deep 會對物件作全部掃描,比較耗效能,建議如果要使用 deep 的方法,可以對單一的 key 做監控
```javascript=
setup() {
const data = ref({ user: {}, age: {}});
watch(
data.value.user,
(newVal) => {
console.log(newVal);
},
{ deep: true }
);
setTimeout(() => {
data.value.user["name"] = "mike";
}, 1000);
return {};
},
```
### 六、watchEffect
- watchEffect 在開始時就會執行一次,不論監控的值是否有改變。
- 會掃描在 watchEffect 內被調用的值
- watchEffect 可以被停止,透過回傳的 function 停止
```javascript=
setup() {
const num = ref(0);
const numData = reactive({ idx: 0 });
const stop = watchEffect(() => {
console.log(num.value);
if(num.value>=4) {
stop();
}
});
setInterval(() => {
num.value++;
numData.idx++;
}, 1000);
return {};
},
```
### 七、非同步請求
```javascript=
axios.get("https://vue-lessons-api.herokuapp.com/photo/list").then((res) => {
console.log(res);
});
```