乐趣区

关于vue.js:通过差异化对比学习法带你回顾Vue2快速掌握Vue3

海阔凭鱼跃,天高任鸟飞。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 函数应用

// vue2
computed:{num:()=>this.num *2
}
// vue3

const 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 能够这样写

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

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

// vue3
props:{
    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 系列

感激

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

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

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

退出移动版