---
# System prepended metadata

title: VUE 3

---

# VUE 3 
<!-- https://chengpeiquan.com/article/vue3-script-setup.html -->

### setup
- 需要在 template 中使用的數據，都需要在 setup 中 return。
- 不再使用 this 調用響應式數據（改成使用 ref, reactive 響應式 API）
:::info
![](https://i.imgur.com/iobpQRN.png =80%x)
- 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