Vue3 和 Vue2 的异同及开发中具体区别
总体来说
性能提升
- 重写了虚拟DOM的实现(跳过静态节点,只处理动态节点)
- update性能提高1.3~2倍
- 服务端渲染速度提高了2~3倍
树摇(Tree shaking)
可以将无用模块“剪辑”掉,仅打包需要的
原理:
- ES6 Module引入进行静态分析,故而编译的时候正确判断到底加载了那些模块
- 静态分析程序流,判断那些模块和变量未被使用或者引用,进而删除对应代码
碎片化节点(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 对象
- ref 对象拥有一个指向内部值的单一属性 .value
- 当ref在模板中使用的时候,它会自动解套,无需在模板内额外书写 .value
import { ref } from "vue";
export default {
setup() {
let Num = ref(0),
isShow = ref(false);
return {
Num,
isShow
};
}
};
reactive
- 接收一个普通对象然后返回该普通对象的响应式代理等同于 2.x 的 Vue.observable()
- 响应式转换是“深层的”:会影响对象内部所有嵌套的属性
使用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
- watch API 完全等效于 2.x this.$watch
- watch 需要侦听特定的数据源,并在回调函数中执行副作用
- 默认情况是懒执行的,也就是说仅在侦听的源变更时才执行回调侦听单个数据源
点击查看代码
// 侦听器的数据源可以是一个拥有返回值的 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 的异同及开发中具体区别的更多相关文章
- px em rem在WEB前端开发中的区别
我们都知道基于像素的字体大小所用的单位是px,但是随着响应式设计的不断火热,基于相对字体大小的单位em变开始流行起来.当然,rem也在Web前端开发人员讨论如何更好设置字体大小的讨论话题之列.是不是需 ...
- Vue CLI 3开发中屏蔽的EsLint错误 (.eslintrc.js 在vue3+中 修改这个)
1.关闭eslint校验有了eslint的校验,可以来规范开发人员的代码,是挺好的.但是有些像缩进.空格.空白行之类的规范,在开发过程中一直报错,未免太过于苛刻了.所以,我还是会选择关闭eslint校 ...
- 想知道Vue3与Vue2的区别?五千字教程助你快速上手Vue3!
从Vue3发布以来,我就一直对其非常感兴趣,就一直想着将其投入公司的生产中,但是开始考虑到很多不确定性就暂时对一些很小的功能进行一些尝试:慢慢的发现组合式Api的形式非常适合开发(个人感觉),尤其是V ...
- vue3和vue2的区别
一.Vue3介绍 Vue 新版本的理念成型于 2018 年末,当时 Vue 2 的代码库已经有两岁半了.比起通用软件的生命周期来这好像也没那么久,但在这段时期,前端世界已经今昔非比了 在更新(和重写) ...
- MVP模式在Android开发中的应用
一.MVP介绍 随着UI创建技术的功能日益增强,UI层也履行着越来越多的职责.为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数据的可视化以及与用户的交互.同一 ...
- SQL开发中容易忽视的一些小地方(一)
原文:SQL开发中容易忽视的一些小地方(一) 写此系列文章缘由: 做开发三年来(B/S),发现基于web 架构的项目技术主要分两大方面: 第一:C#,它是程序的基础,也可是其它开发语言,没有开发语言也 ...
- vue2.0与实战开发
慕课网实战 百度云 web前端实战: Node.js入门到企业Web开发中的应用 Web前端性能优化 让你的页面飞起来 前端跳槽面试必备技巧 前端JavaScript面试技巧全套 node.JS 线上 ...
- 活到老学到老:iOS开发中的基础知识(一)
本文参考 标哥的博客:宝库iOS开发笔试题 进行学习整理.与其说是看面试题,不如说是对自己知识的巩固.工欲善其事必先利其器,基础知识不牢固可能会导致编程中的一些注意不到的问题.总之一句话:活到老,学到 ...
- C#中??和?分别是什么意思? 在ASP.NET开发中一些单词的标准缩写 C#SESSION丢失问题的解决办法 在C#中INTERFACE与ABSTRACT CLASS的区别 SQL命令语句小技巧 JQUERY判断CHECKBOX是否选中三种方法 JS中!=、==、!==、===的用法和区别 在对象比较中,对象相等和对象一致分别指的是什么?
C#中??和?分别是什么意思? 在C#中??和?分别是什么意思? 1. 可空类型修饰符(?):引用类型可以使用空引用表示一个不存在的值,而值类型通常不能表示为空.例如:string str=null; ...
- 使用Vue2+webpack+Es6快速开发一个移动端项目,封装属于自己的jsonpAPI和手势响应式组件
导语 最近看到不少使用vue制作的音乐播放器,挺好玩的,本来工作中也经常使用Vue,一起交流学习,好的话点个star哦 本项目特点如下 : 1. 原生js封装自己的跨域请求函数,支持promise调用 ...
随机推荐
- 利用kali自带的msfvenom工具生成远程控制软件
一.首先还是得打开postgresql service postgresql start 然后让我们看看它有哪些功能 部分参数 -p 选择一个载荷,或者说一个模块吧. -i 载荷列表 -f 生成的文件 ...
- C# Image 图片缩放 截取
从大图中截取一部分图片 /// <summary> /// 从大图中截取一部分图片 /// </summary> /// <param name="fromIm ...
- CornerNet-Lite:CornerNet粗暴优化,加速6倍还提点了 | BMVC 2020
论文对CornerNet进行了性能优化,提出了CornerNet-Saccade和CornerNet-Squeeze两个优化的CornerNet变种,优化的手段具有很高的针对性和局限性,不过依然有很多 ...
- archlinux xfce 修改用户主目录名称
操作有风险,修改用户主目录名称后一些链接了旧主目录的的链接可能仍未修改.导致链接用不了,需要手动指定链接 1.删除指定用户保存的会话,未删除应该会导致修改用户主目录名称后进不去会话 2.切换到其它用户 ...
- 字符串 Hash 的一些应用
字符串 Hash 可以快速的解决一类需要字符串匹配的问题.同时还可以以较小的思维量和代码量通过一些难题. P3809 [模板]后缀排序,这题的正解显然是 $\mathcal{O}(n\log n)$ ...
- 谈谈 OI 中的查重
鉴于最近洛谷的公开赛出现的重题引起的纠纷,我打算整理一下此类问题的危害和做法. 也许有时候无意的重题不会被处罚,但我想也应该尽量避免来换取选手的更好体验. Part 0 什么是重题 原题大致可分为完全 ...
- wordpress自建博客站,为文章添加显示浏览次数功能
wordpress自建博客站,为文章添加显示浏览次数功能 笔者使用的主题是 GeneratePress 版本:3.1.3 1.后台文章管理列表添加浏览次数列 效果如图: 实现: 编辑funct ...
- Fast多维数组
#include<iostream> #include<chrono> struct Timer { std::chrono::time_point<std::chron ...
- #差分约束系统#CodeChef Digit Matrix&洛谷 7515 [省选联考 2021 A 卷] 矩阵游戏
洛谷传送门 DGMATRIX 分析 先任意构造出一个不一定满足值域的矩阵,现在只需要满足值域就可以了. 可以发现,给一行或一列依次加一减一2*2矩阵的和仍然不变,并且如果有解一定能构造出一组方案. 因 ...
- OpenHarmony父子组件单项同步使用:@Prop装饰器
@Prop装饰的变量可以和父组件建立单向的同步关系.@Prop装饰的变量是可变的,但是变化不会同步回其父组件. 说明: 从API version 9开始,该装饰器支持在ArkTS卡片中使用. 概述 ...