vue3.0的变化与2.0的区别【一】
生命周期的变化
vue3.x的生命周期

vue2.x

对比之下可以看出来vue3.0和vue2.0之间生命周期函数在销毁的时候有区别
beforeUnmount -->beforeDestroy
unmounted-->destroyed
定义全局变量的方法变化
vue2.x
Vue.prototype.$axios = () => {}
vue3.x
const app = createApp({})
app.config.globalProperties.$axios = () => {}
创建vue实例化
vue2.x
import Vue from 'vue' import App from './App.vue' import router from './router' Vue({ router, render: h => h(App) }).$mount('#app')
vue3.x
//该函数接收一个根组件选项对象作为第一个参数
//使用第二个参数,我们可以将根 prop 传递给应用程序
import { createApp } from 'vue' import App from './App.vue' import router from './router'
var app = createApp(App)
app.use(router)
app.mount('#app') //由于 createApp 方法返回应用实例本身,因此可以在其后链式调用其它方法。
插槽使用变化
vue2.x
vue 在 2.6.0 中,具名插槽和作用域插槽引入了一个新的统一的语法 :v-slot 指令。 它取代了 slot 和 slot-scope 这两个目前已被废弃但未被移除且仍有用的特性。 但是将会在vue 3 中,这两个指令将会被废弃
子组件
<template>
<div class="my-card">
<!-- 把数据传给父组件,接收作用域插槽 !-->
<!--
父组件复用子组件的时候 对某一个子组件内容样式不满意 此时在 子组件内你希望改变的那部分内容外 包裹一个slot标签 给slot自定义一个属性(名称自己起)父组件模板定义一个slot-scope="slot"属性 模板内通过slot.xxx可以拿到子组件的数据 拿到数据后就好办了 可以任你蹂躏了 你想把它弄成什么样就弄成什么样!-->
<!--父组件改变了子组件的样式 但是内容还是子组件的!-->
<slot name="scope_slot" :user=user :text=text></slot> <!-- 接收具名插槽 !-->
<!--在子组件template属性中添加多个slot标签 而这个slot标签都各自带有自己的name属性 属性值都不一样!-->
<!--父组件可以对应不同的name值 把相对应的内容 插入到各自slot标签里!-->
<!--slot标签内可以包裹任意原子组件的内容 插入的内容将会替换掉它!-->
<slot name="named_slot"></slot>
<!-- 接收默认匿名插槽 !-->
<!--在子组件template属性中添加一个slot标签 而这个slot标签不带name属性!-->
<!--父组件里任何内容都默认加到这个slot标签里!-->
<!--slot标签内可以包裹任意原子组件的内容 插入的内容将会替换掉它!-->
<slot></slot>
</div>
</template>
<script>
export default {
name:'card',
data()
{ return{
user:[
{ name:'张三', age:'21' },
{ name:'李四', age:'20' } ],
text:{ msg:'作用域插槽' }
}
}
}
</script>
父组件
<template>
<div class="home-container">
<h1>Home</h1>
<card>
<!-- 作用域插槽 v-slot:插槽名 = '接受子组件数据的对象名,可自定义' -->
<template v-slot:scope_slot = 'item'>
<h1>{{item.text.msg}}</h1>
<div v-for="u in item.user" :key='u'>
<h3>{{u.name}}</h3>
</div>
</template>
<!-- 具名插槽 v-slot:插槽名字 -->
<template v-slot:named_slot>
<h1>具名插槽</h1>
</template>
<template>
<h1>匿名插槽</h1>
</template>
</card>
</div>
</template>
vue3.x
//在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> //一个组件里面具有多个插槽时,一定要带上名称,否则可能会导致作用域错乱
自定义指令
vue2.x
// 注册一个全局自定义指令 `v-focus` Vue.directive('focus', { // 当被绑定的元素插入到 DOM 中时…… inserted: function (el) { // 聚焦元素 el.focus() } })
在 Vue 2 中, 自定义指令通过以下几个可选钩子创建:
bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)。
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind:只调用一次,指令与元素解绑时调用。
vue3.x
const { createApp } from "vue"
const app = createApp({})
app.directive('focus', {
mounted(el) {
el.focus()
}
})
双向数据绑定
vue2.x
VUe2.0通过Object.definePropety来劫持对象属性的getter和setter操作,当数据发生变化时通知

vue3.x
vue3.0通过Proxy来劫持数据,当数据发生变化时发出通知

proxy相较于object.defineProperty的优势
- defineProperty只能监听某个属性,不能对全对象监听
- Proxy可以监听数组的变化,不用再去单独的对数组做特异性操作
- 可以检测到数组内部数据的变化
异步组件的使用
vue2定义异步组件
<template> <div> <button @click="show = true">Load Tooltip</button> <div v-if="show"> <Tooltip /> </div> </div> </template> <script> export default { data: () => ({ show: false }), components: { Tooltip: () => import('./components/Tooltip') } } </script>
vue3中使用defineAsyncComponent 定义异步组件
<template> <!-- 异步组件的使用 --> <AsyncPage /> </tempate> <script> import { defineAsyncComponent } from "vue"; export default { components: { // 无配置项异步组件 AsyncPage: defineAsyncComponent(() => import("./NextPage.vue")), // 有配置项异步组件 AsyncPageWithOptions: defineAsyncComponent({ loader: () => import(".NextPage.vue"), delay: 200, timeout: 3000, errorComponent: () => import("./ErrorComponent.vue"), loadingComponent: () => import("./LoadingComponent.vue"), }) }, } </script>
Composition API
使用Composition API 解决我们在完成功能时,在 data、methods、computed 以及 mounted 中反复的跳转,他将零散分布的 逻辑组合在一起维护,并可以将单独的逻辑再分为单独的文件
-
setup
- setup是Vue3.x的新增选项,是组件内使用Composition API的入口
<script> import { defineComponent, reactive } from "vue"; export default defineComponent({ beforeCreate() { console.log("++++beforeCreate+++++"); }, created() { console.log("+++created+++"); }, setup() { const state = reactive({ count: 0 }); console.log("++++setup++++++"); return { state, }; }, }); </script>
输出结果:

总结:setup 执行时机是在 beforeCreate 之前执行
setup参数
setup接收两个参数(props和context),props是响应式的,当传入新的props时,会及时更新。由于是响应式的,所以不可以使用ES6解构,解构会消除它的响应式
setup(props) { const { userName } = props; console.log(userName ); const state = reactive({ num: 0 }); return { state, }; },
reactive、ref、toRefs
在 vue2.x 中, 定义数据都是在data中。Vue3.x可以使用reactive和ref来进行数据定义
reactive用于处理对象的双向绑定
ref处理js基础数据类型或者处理对象的双向绑定
<template>
<div>
<p>计数:{{ num }}s</p>
<p>人年龄:{{ person.age }}</p>
<p>人姓名:{{ person.name }}</p>
<p>狗类别:{{ dog.type }}</p>
<p>狗名称:{{ dog.name }}</p>
<p>狗年龄:{{ dog.age }}</p>
</div>
</template>
<script>
import { defineComponent, reactive, ref } from "vue";
export default defineComponent({
setup() {
//使用ref声明基本类型
const num = ref(0);
//使用ref声明对象
const person = ref({ age: 20, name: "张三" });
//使用reactive声明对象
const dog= reactive({ type: "金毛", name: "小花", age: 5 });
setTimeout(() => {
person.value.age = person.value.age + 1;
person.value.name = "李四";
dog.age++;
}, 1000);
setInterval(() => {
num.value++;
}, 1000);
return {
num,
dog,
person,
};
},
});
</script>
通过绑定dog.name,dog.type写的比较繁琐,就需要解构数据,但是又不能又ES6解构,因为会会消除props响应式。既想要解构后的数据又不使用解构,解决办法就是使用toRefs。
toRefs作用就是将一个reactive对象转化为属性全部为ref对象的普遍对象
<template>
<div>
<p>计数:{{ num }}s</p>
<p>人年龄:{{ person.age }}</p>
<p>人姓名:{{ person.name }}</p>
<p>狗类别:{{ type }}</p>
<p>狗名称:{{ name }}</p>
<p>狗年龄:{{ age }}</p>
</div>
</template>
<script>
import { defineComponent, reactive, ref ,toRefs} from "vue";
export default defineComponent({
setup() {
//使用ref声明基本类型
const num = ref(0);
//使用ref声明对象
const person = ref({ age: 20, name: "张三" });
//使用reactive声明对象
const dog= reactive({ type: "金毛", name: "小花", age: 5 });
setTimeout(() => {
person.value.age = person.value.age + 1;
person.value.name = "李四";
dog.age++;
}, 1000);
setInterval(() => {
num.value++;
}, 1000);
return {
num,
...toRefs(dog),
person,
};
},
});
</script>
- 生命周期钩子
vue3.x
import { defineComponent, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, onErrorCaptured, onRenderTracked, onRenderTriggered, } from "vue"; export default defineComponent({ setup() { console.log("setup"); onBeforeMount(() => { console.log("onBeforeMount"); }); onMounted(() => { console.log("onMounted"); }); onBeforeUpdate(() => { console.log("onBeforeUpdate"); }); onUpdated(() => { console.log("onUpdated"); }); onBeforeUnmount(() => { console.log("onBeforeUnmount"); }); onUnmounted(() => { console.log("onUnmounted"); }) }, });
vue2.x
<script> export default{ el: '#app', data: { message : "boy" }, beforeCreate() { console.group('beforeCreate 创建前状态===============》'); }, created() { console.group('created 创建完毕状态===============》'); }, beforeMount() { console.group('beforeMount 挂载前状态===============》'); }, mounted() { console.group('mounted 挂载结束状态===============》'); }, beforeUpdate() { console.group('beforeUpdate 更新前状态===============》'); }, updated() { console.group('updated 更新完成状态===============》'); }, beforeDestroy() { console.group('beforeDestroy 销毁前状态===============》'); }, destroyed() { console.group('destroyed 销毁完成状态===============》'); } } </script>


浙公网安备 33010602011771号