快速了解Vue2.x与Vue3.x的差异
Vue3.x出来以后跟Vue2.x有很多写法上面的差异差异,最开始的创建就有一定的不同了,以前Vue2.x通过new Vue(),手动生成,并且全局API挂在Vue上,如下:
// vue2 import Vue from 'vue'; import App from './App.vue'; Vue.component('loading', {}) new Vue({ render: h => h(App) }).$mount('#app')
现在Vue3.x通过createApp实例化,并且全局API挂在vue实例上 app,如下:
// vue3 import { createApp } from 'vue' import ElementPlus from 'element-plus' import * as ElIconModules from "@element-plus/icons-vue"; import 'element-plus/dist/index.css' import App from './App.vue' import router from './router' import store from './store' const app = createApp(App) app.use(store) app.use(ElementPlus) app.use(router) app.component('loading', {}) Object.keys(ElIconModules).forEach(function (key) { app.component(ElIconModules[key].name, ElIconModules[key]); }); app.mount('#app')
以下还有一些差异跟大家分享一下
1. 生命周期钩子
① 2.x
export default { name: '', data() { return {} }, components: {}, methods: {}, computed: {}, beforeCreate() { console.log('beforeCreate 创建vue实例完成之前所执行的') }, created() { console.log('created 实例创建完成之后的,初始化data和methods') }, beforeMount() { console.log('beforeMount 开始编译把data里面的数据和vue语法生成html模板') }, mounted() { console.log('mounted 开始挂载编译生成的html渲染到页面') }, beforeUpdate() { console.log('beforeUpdate 当data里面数据改变时触发') }, updated() { console.log('updated data里面的数据和页面保持同步') }, beforeDestroy() { console.log('beforeDestroy vue实例从运行状态进入销毁状态,data、methods、指令等还处于可用状态') }, destroyed() { console.log('destroyed 组件完全被销毁,data、methods、指令等已经不可用了') }}
② 3.x
export default defineComponent({ name: "ed", props: { title: { type: String, default: "", }, }, //setup取消了beforeCreate和created在beforeCreate和created之前执行 setup(porps, { emit }) { onBeforeMount(() => { console.log("onBeforeMount - 组件挂载到节点上之前执行的函数"); }); onMounted(() => { console.log("onMounted - 组件挂载完成后执行的函数"); }); onBeforeUpdate(() => { console.log("onBeforeUpdate - 组件更新之前执行的函数"); }); onUpdated(() => { console.log("onUpdated - 组件更新完成之后执行的函数"); }); onBeforeUnmount(() => { console.log("onBeforeUnmount - 组件卸载之前执行的函数"); }); onUnmounted(() => { console.log("onUnmounted - 组件卸载完成后执行的函数"); }); const state = reactive({ //数据 username: "", password: "", lowerCaseUsername: computed(() => state.username.toLowerCase()), //计算属性 }); //方法 const fn= () => {}; return { fn, onMounted, ...toRefs(state), }; }, computed: {}, components: {}, data() { return {}; }, methods: {},});
以上可以看出vue2.0和3.0差异
Vue2--------------Vue3
beforeCreate----setup()
created----setup()
beforeMount----onBeforeMount
mounted----onMounted
beforeUpdate---- onBeforeUpdate
updated ---- onUpdated
beforeDestroy ---- onBeforeUnmount
destroyed ---- onUnmounted
并且还可以看出vue2.0中响应性数据一般都在data,computed,方法基本都是局限在methods中使用,而3.0响应性数据正常可以通过引入的reactive,把数据放入reactive中,通过setup()方法来返回我们的响应性数据,函数可以直接放在setup中并return出去,这使代码会更加简便和整洁
2.双向数据绑定原理
Vue2.x 基于Object.definePropert()对数据进行劫持 结合 发布订阅模式的方式来实现的。 Vue3.x基于Proxy来做数据大劫持代理,可以原生支持到数组的响应式,不需要重写数组的原型,还可以直接支持新增和删除属性,比Vue2.x的Object.defineProperty更加的清晰明了。
proxy和definePropert差异:
proxy相比于definePropert,defineProperty只能监听某个属性,不能对全对象监听,proxy可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可),也可以监听数组,不用再去单独的对数组做特异性操作 vue3.x可以检测到数组内部数据的变化,但是proxy无法兼容全部浏览器,无法polyfill
3.支持碎片
vue2只能有一个节点
<template> <div class="form"> <h3></h3> </div></template>
vue3可以有多个节点
<template> <div class="form"></div> <h3></h3></template>
4.取消filter
2.x经常在组件中可以使用filter,但在 3.x 中,过滤器已移除,且不再支持。建议可以使函数方法调用或计算属性来替换它们。
5. 函数组件写法改变 - h
在 2.x 中,render 函数会自动接收 h 函数当一个参数
// vue2Vue.component('loading', {render(h) {return h('div', {title: ''}, [''])},})
在 3.x 中,h 函数现在是全局通过vue导入的,而不是作为参数自动传递。
// vue3import { h } from 'vue'app.component('loading', {render(props, context) {return h('div', {title: ''}, [''])},})
6. router、vuex、refs的以及nextTick使用
// vue2<div ref="popover"></div>import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'// 字符串this.$router.push('home')// 对象this.$router.push({path: '/login?url=' + this.$route.path});// 命名的路由this.$router.push({ name: 'user', params: { userId: 123 }})// 带查询参数,变成/backend/order?selected=2this.$router.push({path: '/backend/order', query: {selected: "2"}});//访问store属性下state下面的namethis.$store.state.name//访问store里的user.js的login方法,从而要更新。this.$store.dispatch(‘Login’, this.loginForm)//this.$nextTick(() => { console.log(this.$refs.popover)});methods: { ...mapMutations({add:'JIA',jf:'JIAN'}), ...mapActions(['jadd','delayAdd'])},
// vue3<div ref="popover"></div>import{ nextTick , ref} from "vue";import { useRouter } from "vue-router";import { mapGetters } from "vuex";import { useStore } from "vuex";export default defineComponent({ setup() { const popover= ref(null); const router = useRouter(); const store = useStore(); const state = reactive({ urls: "", user: '', }); const toggleSideBar = () => { store.dispatch("app/toggleSideBar"); }; const goTO = () => { router.push({ path: "/user/info" }); }; onMounted(() => { nextTick(() => { console.log(popover.value) }) }); return { toggleSideBar, ...toRefs(state), onMounted, goTO, popover }; }, computed: { ...mapGetters(["sidebar", "avatar", "device", "name"]), }, components: { }, data() { return {}; },});
7.computed和watch区别
//vue2 watch:{ 'form.minimumChargeAmount':{ handler(val){ console.log(val) } }, name(newValue, oldValue){ console.log("修改了name", newValue, oldValue); }, result: { immediate: true, deep: true, handler(newValue, oldValue) { console.log("修改了result", newValue, oldValue); }, }, },computed: { totalPage: function () { return Math.ceil(this.total / this.pageSize); }, fullName: { get() { return this.firstName + "-" + this.lastName; }, set(val) { const nameArr = val.split("-"); this.firstName = nameArr[0]; this.lastName = nameArr[1]; }, },}
//vue3import { defineComponent, reactive, computed, toRefs, watch, ref, watchEffect,} from "vue";export default defineComponent({ name: "", setup() { const state = reactive({ //数据 username: "", password: "", lowerCaseUsername: computed(() => state.username.toLowerCase()), //计算属性 demo: "demo", name1: "1", name2: "2", }); let name = computed(() => state.name1 + "-" + state.name2); let sure = computed({ get() { return state.name1 + "-" + state.name2; }, set(val) { const nameArr = val.split("-"); state.name1 = nameArr[0]; state.name2 = nameArr[1]; }, }); //监听指定对象下面的属性 // watch( // () => state.demo, // (newValue, oldValue) => { // console.log("state.demo", newValue, oldValue); // }, // { // immediate: true, // } // ); let sum = ref(0); let msg = ref("watch使用"); // 监视ref所定义的多个响应式数据 watch( [sum, msg], ([s, m], [olds, oldm]) => { console.log("sum/msg变化", s, m, olds, oldm); }, { immediate: true } ); watchEffect(() => { console.log("监听state.demo", state.demo); }); return { ...toRefs(state), name, sure, sum, msg, }; }, components: {}, data() { return {}; },});