Vue3 學習筆記—Vue3 setup() 高級用法
從 vue2 升級到 vue3,vue3 是可以兼容 vue2 的,所以 vue3 可以采用 vue2 的選項式API。由于選項式API一個變量存在于多處,如果出現問題時,就需要去多個函數內檢查,項目較大時,遇到問題,增加排故的難度。所以 vue3 中新增了 setup 配置項,用它來寫組合式API。
一、選項式API 和 組合式API 區別
有些同學稀里糊涂用了vue一年了,竟然不知道選項式api !你是那個同學嗎?是的話,趕緊收藏起來。
vue2 中的 Options API 就是選項式api,一個中文,一個英文,怎么叫都可以。
在一個 vue 文件內,會有 data、methods、mounted、computed、watch 等等用來定義屬性和方法,共同來處理頁面邏輯,我們把這種方式稱為 Options API。
示例1:計數器
- <template>
- <div>
- <button @click="add">+</button>
- {{num}}
- <button @click="reduce">-</button>
- </div>
- </template>
- <script>
- export default {
- data(){
- return {
- num:0
- }
- },
- methods:{
- add(){
- this.num++
- },
- reduce(){
- this.num--
- }
- }
- }
- </script>
觀察上述示例,我們發現 num 值的處理涉及到 data 和 methods 兩個選項,業務處理的比較分散,項目小了看著清晰明了,但是項目變大之后,data 和 methods會包含很多屬性和方法,此時就很難分清哪個屬性對應哪個方法。所以 vue3 新增 setup 寫組合式API。
Vue3 的 Composition API 就是組合式api。
組合式api 就是一個功能所定義的 api 會放在一起,這樣子即使項目變大,功能增大,我們能夠很快找到功能相關的所有api,不像 Options API 功能分散,需要改動時,需要多處查找過程比較困難。
示例2:計數器
- <template>
- <div>
- <button @click="add">+</button>
- {{num}}
- <button @click="reduce">-</button>
- </div>
- </template>
- <script>
- import { ref } from 'vue'
- export default{
- setup(){
- const num = ref(1)
- return{
- num,
- add(){
- num.value++
- },
- reduce(){
- num.value--
- }
- }
- }
- }
- </script>
ref 是讓基礎數據類型具備響應式的,下篇文章具體介紹它的用法,需要的同學可以點個關注不迷路!
用一張圖告訴你它們的區別:

二、setup 具體怎么用?
2.1、setup 什么時候執行?
setup 用來寫組合式 api,從生命周期鉤子函數角度分析,相當于取代了 beforeCreate 。會在 creted 之前執行。
- <script>
- export default{
- created(){
- console.log('created');
- },
- setup(){
- console.log('setup');
- }
- }
- </script>
執行之后,setup 打印結果始終在前邊。
2.2、setup 數據和方法如何使用?
示例3:直接定義使用變量
- <template>
- {{a}}
- </template>
- <script>
- export default{
- setup(){
- const a = 0
- }
- }
- </script>
運行后發現結果異常:
runtime-core.esm-bundler.js?5c40:6584 [Vue warn]: Property "a" was accessed during render but is not defined on instance.
提示我們訪問的屬性 a 并沒有掛載到實例上。
setup 內部的屬性和方法,必須 return 暴露出來,將屬性掛載到實例上,否則沒有辦法使用,上述代碼添加 return:
- <script>
- export default{
- setup(){
- const a = 0
- return{
- a
- }
- }
- }
- </script>
2.3、setup 內部有 this 嗎?
自己在 setup 中打印下 this ,返回結果 是undefined 。說明在 setup 內部是不存在 this ,不能掛載 this 相關的東西。
2.4、setup 內鉤子函數如何使用?
vue3 是可以兼容 vue2 的選項式寫法,所以 鉤子函數可以與 setup 并列存在,就相當于 Options API。
示例4:
- export default{
- setup(){
- console.log('setup');
- },
- mounted(){
- console.log('mounted');
- }
- }
vue3 新增的 setup() 函數用來寫組合式 api,所以不建議這樣寫代碼。所以需要使用 onXXX 一族的函數來注冊鉤子函數,注冊成功之后調用時傳遞的是一個回調函數。
示例5:
- import { onMounted } from "vue";
- export default{
- setup(){
- const a = 0
- return{
- a
- },
- onMounted(()=>{
- console.log("執行");
- })
- }
- }
注冊的這些生命周期鉤子函數只能在 setup 期間同步使用,因為它們依賴全局內部狀態來定位當前組件實例,不在當前組件下調用函數時會拋出錯誤。
其他的鉤子函數是一樣的,根據需要引入就好了。
2.5、setup與鉤子函數關系
setup 與鉤子函數并列時,setup 不能調用生命周期相關函數,但生命周期可以調用 setup 相關的屬性和方法。
示例6:
- <template>
- <button @click="log">點我</button>
- </template>
- <script>
- export default{
- setup(){
- const a = 0
- return{
- a
- }
- },
- methods:{
- log(){
- console.log( this.$options.setup() );//返回一個對象
- }
- }
- }
- </script>
this.$options.setup() 返回的是一個大對象,該對象內包含了 setup 內的所有屬性和方法。
三、setup 參數
使用setup 時,它將接收兩個參數:props 和 context 。
3.1、props
第一個參數是 props ,表示父組件給子組件傳值,props 是響應式的,當傳入新的 props 時,自動更新。
示例7:
- export default{
- props: {
- msg: String,
- ans: String,
- },
- setup(props,context){
- console.log(props);//Proxy {msg: "著急找對象", ans: "你有對象嗎?"}
- },
- }
因為 props 是響應式的,不能使用 ES6 解構,會消除prop的響應特性,此時需要借用 toRefs 解構。示例8:
- import { toRefs } from "vue";
- export default{
- props: {
- msg: String,
- ans: String,
- },
- setup(props,context){
- console.log(props);
- const { msg,ans } = toRefs(props)
- console.log(msg.value); //著急找對象
- console.log(ans.value); //你有對象嗎?
- },
- }
使用組件時,經常會遇到可選參時,有些地方需要傳遞某個值,有些時候不需要,該如何處理呢?
如果 ans 是一個可選參數,則傳入 props 中可能沒有 ans 。在這種情況下 toRefs 將不會為 ans 創建一個 ref ,需要使用 toRef 代替它。
- import { toRef } from "vue";
- setup(props,context){
- let ans = toRef(props ,'ans')// 不存在時,創建一個ans
- console.log(ans.value);
- }
3.2、context
context 上下文環境,其中包含了 屬性、插槽、自定義事件三部分。
- setup(props,context){
- const { attrs,slots,emit } = context
- // attrs 獲取組件傳遞過來的屬性值,
- // slots 組件內的插槽
- // emit 自定義事件 子組件
- }
attrs 是一個非響應式對象,主要接收 no-props 屬性,經常用來傳遞一些樣式屬性。
slots 是一個 proxy 對象,其中 slots.default() 獲取到的是一個數組,數組長度由組件的插槽決定,數組內是插槽內容。
setup 內不存在this,所以 emit 用來替換 之前 this.$emit 的,用于子傳父時,自定義事件觸發。
示例9:
- <template>
- <div :style="attrs.style">
- <slot></slot>
- <slot name="hh"></slot>
- <button @click="emit('getVal','傳遞值')">子向父傳值</button>
- </div>
- </template>
- <script>
- import { toRefs,toRef } from "vue";
- export default{
- setup(props,context){
- const { attrs,slots,emit } = context
- // attrs 獲取組件傳遞過來 style 屬性
- console.log('slots',slots.default());//插槽數組
- console.log('插槽屬性',slots.default()[1].props); //獲取插槽的屬性
- return{
- attrs,
- emit
- }
- },
- }
- </script>
四、setup 特性總結
1、這個函數會在 created 之前執行,上述已解釋。
2、setup 內部沒有 this,不能掛載 this 相關的東西。
3、setup 內部的屬性和方法,必須 return 暴漏出來,否則沒有辦法使用。
4、setup 內部數據不是響應式的。
5、setup不能調用生命周期相關函數,但生命周期函數可以調用setup內的函數。