異步組件(vue3.x新增)
vue3.x
- 由于函數(shù)式組件被定義為純函數(shù),因此異步組件的定義需要通過將其包裝在新的
defineAsyncComponent助手方法中來顯式地定義
import { defineAsyncComponent } from 'vue'
import ErrorComponent from './components/ErrorComponent.vue'
import LoadingComponent from './components/LoadingComponent.vue'
// 不帶選項的異步組件
const asyncPage = defineAsyncComponent(() => import('./NextPage.vue'))
// 帶選項的異步組件
const asyncPageWithOptions = defineAsyncComponent({
loader: () => import('./NextPage.vue'),
delay: 200,
timeout: 3000,
errorComponent: ErrorComponent,
loadingComponent: LoadingComponent
})
-
component選項現(xiàn)在被重命名為loader,loader函數(shù)不再接收resolve和reject參數(shù),且必須返回promise
const asyncComponent = defineAsyncComponent(
()=>new Promise((resolve,reject)=>{
/*...*/
})
)
片段(vue3.x新增)
vue3.x
組件可以有多個根節(jié)點
// vue2.x
<template>
<div>
<header>...</header>
<main>...</main>
<footer>...</footer>
</div>
</template>
// vue3.x
<template>
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
</template>
v-for
vue2.x
v-for指令可以綁定數(shù)組的數(shù)據(jù)來渲染列表
<div v-for="item in items" :key="item.message">
{{ item.message }}
</div>
vue3.x
從單個綁定獲取多個ref,ref會通過迭代的key被設(shè)置(新特性)
<div v-for="item in list" :ref="setItemRef"></div>
自定義元素交互
vue2.x
通過Vue.config.ignoredElements配置自定義元素白名單
Vue.config.ignoredElements = ['plastic-button']
vue3.x
在模板編譯期間執(zhí)行指示編譯器將<plastic-button>視為自定義元素
- 如果使用生成步驟:將
isCustomElement傳遞給 Vue模板編譯器,如果使用vue-loader,則應(yīng)通過 vue-loader 的compilerOptions選項傳遞
rules: [
{
test: /\.vue$/,
use: 'vue-loader',
options: {
compilerOptions: {
isCustomElement: tag => tag === 'plastic-button'
}
}
}
]
- 如果使用動態(tài)模板編譯,通過
app.config.isCustomElement傳遞
const app = Vue.createApp({})
app.config.isCustomElement = tag => tag === 'plastic-button'
自定義內(nèi)置元素的方法是向內(nèi)置元素添加is屬性
v-is要使用注冊名稱來渲染組件,其值應(yīng)為 JavaScript字符串文本
<tr v-is="'blog-post-row'"></tr>
Data選項
vue2.x
可以自定義data選項是object或function
// object 聲明
<script>
const app = new Vue({
data: {
num: '123'
}
})
</script>
// function 聲明
<script>
const app = new Vue({
data() {
return {
num: '123'
}
}
})
</script>
vue3.x
data選項只接受返回object的function
<script>
import { createApp } from 'vue'
createApp({
data() {
return {
num: '123'
}
}
}).mount('#app')
</script>
全局API
vue2.x
有許多全局API和配置,會全局改變vue的行為
vue3.x
調(diào)用createApp返回一個應(yīng)用實例
import {createApp} from 'vue'
const app = createApp({})
config.productionTip移除
config.ignoredElements替換為 config.isCustomElement
下表為2.x與3.x的對比
| 2.x 全局 API | 3.x 實例 API (app) |
|---|---|
| Vue.config | app.config |
| Vue.config.productionTip | 已移除 |
| Vue.config.ignoredElements | app.config.isCustomElement |
| Vue.component | app.component |
| Vue.directive | app.directive |
| Vue.mixin | app.mixin |
| Vue.use | app.use |
全局 API Treeshaking
vue2.x
Vue.nextTick()是一個全局的 API 直接暴露在單個 Vue 對象上,回調(diào)的this上下文自動綁定到當(dāng)前實例
webpack支持tree-shaking,但Vue 2.x 的全局 API 比如 nextTick 無法被 TreeShake,所以就算沒有用到這些 API,它們還是會被打包到你的生產(chǎn)版本的代碼包里
vue3.x
全局和內(nèi)部API進行了重構(gòu),支持使用tree-shaking
需要注意的是:
當(dāng)使用全局 API 時,需要主動將其導(dǎo)入到目標文件中
import { nextTick } from 'vue';
nextTick(() => {
// 和 DOM 有關(guān)的一些操作
});
如果直接調(diào)用Vue.nextTick(),會導(dǎo)致報錯:undefined is not a function
key attribute
vue2.x
建議在v-if/v-else/v-else-if的分支中使用key
// vue2.x
<div v-if="hhhh" key = "yes">YES</div>
<div v-else key = "no">NO</div>
vue3.x
vue會自動生成唯一的key
<div v-if="hhhh">YES</div>
<div v-else>NO</div>
按鍵修飾符
vue2.x
- 支持keyCodes作為修改
v-on的方法 - 可以通過全局config.keyCodes
<!-- 鍵碼版本 -->
<input v-on:keyup.13="submit" />
<!-- 別名版本 -->
<input v-on:keyup.enter="submit" />
vue3.x
- 不再支持使用數(shù)字 (即鍵碼) 作為
v-on修飾符,建議使用kebab-cased大小寫名稱 - 不再支持 config.keyCodes
<input v-on:keyup.delete="confirmDelete" />
在 prop 的默認函數(shù)中訪問this
vue3.x
生成 prop 默認值的工廠函數(shù)不再能訪問 this
渲染函數(shù)API
vue2.x
- render函數(shù)參數(shù)
render函數(shù)自動接收h函數(shù)作為參數(shù)
// vue2.x
export default
render(h){
return h('div')
}
}
- render函數(shù)簽名更改
render函數(shù)自動接收諸如 h 之類的參數(shù)
// vue2.x
export default{
render(h){
return h('div')
}
}
vue3.x
- render函數(shù)參數(shù)
h是全局引入的,而不是作為參數(shù)自動傳遞
// vue 3.x
import {h} from 'vue'
export default{
render(){
return h('div')
}
}
- render函數(shù)簽名更改
render函數(shù)不再接收任何參數(shù),將主要用于setup()內(nèi)部,可以訪問作用域中聲明的響應(yīng)式狀態(tài)和函數(shù)以及傳遞給setup()的參數(shù)
import { h, reactive } from 'vue'
export default {
setup(props, { slots, attrs, emit }) {
const state = reactive({
count: 0
})
function increment() {
state.count++
}
// 返回render函數(shù)
return () =>
h(
'div',
{
onClick: increment
},
state.count
)
}
}
slot統(tǒng)一
vue2.x
在內(nèi)容節(jié)點上定義slot data property
h(LayoutComponent,[
h('div',{slot:'header'},this.header),
h('div',{slot:'content'},this.content)
])
// 引用時
this.$scopedSlots.header
vue3.x
- 插槽被定義為當(dāng)前節(jié)點的子對象
h(LayoutComponent,{},{
header:()=>h('div',this.header),
content:()=>h('div',this.content)
})
- 當(dāng)需要以編程方式引用作用域slot時,被統(tǒng)一到
$slot選項中
this.$slots.header
過渡類名更改
vue3.x
過渡類名 v-enter修改為 v-enter-from、過渡類名v-leave修改為v-leave-from
<transition>組件相關(guān)屬性名也發(fā)生了變化:
leave-class已經(jīng)被重命名為leave-from-class(在渲染函數(shù)或 JSX 中可以寫為:leaveFromClass)
enter-class已經(jīng)被重命名為enter-from-class (在渲染函數(shù)或 JSX 中可以寫為:enterFromClass)
v-model
vue2.x
- 使用
v-model指令必須使用value的prop;
<ChildComponent v-model="pageTitle" />
- 如果出于不同的目的使用其他的
prop,需要使用v-bind.sync
<ChildComponent :title.sync="pageTitle" />
vue3.x
- 如果要改變綁定的屬性名,而不是更改組件內(nèi)綁定的選項,只需要給 v-model 傳遞一個參數(shù)就可以了;
<ChildComponent v-model:title = 'pageitle' />
- 可以自定義多個v-model;
<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" />
- 支持自定義修飾符
<ChildComponent v-model.capitalize="pageTitle" />
v-if與v-for的優(yōu)先級比較
vue2.x
在同一個元素上同時使用v-if和v-for,v-for會優(yōu)先使用;
vue3.x
v-if總是優(yōu)先于v-for生效
v-bind合并行為
vue2.x
如果一個元素同時定義了v-bind="object"和一個相同的單獨的property,那么這個單獨的 property總是會覆蓋object中的綁定
<div id="red" v-bind="{ id: 'blue' }"></div>
// 結(jié)果
<div id="red"></div>
vue3.x
如果一個元素同時定義了v-bind="object"和一個相同的單獨的property,那么聲明綁定的順序決定了它們?nèi)绾魏喜?/p>
<div id="red" v-bind="{ id: 'blue' }"></div>
// 結(jié)果
<div id="blue"></div>
<div v-bind="{ id: 'blue' }" id="red"></div>
// 結(jié)果
<div id="red"></div>
函數(shù)式組件
vue2.x
- 作為性能優(yōu)化
- 返回多個根節(jié)點
export default {
functional: true,
props: ['level'],
render(h, { props, data, children }) {
return h(`h${props.level}`, data, children)
}
}
vue3.x
- 通過函數(shù)創(chuàng)建組件
所有的函數(shù)式組件都是用普通函數(shù)創(chuàng)建的,不需要定義{function:true}組件選項
import { h } from 'vue'
const DynamicHeading = (props, context) => {
return h(`h${props.level}`, context.attrs, context.slots)
}
DynamicHeading.props = ['level']
export default DynamicHeading
- 單文件組件
<template>
<component
v-bind:is="`h${$props.level}`"
v-bind="$attrs"
/>
</template>
<script>
export default {
props: ['level']
}
</script>
function attribute 在<template>中移除
listeners現(xiàn)在作為$attrs的一部分傳遞,可以刪除
下表為vue3.x已移除的api:
| 已移除的api | vue2.x | vue3.x |
|---|---|---|
| $children | 可以使用this.$children直接訪問當(dāng)前實例的子組件 |
$children已移除,如需訪問子組件,建議使用$refs
|
| 事件API | vue實例可用于觸發(fā)通過事件觸發(fā)API強制附加發(fā)處理程序已創(chuàng)建全局事件監(jiān)聽器 | 移除了$on,$off,$once方法,但仍可用$emit觸發(fā)由父組件以聲明方式附加的事件處理程序 |
| 過濾器 | 可以使用過濾器來處理通用文本格式 | 過濾器已刪除,可以用方法調(diào)用或計算屬性替換過濾器 |
| 內(nèi)聯(lián)模塊Attribute | Vue 為子組件提供了inline-template attribute,以便將其內(nèi)部內(nèi)容用作模板,而不是將其作為分發(fā)內(nèi)容 |
不再支持此功能,所有模板寫在HTML頁面中 |