写点什么

手把手带你初探 Vue 3.0 | 京东物流技术团队

  • 2023-07-24
    北京
  • 本文字数:3227 字

    阅读完需:约 11 分钟

手把手带你初探Vue 3.0 | 京东物流技术团队

1 前言

距离 Vue 3.0 正式发布已经过去一段时间了,2 月 7 日 Vue 团队正式宣布 Vue 3 正式成为新的默认版本。最近接触的新项目也使用 Vue 3.0 来开发,因此有必要对它进行一波总结和学习。

2 简介

在最开始的时候,Vue 仅仅是一个运行时库。但经过多年的发展,它已经逐渐变成了一台包含许多子项目的框架。Vue 的核心库只关注图层,不仅易于上手,还便于与第三方库或既有项目整合。那么 Vue 3.0 带来了哪些新的表现呢?


  • 重写了虚拟 Dom

  • 编译模板的优化

  • 更高效的组件初始化

  • SSR 速度提高了 2~3 倍

  • 更新性能提高了 1.3~2 倍

  • 看起来 Vue 3 相比于 2 性能上有了很大的提升,作为终端用户的我们,还是来看看代码是如何实现的吧。

3 新的特性

3.1 组合式 API

Vue 2 中采用的是 Options API(选项式 API),即在 data、methods、computed、watch 中分别写入代码,如果我们需要增加一个逻辑,就需要在这些选项中反复横跳,导致组件难以理解和阅读。Vue 3 新增了 setup 选项,它是组合式 API 的入口。它将同一个逻辑关注点相关代码收集在一起,这样我们需要维护一个功能点的时候,就不需要去关心其他的逻辑。



举个例子


<template>  <div>{{number}}</div>  <button @click="add">Add</button></template>
<script>import { ref } from 'vue'
export default { setup () { const number = ref(0) //ref()函数使变量变为响应式 const add = () => { number.value++ //使用ref创建的响应式变量需要加.value } return { //返回的变量和方法可以在模板中直接使用 number, add } }}</script>
复制代码


这看起来不就是把 data、methods 中的内容都放到 setup 里了吗,也没多大区别啊?其实,我们还可以把 setup 里面的内容分割成一个个独立的函数,每个函数负责独立的功能。这样,我们就可以在不同组件中进行复用,简洁代码,这才是组合式 API 的强大之处。

3.2 响应式 API

3.2.1 ref

在上面的代码中我们使用了 ref 创建了响应式对象,它接受 js 基本类型或引用类型作为参数,返回的就是一个只包含名为 value 参数的 RefImp 对象。在 setup 函数中如果我们要使用该响应式对象,就需要加上.value。但是在模板中被渲染时,自动展开内部的值,因此不需要在模板中追加.value。


ref 常用于基础类型,如果 ref 传入对象,其内部会转换为 reactive 进行处理。


import { ref } from "vue";const str = ref("");const male = ref(true);
str.value = "new val";console.log(str.value); //new val
male.value = false;console.log(male.value) //fals
复制代码

3.2.2 reactive

reactive 函数只接收 object 和 array 等复杂数据类型,它会返回一个 proxy 对象。reactive 可以深层次递归,也就是如果发现展开的属性值是引用类型的而且被引用,还会用 reactive 递归处理。而且属性是可以被修改的。 proxy 是 es6 中用于创建一个对象的代理函数,可以实现对目标对象的增删改查等基本操作的拦截和自定义。


const p=new Proxy(target,handler) //target是proxy包装的目标对象,handler是一个以函数作为属性的对象
复制代码


简单模拟实现 reactive 实现响应式:


      const obj={a:1,b:2}      const p=new Proxy(obj,{          get(target,key){            console.log(`p的${key}属性被访问了!`)            return Reflect.get(target,key)          },          set(target,key,value){            console.log(`p的${key}属性被修改了!`)            return Reflect.set(target,key,value)          },          deleteProperty(target,key){            console.log(`p的${key}属性被删除了!`)            return Reflect.deleteProperty(target,key)          }        })
复制代码


3.2.3 toRefs

通过上面的介绍我们已经知道了 ref 通常用来创建基础类型数据的双向绑定,reactive 通常用来创建引用数据类型的双向绑定。除此之外,ref 也可以创建复杂类型的双向绑定,而 reactive 不能代理基础类型。我们来看一个例子:


<template>  <div>{{user.name}}</div>  <div>{{user.age}}</div>  <div>{{user.sex}}</div>  <button @click="changeInfo">更改个人信息</button></template>
<script>import { ref } from 'vue'
export default { setup () { const user = ref({name:'张三',age:'18',sex:'男'}) const changeInfo = () => { user.name.value='李四' user.age=20 user.sex='女' } return { user } }}</script>
复制代码


上面的代码中我们绑定到页面使用的是 user.name,user.age,这样写感觉很繁琐,那能通过解构解构 user 然后在模板中直接使用吗?答案是不能的,这样做会使 user 丢失掉响应式。但是通过使用 toRefs,就可以直接使用解构后的数据了。 toRefs 用于将一个 reactive 对象转化为属性全部为 ref 对象的普通对象。具体使用方式如下:


<template>  <div>{{name}}</div>  <div>{{age}}</div>  <div>{{sex}}</div>  <button @click="changeInfo">更改个人信息</button></template>
<script>import { ref } from 'vue'
export default { setup () { const user = ref({name:'张三',age:'18',sex:'男'}) const changeInfo = () => { user.name.value='李四' user.age=20 user.sex='女' } return { ...toRefs(user) //使用toRefs } }}
复制代码

3.3 响应式侦听

watch 函数用来侦听特定的数据源,并在回调函数中执行副作用。默认情况是惰性的,也就是说仅在侦听的源数据变更时才执行回调。


watch(source,callback,[options])
复制代码


  • source:可以支持 string,Object,Function,Array; 用于指定要侦听的响应式变量

  • callback:执行的回调函数

  • options:可选项,支持 deep、immediate 和 flush


监听单个数据源的用法:


import { reactive, ref, watch } from "vue";
const state = reactive({ number:0, id:'01'});//侦听reative对象watch( () => state.number, (newvalue, oldvalue) => { console.log(newvalue, oldvalue); //1 0 });state.number++;
const count = ref(0);//侦听ref对象watch(count, (count, prevCount) => { console.log(count, prevCount, "watch"); //2 0});count.value = 2
复制代码


监听多个数据源的用法:


import { reactive, ref, watch } from "vue";

const state = reactive({ number:0, id:'01'});const count = ref(0);watch([count,()=>{state.number}],([curcount,precount],[curnumber,prenumber])=>{ console.log(curcount,precount) //2 0 console.log(curnumber,prenumber) //1 0})state.number++count.value=2
复制代码


对于多层嵌套的引用对象,可以使用{deep:true}开启深度监听。否则仅能监听到外层数据变化。前面提到,默认清空下 watch 的回调函数是惰性的,只有当监听数据变化时才会执行。当配置{immediate: true}时,可以立即执行回调函数。

3.4 生命周期

在 Vue2 中有 8 个生命周期函数:


  • beforeCreate

  • created

  • beforeMount

  • mounted

  • beforeUpdate

  • updated

  • beforeDestroy

  • destroyed


在 vue3 中,新增了一个 setup 生命周期函数,setup 执行的时机是在 beforeCreate 生命函数之前执行,因此在这个函数中是不能通过 this 来获取实例的;同时为了命名的统一,将 beforeDestroy 改名为 beforeUnmount,destroyed 改名为 unmounted,因此 vue3 有以下生命周期函数:


  • beforeCreate -> 不需要

  • created -> 不需要

  • beforeMount -> onBeforeMount

  • mounted -> onMounted

  • beforeUpdate -> onBeforeUpdate

  • updated -> onUpdated

  • beforeUnmount -> onBeforeUnmount

  • unmounted -> onUnmounted

  • errorCaptured -> onErrorCaptured

  • renderTracked -> onRenderTracked

  • renderTriggered -> onRenderTriggered

4 总结

通过对以上知识的总结对 Vue 3 有了进一步的认识,基本能够满足项目开发。更多的改动大家可以自行查阅官方文档和阅读源码,相信 Vue 3 能给我们带来更多新的体验。


作者:京东物流 颜之婷

来源:京东云开发者社区 自猿其说 Tech

发布于: 刚刚阅读数: 3
用户头像

拥抱技术,与开发者携手创造未来! 2018-11-20 加入

我们将持续为人工智能、大数据、云计算、物联网等相关领域的开发者,提供技术干货、行业技术内容、技术落地实践等文章内容。京东云开发者社区官方网站【https://developer.jdcloud.com/】,欢迎大家来玩

评论

发布
暂无评论
手把手带你初探Vue 3.0 | 京东物流技术团队_前端_京东科技开发者_InfoQ写作社区