DEV Community


Posted on • Updated on

Vue 3 Migrations

Vue 3 migration introduction

New Features

Composition API = hooks
Teleport = Portal
Fragments = Fragments
emits Component Option = 定義 emit 的事件
v-model modifiers = 可以在 v-model 用 mod
createRenderer = can create custom renderers




Breaking Changes

# Global Vue -> app instance

// 2.x
import Vue from 'vue';

import { createApp } from 'vue';
const app = createApp({});
2.x Global API 3.x Instance 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

# Global Vue methods -> named export

// 2.x
import Vue from 'vue'

// 3.x
import { nextTick } from 'vue'
Vue.observable replaced by reactive
Vue.compile only in full builds
Vue.set only in compat builds
Vue.delete only in compat builds

# Render function h -> named export

import { h } from 'vue'

export default {
  render() {
    return h('div')

# v-model & .sync

myProp.sync 語法移除,改為 v-model:myProp
v-model 語法糖改為等同於 v-model:modelValue

shorthand prop event
2.x v-model value input
:myProp.sync myProp update:myProp
3.x v-model modelValue update:modelValue
v-model:myProp myProp update:myProp

# Functional component

<template functional>{ functional: true } 被移除
functional component 對效能幾乎沒有影響,可以不用刻意標示

真的要做 functional component 的話只能以匯出 function 的方式

import { h } from 'vue'

const DynamicHeading = (props, context) => {
  return h(`h${props.level}`, context.attrs, context.slots)

DynamicHeading.props = ['level']
export default DynamicHeading


# Async components

  • 非同步組件必須用 defineAsyncComponent 包起來
  • component 屬性改名為 loader
  • loader 函式必須回傳 Promise
// 3.x
import { defineAsyncComponent } from 'vue'

// Async component without options
const asyncPage = defineAsyncComponent(() => import('./NextPage.vue'))

// Async component with options
const asyncPageWithOptions = defineAsyncComponent({
  loader: () => import('./NextPage.vue'),
  delay: 200,
  timeout: 3000,
  errorComponent: ErrorComponent,
  loadingComponent: LoadingComponent
// 3.x
const asyncComponent = defineAsyncComponent(
  () => new Promise(...)

# data 現在一律必須是 function


# Watch

不再支援 path 作為 watcher (例如 '$store.state.count'())
必須透過 computed

Breaking Changes (比較不常用的東西)

# Custom elements

Vue.ignoredElements 要改為 vue-loader 的 options, 或者 app.config.isCustomElement

# is & v-is

is 現在只能用在 <component>
在 custom component (Web Component API) 上要換成 v-is

# $scopedSlots

this.$scopedSlots 都要改成 this.$slots

# Attributes coercion strategy

簡單來說如果 v-bind 一個 attribute 到一個 element 上
2.x 如果值是 null undefined false 那屬性會從元素被移除,但對於某些特殊屬性如 draggable 又不太一致
3.x 統一為 null undefined 會被移除,其他都會照原本值 render 出來

# v-directive

當定義 directive 的時候 (例如寫一個 v-tooltip 時),lifecycle hooks 的命名改了,改成跟一般 component 的 lifecycle 一樣

2.x 3.x
bind beforeMount
inserted mounted
- beforeUpdate
update -
componentUpdated updated
- beforeUnmount
unbind unmounted

# Transition classes

v-enter -> v-enter-from
v-leave -> v-leave-from

# outerHTML -> innerHTML

2.x 會把指定的 root element 透過 outerHTML 整個換掉
3.x 會用 innerHTML 塞裡面

# keyCode

直接以數字 keyCode 作 modifier 被移除
但還是可以用鍵名例如 @keyup.delete

// removed
<input v-on:keyup.112="showHelpText" />

# \$on, \$off, \$once

移除.vue instance 不再實作 event emitter

// removed
this.$on('some-event', ...)

# Filters


// removed
<p>{{ accountBalance | currencyUSD }}</p>

超讚,討厭 filter

# Inline template


// removed
<my-component inline-template>
    <p>These are compiled as the component's own template.</p>
    <p>Not parent's transclusion content.</p>


Top comments (1)

yellow1912 profile image

Dang. That's lots of changes. I will wait till everything is stable and English document is fully available.