# VUE 3
<!-- https://chengpeiquan.com/article/vue3-script-setup.html -->
### setup
- 需要在 template 中使用的數據,都需要在 setup 中 return。
- 不再使用 this 調用響應式數據(改成使用 ref, reactive 響應式 API)
:::info

- mounted -> onMounted
- 使用前要先 import,且需要放在 setup 裏面。
:::
#### defineComponent
> 爲了 TS 方便定義型別而定的 API(會自動推導型別)
```typescript=
import { defineComponent } from 'vue'
export default defineComponent({
setup (props, context) {
// ...
return {
// 需要给 template 用的數據、函式
}
}
})
```
#### ref
- 包裹的變量都將轉爲**物件**
- 使用 .value 取得值
```typescript=
// 在 ref 中定義型別(不可以用:)
const msg = ref<string>('Hello World!'); //單一型別
const phoneNumber = ref<number | string>(13800138000); // 複合型別
const uids = ref<number[]>([ 1, 2, 3 ]); // 純型別物件
// 定義成聲明的物件型別
interface Member {
id: number,
name: string
};
const userInfo = ref<Member>({
id: 1,
name: 'Tom'
});
```
```typescript=
// 將 ref 挂載在 DOM 節點
<template>
<!-- 挂载DOM元素 -->
<p ref="msg">
留意该节点,有一个ref属性
</p>
<!-- 挂载DOM元素 -->
<!-- 挂载子组件 -->
<Child ref="child" />
<!-- 挂载子组件 -->
</template>
// 取得 ref 值 (.value)
msg.value
```
#### reactive
- 只能於**物件**、**陣列**中使用
```typescript=
// 在 reactive 中定義型別
let uids: number[] = [ 1, 2, 3 ]; // 純型別物件
// 定義成聲明的物件型別
interface Member {
id: number,
name: string
};
const userInfo: Member = reactive({
id: 1,
name: 'Tom'
});
```
:::warning
**響應式失效**
```typescript=
let uids: number[] = reactive([ 1, 2, 3 ]);
uids = []; // 會使得響應式失效!!! (解構也會造成響應式失效)
uids.length = 0; // 請改成這樣!!!
setTimeout( () => {
uids.push(1);
}, 1000);
```
:::
### script setup <script setup lang="ts">
:::info
**setup 函式的語法糖,會將整個 script 自動變成 setup 函式。**
- 不在需要 return(所有數據默認 return)
- import component 後不需要在定義
:::
```typescript=
<template>
// :傳遞 prop // @傳遞 emit
<Child :name="name" @change-name="changeName" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import Child from '@cp/Child.vue'
const name = ref<string>('Petter')
const changeName = (): void => {
name.value = 'Tom'
}
</script>
```
#### defineProps
```typescript=
import { defineProps } from 'vue'
// JS 寫法
const props = defineProps(['name', 'userInfo', 'tags'])
console.log(props.name)
// TS 判別型別
defineProps<{
name: string
userInfo: object
tags: string[]
}>()
```
#### defineEmit
#### useContext
### API
- **setup**
```javaScript=
<script lang="ts">
import { defineComponent, ref } from 'vue'
import Content from '@cp/Content.vue'
export default defineComponent({
components: {
Content,
},
setup() {
const name = ref<string>('Petter')
const changeName = (): void => {
name.value = 'Tom'
}
return {
name,
changeName,
}
},
})
</script>
```
- **withDefaults**
```
interface Props {
msg?: string
labels?: string[]
}
const props = withDefaults(defineProps<Props>(), {
msg: 'hello',
labels: () => ['one', 'two']
})```
- **ref**
- **reactive**
- **script setup**
```typescript=
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup(){
const year = ref(2020);
const student = reactive({ name: 'Kelly', age: 80 })
}
})
```
### 插件
- **volar**
- **vetur**
- **vue-global-api** 自動引入常見的 api(ref, computed...)
#### watch
- 需要先引入
```typescript=
import { defineComponent, ref, watch } from 'vue' // 要先引入 watch
export default defineComponent({
setup(){
const name = ref<string>('Petter'); // 只能監聽響應式的值
watch( name, (newVal, oldVal) => { // newVal 為變化後的值 // oldVal 為舊值
console.log('前後變化', { oldVal, newVal });
})
}
})
```
#### watchEffect