--- tags: Vue 直播班 - 2022 冬季班 --- # Composition API ## 與Option API 差異 ![](https://hackmd.io/_uploads/B1DEBxXv2.png) (依功能來分區,但商業邏輯區塊分散) ### OptionAPI 功能依照程式邏輯來拆分 * 優點 1.易學 * 缺點:商業、功能邏輯拆散易讀性差 ![](https://hackmd.io/_uploads/Sy738e7Dh.png) (顏色為商業邏輯區塊) ### CompositionAPI 整合於setup()內,可以自行依照商業或功能邏輯來區分 * 優點: 1.高度彈性 2.可引入外部涵式 3.熟悉OptionAPI則好上手 * 缺點:需要具備基礎的OptionAPI能力 --- ## Proxy (es6原生語法) > Proxy 是 JavaScript 的內建物件,它允許你創建一個代理(proxy)對象,用於控制對目標物件的訪問和操作。通過使用 Proxy,你可以修改對目標物件的默認行為,並添加自定義的邏輯。 ### Proxy資料 * target 是要代理的目標物件,定義的資料會存在這裡。 * handler 是一個處理器(handler)對象,用於定義代理的行為。 ![](https://hackmd.io/_uploads/HJ4y9l7wn.png) (proxy範例圖) ### 一些常見的 Proxy方法 (handler traps): * get(target, property, receiver): 當代理對象訪問目標物件的屬性時觸發,可以修改或攔截該屬性的訪問。 * set(target, property, value, receiver): 當代理對象設置目標物件的屬性值時觸發,可以修改或攔截該屬性的賦值操作。 * apply(target, thisArg, argumentsList): 當代理對象作為函式調用時觸發,可以修改或攔截函式的調用操作。 * construct(target, argumentsList, newTarget): 當代理對象作為構造函式(使用 new 關鍵字)創建新實例時觸發,可以修改或攔截該構造函式的行為。 (雙向綁定與邏輯示範) ``` const handler = { get(obj, property) { console.log(`get:`,obj, property,value); // 需回傳才會把值傳出去 return obj[property] }, set(obj, property, newVal) { console.log(`set:` ,obj, property, newVal); // 要更改屬性必須在此操作,該物件的屬性 = 新值 obj[property] = newVal //會將設置修改的資料觸發渲染行為,進行所謂雙向綁定 render(obj,obj[property]) // 會跳錯,輸入 return true,告訴他操作完畢就不會跳錯 return true }, }; // 建立proxy物件,前者必定是物件!!後者為控制器 const newObj = new Proxy({a:1},handler) newObj.a = 2; // 因設置更改數值,觸發 set() // set()中,obj = newObj property = a newval = 2 // 會將你寫的值 傳入,並觸發內部涵式更改數值 console.log(newObj.a) // 因要取得數值,觸發 get() // get()中,obj = newObj property = a // log 中的值 為get()內部的, 外層log會為 undefined ,因內部沒有return回傳出來 const render = (prop , data)=> { const target = document.querySelector('#app') target.innerHTML = `${prop}:${data}` } // 兩秒過後,就會看到資料被更改並渲染出來 setTimeout(()=>{ newObj.name = '你好棒' },2000) ``` --- ## setup() 起手示 Vue本身就是一個大物件,內部具有許多的方法,因此可以利用解構方法,把相關方法取出使用 console.log(Vue) 可查看 optionAPI 版 ![optionAPI](https://hackmd.io/_uploads/rJ4wLZQD3.png) ``` // 透過inport與解構式 取出相關方法 常見於 VueCli ,ESM // import {} from 'vue' ; const { creatrApp } = Vue; // 1. const app = Vue.createApp({}) 寫法之一 // 2. const app = creatrApp({}) 寫法之一 const app = Vue.createApp({ data(){ return { num: 1, } }, methods: { add() {( this. num++; ); } }); app.mount('#app') ; ``` CompositionAPI 版 * setup(){} 起手 * ref 為定義資料的方法之一 * ref 取值須於後面加入.value * function add (){} 不會用到this * return 需將變數和方法傳出去,才能呈現於畫面與執行 ``` const { creatrApp, ref } = Vue; const app = creatrApp({ setup () { // ref 為定義資料的方法之一 const num = ref(1) // compositionAPI 不會使用到this function add (){ //ref 取用方法須加入.value num.value++ } // 需將變數和方法傳出去,才能呈現於畫面與執行 return { num,add } } }); app.mount('#app') ; ``` --- ## ref 與 reactive ### 定義資料方法 兩者方法皆須要使用**const**,使用let,一旦被覆蓋掉就會失去效果,變成一般的變數 直接宣告的變數,並不具有雙向綁定的效果,如果想要具有雙向綁定的效果,Vue3的有兩種寫法分別為 **ref** 和 **reactive** * **reactive** proxy物件,一定是物件!如果傳入純值則會出錯 reactive Code : ``` const { creatrApp, reactive ,ref } = Vue; const app = creatrApp({ setup () { // 直接宣告的變數,並不具有雙向綁定的效果 const person= { name:'王曉明' } // proxy物件 const person2= reactive({ name:'王曉明' }) // 使用物件方法來改值 person.name = '陳小美' // 需將變數和方法傳出去,才能呈現於畫面與執行 return { person,person2 } } }); app.mount('#app') ; ``` * **ref** 可以定義純值或物件,是RefImpl物件,具雙向綁定 ![](https://hackmd.io/_uploads/H1cbPO4Pn.png) 資料存於 value 中 ,因此需使用 .value like: * num.value * numObj.value.name (深層結構可,也能替換整個物件) ref Code : ``` const { creatrApp, reactive ,ref } = Vue; const app = creatrApp({ setup () { // ref 可定義純值,並且不是proxy物件 const num = ref(1) num.value = 5 // ref 物件取值方法 const numObj = ref ({ name:'劉德華' }) numObj.value.name = '周杰倫' // ref 替換整個物件方法 numObj.value = { name:'小小兵' } // 需將變數和方法傳出去,才能呈現於畫面與執行 return { num,numObj } } }); app.mount('#app') ; ``` ### 如何選擇 ref 或 reactive * reactive 特性: proxy,須為物件,handler監控控制器(當proxy內部值有變化時,就會觸發) ![](https://hackmd.io/_uploads/HJxFQjVv2.png) ``` const { creatrApp, reactive ,ref } = Vue; const app = creatrApp({ setup () { // ref const person = ref({ name:'王曉明' }) // reactive const person2 = reactive({ name:'王曉明' }) return { person,person2 } } }); app.mount('#app') ; ``` * ref 特性: proxy,須為物件,handler監控控制器(當proxy內部值有變化時,就會觸發) ``` const { creatrApp, reactive ,ref } = Vue; const app = creatrApp({ setup () { // ref const person = ref({ name:'王曉明' }) // reactive const person2 = reactive({ name:'王曉明' }) return { person,person2 } } }); app.mount('#app') ; ```