vue2.x与vue3.x的对比

异步组件(vue3.x新增)

vue3.x

  • 由于函数式组件被定义为纯函数,因此异步组件的定义需要通过将其包装在新的 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选项现在被重命名为loader,loader函数不再接收resolvereject参数,且必须返回promise
const asyncComponent = defineAsyncComponent(
  ()=>new Promise((resolve,reject)=>{
    /*...*/
  })
)

片段(vue3.x新增)

vue3.x
组件可以有多个根节点

// 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指令可以绑定数组的数据来渲染列表

<div v-for="item in items" :key="item.message">
    {{ item.message }}
  </div>

vue3.x
从单个绑定获取多个ref,ref会通过迭代的key被设置(新特性)

<div v-for="item in list" :ref="setItemRef"></div>

自定义元素交互

vue2.x
通过Vue.config.ignoredElements配置自定义元素白名单

Vue.config.ignoredElements = ['plastic-button']

vue3.x
在模板编译期间执行指示编译器将<plastic-button>视为自定义元素

  • 如果使用生成步骤:将isCustomElement传递给 Vue模板编译器,如果使用vue-loader,则应通过 vue-loader 的compilerOptions选项传递
rules: [
  {
    test: /\.vue$/,
    use: 'vue-loader',
    options: {
      compilerOptions: {
        isCustomElement: tag => tag === 'plastic-button'
      }
    }
  }
]
  • 如果使用动态模板编译,通过 app.config.isCustomElement传递
const app = Vue.createApp({})
app.config.isCustomElement = tag => tag === 'plastic-button'

自定义内置元素的方法是向内置元素添加is属性
v-is要使用注册名称来渲染组件,其值应为 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
调用createApp返回一个应用实例

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 对象上,回调的this上下文自动绑定到当前实例
webpack支持tree-shaking,但Vue 2.x 的全局 API 比如 nextTick 无法被 TreeShake,所以就算没有用到这些 API,它们还是会被打包到你的生产版本的代码包里

vue3.x
全局和内部API进行了重构,支持使用tree-shaking
需要注意的是:
当使用全局 API 时,需要主动将其导入到目标文件中

import { nextTick } from 'vue';
 
nextTick(() => {
  // 和 DOM 有关的一些操作
});

如果直接调用Vue.nextTick(),会导致报错: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

  • 不再支持使用数字 (即键码) 作为v-on 修饰符,建议使用kebab-cased大小写名称
  • 不再支持 config.keyCodes
<input v-on:keyup.delete="confirmDelete" />

在 prop 的默认函数中访问this

vue3.x
生成 prop 默认值的工厂函数不再能访问 this

渲染函数API

vue2.x

  • render函数参数
    render函数自动接收h函数作为参数
// vue2.x
export default
  render(h){
    return h('div')
  }
}
  • render函数签名更改
    render函数自动接收诸如 h 之类的参数
// vue2.x
export default{
  render(h){
    return h('div')
  }
}

vue3.x

  • render函数参数
    h是全局引入的,而不是作为参数自动传递
// vue 3.x
import {h} from 'vue'
export default{
  render(){
    return h('div')
  }
}
  • render函数签名更改
    render函数不再接收任何参数,将主要用于setup()内部,可以访问作用域中声明的响应式状态和函数以及传递给setup()的参数
import { h, reactive } from 'vue'

export default {
  setup(props, { slots, attrs, emit }) {
    const state = reactive({
      count: 0
    })

    function increment() {
      state.count++
    }

    // 返回render函数
    return () =>
      h(
        'div',
        {
          onClick: increment
        },
        state.count
      )
  }
}

slot统一

vue2.x
在内容节点上定义slot data property

h(LayoutComponent,[
  h('div',{slot:'header'},this.header),
  h('div',{slot:'content'},this.content)
])

// 引用时
this.$scopedSlots.header

vue3.x

  • 插槽被定义为当前节点的子对象
h(LayoutComponent,{},{
  header:()=>h('div',this.header),
  content:()=>h('div',this.content)
})
  • 当需要以编程方式引用作用域slot时,被统一到$slot选项中
this.$slots.header

过渡类名更改

vue3.x
过渡类名 v-enter修改为 v-enter-from、过渡类名v-leave修改为v-leave-from

<transition>组件相关属性名也发生了变化:
leave-class已经被重命名为leave-from-class(在渲染函数或 JSX 中可以写为:leaveFromClass)
enter-class已经被重命名为enter-from-class (在渲染函数或 JSX 中可以写为:enterFromClass)

v-model

vue2.x

  • 使用v-model指令必须使用valueprop;
<ChildComponent v-model="pageTitle" />
  • 如果出于不同的目的使用其他的prop,需要使用v-bind.sync
<ChildComponent :title.sync="pageTitle" />

vue3.x

  • 如果要改变绑定的属性名,而不是更改组件内绑定的选项,只需要给 v-model 传递一个参数就可以了;
<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的优先级比较

vue2.x
在同一个元素上同时使用v-ifv-for,v-for会优先使用;

vue3.x
v-if总是优先于v-for生效

v-bind合并行为

vue2.x
如果一个元素同时定义了v-bind="object"和一个相同的单独的property,那么这个单独的 property总是会覆盖object中的绑定

<div id="red" v-bind="{ id: 'blue' }"></div>
// 结果
<div id="red"></div>

vue3.x
如果一个元素同时定义了v-bind="object"和一个相同的单独的property,那么声明绑定的顺序决定了它们如何合并

<div id="red" v-bind="{ id: 'blue' }"></div>
// 结果
<div id="blue"></div>
<div v-bind="{ id: 'blue' }" id="red"></div>
// 结果
<div id="red"></div>

函数式组件

vue2.x

  • 作为性能优化
  • 返回多个根节点
export default {
  functional: true,
  props: ['level'],
  render(h, { props, data, children }) {
    return h(`h${props.level}`, data, children)
  }
}

vue3.x

  • 通过函数创建组件
    所有的函数式组件都是用普通函数创建的,不需要定义{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现在作为$attrs的一部分传递,可以删除

下表为vue3.x已移除的api:

已移除的api vue2.x vue3.x
$children 可以使用this.$children直接访问当前实例的子组件 $children已移除,如需访问子组件,建议使用$refs
事件API vue实例可用于触发通过事件触发API强制附加发处理程序已创建全局事件监听器 移除了$on,$off,$once方法,但仍可用$emit触发由父组件以声明方式附加的事件处理程序
过滤器 可以使用过滤器来处理通用文本格式 过滤器已删除,可以用方法调用或计算属性替换过滤器
内联模块Attribute Vue 为子组件提供了inline-template attribute,以便将其内部内容用作模板,而不是将其作为分发内容 不再支持此功能,所有模板写在HTML页面中
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,755评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,369评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,799评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,910评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,096评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,159评论 3 411
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,917评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,360评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,673评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,814评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,509评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,156评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,123评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,641评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,728评论 2 351

推荐阅读更多精彩内容