# 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 ![](https://i.imgur.com/c1787k0.png) ### 三、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 的不同 ![](https://i.imgur.com/L2swVCC.png) #### 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 只能監控被讀取的值。 - 如果監控的值非只能被讀取的值,會跳以下錯誤 ![](https://i.imgur.com/t5k1vod.png) - 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); }); ```