vue3 學習筆記 (四)——vue3 setup() 高階用法

前端人發表於2021-11-19

本篇文章乾貨較多,建議收藏!


從 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 是讓基礎資料型別具備響應式的,下篇文章具體介紹它的用法,需要的同學可以點個關注不迷路!

用一張圖告訴你它們的區別:

vue3 學習筆記 (四)——vue3 setup() 高階用法

 

二、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內的函式。

相關文章