
异步组件
在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。
2.0中 我们这么用⬇️
const asyncPage = () => import('./NextPage.vue') //return a promise
const asyncPage = {
component: () => import('./NextPage.vue'),
delay: 200,
timeout: 3000,
error: ErrorComponent,
loading: LoadingComponent
}
3.0用法(由于组件被定义为纯函数,我们需要引入defineAsyncComponent实现异步)
import { defineAsyncComponent } from 'vue'
import ErrorComponent from './components/ErrorComponent.vue'
import LoadingComponent from './components/LoadingComponent.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
})
自定义指令
2.0中 我们这么用⬇️
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
钩子函数:

3.0用法(添加了更加丰富的生命周期钩子函数)
const MyDirective = {
beforeMount(el, binding, vnode, prevVnode) {},
mounted() {},
beforeUpdate() {},
updated() {},
beforeUnmount() {}, // new
unmounted() {}
}
const app = Vue.createApp({})
app.directive('highlight', {
beforeMount(el, binding, vnode) {
el.style.background = binding.value
}
})
自定义元素互操作更改(破坏性改变)
2.0中 我们这么用⬇️
1. ignoredElements
Vue.config.ignoredElements = [
'my-custom-web-component',
'another-web-component',
// 用一个 `RegExp` 忽略所有“ion-”开头的元素
// 仅在 2.5+ 支持
/^ion-/
]
使 Vue 忽略在 Vue 之外的自定义元素 (e.g. 使用了 Web Components APIs)。否则,它会假设你忘记注册全局组件或者拼错了组件名称,从而抛出一个关于 Unknown custom element 的警告。
举例:
假如我使用了未定义的<icon></icon>
组件


3.0用法
// in webpack config
rules: [
{
test: /\.vue$/,
use: 'vue-loader',
options: {
compilerOptions: {
isCustomElement: tag => tag === 'plastic-button'
}
}
}
// ...
]
改变原因:自定义ignoredElements现在在模板编译期间执行,应通过编译器选项(而不是运行时配置)进行配置。
2.is属性的使用
2.0中 我们这么用⬇️
<button is="plastic">Click Me!</button>
它被解释为使用name渲染Vue组件plastic,等同于:
<plastic> Click Me!</plastic>
或者
<component v-bind:is="currentTabComponent" class="tab"></component>
这里的用法是动态组件渲染 不了解is具体使用的看这里:用于动态组件且基于 DOM 内模板的限制来工作。
在3.0中,仅将Vue对 is prop 的特殊处理限制在标签上。
<component v-bind:is="currentTabComponent"></component>
也即是说在上面button标签例子中的is在vue3.0只会呈现一个普通prop的效果
3.is进行In-DOM模板解析的变通办法
这个不太常见,只在HTML中使用vue会出现这个问题,.vue文件没有这个情况
2.0中 我们这么用⬇️
<ul>
<li></li>
<li></li>
<li></li>
</ul>
总所周知,ul里面嵌套li的写法是html语法的固定写法(还有如table,select等)
<ul>
<my-component></my-component>
<my-component></my-component>
</ul>
my-component是我们自己写的组件,但是html在渲染dom的时候,my-component对ul来说并不是有效的dom,甚至会报错。
解决方法:
<ul>
<li is='my-component'></li>
</ul>
在3.0中
<ul>
<li v-is='"my-component"'></li>
</ul>
用v-is取代了is,在写法上和上面一种is的功能也区分开了
data定义(破坏性改变)
2.0中 我们这么用⬇️
<!-- Object Declaration -->
<script>
const app = new Vue({
data: {
apiKey: 'a1b2c3'
}
})
</script>
<!-- Function Declaration -->
<script>
const app = new Vue({
data() {
return {
apiKey: 'a1b2c3'
}
}
})
</script>
Data支持两种格式(Function/Object)的定义
vue3.0中只支持Function这一种定义方法
Fragment
2.0中 我们这么用⬇️
<!-- Layout.vue -->
<template>
<div>
<header>...</header>
<main>...</main>
<footer>...</footer>
</div>
</template>
如果不加这个<div>
就会报下面这个错:
Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead
3.0中支持不止一个根标签:
<!-- Layout.vue -->
<template>
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
</template>
渲染API
2.0中 我们这么用⬇️
export default {
render(h) {
return h('div')
}
}
3.0中h 函数现在已全局导入,而不是传递给渲染函数作为参数
import { h } from 'vue'
export default {
render() {
return h('div')
}
}
v-model
2.0中 我们这么用⬇️
<ChildComponent v-model="pageTitle" />
<!-- 上下等效 -->
<ChildComponent :value="pageTitle" @input="pageTitle = $event" />
3.0中变化为这样:
<ChildComponent v-model="pageTitle" />
<!-- 上下等效 -->
<MyBook :modelValue="pageTitle" @update:modelValue="pageTitle = $event" />
1.一个组件支持多个v-model

<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" />
<ChildComponent
:title="pageTitle"
@update:title="pageTitle = $event"
:content="pageContent"
@update:content="pageContent = $event"
/>
2.v-model自定义修饰符
类似于2.0的.tirm修饰符
例子:
<div id="app">
<my-component v-model.capitalize="myText"></my-component>
{{ myText }}
</div>
const app = Vue.createApp({
data() {
return {
myText: ''
}
}
})
app.component('my-component', {
props: {
modelValue: String,
modelModifiers: {
default: () => ({})
}
},
methods: {
emitValue(e) {
let value = e.target.value
if (this.modelModifiers.capitalize) {
value = value.charAt(0).toUpperCase() + value.slice(1)
}
this.$emit('update:modelValue', value)
}
},
template: `<input
type="text"
v-bind:value="modelValue"
v-on:input="emitValue">`
})
app.mount('#app')
Vue实例
2.0中 我们这么用⬇️
Vue.component('button-counter', {
data: () => ({
count: 0
}),
template: '<button @click="count++">Clicked {{ count }} times.</button>'
})
Similarly, this is how a global directive is declared:
Vue.directive('focus', {
inserted: el => el.focus()
})
从技术上讲,Vue 2没有app的概念。我们定义为app的只是通过创建的根Vue实例new Vue()从同一个Vue构造函数创建的每个根实例都共享相同的全局配置。用起来很方便,但结果是不可避免的造成了全局污染,并且全局配置使测试过程中意外污染其他测试案例变得容易。
vue3.0:
调用createApp返回一个新的vue实例,这是Vue 3中的一个新概念,每个实例拥有了自己的配置项。
import { createApp } from 'vue'
const app = createApp()

import { createApp } from 'vue'
import MyApp from './MyApp.vue'
const app = createApp(MyApp)
app.mount('#app')
const app = createApp(MyApp)
app.component('button-counter', {
data: () => ({
count: 0
}),
template: '<button @click="count++">Clicked {{ count }} times.</button>'
})
app.directive('focus', {
mounted: el => el.focus()
})
app.mount('#app')
2.在app之间共享配置
import { createApp } from 'vue'
import Foo from './Foo.vue'
import Bar from './Bar.vue'
const createMyApp = (VueInstance) => {
const app = createApp(VueInstance)
app.directive('focus' /* ... */)
return app
}
createMyApp(Foo).mount('#foo')
createMyApp(Bar).mount('#bar')
现在,该focus指令将在Foo和Bar实例及其后代中可用。
相关参考文档:v3.vuejs.org/