海阔凭鱼跃,天高任鸟飞。Hey 你好!我是猫力Molly

Vue3曾经公布有一段时间了,同时也失去了各大厂商和社区的反对和泛滥开发者青睐,周边生态也正在逐步完善。堪称是一片欣欣向荣的美景。本文意在通过梳理Vue2罕用api通过差异化比照Vue3,帮忙你疾速把握Vue3

本文假如你曾经有肯定vue2实操教训,不会过多形容api细节

为什么要降级Vue3?

两个要害的因素导致了咱们思考重写Vue新的次要版本:

  1. 支流浏览器对新的JavaScript语言个性的广泛反对。
  2. 以后Vue代码库随着工夫的推移而裸露进去的设计和体系架构问题。

更多细节,咱们能够听听祖师爷在知乎的答复尤雨溪亲笔:重头来过的 Vue 3 带来了什么?

vue2 VS vue3(编码体感)

近期做了一个对于“共享童车”的后盾管理系统我的项目,因为是新我的项目,我便大胆选定了vue3+vite+typescript+element plus作为根底技术栈。不过目前市面上并没有一款收费且好用的中后盾根底模板框架,于是我又仿照着花裤衩大佬的传送门:vue-admin-template照猫画虎的写了一个vue3版本的vue-element-admin并且利用到理论我的项目中。就我集体编码习惯而言,绝对于vue2Option api的直观明了,vue3Composition api能够更好的组织代码,反对自定义hooks来达到代码复用,从而取代mixin,代码格调上,也能够把相似的业务逻辑写到一个代码块,从而防止代码扩散,走读代码须要高低重复横跳。更敌对的反对了TS以及泛滥新个性的退出,也让vue3写起来更爽,更利于代码保护和拓展。联合vite应用,更是极大晋升了开发体验。总体来说,让咱们拥抱vue3吧,给vue团队点个赞

vue3比拟直观的新个性

  • 全新的Composition api让咱们换一种形式组织代码
  • <script setup> 语法糖,使得代码更简洁
  • 能够省去template的根元素包裹标签
  • 提供了新的内置组件<teleport>,反对了组件能够挂载到任意dom节点下
  • 提供了在css中应用v-bind来引入script变量,又一个弱小的黑魔法小技巧
  • 应用createApp来创立利用实例
  • 更敌对的TS反对
  • 应用proxy代理形式来替换掉defineproperty
  • 全局和外部 API 曾经被重构为反对 tree-shake

option api VS composition api

composition apivue3的一大特色,vue3对外裸露了大量函数供以咱们按需援用,随便组合

option api中,咱们通过实例化Vue并将行为对象作为参数传入

new Vue({    data(){        return {}    },    methods:{},    computed:{},    created(){},    ...})

Composition api 咱们能够通过setup作为入口函数,并返回一个对象数据裸露给模板应用

<template>  <div @click="hi">{{ msg }}</div></template><script>export default {    setup() {      const msg = ref('Hello!')      function hi() {        console.log(msg)      }      // 裸露给模板      return {        msg,        hi      }    }  }</script>

setup还反对另一种写法,更加简化了代码

<template>  <div @click="hi">{{ msg }}</div></template><script setup>const msg = ref('Hello!')function hi() {  console.log(msg)}</script>

当应用 <script setup> 的时候,任何在 <script setup> 申明的顶层的绑定 (包含变量,函数申明,以及 import 引入的内容) 都能在模板中间接应用

响应数据的定义

vue2中把响应数据定义到data函数的return

data(){    return {        ...    }}

vue3中咱们能够通过refreactive来定义响应数据

const num = ref(0)const obj = reactive({name:'molly'})

ref:

  • 在模板中能够间接应用ref定义的数据,在js中则须要应用.value来取值或赋值
  • 应用geterseter形式实现响应式
  • 倡议应用ref来定义根底数据

reactive:

  • 可应用toRefs将其解包,在模板中间接应用对应的attribute
  • 应用proxy代理形式实现响应式
  • 倡议应用reactive来定义简单数据

生命周期钩子

vue2中提供了11个生命周期钩子,咱们可在选项对象上间接定义应用

vue3中把生命周期钩子独自抽离成了一个个对应的hooks函数,以onXXX的模式调用。值得注意的是生命周期钩子注册函数只能在setup期间同步应用,这就意味着beforeCreatecreated等同于setup执行阶段。其余的周期用法基本一致,例如:mounted对应onMounted

import { onMounted } from 'vue'setup() {    onMounted(() => {        console.log('mounted!')    })}

computed

两个版本的computed根本保持一致,不同的是vue3computed抽离成一个hooks函数应用

// vue2computed:{    num:()=>this.num *2}
// vue3const numVal = computed(() => num.value *2)

watch

vue2:

watch监听一个特定数据源的后果变动,回调函数失去的参数为新值和旧值。除了监听data中的数据
还能够监听props$route$emitcomputed。可通过选项参数deep来深度监听,指定 immediate: true 将立刻触发回调

watch:{    obj:(val,old)=>{        deep: true,        immediate: true    }}

vue3

vue3的计算属性失去了很大的增强,反对监听多个数据源和执行副作用

// 监听单个数据源const count = ref(0)watch(count, (val, old) => {  /* ... */})// 假如count是一个对象,也反对监听整个对象,而无需指定deep属性
// 监听多个数据源const count = ref(0)const obj = reactive({name:'molly'})watch([() => obj.name, count], ([newName, newCount], [oldName, oldCount]) => {    /* ... */})// 监听多个数据源时,watch函数的第一个参数可传入数据源数组,第二个回调函数的参数也是一个数组

vue3还新增了watchEffect,示意立刻执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时从新运行该函数。

watch相比,watchEffect不须要传入指定监听的数据源,它会主动收集依赖。也没有新值旧值的概念,只有依赖发生变化,就会从新执行函数

const count = ref(0)watchEffect(() => console.log(count.value))setTimeout(() => {  count.value++}, 100)

watchEffect 会返回一个用于进行这个监听的函数

watchEffect在组件的setup函数或生命周期钩子被调用时,侦听器会被链接到该组件的生命周期,并在组件卸载时主动进行。

const stop = watchEffect(() => {  /* ... */})stop()

filters

vue2中咱们能够很不便的应用filters过滤器来解决一些文本格式转换,对数据进行加工。

filters: {  sum(num1,num2) {    return num1+num2  }}

请留神:vue3中,将移除过滤器,且不再反对。官网更举荐咱们应用办法调用或计算属性来替换filters

至于为啥要移除这个api官网的解释是:尽管这看起来很不便,但它须要一个自定义语法,突破了大括号内的表达式“只是 JavaScript”的假如,这不仅有学习老本,而且有实现老本。

我的了解是:api功能设计反复,filters无能的事儿,计算属性和函数调用也无能,且干的更好。所以尤大大含泪移除filters,可怜的filters只能被摈弃

人生亦是如此,职场中优胜劣汰,心愿咱们永远都不会是那个被优化掉的filters

components

vue2中咱们须要通过选项components进行组件注册,而在vue3中,咱们能够间接应用组件

//vue2 import A from './a.vue'components:{    A}
//vue3<template>  <A/></template><script setup>    import A from './a.vue'</script>

指令:vue2 VS vue3

两个版本的指令用法基本相同,这里我只列出vue3差别局部

v-model

vue2中咱们实现一个自定义v-model能够这样写

// vue2props:{    title:{        type:String,        default: 'molly'    }},model: {    prop: 'title',    event: 'change',},methods:{    change(val){        this.$emit('input',val)    }},

vue3中能够定义v-model参数名,同时还反对设置多个v-model,几乎美滋滋

// vue3props:{    title:{        type:String    },    num:{        type:Number    },},setup(props,{emit}){    function change1(val){        emit('update:title',val)    }    function change2(val){        emit('update:num',val)    }    return {        change1,        change2    }}// 在父组件中应用<Son v-model:title="molly" v-model:num="18" />

新增指令

  • v-memo,该指令记住一个模板的子树。元素和组件上都能够应用。该指令接管一个固定长度的数组作为依赖值进行记忆比对。如果数组中的每个值都和上次渲染的时候雷同,则整个该子树的更新会被跳过。相当于内存换工夫,雷同渲染内容则从内存读取。这对于长列表场景很有用

其余变更

  • 对于 v-if/v-else/v-else-if 的各分支项 key 将不再是必须的,因为当初 vue3 会主动生成惟一的 key
  • <template v-for> 的 key 应该设置在 <template> 标签上 (而不是设置在它的子节点上)。
  • 作用于同一个元素上时,v-if 会领有比 v-for 更高的优先级。
  • v-on 的 .native 修饰符已被移除。
  • v-for 中的 ref 不再注册ref数组
  • 在应用v-bind="object"与组件独立属性重名时,那么绑定的申明程序将决定它们如何被合并。当前者为规范

    <!-- 模板 --><div id="red" v-bind="{ id: 'blue' }"></div><!-- 后果 --><div id="blue"></div><!-- 模板 --><div v-bind="{ id: 'blue' }" id="red"></div><!-- 后果 --><div id="red"></div>

组件通信:vue2 VS vue3

vue2中提供了多种api供以咱们进行组件通信:

  • props / $emit / $on
  • $attrs / $listeners
  • provide / inject
  • $parent / $children / ref

vue3中仍然反对大部分api,并做了适当调整

  • 移除了$on$off$once实例办法
  • 移除了$children实例property
  • $attrs 当初蕴含了所有传递给组件的 attribute,包含 class 和 style
  • 在 <script setup> 中必须应用 defineProps 和 defineEmits API 来申明 props 和 emits ,它们具备残缺的类型推断并且在 <script setup> 中是间接可用的

插槽 vue2 VS vue3

在插槽这一块两个版本根本保持一致,没有太多的改变,还是保留原来的应用形式。vue3做了一点点小更新

  • this.$slots 当初将插槽作为函数公开
  • 移除 this.$scopedSlots

代码复用 vue2 VS vue3

vue2中代码复用的伎俩很多,次要有以下几种形式

  • 组件抽离
  • 自定义指令
  • 实例全局挂载
  • 插件封装
  • mixin
  • extend

vue3中同样涵盖以上伎俩,并做了相应优化与更新

  • 实例全局挂载这一伎俩在vue2中,咱们个别是简略粗犷的通过prototype将行为对象挂载到vue原型上,这种形式尽管简单明了,然而也存在全局净化的问题。
Vue.prototype.$xxx = {name:'molly'}

对应到vue3中,则不容许咱们这样子干,取而代之的是 app.config.globalProperties

  • mixin也是代码复用的一大利器,不过相应的也暴露出一些问题。当mixin被滥用或大量应用时,会导致依赖关系不明确,不易保护。在vue3中更举荐咱们应用自定义hooks的形式来复用代码。

实现一个自定义hooks

咱们能够把一个性能相干的数据和逻辑都抽离进去放到一起保护,例如实现一个累加器

import {ref, onUnmounted} from 'vue'export function useAccumulator(){    const count = ref(0)    let timer = null    timer = setInterval(()=>{        count.value ++    },1000)    onUnmounted(()=>{        clearInterval(timer)    })    return {count}}

咱们定义了一个累加器的hooks函数,在组件入口就能够像一般函数一样应用useAccumulator()

import {useAccumulator} from '../utils'let {count} = useAccumulator()

script setup 补充

贴上官网的形容

<script setup> 是在单文件组件 (SFC) 中应用组合式 API的编译时语法糖。相比于一般的 <script> 语法,它具备更多劣势:

  • 更少的样板内容,更简洁的代码。
  • 可能应用纯 Typescript 申明 props 和抛出事件。
  • 更好的运行时性能 (其模板会被编译成与其同一作用域的渲染函数,没有任何的两头代理)。
  • 更好的 IDE 类型推断性能 (缩小语言服务器从代码中抽离类型的工作)。

<script setup> 为咱们带来了极大的便当,劣势如下:

  • 所有顶层绑定变量内容都能在模板中间接应用
  • <script setup> 范畴里的值也能被间接作为自定义组件的标签名应用,相当于咱们能够不必通过components 注册组件
  • 反对应用:is来绑定动静组件
  • 反对顶层await,先比JavaScript一步实现这个个性,就是爽

弱小的style个性

弱小的style个性是vue3的又一个神兵利器

深度选择器

为了使组件之间款式互不影响,咱们能够这样写<style scoped>,当处于scoped下想做深度抉择时,能够应用:deep()伪类

<style scoped>.a :deep(.b) {  ...}</style>

插槽选择器

默认状况下,作用域款式不会影响到<slot/>内容,能够应用:slotted伪类来抉择到插槽

:slotted(div) {  color: red;}

全局选择器

可通过:global伪类来实现全局款式

:global(.red) {  color: red;}

css module的反对

可通过<style module>形式将css类作为$style对象裸露进去给组件应用,同时也反对自定义名称:<style module=“molly” >

<template>  <p :class="molly.red">red</p></template><style module="molly">.red {  color: red;}</style>

状态驱动的动静css

这是我认为最不便的一个个性,能够让咱们少写很多代码,十分爽

style中容许咱们应用v-bind来将css值动静关联到组件上

<template>  <div class="text">hello</div></template><script>export default {  data() {    return {      color: 'red'    }  }}</script><style>// v-bind能够间接引入script中的响应数据作为值.text {  color: v-bind(color);}</style>

好啦,总结至此应该能够轻松上手vue3我的项目了,喜爱的小伙伴欢送点赞留言探讨。点赞超过30我将继续更新差异化比照vue-router4.x 和vuex 4.x 系列

感激

撒花✿✿ヽ(°▽°)ノ✿

点击关注我让咱们换个姿态玩儿前端,愿你一路前行,眼里有光!

撒花✿✿ヽ(°▽°)ノ✿