总体来说

性能提升

  1. 重写了虚拟DOM的实现(跳过静态节点,只处理动态节点)
  2. update性能提高1.3~2倍
  3. 服务端渲染速度提高了2~3倍

树摇(Tree shaking)

可以将无用模块“剪辑”掉,仅打包需要的

原理:

  1. ES6 Module引入进行静态分析,故而编译的时候正确判断到底加载了那些模块
  2. 静态分析程序流,判断那些模块和变量未被使用或者引用,进而删除对应代码

参考:介绍一下 tree shaking 及其工作原理

碎片化节点(Fragment)

在 vue2.x 中,每个组件只能有一个根,所以,写每个组件模板时都要套一个父元素。

在 vue3 中,为了更方便的书写组件模板,新增了一个类似 dom 的标签元素 ,也就是 vue3 中组件可以拥有多个根了。

这样做的好处在于:减少标签层级, 减小内存占用。

传送门 (Teleport)

可以将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去。

Suspense

用于协调对组件树中嵌套的异步依赖的处理。

如果在渲染时遇到异步依赖项 (异步组件和具有 async setup() 的组件),它将等到所有异步依赖项解析完成时再显示默认插槽。

https://cn.vuejs.org/api/built-in-components.html#suspense

更好的TypeScript支持

Composition API

组合式API,替换原有的 Options API

根据逻辑相关性组织代码,提高可读性和可维护性

更好的重用逻辑代码(避免mixins混入时命名冲突的问题)

兼容了VUE2中的写法,原有Options API依然可以延用

响应式原理

不再基于 Object.defineProperty而是基于ES6中的Proxy

开发时差异

0. setup

组合式API以setup函数作为组件的入口

<script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。当同时使用 SFC 与组合式 API 时该语法是默认推荐。相比于普通的 <script> 语法,它具有更多优势:

  • 更少的样板内容,更简洁的代码。
  • 能够使用纯 TypeScript 声明 props 和自定义事件。
  • 更好的运行时性能 (其模板会被编译成同一作用域内的渲染函数,避免了渲染上下文代理对象)。
  • 更好的 IDE 类型推导性能 (减少了语言服务器从代码中抽取类型的工作)。
// setup 函数的第一个参数是组件的 props
// 没有vue2.x中的this指向vue对象了
export default {
props: {
title: String
},
setup(props) {
console.log(props.title)
}
}

1. 生命周期调用

<script setup>
// 在vue中解构出方法
import { onMounted, onUpdated } from 'vue' onMounted(() => {
...
}) onUpdated(() => {
...
})
</script>

beforeCreate -> 使用 setup()

created -> 使用 setup()

beforeMount -> onBeforeMount

mounted -> onMounted

beforeUpdate -> onBeforeUpdate

updated -> onUpdated

beforeDestroy -> onBeforeUnmount

destroyed -> onUnmounted

errorCaptured -> onErrorCaptured

2. 响应式(数据)API

ref

接受一个参数值并返回一个响应式且可改变的 ref 对象

  1. ref 对象拥有一个指向内部值的单一属性 .value
  2. 当ref在模板中使用的时候,它会自动解套,无需在模板内额外书写 .value
import { ref } from "vue";
export default {
setup() {
let Num = ref(0),
isShow = ref(false); return {
Num,
isShow
};
}
};

reactive

  1. 接收一个普通对象然后返回该普通对象的响应式代理等同于 2.x 的 Vue.observable()
  2. 响应式转换是“深层的”:会影响对象内部所有嵌套的属性

使用toRefs(state)可将其创建的传为Refs类型,方便在模板中直接取值,而不用.value

import { ref, reactive } from "vue";
export default {
props: { title: String },
setup() {
let state = reactive({
Num: 0,
arr: [1, 2]
});
let change = () => {
state.arr[0] = state.arr[0] + 1;
state.name = "flytree";
}; return {
state,
change
};
}
};

相关的一些方法:

unref / toRef / toRefs / isRef / isProxy / isReactive / isReadonly

3.计算属性computed

传入一个 getter 函数,返回一个默认不可手动修改的 ref 对象

const count = ref(1);
const plusOne = computed(() => count.value + 1);
console.log(plusOne.value); //2
plusOne.value++; //错误!

或者传入一个拥有 get 和 set 函数的对象,创建一个可手动修改的计算状态

const count = ref(1);
const plusOne = computed({
get: () => count.value + 1,
set: val => {
count.value = val - 1;
}
});
plusOne.value = 1;
console.log(count.value); //0

4.侦听器watch

watchEffect

立即执行传入的一个函数,并响应式追踪其依赖,并在其依赖变更时重新运行该函数

export default {
props: {
title: String,
},
setup(props) {
watchEffect(() => {
console.log(`title is: ` + props.title);
});
}
};

watch

  1. watch API 完全等效于 2.x this.$watch
  2. watch 需要侦听特定的数据源,并在回调函数中执行副作用
  3. 默认情况是懒执行的,也就是说仅在侦听的源变更时才执行回调侦听单个数据源
点击查看代码
// 侦听器的数据源可以是一个拥有返回值的 getter 函数,也可以是 ref
const state = reactive({ count: 0 })
watch(
() => state.count,
(count, prevCount) => {
/* ... */
}
); const count = ref(0)
watch(count, (count, prevCount) => {
/* ... */
});
import { ref, reactive, toRefs, computed, watch } from "vue";
export default {
setup() {
.... let ratio = ref("--");
watch(state, (state, preState) => {
let total = state.supNum + state.oppNum;
ratio.value =
total === 0 ? "--" : ((state.supNum / total) * 100).toFixed(2) + "%";
}); return {
...,
ratio
};
}
};

5. 获取DOM元素refs

模板的Refs

当使用组合式 API 时,reactive refs 和 template refs 的概念已经是统一的

点击查看代码
<template>
<div ref="root"></div>
</template> <script>
import { ref, onMounted } from 'vue';
export default {
setup() {
const root = ref(null);
onMounted(() => {
console.log(root.value);
});
return {
root
};
}
}
</script>

6. 路由使用, VUEX ,VUE挂载

先要解构出方法,再去创建对应路由,store或vue对象,其它一样

Vue Router 4.x


import { createRouter, createWebHashHistory } from 'vue-router';
import routes from './routes'; const router = createRouter({
history: createWebHashHistory(),
routes
}); router.beforeEach(async (to, from, next) => { ... })
export default router;

Vue Router 3.x

import VueRouter from 'vue-router'
import routes from './routes'; const router = new VueRouter({
routes
})
export default router;

VUEX 4.x

import { createStore, createLogger } from 'vuex';
export default createStore({
state: {},
mutations: {},
actions: {},
plugins: [createLogger()]
})

VUEX 3.x

import Vue from 'vue'
import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({
state: {},
state: {},
mutations: {},
actions: {},
})
export default store

实例创建

VUE 3.x

import { createApp } from 'vue';
const app = createApp(App);
app.use(store);
app.use(router);
app.mount('#app');

VUE 2.x

import Vue from 'vue'

new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')

7. 自定义指令处理技巧

export default function directive(app) {
app.directive('xxx', {
// 指令首次绑定到元素且在安装父组件之前...「等同于bind」
beforeMount(el, binding, vnode, prevVnode) {
// binding:数据对象
// + arg:传给指令的参数 v-xxx:n -> arg:"n"
// + modifiers:修饰符对象 v-xxx.stop -> modifiers:{stop:true}
// + value:指令绑定的值 v-xxx="1+1" -> value:2
// + oldValue:之前绑定的值
},
// 安装绑定元素的父组件时...「等同于inserted」
mounted() {},
// 在包含组件的VNode更新之前...
beforeUpdate() {},
// 在包含组件的VNode及其子VNode更新后...「等同于componentUpdated」
updated() {},
// 在卸载绑定元素的父组件之前...
beforeUnmount() {},
// 指令与元素解除绑定且父组件已卸载时...「等同于unbind」
unmounted() {}
});
};
// main.js
import {
createApp
} from 'vue';
import App from './App.vue';
import directive from './directive';
const app = createApp(App);
directive(app);
app.mount('#app');

8.emit

在子组件向父组件传值,或者发送事件时,我们通常使用emit,进行操作。

because composition functions are used inside the setup hook which doesn't have access to the other options like methods and emits:

export default defineComponent({
name: "layout",
emits: ['showsidebar'],
setup(props, { emit }) {
const showSidebar = ref(true);
const { breakpoints } = useBreakpoint();
watch(breakpoints, (val) => {
showSidebar.value = !(val.is === "xs" || val.is === "sm");
emit('showsidebar',showSidebar.value);
});
return {
showSidebar,
};
},
data() {
// ...
},
});
<script setup>
import { defineEmits,watch,ref } from 'vue' const emit = defineEmits(['showsidebar'])
const showSidebar = ref(true);
const { breakpoints } = useBreakpoint();
watch(breakpoints, (val) => {
showSidebar.value = !(val.is === "xs" || val.is === "sm");
emit('showsidebar',showSidebar.value);
});
</script> <script setup>
const emit = defineEmits({
// No validation
inFocus: null, // Validate submit event
submit: ({ email, password }) => {
if (email && password) return true
else return false
}
}) function submitForm(email, password) {
emit('submit', { email, password })
}
</script> // Typing with TS:
<script setup lang="ts">
const emit = defineEmits<{
(e: 'change', id: number): void
(e: 'update', value: string): void
}>()
</script>

Vue3 和 Vue2 的异同及开发中具体区别的更多相关文章

  1. px em rem在WEB前端开发中的区别

    我们都知道基于像素的字体大小所用的单位是px,但是随着响应式设计的不断火热,基于相对字体大小的单位em变开始流行起来.当然,rem也在Web前端开发人员讨论如何更好设置字体大小的讨论话题之列.是不是需 ...

  2. Vue CLI 3开发中屏蔽的EsLint错误 (.eslintrc.js 在vue3+中 修改这个)

    1.关闭eslint校验有了eslint的校验,可以来规范开发人员的代码,是挺好的.但是有些像缩进.空格.空白行之类的规范,在开发过程中一直报错,未免太过于苛刻了.所以,我还是会选择关闭eslint校 ...

  3. 想知道Vue3与Vue2的区别?五千字教程助你快速上手Vue3!

    从Vue3发布以来,我就一直对其非常感兴趣,就一直想着将其投入公司的生产中,但是开始考虑到很多不确定性就暂时对一些很小的功能进行一些尝试:慢慢的发现组合式Api的形式非常适合开发(个人感觉),尤其是V ...

  4. vue3和vue2的区别

    一.Vue3介绍 Vue 新版本的理念成型于 2018 年末,当时 Vue 2 的代码库已经有两岁半了.比起通用软件的生命周期来这好像也没那么久,但在这段时期,前端世界已经今昔非比了 在更新(和重写) ...

  5. MVP模式在Android开发中的应用

    一.MVP介绍      随着UI创建技术的功能日益增强,UI层也履行着越来越多的职责.为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数据的可视化以及与用户的交互.同一 ...

  6. SQL开发中容易忽视的一些小地方(一)

    原文:SQL开发中容易忽视的一些小地方(一) 写此系列文章缘由: 做开发三年来(B/S),发现基于web 架构的项目技术主要分两大方面: 第一:C#,它是程序的基础,也可是其它开发语言,没有开发语言也 ...

  7. vue2.0与实战开发

    慕课网实战 百度云 web前端实战: Node.js入门到企业Web开发中的应用 Web前端性能优化 让你的页面飞起来 前端跳槽面试必备技巧 前端JavaScript面试技巧全套 node.JS 线上 ...

  8. 活到老学到老:iOS开发中的基础知识(一)

    本文参考 标哥的博客:宝库iOS开发笔试题 进行学习整理.与其说是看面试题,不如说是对自己知识的巩固.工欲善其事必先利其器,基础知识不牢固可能会导致编程中的一些注意不到的问题.总之一句话:活到老,学到 ...

  9. C#中??和?分别是什么意思? 在ASP.NET开发中一些单词的标准缩写 C#SESSION丢失问题的解决办法 在C#中INTERFACE与ABSTRACT CLASS的区别 SQL命令语句小技巧 JQUERY判断CHECKBOX是否选中三种方法 JS中!=、==、!==、===的用法和区别 在对象比较中,对象相等和对象一致分别指的是什么?

    C#中??和?分别是什么意思? 在C#中??和?分别是什么意思? 1. 可空类型修饰符(?):引用类型可以使用空引用表示一个不存在的值,而值类型通常不能表示为空.例如:string str=null; ...

  10. 使用Vue2+webpack+Es6快速开发一个移动端项目,封装属于自己的jsonpAPI和手势响应式组件

    导语 最近看到不少使用vue制作的音乐播放器,挺好玩的,本来工作中也经常使用Vue,一起交流学习,好的话点个star哦 本项目特点如下 : 1. 原生js封装自己的跨域请求函数,支持promise调用 ...

随机推荐

  1. springboot 低于 2.6 版本设置 SameSite=None,springboot 1.x set SameSite=none in embedded tomcat

    speingboot 使用自带的 tomcat 运行,设置 SameSite. springboot 过低的版本没有 SameSite 的属性设置,升级到 1.5.22 版本后,虽然 Rfc6265C ...

  2. 应急响应靶机训练-Linux2

    靶机来源: 知攻善防实验室公众号 https://mp.weixin.qq.com/s/xf2FgkrjZg-yWlB9-pRXvw 我是在另一台主机上通过ssh连接到靶机进行解题的,我的ip为192 ...

  3. OpenCV 方法及应用速查表

    序  号 方    法 说    明 技术分类 1 image = cv2.imread(filename, flags) 读取图像 基本操作 2 cv2.imshow(winname, mat) 显 ...

  4. d3d12龙书阅读----绘制几何体(上)

    d3d12龙书阅读----绘制几何体(上) 本节主要介绍了构建一个简单的彩色立方体所需流程与重要的api 下面主要结合立方体代码分析本节相关知识 顶点 输入装配器阶段的输入 首先,我们需要定义立方体的 ...

  5. Android记账本界面实现

    <!--activity_main.xml-->1 <?xml version="1.0" encoding="utf-8"?> 2 & ...

  6. 【已解决】ERROR 2003 (HY000): Can't connect to MySQL server on 'localhost' (10061)---mysql数据库本地服务器localhost连接失败

    出现错误mysql数据库本地服务器localhost连接失败: 1.输入命令 mysql -uroot -p  输入密码进入数据库发现错误 2.输入命令 mysqld --install 出现Serv ...

  7. 使用OHOS SDK构建filament

    参照OHOS IDE和SDK的安装方法配置好开发环境. 从gitee下载源码. 执行如下命令: git clone https://gitee.com/oh-graphics/filament.git ...

  8. OpenHarmony社区运营报告(2023年5月)

      本月快讯 ● 2023年6月11-13日,2023开放原子全球开源峰会即将在北京北人亦创国际会展中心盛大开幕.2023开放原子全球开源峰会上,OpenAtom OpenHarmony(以下简称&q ...

  9. 我为OpenHarmony 写代码,战“码”先锋第二期正式开启!

    OpenAtom OpenHarmony(以下简称"OpenHarmony")问世以来,两年多时间汇聚了160万+社区用户,全球下载次数高达6300万,5.5万+次代码提交,吸引了 ...

  10. 常用的Numpy通用函数列表

    官网来源:Universal functions (ufunc) - NumPy v1.21 Manual 数学运算(Math operations) 表达式 定义 add(x1, x2, /[, o ...