1.生命周期的变化:3.x(上) 2.x(下)
不难看出,vue3.0与vue2.0之间生命周期函数在销毁的时候有变化:
beforeDestroy --> beforeUnmount
destroyed --> unmounted
其他的区别主要在于书写使用的语言上的差别
在ts中使用 class 类组件书写可以 参考 vue-class-component 或者 vue-property-decorator
书写的风格和vue2.0的选项式区别不大。
如果使用js书写代码 则应当使用组合式。
具体变化带来的问题,会在下面的组合式写法中讲解。
2.定义全局变量的方法变化
// 之前(Vue 2.x)
Vue.prototype.$http = () => {}
Vue.prototype.url= 'http://123'
// 之后(Vue 3.x)
const app = createApp({})
app.config.globalProperties.$http = () => {}
app.config.globalProperties.url= 'http://123'
3.创建vue实例变化
//=======vue3.x
//使用createApp函数来实例化vue,
//该函数接收一个根组件选项对象作为第一个参数
//使用第二个参数,我们可以将根 prop 传递给应用程序
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
createApp(App,{ userName: "blackLieo" })
.use(store)
.use(router)
.mount('#app')
//由于 createApp 方法返回应用实例本身,因此可以在其后链式调用其它方法,这些方法可以在以下部分中找到。
//=======vue2.x
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
4.插槽使用变化
//================vue2.0使用插槽基本上直接使用slot进行操作
//其中vue2.0经历了两次更迭,2.6.0版本slot升级为v-slot
<div>
<slot :current="toolTipData" name="test"></slot> // 具名 作用域插槽
<slot></slot> //默认插槽
</div>
//父组件调用该组件
<test>
<template>
<div>默认插槽</div>
</template>
// 作用域插槽
<template slot-scope="{ current }" slot="test">
<el-form label-width="80px" :model="current">
<el-form-item label="id:">
<el-link type="info">{
{ current.id }}</el-link>
</el-form-item>
<el-form-item label="name:">
<el-link type="info">{
{ current.name }}</el-link>
</el-form-item>
<el-form-item label="label:">
<el-link type="info">{
{ current.label }}</el-link>
</el-form-item>
<el-form-item label="group:">
<el-link type="info">{
{ current.group }}</el-link>
</el-form-item>
<el-form-item label="runtime:">
<el-link type="info">{
{ current.runtime }}</el-link>
</el-form-item>
<el-form-item label="category:">
<el-link type="info">{
{ current.category }}</el-link>
</el-form-item>
</el-form>
</template>
</test>
//==============vue3.0使用插槽
//在vue3.0中,插槽使用v-slot 简写用#
<div>
<slot name="test" :newData="slotsData"></slot>
<slot></slot>
</div>
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App">
<template #default> // 可以写为v-slot:default #后面跟的是插槽名称
<div>默认插槽</div>
</template>
//作用域插槽
<template #test="{ newData }"> // 可以写为v-slot:test="newData"
<p>{
{ newData.aa }}</p>
<p>{
{ newData.bb }}</p>
</template>
</HelloWorld>
//一个组件里面具有多个插槽时,一定要带上名称,否则可能会导致作用域错乱
5.自定义指令
在 Vue 2 中实现一个自定义指令:
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
在 Vue 2 中, 自定义指令通过以下几个可选钩子创建:
- bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
- inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)。
- update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
- componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
- unbind:只调用一次,指令与元素解绑时调用。
在 Vue 3 中对自定义指令的 API 进行了更加语义化的修改, 就如组件生命周期变更一样, 都是为了更好的语义化, 变更如下:
所以在 Vue3 中, 可以这样来自定义指令:
const { createApp } from "vue"
const app = createApp({})
app.directive('focus', {
mounted(el) {
el.focus()
}
})
然后可以在模板中任何元素上使用新的 v-focus指令, 如下:
<input v-focus />
6.v-model 升级
Vue 3 中 v-model 发生了很大的变化:
变更:在自定义组件上使用v-model时, 属性以及事件的默认名称变了
变更:v-bind的.sync修饰符在 Vue 3 中又被去掉了, 合并到了v-model里
新增:同一组件可以同时设置多个 v-model
新增:开发者可以自定义 v-model修饰符
我们来详细了解一下,并对比一下vue2与vue3 在组件上使用 v-model,
例如:
vue2 的输入框的双向绑定,其实就相当于传递了value属性, 并触发了input事件:
<!-- Vue 2 -->
<input v-model="searchValue"><input>
<!-- 相当于 -->
<input :value="searchValue" @input="searchValue=$event"><input>
这时v-model只能绑定在组件的value属性上,那如果我们要给自己的组件用一个别的属性,并且我们不想通过触发input来更新值。
但是在实际开发中,有些场景我们可能需要对一个 prop 进行 “双向绑定”, 这里以最常见的 dialog 为例子:dialog 挺合适属性双向绑定的,
外部可以控制组件的visible显示或者隐藏,组件内部关闭可以控制 visible属性隐藏,同时 visible 属性同步传输到外部。组件内部,
当我们关闭dialog时, 在子组件中以 update:PropName 模式触发事件。
事件为
this.$emit('update:visible', false)
然后在父组件中可以监听这个事件进行数据更新:
<el-dialog :visible="isVisible" @update:visible="isVisible = $event"></el-dialog>
在vu