首页 前端知识 vue2和vue3的差异整理(轻松过度到vue3)

vue2和vue3的差异整理(轻松过度到vue3)

2024-08-30 20:08:49 前端知识 前端哥 17 229 我要收藏

        随着2023年末vue官方宣布vue2日后不在更新,vue3将成为日后开发框架的新首选项。特此记录下vue2与vue3中的语法,常用插件等使用差异

一,api及语法

1,双向绑定原理

        Vue2使用Object.defineProperty 为每个属性创建getter和setter,通过getter和setter来捕获操作以实现响应式更新; 很多情况下,属性的新增和删除拦截不到(比如数组的长度变化)

        Vue3 通过Proxy实现,proxy是ES6新特性,提供了更多的拦截操作;能监听到属性的删除和新增

v2使用object.defineProperty来劫持数据的setter和getter方法,对象改变需要借助api去深度监听
v3Proxy来实现数据劫持,删除了一些api($on,$once,$off) fiter等,优化了Block tree,solt,diff 算法等

        Vue2在data中定义的数据就会自动遍历绑定Object.defineProperty以实现响应式;Vue3中要用ref包装,通过返回值的 .value属性获取响应式的值 ,修改也需要对 .value进行修改

(注意在js中要.value,在模板html中解析时会自动添加.value,不需要添加)

<template>
 <div>
<!-- 不需要.value -->
 {{ testOne }}
 {{ testTwo.directionD}}
 </div>
</template>

<script setup>
  const testOne= ref(0)
  
  const testTwo= ref({
    directionD: '',
    directionA: '',
    arr: []
  })
  
  const dataThree= ref({})

  // 使用需要.value
  console.log(testOne.value);
  console.log(dataThree.value);
  console.log(testTwo.value.directionD);
  console.log(testTwo.value.directionD);

</script>

        除了ref()之外,还有reative也能实现响应式(reative不加.value)

        二者用法差异不在此赘述,可见大佬文章:http://t.csdnimg.cn/wpu6r

2,vue3支持碎片化

        v2中只能存在一个根节点,v3中可以保持如下多个根节点,一定程度上减少了标签的层级

        注意:下列情况若子组件中存在多个根节点, 则使用组件时不能使用 v-show(无法对子组件根节点添加display)

        解决: 1, 可用v-if代替(可能存在首次渲染失效)  2,只保留一个根节点

<template>
  <div class="container">
     <!-- 此时v-show无效 -->
     <son  v-show="false"></son>  
  </div>
</template>

-----son 组件

<template>
  <div class="son_container">
     1
  </div>

  <div class="son_container2">
     2
  </div>

  <div class="son_container3">
     3
  </div>
</template>

3,生命周期

Vue2Vue3
beforeCreate()setup()组件开始创建数据实例之前
created()setup() 组件实例完成
beforeMount()onBeforeAMount() DOM挂载之前
mounted()onMounted()DOM挂载完成
beforeUpdate()onBeforeUpdate()组件更新之前
undated() onUpdated()组件更新之后
beforeDestroy()onBeforeunmount() 组件销毁之前
destroyed()onUnmounted()组件销毁之后

        大部分生命周期在vue2的周期前加 on 即可;vue3没有beforeCreate 和 created两个周期,那想在这两个周期中进行逻辑处理怎么办呢?  setup中写好了调用即可👇

4, 去除this

        Vue3中没有this, 使用this报错 需要组件内的某个方法直接使用即可(注意使用的数据必须在调用前定义)

5,组件传值props和emit

        Vue2中是 props和 this.$emit    Vue3中则是[defineEmits defineProps] props emit; 

        需要注意的是 Vue2中传值给子组件可以的属性可以直接使用,Vue3中子组件接收的值在props对象中,所以在ts/js中使用需要 props.name

        emit触发的事件,需要defineProps声明接收数据,defineEmits 声明以明确事件定义

// 父组件中使用子组件
<son ref="bottomContract" @transferData="transferData" @reloadEcharts="reloadEcharts" :dataOne="tableTime" :dataTwo="echartsColumnData" :dataThree="dataThree" />



// 子组件
<script lang="ts" setup>
    //子组件中接收
    const props = defineProps({
      dataOne: {
        default: () => 0
      },
      dataThree: {
        type: Number,
        default: () => 0
      },
      dataTwo: {
        default: () => []
      }
  })

  // 也可以数组形式
  // const emit = defineEmits(["dataFour", "dataFive", "dataSix"])


// 子组件中使用
const test = () => {
    console.log(props.dataOne)
}


// defineEmits明确事件定义
const emit = defineEmits(["transferData", "reloadEcharts"])


const testTwo = ()=> {
    emit("transferData", 'value')
    emit("transferData", 'value')
}
</script>

6,watch和computed

        watch

        watch,computed与vue2用法差别不大,写法改变了; vue2是将要监听的值放在watch:{ }中

Vue2

        Vue3,监听watch第一个参数是直接传入要监听的对象 ;深度监听复杂对象 {deep: true}

const demo = reactive({
	name: '前端',
	nickName: '1',
	Yiqian: {
		name: '',
		nickName: ''
	}
})

// 深度监听复杂对象 {deep: true}
watch(demo, (newValue, oldValue) => {
    console.log('watch 已触发', newValue)
}, {deep: true})

// 也可以只监听其中的某个属性
watch(() => ({ ...demo }), (newValue, oldValue) => {
    console.log('watch 已触发', newValue)
})

        监听一个属性就要用一个watch,是不是不太妙? 那当然也可以组合到一起,此时的第一个参数是一个数组,第二参数箭头函数的参数也是数组的形式,按照数组下标对应监听值

watch(() => [demo.name, demo.nickname], (newValue, oldValue) => {
  console.log(newValue); // 此时newValue是数组,按照数据下标获取对应监听属性值
  console.log(newValue[0])
  console.log(newValue[1])
})
       
        computed 

        与vue2的computed配置写法基本一致     

const user = ref({
   testOne: 'A',
   testTwo: 'B'
});

    // 只有getter的计算属性
     const fullName1 = computed(() => {
        return user.value.testOne+ '-' + user.value.testTwo;
     })


     // 有getter与setter的计算属性
    const fullName2 = computed({
      get () {
        return user.value.testOne+ '-' + user.value.testTwo;
      },
      set (value: string) {
        const names ='111';
        user.value.testOne= names;
        user.value.testTwo= names;
      }
    });

7,子组件实例,调用组件方法

        Vue2中 子组件定义ref="name"后使用this.$refs.name 就能拿到组件name的实例;同时可以this.$refs.name.test() 的方式直接调用子组件的test()方法

        Vue3中,子组件定义ref="name",需要用ref()来定义引用,将其绑定到对应子组件上;若想直接调用子组件的方法,需要在子组件中defineExpose显示暴露出对应的方法(组件封装性),若不暴露出来则子组件实例上不会存在此方法

// -----父组件------
<template>
  <ChildComponent ref="timingEchartsModule" />
</template>

<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

// 定义一个 ref 来引用子组件实例
const timingEchartsModule = ref();

// 在某个生命周期钩子中访问子组件实例
onMounted(() => {
  console.log(timingEchartsModule.value);
  timingEchartsModule.value.test() //调用子组件方法
});
</script>


// ----子组件----
<script setup>
const test= () => {
  console.log('someMethod called');
};

// defineExpose暴露方法  若不暴露,此方法不会存在组件实例上
defineExpose({
  test
})
</script>

8,选项式api和组合式api

        Vue2中 选项式的api,创建组件时需要使用各种选项 data methods  watch等

选项式


        Vue3组合式允许将相关的代码逻辑放在一起处理,让代码更易于理解和维护

    const message = ref('Hello Vue!');
    
    const greet = () => {
      alert(message.value);
    };

    const test = computed(() => {
        return meaages
    })
    
    watch(() => message, (newValue: any, oldValue: any) => {
       
     })

9,mixins和hooks

        Vue 2 中,Mixins 是一种全局特性,可以在多个组件之间共享代码。你可以创建一个 Mixin 对象,然后在组件中通过 Mixins 选项引入这个对象,从而将 Mixin 中的属性和方法合并到组件中;如果多个 Mixins 中有相同的属性或方法,可能会导致命名冲突。另外,由于 Mixins 是全局的,它们会增加组件的耦合度,使得代码难以维护

        Vue3的Hooks允许你将相关的逻辑组合到一起,形成一个逻辑单元,组件内部使用的,而不是全局的,这减少了命名冲突和耦合度。

import { ref } from 'vue'
export default function() {
	const count = ref(0);
	const add = () => {
		count.value++;
	}
	const decrement = () => {
		count.value--;   
	}
	// 把方法和数据返回出去
	return {
	    count,
	    add,
	    decrement
	}
}


// 在用到的文件中引入此hook.js 文件
<script setup>
	//引入hooks文件
	import useCount from "../hooks/useCount"
	// 导入
	const { count, add, decrement } = useCount()
</script>

二,插件

        Vue3中,部分相关插件的用法也存在差异

1,vue-router

        基本类似,在使用时需要引入; route和router, router获取路由器实例 ; route对象包含了当前路由的各种信息

const router = useRouter() // 此为引入router
router.push({path:'name'})
router.back();

const route = useRoute() // 此为引入route
console.log(route.params)
console.log(route.query)

       

2,状态管理Vuex 和 Pinia

         Vuex使用 storestatemutationsactionsgetters 的概念,结构化更严格

         Pinia 更简洁和模块化,使用 defineStore 函数创建状态,避免了冗长的代码结构

        详细使用步骤见大佬文章:http://t.csdnimg.cn/mgdAX

import { defineStore } from 'pinia'

const useTimingInfoStore = defineStore('timingApproval', {
  state: () => ({
    testOne:  1, 
    testTwo:  2, 
  }),
  actions: {
    addSchemeData(data){
      this.testOne= data
    },
    addTimingData(data){
      this.testTwo= data
    }
  },
  getters: {
    doubleCount: (state) => state.testOne* 2
  }
})

export default useTimingInfoStore


// 组件中使用
import { useTimingInfoStore} from '@/stores/timingApproval';
const timingInfoStore = useTimingInfoStore()
console.log(timingInfoStore.testOne)

timingInfoStore.addSchemeData(2)

码字不易,望各位未来大牛点赞支持一波~

转载请注明出处或者链接地址:https://www.qianduange.cn//article/17257.html
标签
评论
发布的文章

JWT(JSON WEB TOKEN)详解

2024-09-10 23:09:36

NPM 常用命令(十二)

2024-09-10 23:09:24

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!