在通读了vue的官网文档后,我记录下了如下这些绝对于2.x的变动之处。
1.创立利用实例的变动
之前个别是这样:
let app = new Vue({
// ...一些选项
template: '',// 字符串模板
render: h => h(App)// 单文件状况下
})
let vm = app.$mount('#app')
app === vm// true
而当初变成这样:
import { createApp } from 'vue'
import App from './App.vue'
let app = createApp({
// ...组件选项
})
let app = createApp(App)// 单文件状况下
let vm = app.mount('#app')
app === vm // false
改成这样的最次要起因是为了防止对Vue
的全局配置会影响每个创立的实例。
2.data
选项变动
之前在非组件的状况下创立实例能够应用对象,然而当初所有状况下都只能应用一个返回对象的函数。
3.生命周期变动
beforeDestroy
=>beforeUnmount
,destroyed
=>unmounted
,另外新增了两个生命周期renderTracked
和renderTriggered
,用来跟踪虚构DOM从新渲染。
4.事件监听反对多个处理函数
在3.0中v-on
指令能够绑定多个处理函数:
<button @click="one(),two(),three($event)"></button>
export default {
methods: {
one(){},
two(){},
three(){}
}
}
绑定多个函数时必须应用内联函数调用形式,即不能只写一个函数名。
5.实例多了一个数据选项:emits
显式申明该组件能触发的自定义事件,就像props
属性一样,能够是简略的字符串数组,也能够是对象,同样的,对象类型的话能够用来定义校验,应用办法如下:
export default {
emits: ['change', 'select'],// 数组类型
emits: {// 对象类型
change: null,// 没有验证函数
select: (arg) => {// 接管this.$emit('select', ..args)的args参数
return true// 返回true或false代表事件参数是否无效,校验失败事件还是能失常触发,然而控制台会弹出一行正告信息
}
},
methods: {
emit() {
this.$emit('change')
this.$emit('select', 1, 2, 3)
}
}
}
该申明是可选的。
6.新增了v-is
指令
这个指令用来承当2.x版本里的非凡attributeis
的局部性能。
在2.x里is
可用在两个场景下,一是用于动静组件component
来切换要渲染的组件,二是用于在应用DOM模板时的一些HTML元素的限度,比方ul
元素里只能呈现li
元素,这样当ul
里应用自定义组件时浏览器会认为是有效内容,此时能够应用is
属性:
<ul>
<!--<my-component></my-component> x这样不行-->
<li is="my-component"></li>
</ul>
而在3.0版本is
只能用在component
上,上述性能须要应用v-is
来代替:
<ul>
<li v-is="'my-component'"></li>
</ul>
留神上述的单引号是必须的。
7.未声明的emits
因为新增了相似props
的选项emits
,如果某些传递给组件的属性并没有在props
申明,那么能够通过$attrs
属性来拜访,事件监听器也一样:
<!--父组件-->
<sub-component @change="change" @select="select"></sub-component>
// 子组件
export default {
emits: ['change'],
created(){
console.log(this.$attrs)// { onSelect: () => {} }
},
}
另外,在2.x中这些未声明的props
或emits
会间接继承到该组件的根节点上,比方:
<!--父组件-->
<sub-component class="warn"></sub-component>
<!--子组件-->
<div class="info"></div>
<!--理论渲染后果-->
<div class="info warn"></div>
但在3.x中组件反对多个根节点,当呈现多个根节点时,属性将不会被动继承,须要手动给须要继承属性的组件进行绑定,如果一个都没绑定的话vue会给出正告:
<template>
<my-momponent class="bar" @change="change"></my-component>
</template>
<template>
<div v-bind="$attrs"></div>
<div></div>
</template>
8.v-model
的变动
在2.x中给一个组件自定义v-model
个别是这样的:
export default {
model: {// v-model默认是利用名为value的prop及input事件,可应用model选项来批改
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
},
methods: {
emit() {
this.$emit('change', true)
}
}
}
/*
<my-component v-model="checked"></my-component>
*/
在3.x中v-model
指令多了一个参数,比方:v-model:value="value"
,所以就不须要应用model
选项了,vue
会间接利用value
属性及事件名update:value
:
export default {
props: {
checked: Boolean
},
methods: {
emit() {
this.$emit('update:checked', true)
}
}
}
/*
<my-component v-model:checked="checked"></my-component>
*/
当然你也能够省略value
,这样会默认绑定到名为modelValue
的prop
上:
export default {
props: {
modelValue: Boolean
},
methods: {
emit() {
this.$emit('update:modelValue', true)
}
}
}
/*
<my-component v-model="checked"></my-component>
*/
这样的一个益处是能够绑定多个v-model
:
export default {
props: {
modelValue: Number,
checked: Boolean,
value: String
},
methods: {
emit() {
this.$emit('update:modelValue', 1)
this.$emit('update:checked', true)
this.$emit('update:value', 'abc')
}
}
}
/*
<my-component v-model="count" v-model:checked="checked" v-model:value="value"></my-component>
*/
最初一点是3.x反对自定义v-model
的修饰符,大抵就是修饰符也能通过props
获取到,而后能够依据修饰符存在与否进行一些对应的数据格式化操作:
/*
<my-component v-model.double="count" v-model:count2.double="count2"></my-component>
*/
export default {
props: {
modelValue: Number,
count2: Number,
modelModifiers: Object,// 没有参数的v-model的修饰符数据,名称为modelModifiers,对象格局:{double: true},如果修饰符不存在为undefined
count2Modifiers: Object// 带参数的v-model的修饰符数据名称为:参数+"Modifiers",对象格局:{double: true},如果修饰符不存在为undefined
},
methods: {
emit() {
// 在这里能够依据modelModifiers和count2Modifiers的值来判断是否要进行一些数据操作
this.$emit('update:modelValue', xxx)
this.$emit('update:value', xxx)
}
}
}
9.响应式provide/reject
provide/reject
默认是没有响应性的,父组件的provide
值变动了,子组件应用reject
接管的值不会相应更新,在2.0中,想要使它变成可响应比拟麻烦,上面这种形式是不行的,父组件的count
变动了子组件的count
并不会变动:
<template>
<div>{{count}}</div>
</template>
<script>
export default {
inject: ['count']
}
</script>
export default {
provide() {
return {
count: this.count
}
},
data: {
count: 0
}
}
vue
2.x文档里有个提醒:
提醒:
provide
和inject
绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。
后半句我的了解是如果provide
返回的对象的属性值是一个可响应对象的话,那么是能够的,比方:
export default {
provide() {
return {
count: this.countObj
}
},
data: {
countObj: {
value: 0
}
}
}
这样的话批改countObj.value
的值,子组件会相应的更新,然而如果想像下面那样依赖count
的值,即便你应用computed
也是不行的:
export default {
provide() {
return {
count: this.countObj
}
},
data: {
count: 0
},
computed: {
countObj() {
return {
value: this.count
};
}
}
}
那么就只能应用watch
和Vue.observable
办法来配合实现:
let countState = Vue.observable({ value: 0 });
export default {
provide() {
return {
count: countState
};
},
data: {
count: 0
},
watch: {
count(newVal) {
countState.value = newVal
}
}
}
然而在3.x中就比较简单了,能够间接应用组合式api里的computed
办法:
import {computed} from 'vue'
export default {
provide() {
return {
count: computed(() => {
return this.count
})
};
},
data: {
count: 0
}
}
前面这些在子组件里应用的时候都须要拜访count.value
属性。
10.异步组件
在2.x中,异步组件个别应用如下办法定义:
// 全局
Vue.component('async-component', () => import('./my-async-component'))
// 部分
{
components: {
'async-component': () => import('./my-async-component')
}
}
在3.x中新增了一个函数defineAsyncComponent
来做这件事件:
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
import('./components/AsyncComponent.vue')
)
// 全局
app.component('async-component', AsyncComp)
// 组件内
{
components: {
'AsyncComponent': AsyncComp
}
}
11.过渡class的变动
3.x和2.x一样,依然有6个class,意义齐全一样,惟一的变动只有v-enter
->v-enter-from
、v-leave
->v-leave-from
两个名字以及enter-class
->enter-from-class
、leave-class
->leave-from-class
两个自定义类名的变动。
12.自定义指令变动
在2.x中提供了bind
、inserted
、update
、componentUpdated
、unbind
五个指令,在3.x中新增了一个,一共有六个:
beforeMount
(指令第一次绑定到元素并且还未挂载到父组件上调用,对应于bind
,用来进行一些初始化操作)
mounted
(绑定元素的父组件被挂载时调用,对应inserted
,然而inserted
的形容里说仅保障父组件存在但不肯定被插入到文档中,mounted
的形容里没有这句话)
beforeUpdate
(在蕴含该组件的虚构节点被更新前调用,对应update
)
updated
(在蕴含该组件的虚构节点及其所有子组件的虚构节点都更新后调用,对应componentUpdated
)
beforeUnmount
(在卸载绑定元素的父组件前调用,为新增钩子)
unmounted
(指令与元素解除绑定且父组件曾经卸载时调用,对应unbind
)
总的来说改名后的自定义钩子和vue自身的生命周期钩子趋于统一。
13.新增Teleport
在2.x中有一个常见的痛点:
<div>
<Dialog></Dialog>
<Loading></Loading>
</div>
在上述组件里蕴含了两个子组件,像这种弹窗或loading组件个别都是心愿它们的DOM节点间接挂在body元素下,这样在款式尤其是层级上比拟好管制,然而理论渲染进去是在这个div节点下的,那么就只能把这两个组件移到body下,然而逻辑上这两个组件又是属于该组件,所以就比拟不爽。
在3.x中新增了teleport
组件能够用来解决这个问题:
<div>
<teleport to="body">
<Dialog></Dialog>
</teleport>
<teleport to="#xxx">
<Loading></Loading>
</teleport>
</div>
间接将须要提到外层的组件放到teleport
标签里,通过to
属性来指定要挂载到的元素,to
能够是无效的元素查问选择器,比方id选择器,类选择器等。
14.渲染函数的变动
在2.x中应用render
函数须要应用注入的办法来创立虚构节点,示例如下:
Vue.component('my-component', {
render(createElement) {
return createElement('div', '我是文本')
}
})
在3.x中应用vue对象的静态方法来实现:
Vue.component('my-component', {
render() {
return Vue.h('div', '我是文本')
}
})
h
函数接管的参数和createElement
根本都是tag
、props
、children
,然而props
构造产生了很大变动,比方事件绑定:
Vue.component('my-component', {
render(createElement) {
return createElement('div', {
on: {
'click': this.clickCallback
}
})
}
})
Vue.component('my-component', {
render() {
return Vue.h('div', {
onClick: this.clickCallback
})
}
})
在2.x中不反对v-model
,3.x
中曾经反对了,其余变动之处也很大,须要读者本人去具体理解,这一节的官网文档应该还须要欠缺,props
的具体形容并未看到,然而大抵的扭转就是更加扁平化,比方2.x的构造:
{
class: ['xxx', 'xxx'],
style: { color: '#fff' },
attrs: { id: 'xxx' },
domProps: { innerHTML: 'xxx' },
on: { click: onClick },
key: 'xxx'
}
在3.x中变成这样:
{
class: ['xxx', 'xxx'],
style: { color: '#fff' },
id: 'xxx',
innerHTML: 'xxx',
onClick: onClick,
key: 'xxx'
}
15.插件开发的变动
在2.x中注册插件时调用插件的install
办法时会注入Vue
对象和参数对象,在3.x中因为将Vue
上的全局属性和办法都移到了由createApp
办法创立的实例app
上,所以注册插件须要在createApp
办法执行之后,另外注入性能时也会有一些轻微的变动。
16.去掉了过滤器选项
在3.x中能够应用办法来实现该性能。
17.响应性原理变动
家喻户晓,在2.x中是应用Object.defineProperty
来实现数据响应的,在3.x默认应用ES6
的Proxy
来实现,并且在IE
浏览器上应用Object.defineProperty
进行降级。
另外在3.x中减少了很多能够用来给数据减少响应行性能的办法,比方:
// 非原始值
import {reactive} from 'vue'
// 响应式状态
const state = reactive({
count: 1
})
// 原始值
import {ref} from 'vue'
// 响应式状态
const count = ref(0)
console.log(count.value)
此外还新增了computed
、watch
等等能够间接应用的办法,这些办法个别在应用组合式api的状况下应用。
18.新增响应式和组合式api
这个曾经有十分多的文章具体的介绍它了,能够在掘金上搜寻或间接去官网上看,此处不赘述。
19.ref的变动
在2.x中ref
是用来拜访组件实例或者是DOM元素的属性:
<div ref="div">
<ul>
<li v-for="item in list" ref="liList"></li>
</ul>
<MyComponent ref="component"></MyComponent>
</div>
export default {
mounted() {
console.log(this.$refs.div, this.$refs.component)
console.log(this.$refs.liList)// liList会主动是一个数组
}
}
其中当在循环里应用ref
是不明确的,尤其是存在嵌套循环,所以在3.x中ref
反对绑定到一个函数:
<div ref="div">
<ul>
<li v-for="item in list" :ref="setLiList"></li>
</ul>
<MyComponent ref="component"></MyComponent>
</div>
export default {
data() {
return {
liList: []
}
}
mounted() {
console.log(this.$refs.div, this.$refs.component)
console.log(this.liList)
},
methods: {
setLiList(el) {
this.liList.push(el)
}
}
}
20.Vue-Router变动
vue-router
降级到了新版本,装置命令为:npm install vue-router@4
。
接下来应用一个简略的例子看一下2.x和3.x的区别:
// 2.x
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
// ...
]
const router = new VueRouter({
// ...一些选项配置
routes
})
const app = new Vue({
router
}).$mount('#app')
// 3.x
import Vue from 'vue'
import VueRouter from 'vue-router@4'
const routes = [
// ...
]
const router = VueRouter.createRouter({
// ...一些选项配置
routes
})
const app = Vue.createApp({})
app.use(router)
app.mount('#app')
除了创立路由的形式有变动外,其余也有很多细节变动,以及如何在组合式api中应用,笔者没看完,请自行浏览vue-router
文档。
21.Vuex变动
除路由外,官网的状态治理库vuex
也配套降级了新版本,装置:npm install vuex@next --save
。
同样以一个非常简略的例子看一下初始化的变动:
// 2.x
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {},
actions: {},
// ...
})
new Vue({
store
})
// 3.x
import {createApp} from 'vue'
import {createStore} from 'vuex'
const store = createStore({
state() {
return {
count:0
}
},
mutations: {},
actions: {},
// ...
})
const app = createApp({})
app.use(store)
vuex
的api根本没有大的变动,更多的能够去理解一下如何在组合式api中应用。
22.其余变动一览
$attrs
里也蕴含class
和style
- 移除了
$children
,如需拜访子组件请应用ref
-
移除了
Vue
实例的$on
、$emit
、$once
办法,之前常见的应用形式当初须要本人实现或者应用其余事件库:import Vue from 'vue' Vue.prototype.$bus = new Vue()
这一常见操作齐全被干掉了,因为当初要减少全局性能的话须要通过利用实例的
globalProperties
属性:app.config.globalProperties.$bus = new OtherEvent()
-
反对多个根节点:
<template> <div></div> <Header></Header> </template>
- 一些2.x的全局api都改成应用导出的形式进行应用,比方:
import {nextTick} from 'vue'
,这样能够利于构建工具去掉无用代码 -
应用
template
组件进行循环操作时,key
属性能够须要间接设置在template
标签上:<template> <template v-for="item in list" :key="item.id"></template> </template>
以上大部分内容在vue
的官网降级指南中也提到了,有趣味的也能够间接去看官网文档:https://v3.vuejs.org/guide/migration/introduction.html,以及中文版:https://v3.cn.vuejs.org/guide/migration/introduction.html,如果有任何谬误的话欢送指出。
发表回复