vue2.x與vue3.x的對比

異步組件(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ù)不再接收resolvereject參數(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選項是objectfunction

// object 聲明
<script>
  const app = new Vue({
    data: {
      num: '123'
    }
  })
</script>

// function 聲明 
<script>
  const app = new Vue({
    data() {
      return {
        num: '123'
      }
    }
  })
</script>

vue3.x
data選項只接受返回objectfunction

<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指令必須使用valueprop;
<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-ifv-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頁面中
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容