---
tags: Vue 直播班 - 2022 冬季班
---
# Composition API
## 與Option API 差異

(依功能來分區,但商業邏輯區塊分散)
### OptionAPI
功能依照程式邏輯來拆分
* 優點
1.易學
* 缺點:商業、功能邏輯拆散易讀性差

(顏色為商業邏輯區塊)
### CompositionAPI
整合於setup()內,可以自行依照商業或功能邏輯來區分
* 優點:
1.高度彈性
2.可引入外部涵式
3.熟悉OptionAPI則好上手
* 缺點:需要具備基礎的OptionAPI能力
---
## Proxy (es6原生語法)
> Proxy 是 JavaScript 的內建物件,它允許你創建一個代理(proxy)對象,用於控制對目標物件的訪問和操作。通過使用 Proxy,你可以修改對目標物件的默認行為,並添加自定義的邏輯。
### Proxy資料
* target 是要代理的目標物件,定義的資料會存在這裡。
* handler 是一個處理器(handler)對象,用於定義代理的行為。

(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 版

```
// 透過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物件,具雙向綁定

資料存於 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內部值有變化時,就會觸發)

```
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') ;
```