聊聊vue2和vue3的区别
❤聊聊vue2和vue3的区别
① vue2和vue3双向数据绑定原理
双向数据绑定的原理不同: Vue2使用的是ES5 的一个 API【Object.defineProperty】Object.defineProperty,通过发布/订阅实现
Vue3使用的是ES6的Proxy,对数据进行代理,能够监听对象和数组的变化
proxy的优势如下
- defineProperty只能监听某个属性,不能对全对象监听
- 可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)
- 可以监听数组,不用再去单独的对数组做特异性操作 vue3.x可以检测到数组内部数据的变化
典型的就是this.$set()没有必要使用了!
② 生命周期
Vue2的生命周期钩子函数 beforeCreate、created、beforeMount、mounted等
Vue3的生命周期钩子函数 setup、onBeforeMount、onMounted
等 并且提供了两个调试的钩子onRenderTracked和onRenderTriggered
Vue2和Vue3的生命周期
Vue 2 生命周期钩子 | Vue 3 生命周期钩子 |
---|---|
beforeCreate |
setup() |
created |
setup() |
beforeMount |
onBeforeMount |
mounted |
onMounted |
beforeUpdate |
onBeforeUpdate |
updated |
onUpdated |
beforeDestroy |
onBeforeUnmount |
destroyed |
onUnmounted |
activated |
onActivated |
deactivated |
onDeactivated |
Vue2
:::tip
- beforeCreate: 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
- created: 在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。
- beforeMount: 在挂载开始之前被调用:相关的 render 函数首次被调用。
- mounted: el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。
- beforeUpdate: 数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。
- updated: 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。
- beforeDestroy: 实例销毁之前调用。在这一步,实例仍然完全可用。
- destroyed: Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
- activated: keep-alive 组件激活时调用。
- deactivated: keep-alive 组件停用时调用。
:::
Vue3
:::tip
- setup() :开始创建组件之前,在beforeCreate和created之前执行。创建的是data和method
- onBeforeMount() : 组件挂载到节点上之前执行的函数。
- onMounted() : 组件挂载完成后执行的函数。
- onBeforeUpdate(): 组件更新之前执行的函数。
- onUpdated(): 组件更新完成之后执行的函数。
- onBeforeUnmount(): 组件卸载之前执行的函数。
- onUnmounted(): 组件卸载完成后执行的函数
:::
若组件被<keep-alive></keep-alive>
包含,则多出下面两个钩子函数。
- onActivated(): 被包含在中的组件,会多出两个生命周期钩子函数。被激活时执行 。
- onDeactivated(): 比如从 A组件,切换到 B 组件,A 组件消失时执行。
③API
Vue2使用的是选项式API,里面有data、methods、mounted等
Vue3使用的是组合式API,使用的是setup函数
分别简单写出vue2和vue3的东西我们可以发现如下:
Vue2
<template>
<div>
<h2>{{ title }} </h2>
</div>
</template>
<script>
export default {
components: {}, // 组件
props: {
title: String
},
data() {
return {
title: 'Vue2'
};
},
mounted() {
// 在组件挂载时执行的代码
},
methods: {
// 方法定义
},
computed: {
fullName() {
return this.firstName + ' ' + this.lastName;
}
}
};
</script>
Vue3
<template>
<div>
<h2> {{title}}</h2>
</div>
</template>
<script>
import {ref,reactive} from 'vue'
export default {
components:{}, //组件
props:{title:String},
setup(){
// 数据
const state=reactive({
userName:'',
phone:conmputed(()=>{})
});
const numbertotal=()=>{
// 计算数字总和
};
return {
state,
numbertotal,
}
}
}
</script>
直接使用setup函数可以写成如图:
<script setup>
import { onMounted } from 'vue'; // 使用前带引入生命周期钩子
onMounted(() => {
// 逻辑1
});
onMounted(() => {
// 逻辑2
});
</script>
④支持碎片化((Fragments))
Vue2中,template下只允许存在一个根节点
Vue3中可以有多个根节点,为我们创建一个虚拟的Fragment节点。
Vue2
<template>
<div>
<h2> { title} </h2>
</div>
</template>
Vue3
<template>
<div></div>
<h2> { title} </h2>
</template>
⑤ 定义数据变量
Vue2中数据放在data里,方法放在methods里
Vue3在setup方法里定义数据,这个方法在组件初始化的时候触发,使用reactive和ref将数据变成响应式数据
Vue2
<script>
export default {
components: {}, // 组件
props: {
title: String
},
data() {
return {
title: 'Vue2'
};
}
};
</script>
Vue3
在Vue3.0,使用一个新的setup()方法,此方法在组件初始化构造的时候触发。
<script setup>
import { reactive } from 'vue';
const state = reactive({
username: '',
password: ''
});
defineProps({
title: String
});
return { state };
</script>
⑥ v-for 和 v-if 的区别
在vue2中v-for与 v-if 可以同时用,【优先级】:v-for > v-if
v-for的优先级比v-if高,所以可以一起用, 但是每次页面渲染的时候都会重复的进行判断是十分消耗性能的,不推荐使用
因为v-if和v-for在同一层级,Vue在渲染组件的时 先根据v-for遍历所有 数据 并将他们都生成对应的虚拟DOM,之后再根据v-if的判断去对不符合条件的 元素进行从虚拟DOM的删除
这里为什么不推荐显而易见: 就是因为 会先执行v-for循环遍历出所有的数据 但是这个时候不是先进行v-if的 判断而是会去先对所有的数据都生成对应的虚拟DOM 然后再去通过v-if的判断 去 去掉不符合条件的虚拟DOM 这样就会造成性能的消耗 生成了没必要的虚拟 DOM元素 并且还对这些没必要的虚拟DOM元素进行了一次删除大大提高了 性能的损耗
Vue3中正好相反 v-if > for 【优先级】 v-if > v-for
所以在Vue3中想要把v-if和v-for一起放在标签内一起使用是不可能的会直接报
错
原因:在Vue3中的v-if是比v-for的优先级高的 所以会先执行v-if但是v-if 的
执行又需要依靠到v-for的数据 但是这里是先执行v-if这个时候v-for还没有遍
历数据 所以会报一个当前v-if判断的变量还没有被定义的错误
解决方案
1:嵌套使用
2:使用computed计算属性或提前对数组进行filter过滤操作
(1)嵌套使用:
我们把优先级高的指令放到内层嵌套的形式去写也就是在Vue3中我们外层 使用v-for 内层去使用v-if判断 这样就可以保证v-for先执行把数据都遍历出来供 我们的v-if使用 并且Vue可以先根据v-for遍历出来的所有子元素 去渲染只符合 v-if判断条件的元素将符合条件的渲染并且生成虚拟DOM,而不符合条件的不会生成虚拟DOM
这样可以避免不必要的性能消耗 提高页面渲染的速度
为什么使用嵌套不会产生额外的虚拟DOM元素呢 ? 因为在这里的嵌套是父子级 的关系 v-if是v-for的子级也就是说在v-for循环出来所有的数据之后 就会到子级 去执行生成对应子级虚拟DOM的任务 但是在子级的元素标签上有v-if的判断 不符合的不会渲染 所以 不符合的元素的虚拟DOM就不会生成了
(2)我们可以避免同时使用v-if和v-for
我们首先明确我们的目的 如果遇到了这种需要同时使用的时候一般是因为 我们的数组还没有经过处理 所以需要遍历数组的同时对数组中的值进行处理 所以我们可以先一步对数组进行处理后 再进行遍历 例如我们可以通过数组的filter方法提前过滤 或者放到computed 计算属性中提前处理好 只使用一个v-for去遍历通过computed计算属性过滤好的元素。 ————————————————
⑦兼容性
支持TypeScript性
Vue3完全支持TypeScript,提高项目的可维护性 Vue2对TypeScript的支持有限
⑧ Vue3新增组件
Vue3新增了Teleport传送门组件和Suspense组件
Teleport传送门组件
你写的组件挂载到任何你想挂载的DOM上
弹窗组件:
<template>
<teleport>
<div id="center">
<h2><slot>this is a modal</slot></h2>
<button @click="buttonClick">Close</button>
</div>
</teleport>
</template>
<script>
export default {
props: {
isOpen: Boolean
},
emits: ['close-modal'],
setup(props, context) {
const buttonClick = () => {
context.emit('close-modal');
};
return {
buttonClick
};
}
};
</script>
<style>
#center {
width: 200px;
height: 200px;
border: 2px solid black;
background: white;
position: fixed;
left: 50%;
top: 50%;
margin-left: -100px;
margin-top: -100px;
}
</style>
在app.vue中使用的时候跟普通组件调用 vue2你可能只能嵌套在#app中
但是vue3之中,Teleport 可以把modal组件渲染到任意你想渲染的外部Dom上,不必嵌套在#app中
(举例)
可将弹窗 移动到 #app中之外的位置
使用to属性去移动到想要的地方:
<template>
<button @click="dialogVisible = true">显示弹窗</button>
<teleport to="body">
<div class="dialog" v-if="dialogVisible">
我是弹窗,我直接移动到了 body 标签下
</div>
</teleport>
</template>
异步组件(Suspense)
允许程序在等待异步组件加载完成前渲染兜底的内容,如 loading ,使用户的体验更平滑。使用它,需在模板中声明,并包括两个命名插槽:default 和 fallback。Suspense 确保加载完异步内容时显示默认插槽,并将 fallback 插槽用作加载状态。
⑨ 更小的打包体积
Tree Shaking概念
Tree Shaking 指的就是当引入一个模块的时候,只引入需要的代码而不引入这个模块的所有代码
官方标准的说法:
Tree-shaking的本质是消除无用的js代码。无用代码消除在广泛存在于传统的编程语言编译器中,编译器可以判断出某些代码根本不影响输出,然后消除这些代码,这个称之为DCE(dead code elimination)
webpack 里面自带 Tree Shaking 这个功能来
在 webpack 项目中,有一个入口文件,相当于一棵树的主干,入口文件有很多依赖的模块,相当于树枝。实际情况中,虽然依赖了某个模块,但其实只使用其中的某些功能。通过 Tree-Shaking,将没有使用的模块摇掉,这样来达到删除无用代码的目的。
在Vite项目中,Tree-shaking是默认启用的,只需确保在代码中只引入实际使用的模块即可
- 点赞
- 收藏
- 关注作者
评论(0)