# 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