共计 7025 个字符,预计需要花费 18 分钟才能阅读完成。
海阔凭鱼跃,天高任鸟飞。Hey 你好!我是猫力 Molly
Vue3 曾经公布有一段时间了,同时也失去了各大厂商和社区的反对和泛滥开发者青睐,周边生态也正在逐步完善。堪称是一片欣欣向荣的美景。本文意在通过梳理 Vue2 罕用 api 通过差异化比照 Vue3,帮忙你疾速把握 Vue3
本文假如你曾经有肯定 vue2
实操教训,不会过多形容 api
细节
为什么要降级 Vue3?
两个要害的因素导致了咱们思考重写 Vue 新的次要版本:
- 支流浏览器对新的
JavaScript
语言个性的广泛反对。 - 以后
Vue
代码库随着工夫的推移而裸露进去的设计和体系架构问题。
更多细节,咱们能够听听祖师爷在知乎的答复尤雨溪亲笔:重头来过的 Vue 3 带来了什么?
vue2 VS vue3(编码体感)
近期做了一个对于“共享童车”的后盾管理系统我的项目,因为是新我的项目,我便大胆选定了 vue3
+vite
+typescript
+element plus
作为根底技术栈。不过目前市面上并没有一款收费且好用的中后盾根底模板框架,于是我又仿照着花裤衩大佬的传送门:vue-admin-template 照猫画虎的写了一个 vue3
版本的 vue-element-admin
并且利用到理论我的项目中。就我集体编码习惯而言,绝对于 vue2
的Option api
的直观明了,vue3
的 Composition 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 api
是 vue3
的一大特色,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
中咱们能够通过 ref
和reactive
来定义响应数据
const num = ref(0)
const obj = reactive({name:'molly'})
ref:
- 在模板中能够间接应用
ref
定义的数据,在js
中则须要应用.value
来取值或赋值 - 应用
geter
,seter
形式实现响应式 - 倡议应用
ref
来定义根底数据
reactive:
- 可应用
toRefs
将其解包,在模板中间接应用对应的attribute
- 应用
proxy
代理形式实现响应式 - 倡议应用
reactive
来定义简单数据
生命周期钩子
vue2
中提供了 11 个生命周期钩子,咱们可在选项对象上间接定义应用
vue3
中把生命周期钩子独自抽离成了一个个对应的 hooks
函数,以 onXXX
的模式调用。值得注意的是生命周期钩子注册函数只能在 setup
期间同步应用,这就意味着 beforeCreate
和created
等同于 setup
执行阶段。其余的周期用法基本一致,例如:mounted
对应onMounted
import {onMounted} from 'vue'
setup() {onMounted(() => {console.log('mounted!')
})
}
computed
两个版本的 computed
根本保持一致,不同的是 vue3
将computed
抽离成一个 hooks
函数应用
// vue2
computed:{num:()=>this.num *2
}
// vue3
const numVal = computed(() => num.value *2)
watch
vue2:
watch
监听一个特定数据源的后果变动,回调函数失去的参数为新值和旧值。除了监听 data
中的数据
还能够监听 props
、$route
、$emit
、computed
。可通过选项参数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 系列
感激
撒花✿✿ヽ (°▽°) ノ✿
点击关注我让咱们换个姿态玩儿前端,愿你一路前行,眼里有光!
撒花✿✿ヽ (°▽°) ノ✿