
前端(vue)入門到精通課程:進入學習
Apipost = Postman + Swagger + Mock + Jmeter 超好用的API調試工具:點擊使用
script setup 語法糖
組合式 API:setup()
基本使用
Vue 3 的 Composition API 系列里,推出了一個全新的 setup 函數,它是一個組件選項,在創建組件之前執行,一旦 props 被解析,并作為組合式 API 的入口點。【學習視頻分享:vue視頻教程、web前端視頻】
setup 選項是一個接收 props 和 context 的函數,我們參考文檔進行討論。此外,我們將 setup 返回的所有內容都暴露給組件的其余部分 (計算屬性、方法、生命周期鉤子等等) 以及組件的模板。
<script> // 這是一個基于 TypeScript 的 Vue 組件 import { defineComponent } from 'vue' export default defineComponent({ setup(props, context) { // 在這里聲明數據,或者編寫函數并在這里執行它 return { // 需要給 `<template />` 用的數據或函數,在這里 `return` 出去 } }, }) </script>
新的 setup 選項是在組件創建之前, props 被解析之后執行,是組合式 API 的入口。
注意:
在setup中你應該避免使用this,因為它不會找到組件實例。setup的調用發生在dataproperty、computedproperty 或methods被解析之前,所以它們無法>在setup中被獲取。
在添加了setup的script標簽中,我們不必聲明和方法,這種寫法會自動將所有頂級變量、函數,均會自動暴露給模板(template)使用
這里強調一句 “暴露給模板,跟暴露給外部不是一回事”
TIP:說的通俗一點,就是在使用 Vue 3 生命周期的情況下,整個組件相關的業務代碼,都可以放在 setup 里執行。
因為在 setup 之后,其他的生命周期才會被啟用,我們對比一下Vue2的Vue3生命周期的變化
組件生命周期
關于 Vue 生命周期的變化,可以從下表直觀地了解:
| Vue 2 生命周期 | Vue 3 生命周期 | 執行時間說明 |
|---|---|---|
| beforeCreate | setup | 組件創建前執行 |
| created | setup | 組件創建后執行 |
| beforeMount | onBeforeMount | 組件掛載到節點上之前執行 |
| mounted | onMounted | 組件掛載完成后執行 |
| beforeUpdate | onBeforeUpdate | 組件更新之前執行 |
| updated | onUpdated | 組件更新完成之后執行 |
| beforeDestroy | onBeforeUnmount | 組件卸載之前執行 |
| destroyed | onUnmounted | 組件卸載完成后執行 |
| errorCaptured | onErrorCaptured | 當捕獲一個來自子孫組件的異常時激活鉤子函數 |
可以看到 Vue 2 生命周期里的 beforeCreate 和 created ,在 Vue 3 里已被 setup 替代。
script setup 語法糖
它是 Vue3 的一個新語法糖,在 setup 函數中。所有 ES 模塊導出都被認為是暴露給上下文的值,并包含在 setup() 返回對象中。相對于之前的寫法,使用后,語法也變得更簡單。
自動注冊屬性和方法無需返回,直接使用
1.<script setup> 語法糖并不是新增的功能模塊,它只是簡化了以往的組合API(compositionApi)的必須返回(return)的寫法,并且有更好的運行時性能。
2.在 setup 函數中:所有 ES 模塊導出都被認為是暴露給上下文的值,并包含在 setup() 返回對象中。相對于之前的寫法,使用后,語法也變得更簡單。
你不必擔心setup語法糖的學習成本,他是組合式API的簡化,并沒有新增的知識點。你只需要了解一些用法和細微的不同之處,甚至比之前寫setup()還要順手!
使用方式也很簡單,只需要在 script 標簽加上 setup 關鍵字即可
<script setup> </script>
組件核心 API 的使用
組件自動注冊
在 script setup 中,引入的組件可以直接使用,無需再通過components進行注冊,并且無法指定當前組件的名字,它會自動以文件名為主,也就是不用再寫name屬性了。
示例:
<template> <Child /> </template> <script setup> import Child from '@/components/Child.vue' </script>
定義組件的 props
defineProps —-> [用來接收父組件傳來的 props] 代碼示列:
通過defineProps指定當前 props 類型,獲得上下文的props對象。
示例:
<script setup> import { defineProps } from 'vue' const props = defineProps({ title: String, }) </script> <!-- 或者 --> <script setup> import { ref,defineProps } from 'vue'; type Props={ msg:string } defineProps<Props>(); </script>
定義 emit
defineEmit —-> [子組件向父組件事件傳遞]
使用defineEmit定義當前組件含有的事件,并通過返回的上下文去執行 emit。
代碼示列:
<script setup> import { defineEmits } from 'vue' const emit = defineEmits(['change', 'delete']) </script>
父子組件通信
defineProps 用來接收父組件傳來的 props ; defineEmits 用來聲明觸發的事件。
//父組件 <template> <Child @getChild="getChild" :title="msg" /> </template> <script setup> import { ref } from 'vue' import Child from '@/components/Child.vue' const msg = ref('parent value') const getChild = (e) => { // 接收父組件傳遞過來的數據 console.log(e); // child value } </script>
//子組件 <template> <div @click="toEmits">Child Components</div> </template> <script setup> // defineEmits,defineProps無需導入,直接使用 const emits = defineEmits(['getChild']); const props = defineProps({ title: { type: String, defaule: 'defaule title' } }); const toEmits = () => { emits('getChild', 'child value') // 向父組件傳遞數據 } // 獲取父組件傳遞過來的數據 console.log(props.title); // parent value </script>
子組件通過 defineProps 接收父組件傳過來的數據,子組件通過 defineEmits 定義事件發送信息給父組件
useSlots() 和 useAttrs()
獲取 slots 和 attrs
注:useContext API 被棄用,取而代之的是更加細分的 api。
可以通過useContext從上下文中獲取 slots 和 attrs。不過提案在正式通過后,廢除了這個語法,被拆分成了useAttrs和useSlots。
-
useAttrs:見名知意,這是用來獲取 attrs 數據,但是這和 vue2 不同,里面包含了class、屬性、方法。
<template> <component v-bind='attrs'></component> </template> <srcipt setup> const attrs = useAttrs(); <script>
-
useSlots: 顧名思義,獲取插槽數據。
使用示例:
// 舊 <script setup> import { useContext } from 'vue' const { slots, attrs } = useContext() </script> // 新 <script setup> import { useAttrs, useSlots } from 'vue' const attrs = useAttrs() const slots = useSlots() </script>
defineExpose API
defineExpose —-> [組件暴露出自己的屬性]
傳統的寫法,我們可以在父組件中,通過 ref 實例的方式去訪問子組件的內容,但在 script setup 中,該方法就不能用了,setup 相當于是一個閉包,除了內部的 template模板,誰都不能訪問內部的數據和方法。
<script setup>的組件默認不會對外部暴露任何內部聲明的屬性。
如果有部分屬性要暴露出去,可以使用defineExpose
注意:目前發現
defineExpose暴露出去的屬性以及方法都是unknown類型,如果有修正類型的方法,歡迎評論區補充。
如果需要對外暴露 setup 中的數據和方法,需要使用 defineExpose API。示例:
//子組件 <template> {{msg}} </template> <script setup> import { ref } from 'vue' let msg = ref("Child Components"); let num = ref(123); // defineExpose無需導入,直接使用 defineExpose({ msg, num }); </script>
//父組件 <template> <Child ref="child" /> </template> <script setup> import { ref, onMounted } from 'vue' import Child from '@/components/Child.vue' let child = ref(null); onMounted(() => { console.log(child.value.msg); // Child Components console.log(child.value.num); // 123 }) </script>
定義響應變量、函數、監聽、計算屬性computed
<script setup > import { ref,computed,watchEffect } from 'vue'; const count = ref(0); //不用 return ,直接在 templete 中使用 const addCount=()=>{ //定義函數,使用同上 count.value++; } //創建一個只讀的計算屬性 ref: const plusOne = computed(() => count.value + 1) // 創建一個可寫的計算屬性 ref const plusOne = computed({ get: () => count.value + 1, set: (val) => { count.value = val - 1 } }) //定義監聽,使用同上 //...some code else watchEffect(()=>console.log(count.value)); </script>
watchEffect和watch區別
1、watch是惰性執行,也就是只有監聽的值發生變化的時候才會執行,但是watchEffect不同,每次代碼加載watchEffect都會執行(忽略watch第三個參數的配置,如果修改配置項也可以實現立即執行)
2、watch需要傳遞監聽的對象,watchEffect不需要
3、watch只能監聽響應式數據:ref定義的屬性和reactive定義的對象,如果直接監聽reactive定義對象中的屬性是不允許的,除非使用函數轉換一下
4、watchEffect如果監聽reactive定義的對象是不起作用的,只能監聽對象中的屬性。
reactive
返回一個對象的響應式代理。
<script setup> import { reactive, onUnmounted } from 'vue' const state = reactive({ counter: 0 }) // 定時器 每秒都會更新數據 const timer = setInterval(() => { state.counter++ }, 1000); onUnmounted(() => { clearInterval(timer); }) </script> <template> <div>{{state.counter}}</div> </template>
使用ref也能達到我們預期的'counter',并且在模板中,vue進行了處理,我們可以直接使用counter而不用寫counter.value.
ref和reactive的關系:
ref是一個{value:'xxxx'}的結構,value是一個reactive對象
ref 暴露變量到模板
曾經的提案中,如果需要暴露變量到模板,需要在變量前加入export聲明:
export const count = ref(0)
不過在新版的提案中,無需export聲明,編譯器會自動尋找模板中使用的變量,只需像下面這樣簡單的聲明,即可在模板中使用該變量
<script setup > import { ref } from 'vue' const counter = ref(0);//不用 return ,直接在 templete 中使用 const timer = setInterval(() => { counter.value++ }, 1000) onUnmounted(() => { clearInterval(timer); }) </script> <template> <div>{{counter}}</div> </template>
其他 Hook Api
-
useCSSModule:CSS Modules 是一種 CSS 的模塊化和組合系統。vue-loader 集成 CSS Modules,可以作為模擬 scoped CSS。允許在單個文件組件的setup中訪問CSS模塊。此 api 本人用的比較少,不過多做介紹。 -
useCssVars: 此 api 暫時資料比較少。介紹v-bind in styles時提到過。 -
useTransitionState: 此 api 暫時資料比較少。 -
useSSRContext: 此 api 暫時資料比較少。
支持 async await 異步
注意在vue3的源代碼中,setup執行完畢,函數 getCurrentInstance 內部的有個值會釋放對 currentInstance 的引用,await 語句會導致后續代碼進入異步執行的情況。所以上述例子中最后一個 getCurrentInstance() 會返回 null,建議使用變量保存第一個 getCurrentInstance() 返回的引用.
<script setup> const post = await fetch(`/api/post/1`).then((r) => r.json()) </script>
<script setup> 中可以使用頂層 await。結果代碼會被編譯成 async setup():
<script setup> const post = await fetch(`/api/post/1`).then(r => r.json()) </script>
另外,await 的表達式會自動編譯成在 await 之后保留當前組件實例上下文的格式。
注意
async setup()必須與Suspense組合使用,Suspense目前還是處于實驗階段的特性。我們打算在將來的某個發布版本中開發完成并提供文檔 – 如果你現在感興趣,可以參照 tests 看它是如何工作的。
定義組件其他配置
配置項的缺失,有時候我們需要更改組件選項,在setup中我們目前是無法做到的。我們需要在上方再引入一個 script,在上方寫入對應的 export即可,需要單開一個 script。
<script setup> 可以和普通的 <script> 一起使用。普通的 <script> 在有這些需要的情況下或許會被使用到:
- 無法在
<script setup>聲明的選項,例如inheritAttrs或通過插件啟用的自定義的選項。 - 聲明命名導出。
- 運行副作用或者創建只需要執行一次的對象。
在script setup 外使用export default,其內容會被處理后放入原組件聲明字段。
<script> // 普通 `<script>`, 在模塊范圍下執行(只執行一次) runSideEffectOnce() // 聲明額外的選項 export default { name: "MyComponent", inheritAttrs: false, customOptions: {} } </script> <script setup> import HelloWorld from '../components/HelloWorld.vue' // 在 setup() 作用域中執行 (對每個實例皆如此) // your code </script> <template> <div> <HelloWorld msg="Vue3 + TypeScript + Vite"/> </div> </template>
注意:Vue 3 SFC 一般會自動從組件的文件名推斷出組件的 name。在大多數情況下,不需要明確的 name 聲明。唯一需要的情況是當你需要
<keep-alive>包含或排除或直接檢查組件的選項時,你需要這個名字。
(學習視頻分享:web前端開發、編程基礎視頻)
站長資訊網