首页 > 其他分享 >vue2与vue3的区别

vue2与vue3的区别

时间:2024-03-15 09:44:06浏览次数:18  
标签:vue const 区别 setup props vue2 vue3 组件 data

 vue2vue3双向数据绑定原理发生了改变

vue2的双向数据绑定是利用了es5 的一个API Object.definepropert() 对数据进行劫持 结合发布订阅模式来实现的。

vue3中使用了es6的proxyAPI对数据进行处理。

1. vue2和vue3双向数据绑定原理发生了改变

  1. 相比与vue2,使用proxy API 优势有:
  2. defineProperty只能监听某个属性,不能对全对象进行监听;
  3. 可以省去for in 、闭包等内容来提升效率(直接绑定整个对象即可);
  4. 可以监听数组,不用再去单独的对数组做特异性操作,vue3可以检测到数组内部数据的变化。

2.Vue3支持碎片(Fragments)

就是说可以拥有多个跟节点。

vue2

  1. <template>
  2. <div class='form-element'>
  3. <h2> {{ title }} </h2>
  4. </div>
  5. </template>

vue3

  1. <template>
  2. <div class='form-element'>
  3. </div>
  4. <h2> {{ title }} </h2>
  5. </template>

3. Composition API

Vue2 与vue3 最大的区别是vue2使用选项类型api,对比vue3合成型api。

  1. 旧得选项型api在代码里分割了不同得属性:data,computed,methods等;
  2. 新得合成型api能让我们使用方法来分割,相比于旧的API使用属性来分组,
  3. 这样代码会更加简便和整洁。

vue2

  1. export default {
  2. props: {
  3. title: String
  4. },
  5. data () {
  6. return {
  7. username: '',
  8. password: ''
  9. }
  10. },
  11. methods: {
  12. login () {
  13. // 登陆方法
  14. }
  15. },
  16. components:{
  17. "buttonComponent":btnComponent
  18. },
  19. computed:{
  20. fullName(){
  21. return this.firstName+" "+this.lastName;
  22. }
  23. }
  24. }

vue3

  1. export default {
  2. props: {
  3. title: String
  4. },
  5. setup () {
  6. const state = reactive({ //数据
  7. username: '',
  8. password: '',
  9. lowerCaseUsername: computed(() => state.username.toLowerCase()) //计算属性
  10. })
  11. //方法
  12. const login = () => {
  13. // 登陆方法
  14. }
  15. return {
  16. login,
  17. state
  18. }
  19. }
  20. }

4. 建立数据data

Vue2 - 这里把数据放入data属性中

  1. export default {
  2. props: {
  3. title: String
  4. },
  5. data () {
  6. return {
  7. username: '',
  8. password: ''
  9. }
  10. }
  11. }
vue2是把数据放入data中,vue3就需要使用一个新的setup()方法,此方法在组件初始化构造得时候触发。
使用一下三个步骤建立反应性数据:
1. 从vue引入reactive;
2.使用reactive() 方法来声明数据为响应性数据;
3. 使用setup()方法来返回我们得响应性数据,从而template可以获取这些响应性数据。
  1. import { reactive } from 'vue'
  2. export default {
  3. props: {
  4. title: String
  5. },
  6. setup () {
  7. const state = reactive({
  8. username: '',
  9. password: ''
  10. })
  11. return { state }
  12. }
  13. }

template使用,可以通过state.username和state.password获得数据的值。

  1. <template>
  2. <div>
  3. <h2> {{ state.username }} </h2>
  4. <h2> {{ state.password}} </h2>
  5. </div>
  6. </template>

5. 生命周期

  1. vue2 --------------- vue3
  2. beforeCreate setup()
  3. Created setup()
  4. beforeMount onBeforeMount
  5. mounted onMounted
  6. beforeUpdate onBeforeUpdate
  7. updated onUpdated
  8. beforeDestroyed onBeforeUnmount
  9. destroyed onUnmounted
  10. activated onActivated
  11. deactivated onDeactivated
  1. setup() :开始创建组件之前,在beforeCreate和created之前执行。创建的是data和method
  2. onBeforeMount() : 组件挂载到节点上之前执行的函数。
  3. onMounted() : 组件挂载完成后执行的函数。
  4. onBeforeUpdate(): 组件更新之前执行的函数。
  5. onUpdated(): 组件更新完成之后执行的函数。
  6. onBeforeUnmount(): 组件卸载之前执行的函数。
  7. onUnmounted(): 组件卸载完成后执行的函数
  8. 若组件被<keep-alive>包含,则多出下面两个钩子函数。
  9. onActivated(): 被包含在中的组件,会多出两个生命周期钩子函数。被激活时执行 。
  10. onDeactivated(): 比如从 A组件,切换到 B 组件,A 组件消失时执行。

6. 父子传参不同,setup()函数特性

  1. setup()函数接收两个参数props、context(包含attrs、slots、emit)
  2. setup函数是处于生命周期beforeCreated和created俩个钩子函数之前
  3. 执行setup时,组件实例尚未被创建(在setup()内部,this不会是该活跃实例得引用,即不指向vue实例,Vue为了避免我们错误得使用,直接将setup函数中得this修改成了undefined
  4. 与模板一起使用时,需要返回一个对象(在setup函数中定义的变量和方法最后都是需要 return 出去的 不然无法再模板中使用)
  5. 因为setup函数中,props是响应式得,当传入新的prop时,它将会被更新,所以不能使用es6解构,因为它会消除prop的响应性,如需解构prop,可以通过使用setup函数中得toRefs来完成此操作。
  6. 父传子,用props,子传父用事件 Emitting Events。在vue2中,会调用this$emit然后传入事件名和对象;在vue3中得setup()中得第二个参数content对象中就有emit,那么我们只要在setup()接收第二个参数中使用分解对象法取出emit就可以在setup方法中随意使用了。父传子,props
  7. 在setup()内使用响应式数据时,需要通过 .value 获取

6.1、父传子

  1. import { toRefs } from 'vue'
  2. setup(props) {
  3. const { title } = toRefs(props)
  4. console.log(title.value)
  5. onMounted(() => {
  6. console.log('title: ' + props.title)
  7. })
  8. }

 6.2、子传父,事件 - Emitting Events

举例,现在我们想在点击提交按钮时触发一个login的事件。

在 Vue2 中我们会调用到this.$emit然后传入事件名和参数对象。

  1. login () {
  2. this.$emit('login', {
  3. username: this.username,
  4. password: this.password
  5. })
  6. }

 在setup()中的第二个参数content对象中就有emit,这个是和this.$emit是一样的。那么我们只要在setup()接收第二个参数中使用分解对象法取出emit就可以在setup方法中随意使用了。

然后我们在login方法中编写登陆事件
另外:context 是一个普通的 JavaScript 对象,也就是说,它不是响应式的,这意味着你可以安全地对 context 使用 ES6 解构

  1. setup (props, { attrs, slots, emit }) {
  2. // ...
  3. const login = () => {
  4. emit('login', {
  5. username: state.username,
  6. password: state.password
  7. })
  8. }
  9. // ...
  10. }

6.3、attrs和listeners

子组件使用$attrs可以获得父组件除了props传递的属性和特性绑定属性 (class和 style)之外的所有属性。子组件使用$listeners可以获得父组件(不含.native修饰器的)所有v-on事件监听器,在Vue3中已经不再使用;但是Vue3中的attrs不仅可以获得父组件传来的属性也可以获得父组件v-on事件监听器

 Vue 2

我们可以使用$attrs$listeners来传递父组件的属性和事件到子组件中。例如,我们有一个名为ChildComponent的子组件,它的模板如下:

  1. <template>
  2. <div>
  3. <h1>{{ title }}</h1>
  4. <button @click="onClick">{{ buttonText }}</button>
  5. </div>
  6. </template>

我们可以在父组件中使用v-bindv-on来传递属性和事件:

  1. <template>
  2. <div>
  3. <ChildComponent v-bind="$attrs" v-on="$listeners" />
  4. </div>
  5. </template>

Vue 3

  1. <template>
  2. <div>
  3. <h1>{{ title }}</h1>
  4. <button @click="onClick">{{ buttonText }}</button>
  5. </div>
  6. </template>

 $attrs$listeners已经被移除了,如果需要使用它们,需要在子组件中手动声明它们。例如,在ChildComponent中,我们可以使用以下方式声明$attrs$listeners

  1. import { defineComponent } from 'vue'
  2. export default defineComponent({
  3. inheritAttrs: false,
  4. props: {
  5. title: String,
  6. buttonText: String
  7. },
  8. methods: {
  9. onClick() {
  10. this.$emit('click')
  11. }
  12. },
  13. render() {
  14. return (
  15. <div>
  16. <h1>{this.title}</h1>
  17. <button onClick={this.onClick}>{this.buttonText}</button>
  18. {this.$slots.default}
  19. </div>
  20. )
  21. }
  22. })

inheritAttrs: false表示不继承父组件的属性,需要手动声明$attrs$listeners。在模板中,我们可以使用v-bind="$attrs"v-on="$listeners"来传递属性和事件: 

  1. <template>
  2. <div>
  3. <ChildComponent title="Hello World" buttonText="Click Me" v-bind="$attrs" v-on="$listeners" />
  4. </div>
  5. </template>

 6.4、 setup()内使用响应式数据时,需要通过.value获取

  1. import { ref } from 'vue'
  2. const count = ref(0)
  3. console.log(count.value)复制

6.5、 从setup() 中返回得对象上得property 返回并可以在模板中被访问时,它将自动展开为内部值。不需要在模板中追加.value。

例如,如果您在setup()中返回了一个名为person的对象,并且该对象具有一个名为name的属性,您可以在模板中使用{{ person.name }}来访问该属性的值,而无需使用

{{ person.name.value }}

6.5、setup函数只能是同步的不能是异步的。

如果setup()函数是异步的,则无法保证在开始运行应用程序之前完成初始化。如果您需要执行异步操作,请在setup()函数之外执行它们

  1. import { reactive } from 'vue'
  2. export default {
  3. setup() {
  4. const state = reactive({
  5. data: null
  6. })
  7. async function loadData() {
  8. // 从服务器加载数据的异步操作
  9. const response = await fetch('/data')
  10. const data = await response.json()
  11. // 将数据存储在组件状态中
  12. state.data = data
  13. }
  14. loadData()
  15. return {
  16. state
  17. }
  18. }
  19. }

或者 

  1. import { ref, onMounted } from 'vue'
  2. export default {
  3. setup() {
  4. const data = ref(null)
  5. onMounted(async () => {
  6. const response = await fetch('https://api.example.com/data')
  7. data.value = await response.json()
  8. })
  9. return {
  10. data
  11. }
  12. }
  13. }

我们在组件的 created 函数中使用异步函数来获取数据,并将数据保存到组件的状态中。然后,在 setup 函数中使用这个状态来显示数据。

注意,我们使用了 onMounted 函数来在组件挂载后执行异步操作。这是因为在组件挂载之前,组件的状态还没有被设置,无法使用组件的状态来保存异步操作的结果。

在 setup 函数中,我们可以使用异步函数,例如:

  1. import { ref } from 'vue'
  2. export default {
  3. setup() {
  4. const message = ref('Hello, world!')
  5. setTimeout(() => {
  6. message.value = 'Hello, Vue!'
  7. }, 1000)
  8. return {
  9. message
  10. }
  11. }
  12. }

 虽然 setup 函数本身是同步的,但是我们可以在其中使用异步函数来进行一些异步操作。只要这些操作在组件实例创建之前就已经完成,就不会影响组件的正常运行。

7.vue3 Teleport瞬移组件

Teleport一般被翻译成瞬间移动组件,我把他理解成"独立组件", 他可以拿你写的组件挂载到任何你想挂载的DOM上,所以是很自由很独立的,

以一个例子来看: 编写一个弹窗组件

  1. <template>
  2. <teleport to="#modal">
  3. <div id="center" v-if="isOpen">
  4. <h2><slot>this is a modal</slot></h2>
  5. <button @click="buttonClick">Close</button>
  6. </div>
  7. </teleport>
  8. </template>
  9. <script lang="ts">
  10. export default {
  11. props: {
  12. isOpen: Boolean,
  13. },
  14. emits: {
  15. 'close-modal': null
  16. },
  17. setup(props, context) {
  18. const buttonClick = () => {
  19. context.emit('close-modal')
  20. }
  21. return {
  22. buttonClick
  23. }
  24. }
  25. }
  26. </script>
  27. <style>
  28. #center {
  29. width: 200px;
  30. height: 200px;
  31. border: 2px solid black;
  32. background: white;
  33. position: fixed;
  34. left: 50%;
  35. top: 50%;
  36. margin-left: -100px;
  37. margin-top: -100px;
  38. }
  39. </style>

 在app.vue中使用的时候跟普通组件调用是一样的

  1. <template>
  2. <div id="app">
  3. <img alt="Vue logo" src="./assets/logo.png">
  4. <HelloWorld msg="Welcome to Your Vue.js App"/>
  5. <HooksDemo></HooksDemo>
  6. <button @click="openModal">Open Modal</button><br/>
  7. <modal :isOpen="modalIsOpen" @close-modal="onModalClose"> My Modal !!!!</modal>
  8. </div>
  9. </template>
  10. <script>
  11. import HelloWorld from './components/HelloWorld.vue'
  12. import HooksDemo from './components/HooksDemo.vue'
  13. import Modal from './components/Modal.vue'
  14. import{ref} from 'vue'
  15. export default {
  16. name: 'App',
  17. components: {
  18. HelloWorld,
  19. HooksDemo,
  20. Modal
  21. },
  22. setup() {
  23. const modalIsOpen = ref(false)
  24. const openModal = () => {
  25. modalIsOpen.value = true
  26. }
  27. const onModalClose = () => {
  28. modalIsOpen.value = false
  29. }
  30. return {
  31. modalIsOpen,
  32. openModal,
  33. onModalClose
  34. }
  35. }
  36. }
  37. </script>
  38. <style>
  39. #app {
  40. font-family: Avenir, Helvetica, Arial, sans-serif;
  41. -webkit-font-smoothing: antialiased;
  42. -moz-osx-font-smoothing: grayscale;
  43. text-align: center;
  44. color: #2c3e50;
  45. margin-top: 60px;
  46. }
  47. </style>

8、路由

vue3和vue2路由常用功能只是写法上有些区别:

vue3的beforeRouteEnter作为路由守卫的示例是因为它在setup语法糖中是无法使用的;大家都知道setup中组件实例已经创建,是能够获取到组件实例的。而beforeRouteEnter是再进入路由前触发的,此时组件还未创建,所以是无法用在setup中的;如果想在setup语法糖中使用则需要再写一个script 如下:

  1. <script>
  2. export default {
  3. beforeRouteEnter(to, from, next) {
  4. // 在渲染该组件的对应路由被 confirm 前调用
  5. next()
  6. },
  7. };
  8. </script>

vue2

  1. <script>
  2. export default {
  3. beforeRouteEnter (to, from, next) {
  4. // 在渲染该组件的对应路由被 confirm 前调用
  5. next()
  6. },
  7. beforeRouteEnter (to, from, next) {
  8. // 在渲染该组件的对应路由被 confirm 前调用
  9. next()
  10. },
  11. beforeRouteLeave ((to, from, next)=>{//离开当前的组件,触发
  12. next()
  13. }),
  14. beforeRouteLeave((to, from, next)=>{//离开当前的组件,触发
  15. next()
  16. }),
  17. methods:{
  18. toPage(){
  19. //路由跳转
  20. this.$router.push(xxx)
  21. }
  22. },
  23. created(){
  24. //获取params
  25. this.$route.params
  26. //获取query
  27. this.$route.query
  28. }
  29. }
  30. </script>

vue3 路由写法

  1. <script>
  2. import { defineComponent } from 'vue'
  3. import { useRoute, useRouter } from 'vue-router'
  4. export default defineComponent({
  5. beforeRouteEnter (to, from, next) {
  6. // 在渲染该组件的对应路由被 confirm 前调用
  7. next()
  8. },
  9. beforeRouteLeave ((to, from, next)=>{//离开当前的组件,触发
  10. next()
  11. }),
  12. beforeRouteLeave((to, from, next)=>{//离开当前的组件,触发
  13. next()
  14. }),
  15. setup() {
  16. const router = useRouter()
  17. const route = useRoute()
  18. const toPage = () => {
  19. router.push(xxx)
  20. }
  21. //获取params 注意是route
  22. route.params
  23. //获取query
  24. route.query
  25. return {
  26. toPage
  27. }
  28. },
  29. });
  30. </script>

标签:vue,const,区别,setup,props,vue2,vue3,组件,data
From: https://www.cnblogs.com/mounterLove/p/18072891

相关文章

  • 搭建vue3版taro以及相关api
    1.安装Taro1.使用npm或者yarn全局安装@tarojs/cli$npminstall-g@tarojs/cli$yarnglobaladd@tarojs/cli2.项目初始化:taroinitmyApp编译运行使用Taro的build命令可以把Taro代码编译成不同端的代码,然后在对应的开发工具中查看效果。Taro编译分......
  • Vue2/3 实现动态循环的select下拉框去重功能:
    需求:前面下拉框选择某个选项(如:1)了,后面的下拉框不能在有前面选中内容的该选项(即不能在出现1的下拉选项)【Vue实现动态循环出的多个select不能重复选择相同的数据】注:下面注释的都可以根据需求更改 代码<template><divid="app"><divv-fo......
  • 拦截器和过滤器(原理&区别)
    目录一、拦截器拦截器是什么拦截器的使用拦截器的实现导入依赖实现HandlerInterceptor接口注册拦截器拦截器的生命周期拦截器的执行顺序拦截器的生命周期多个拦截器的执行流程拦截器的实际使用拦截器实现日志记录实现接口幂等性校验拦截器的性能优化二、过滤器......
  • Maven 中<optional>true</optional>和<scope>provided</scope>之间的区别(转)
    原文:https://segmentfault.com/a/1190000019266080?utm_source=tag-newest<optional>true</optional>和<scope>provided</scope>有什么区别呢?从语义来上理解optional可选的,可以理解为此功能/此依赖可选,如果不需要某项功能,可以不引用这个包。scopeprovided提供的,可以理解为此......
  • vue3 引入 ElementUI
     vue3使用elementUI会报错,需要引入elementUIPlus。Plus官网:https://element-plus.gitee.io/zh-CN/guide/quickstart.htmlUI官网:https://element.eleme.cn/#/zh-CN/component/installation1.安装ElementUIPlusnpminstallelement-plus--savepackage.json检查。......
  • springboot3+vue3(十一)springboot多环境开发
    在开发中我们往往会遇到,本地环境、测试环境、生产环境分别一套配置。如数据库连接,端口号等配置各不相同的问题。 1、多文件配置    2、多文件分组配置如果配置文件有很多的配置信息几百行的情况,为了方便维护我们可以根据功能的情况进行分组拆分。如:服务器相关配......
  • 一张图搞清楚wait、sleep、join、yield四者区别,面试官直接被征服!
    写在开头在线程的生命周期中,不同状态之间切换时,可以通过调用sleep()、wait()、join()、yield()等方法进行线程状态控制,针对这一部分知识点,面试官们也会做做文章,比如问你这些方法的作用以及之间的区别。那么今天我们就一起来总结一下这几个方法的作用及区别,先画一个思维导图梳理一......
  • RAM和ROM的区别
    RAM(RandomAccessMemory)和ROM(Read-OnlyMemory)是计算机中两种不同类型的存储器,具有不同的特性和用途。易失性vs.非易失性:RAM:RAM是一种易失性存储器,意味着它在断电时会丢失存储的数据。RAM用于存储正在运行的程序和临时数据,因为其读写速度快,但一旦电源断开,其中的数据就会......
  • PEST和SWOT分析的区别与联系
    PEST和SWOT分析的区别与联系1.什么是SWOT分析?SWOT的四个字母分别代表着项目内部和外部的四个关键因素:优势(Strengths):项目的竞争优势。劣势(Weaknesses):内部存在的劣势,相对于竞争对手而言。机会(Opportunities):当前可利用的外部机会。威胁(Threats):可能导致问题并对项目产生负面影......
  • C# Dictionary与List的用法区别与联系
    原文链接:https://blog.csdn.net/qq_22120623/article/details/134280660C#是一门广泛应用于软件开发的编程语言,其中Dictionary和List是两种常用的集合类型。它们在存储和操作数据时有着不同的特点和用途。本文将详细探讨C#Dictionary和List的用法区别与联系,并通过代码示例进行对......