一、元件內的 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 專案中,之所以採用元件形式,就是為了重複多次使用,所以我們多次使用我們的元件試試。
神奇的效果發生了,當我們改變第一個元件的數值時,第二個元件的資料也被修改。修改第二個元件的時候,第一個元件的資料也同步更新。
原因:同一個元件被複用多次,會建立多個例項,如果data是一個物件的話,這些例項用的是同一個建構函式,指標指向的就會是同一個地方,就導致了兩個元件的資料會同時更新。
為了保證元件內的資料各自獨立,不會相互影響,要求每個元件的data必須是函式形式,目的就是把資料放入一個新物件內,這樣就不會出現上述問題了。
說這的主要意義就是告訴我們,在 Vue3.x 中的 data 選項總是為函式形式,返回響應式資料。
Vue2.x VS 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 中函式式元件必須定義為純函式,所以非同步元件有如下變化:
- 必須明確地使用 defineAsyncComponent 方法包裹
- component 選項已經被重新命名為 loader
- 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>