Vue3.x 關於元件的那些變化(新手必看篇)

前端人發表於2021-11-04

一、元件內的 data 為什麼總是函式形式?

我們試著先做一個計數器案例,把 data 的返回形式修改成一個物件。具體的程式碼如下:

<template>
 <div>
  <button @click="num++">+</button>
   {{num}}
  <button @click="num--">-</button>
 </div>
</template>
<script>
const retData = {
 num:0
}
export default {
 data(){
  return retData
 }
}
</script>

 

執行結果,看著是正常的,並無異常。但我們都知道,vue 專案中,之所以採用元件形式,就是為了重複多次使用,所以我們多次使用我們的元件試試。

神奇的效果發生了,當我們改變第一個元件的數值時,第二個元件的資料也被修改。修改第二個元件的時候,第一個元件的資料也同步更新。

Vue3.x 關於元件的那些變化(新手必看篇)

 

原因:同一個元件被複用多次,會建立多個例項,如果data是一個物件的話,這些例項用的是同一個建構函式,指標指向的就會是同一個地方,就導致了兩個元件的資料會同時更新。

為了保證元件內的資料各自獨立,不會相互影響,要求每個元件的data必須是函式形式,目的就是把資料放入一個新物件內,這樣就不會出現上述問題了。

說這的主要意義就是告訴我們,在 Vue3.x 中的 data 選項總是為函式形式,返回響應式資料。

Vue2.x VS Vue3.x 例項建立

Vue3.x 關於元件的那些變化(新手必看篇)

 

二、函式式元件的變化

在Vue3.x中,functional:true 元件選項被移除。vue3.x 不推薦使用函式式元件。

有些小夥伴就會驚歎,媽呀,俺都不知道函式式元件是啥,你說得再簡單我也不懂吶,所以就講講函式式元件幹啥的,原來的 functional 屬性放哪?

2.1、在Vue2.x中的函式式元件:

函式式元件也是元件的一種型別,主要用來定義那些沒有響應資料,也不需要任何生命週期鉤子函式,只 props 來接收傳遞來的資料。

型別1:基於模板的函式式元件

<template functional >
 <div>
  函式式元件內容
 </div>
</template>

 

型別2:元件註冊

Vue.componenet('fun-comp':{
 functional:true,
 props:{
  msg:{
   type:String,
   default:'元件資料'
  }
 },
 render:(h,context)=>{
  return h('div',['元件內容','++',context.props.msg])
 }
})

 

型別3:中介軟體實現 render 方法

// FunComps.js 檔案程式碼
export default {
 functional:true,
 props:{
  render:{
   type:Function
  },
  params:{}
 },
 render:(h,ctx)=>{
  return ctx.props.render(h,ctx.props.params)
 }
}

//元件呼叫
<fun-comp :render="renderHandle" :params="['111','222']" />

 

renderHandle 這個函式,在外層可以任意控制,這樣不但節省開銷,而且複用性也很高。

2.2、在Vue3.x中的函式式元件:

在 SFC 中不能使用 functional 特性宣告是函式式元件,移除了 functional:true 特性。

// 新建一個 FunComp.vue 檔案
<script>
import { h } from "vue"
function Footer(props,context){
 return h(`h${props.level}`,context.attrs , context.slots )
}
Footer.props = ['level']
export default Footer
</script>

//使用函式式元件
<template>
 <FunComp level="1.0.0" >Vue3.x函式式元件內容</FunComp>
</template>
<script >
import FunComp from '../../components/FunComp.vue'
export default{
 component:{
  FunComp
 },
}
</script>

 

這下應該清楚到底移除的屬性在哪了!接著看看非同步元件有什麼改變。。。

三、非同步元件的變化

Vue3.x 非同步元件要求使用 defineAsyncComponent 方法建立。

由於 Vue3 中函式式元件必須定義為純函式,所以非同步元件有如下變化:

  1. 必須明確地使用 defineAsyncComponent 方法包裹
  2. component 選項已經被重新命名為 loader
  3. loader 函式不再接收 resolve 和 reject 回撥方法 。且必須返回一個 Promise 物件 。

3.1、不帶配置的非同步元件對比

在 Vue2.x中非同步元件使用:

{
 path:'/',
 component: ()=> import("@/view/home/index")
}

 

在 Vue3.x 中非同步元件使用:

import { defineAsyncComponent } from 'vue'

{
 path:"/",
 component:defineAsyncComponent(()=>{ import("@/view/home/index.vue") })
}

 

3.2、帶配置的非同步元件

const asyncPageWithOptions = defineAsyncComponent({
 loader:()=> import("../view/index/index.vue"),
 delay:200,
 timeout:3000,
 errorComponent:ErrorComponent,
 loadingComponent:LoadingComponent
})

 

loader 選項是以前的 component 選項。

四、自定義元件白名單的變化

Vue3.x中,自定義元素檢測發生在模板編譯時,如果要新增 vue 之外的自定義元素,需要在編譯器選項中設定 isCustomElement 選項。
使用構建工具時,模板都會用 vue-loader 預編譯,在 vite.config.js 中配置它提供的 vueCompilerOption 即可:

import { defineConfig,vueCompilerOption } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
 plugins: [vue()],
 vueCompilerOptions:{
  isCustomElement:tag => tag==='pie-chart'
 }
})

 

此時遇到 pie-chart 元素時,直接跳過,不對其進行編譯。

五、動態元件

vue3.x 中設定動態元件時,is 屬性只能用於 component 標籤上。

使用方法:

<component :is="currentView"></component>
//currentView 是一個表示式

 

讓多個元件使用同一個掛載點,並動態切換元件。

5.1、動態元件的快取

好多時候多個元件來回切換時,元件的例項都是重新建立的,而我們需要儲存它的狀態,此時就需要快取動態元件。

在Vue2.x中:

<keep-alive>
 <component :is="currentView"></component>
</keep-alive>

 

在 Vue3.x中:keep-alive 必須使用在 router-view內部

<router-view>
 <keep-alive>
  <component :is="currentView"></component>
 </keep-alive>
</router-view>

 

相關文章