前端|简述 vue3.0与2.0区别

1.Templatefragments碎片
组件可以拥有多个根节点,解决多个div嵌套问题
2.数据获取
Vue3的数据获取在反应数据(Reactive Data)中,通常包含在一个反应状态(Reactive State)变量中。(reactive的作用是将对象包装成响应式对象,通过Proxy代理后的对象。)
响应式原理: Proxy代理拦截:reactive函数执行,会将传入的target对象通过Proxy包装,拦截它的get,set等,并将代理的target缓存。(组件在render阶段,视图会读取数据对象上的值进行渲染,此时便触发了Proxy的get,由此触发对应的track函数,记录下了对应的ReactiveEffect,也就是常说的依赖收集。)

1).Ref与reactive区别:
reactive 和 ref 都是用来定义响应式数据的, reactive更推荐去定义复杂的数据类型, ref 更推荐定义基本类型,ref 和 reactive 本质我们可以简单的理解为ref是对reactive的二次包装, ref定义的数据访问的时候要多一个.value。(ref定义基本数据类型,ref也可以定义数组和对象)
2).判断数据到底是ref还是reactive?
通过isRef / isReactive 方法,对当前数据的__v_ref来判断的,如果有这个私有的属性, 并且取值为true, 那么就代表是一个ref类型的数据
3.响应式数据
在Vue3.0,我们就需要使用一个新的setup()方法,此方法在组件初始化构造的时候触发。
使用以下三步来建立反应性数据:
1)从vue引入reactive
2)使用reactive()方法来声名我们的数据为反应性数据
【前端|简述 vue3.0与2.0区别】3)使用setup()方法来返回我们的反应性数据,从而template可以获取这些反应性数据

import { reactive } from 'vue' export default { props: { title: String }, setup () { const state = reactive({ username: '', password: '' })return { state } }}

这里构造的反应性数据就可以被template使用,可以通过state.username和state.password获得数据的值,需要先声名一个方法然后在setup()方法中返回(return), 在组件内就可以调用这个方法了。
4.methods方法
Vue3 的合成型API里面的setup()方法也是可以用来操控methods的。创建声名方法其实和声名数据状态是一样的。需要先声名一个方法然后在setup()方法中返回(return), 这样组件内就可以调用这个方法了。
export default { props: { title: String }, setup () { const state = reactive({ username: '', password: '' })const login = () => { // 登陆方法} return { login, state } }}

5.生命周期钩子
现在 Vue3 的合成型API里面的setup()方法可以包含了基本所有东西。生命周期的钩子就是其中之一!但是在 Vue3 生周期钩子不是全局可调用的了,需要另外从vue中引入,生命周期的挂载钩子叫onMounted,引入后我们就可以在setup()方法里面使用onMounted挂载的钩子了。(与2.0生命周期相似,在前面加了on,setup这个生命周期发生在beforeCreate和created之前,此时无法访问data、computed、methods、refs )
6.计算属性 - Computed Properties
Vue3 的设计模式给予开发者们按需引入需要使用的依赖包,在 Vue3 使用计算属性,需要在组件内引入computed。使用方式就和反应性数据(reactive data)一样,在state中加入一个计算属性。(计算属性可以写在声明的响应式变量内,也可单独声明使用)
setup () { const state = reactive({ username: '', password: '', lowerCaseUsername: computed(() => state.username.toLowerCase()) }) const twiceTheCounter = computed(() => counter.value * 2)

7.接收 Props
接收组件props参数传递这一块为我们带来了Vue2和Vue3之间最大的区别。在 Vue2,this代表的是当前组件,不是某一个特定的属性。所以我们可以直接使用this访问prop属性值。就比如下面的例子在挂载完成后打印处当前传入组件的参数title。在 Vue3 中,this无法直接拿到props属性,emit events(触发事件)和组件内的其他属性。不过全新的setup()方法可以接收两个参数:1.props - 不可变的组件参数
2.context - Vue3 暴露出来的属性(emit,slots,attrs)
setup (props,context) { //Context的使用(// attrs (非响应式对象,等同于 $attrs用于简介传参,slots插槽 非响应式对象,等同于 $slots,emit触发事件方法,等同于 $emit,expose 暴露公共property 函数,将setup里的内容暴露到外部) onMounted(() => { console.log('title: ' + props.title) })一个项目使用 //父组件里的子组件 //子组件的内容

8.模板引用
为了获得对模板内元素或组件实例的引用,一样声明 ref 并从 setup() 返回:

这里在渲染上下文中暴露root,并通过ref=”root”,将其绑定到div作为其ref。(在虚拟dom补丁算法中,若Vnode的ref键对应于渲染上下文中的 ref,则 VNode 的相应元素或组件实例将被分配给该 ref 的值。这是在虚拟 DOM 挂载/打补丁过程中执行的,因此模板引用只会在初始渲染之后获得赋值,即在onMounted生命周期中)
9.watch监听
使用从 Vue 导入的 watch 函数执行相同的操作。它接受 3 个参数:
  1. 一个想要侦听的响应式引用或 getter 函数
  2. 一个回调
  3. 可选的配置选项
import {watch } from 'vue' //一个变量 const counter = ref(0) //监听函数 watch(监听的值,回调,可选的配置选项) watch(counter, (newValue, oldValue) => { console.log('The new counter value is: ' + counter.value) })


注意:侦听模板引用的变更可以替代前面例子中演示使用的生命周期钩子。
但与生命周期钩子的一个关键区别是watch() 和 watchEffect()在 DOM 挂载或更新之前运行副作用,所以当侦听器运行时,模板引用还未被更新。因此,使用模板引用的侦听器应该用 flush: 'post' 选项来定义,这将在 DOM 更新后运行,确保模板引用与 DOM 保持同步。
watchEffect(() => { console.log(root.value) // => This is a root element }, { flush: 'post' })

10.Mixin
简述:Mixin 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个 mixin 对象可以包含任意组件选项。当组件使用 mixin 对象时,所有 mixin 对象的选项将被“混合”进入该组件本身的选项。
局部mixins的配置:
export const mixin1 = { methods: { showName(){ alert('第一个mixin') } }, mounted() { console.log('你好啊!') },} export const mixin2 = { data() { return { sum:100 } }, methods: { showName(){ alert('第二个mixin') } }, }

全局注册:全局mixins 对vm,和所有vm均进行mixins
//引入Vue import Vue from 'vue' //引入App import App from './App.vue' import {mixin1,mixin2} from '../mixin' //关闭Vue的生产提示 Vue.config.productionTip = false Vue.mixin(mixin1) Vue.mixin(mixin2) //创建vm new Vue({ el:'#app', render: h => h(App) })

11.自定义组件
除了核心功能默认内置的指令 (例如 v-model 和 v-show),Vue 也允许注册自定义指令。注意,在 Vue 中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。
举个聚焦输入框的例子,如下:
//全局注册 const app = Vue.createApp({})// 注册一个全局自定义指令 `v-focus` app.directive('focus', { // 当被绑定的元素挂载到 DOM 中时…… mounted(el) { // 聚焦元素 el.focus() }}) 注册局部指令: directives: { focus: { // 指令的定义 mounted(el) { el.focus() } }}注册局部指令: directives: { focus: { // 指令的定义 mounted(el) { el.focus() } }} 使用方式: 使用方式

12. 路由变化
传参和原来一样,取参发生改变:
Params传参: 点击跳转到home页面并传参 vue3.0中import { useRoute } from 'vue-router' const route = useRoute() console.log(route.params.id); //111 query传参: test //接受的时候 import { useRoute } from 'vue-router' const route = useRoute() console.log(route.query.id); //999 Js传参方式: import { useRouter } from 'vue-router' const route = useRouter() route.push({ path:"/lianxi", query:{ id:666 } }); route.push({ name:'lianxi', params:{ id:666 } }); import { useRoute } from 'vue-router' const route = useRoute() console.log(route.query.id); //999

13.总结
现在基本都看到vue2与vue3其实概念与理念都是一样的。只是有一些属性获取方式和声名和定义方式稍微变了。总结一下,我觉得 Vue3 给我们前端开发者带来了全新的开发体验,更好的使用弹性,可控度也得到了大大的提升。全新的合成式API(Composition API)可以提升代码的解耦程度 —— 特别是大型的前端应用,效果会更加明显。还有就是按需引用的有了更细微的可控性,让项目的性能和打包大小有更好的控制。
案例项目代码整理:


    推荐阅读