聊聊vue2和vue3的区别

举报
林太白 发表于 2025/04/11 13:07:41 2025/04/11
【摘要】 聊聊vue2和vue3的区别

❤聊聊vue2和vue3的区别

① vue2和vue3双向数据绑定原理

双向数据绑定的原理不同: Vue2使用的是ES5 的一个 API【Object.defineProperty】Object.defineProperty,通过发布/订阅实现

Vue3使用的是ES6的Proxy,对数据进行代理,能够监听对象和数组的变化

proxy的优势如下

  1. defineProperty只能监听某个属性,不能对全对象监听
  2. 可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)
  3. 可以监听数组,不用再去单独的对数组做特异性操作 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是默认启用的,只需确保在代码中只引入实际使用的模块即可

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。