Vue3 中周边生态升级

本篇文章的内容,是对于Vue周边生态的正式版本的 release 解读。

包含了:

Vue Router 4.0 特性介绍

项目结构优化

Vue Router 被分为三部分(项目地址):

  • History 实现:根据 Vue Router 运行的环境来处理 URL 地址栏(例如,Node,Browser,Mobile等)。
  • Router 匹配器:处理类似 /users/:id 的路由解析和优先级处理
  • Router:将一切连接在一起,并处理路由特定功能,例如导航守卫。

动态路由

动态路由是 Vue Router 最受欢迎的功能之一。4.0版本的 Router 对动态路由的使用有了更详细的介绍,配合上自动优先级排名的高级路径解析功能,我们现在可以更加随意的顺序来定义路由。Router 会根据 URL 字符串的表示来猜测应该匹配的路由。

这里我们需要注意的是,路由匹配方式的变更。

Vue Router 3 版本中介绍章节:

高级匹配模式 vue-router 使用 path-to-regexp 作为路径匹配引擎,所以支持很多高级的匹配模式,例如:可选的动态路径参数、匹配零个或多个、一个或多个,甚至是自定义正则匹配。查看它的 文档 学习高阶的路径匹配,还有 这个例子 展示 vue-router 怎么使用这类匹配。

匹配优先级 有时候,同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:谁先定义的,谁的优先级就最高。

Vue Router4中:

使用 优先级排名,相当于根据你路径书写的规则计算出一个得分,根据得分来优先选取最有可能的那一项。

举个例子来说,你同时写了 /users 和 /:w+ 这两个路由:

1
2
3
4
5
6
7
8
9
10
const routes = [
{
path: '/users',
Component: Users
},
{
path: '/:w+',
Component: NotFound
}
]

在这里,当你输入 /users 这个更精确的路径的时候,走上面的规则,而下面的规则作为兜底规则。避免了旧版 Vue Router 需要通过路由声明的顺序来保证这个行为。

也诞生了 Path Ranker,来计较路由的得分。

Path Ranker

改进的导航系统

新的导航系统更加具有一致性,它改善了滚动行为的体验,使其更加接近原生浏览器的行为。 它还为用户提供了有关导航状态的几乎更多信息,用户可以用这些信息,通过 ProgressBar 和 Modal 之类的全局 UI 元素让用户的体验变得更好。

scrollBehavior 的变化

scrollBehavior 中返回的对象与 ScrollToOptions 类似:x 改名为 lefty 改名为 top。详见 RFC原因:使该对象类似于 ScrollToOptions,以使其感觉更像原生 JS API,并有可能启用将来的新配置。

所有的导航现在都是异步的

所有的导航,包括第一个导航,现在都是异步的,这意味着,如果你使用一个 transition,你可能需要等待路由 ready 好后再挂载程序:

1
2
3
app.use(router)
// 注意:在服务器端,你需要手动跳转到初始地址。
router.isReady().then(() => app.mount('#app'))
否则会有一个初始过渡,就像你提供了 appear 属性到 transition 一样,因为路由会显示它的初始地址(什么都没有),然后显示第一个地址。 请注意,如果在初始导航时有导航守卫,你可能不想阻止程序渲染,直到它们被解析,除非你正在进行服务器端渲染。否则,在这种情况下,不等待路由准备好挂载应用会产生与Vue2 中相同的结果。

history.state 的用法

Vue Router 将信息保存在 history.state 上。如果你有任何手动调用 history.pushState() 的代码,你应该避免它,或者用的 router.push()history.replaceState() 进行重构:

1
2
3
4
5
// 将
history.pushState(myState, '', url)
// 替换成
await router.push(url)
history.replaceState({ ...history.state, ...myState }, '')
同样,如果你在调用 history.replaceState() 时没有保留当前状态,你需要传递当前 history.state
1
2
3
4
// 将
history.replaceState({}, '', url)
// 替换成
history.replaceState(history.state, '', url)
原因:我们使用历史状态来保存导航信息,如滚动位置,以前的地址等。

更强大的Devtools

多亏了新的Vue Devtools,Vue Router 能够和浏览器进行以下更高级的整合。

  1. 时间轴记录路由变化:
vue-devtools
  1. 完整 route 目录,能够帮助你轻松进行调试:
vue-devtools

更好的路由守卫

next 说拜拜,远离一些原本在 路由守卫 内部比较容易犯的错误:返回您传递给 next 的任何值。 仍支持先前版本以简化迁移!

现在的路由守卫 API 更加友好且合理了,可以完美利用 async await 做异步处理,比如这样:

1
2
3
4
router.beforeEach(async (to, from) => {
// canUserAccess() returns `true` or `false`
return await canUserAccess(to)
})

一致的编码

编码方式(Encoding)做了统一的适配,现在将在不同的浏览器和路由位置属性(paramsquery 和 hash)中保持一致。 作为参数传递给 router.push() 时,不需要做任何编码,在你使用 $route 或 useRoute() 去拿到参数的时候永远是解码(Decoded)的状态。

迁移成本低

Vue Router 4 主要致力于于在改善现有 Router 的同时保持非常相似的 API,如果你已经很上手旧版的 Vue Router 了,那你的迁移会做的很顺利,可以查看文档中的完整迁移指南

Vue Router 小结

总的来说, vue-router 相对于 上一代升级的幅度还是比较大的。主要包括了 路由匹配的规则、导航系统的变更、路由守卫的async

Vuex 4.0

相对于 Vue Router 的升级幅度巨大,带来很多变化性的新功能,Vuex 所强调的是兼容性。 Vuex 4 支持 Vue 3,并且提供与 Vuex 3 完全相同的 API,因此用户可以在 Vue 3 中重用其现有的 Vuex 代码。

相对的,Vuex 4.0 的一些重要变更,下面也会总结以下:

安装过程发生了改变

为了与新的 Vue3 保持一致,Vuex的安装过程发生了更改。现在鼓励引入了 createStore 来创建一个 store 实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { createStore } from 'vuex'

export const store = createStore({
state() {
return {
count: 1
}
}
})

// main.js
import { createApp } from 'vue'
import { store } from './store'
import App from './App.vue'

const app = createApp(App)

app.use(store)

app.mount('#app')

注意:new Store(...) 语法依然可以使用,createStore 为推荐用法。

Vuex 4.0 的包和 Vue 3 对齐

  • vuex.global(.prod).js
    • 直接在浏览器中 <script src="..."> 引用。全局公开 Vuex 。
  • vuex.esm-browser(.prod).js
    • 适用于本机ES模块导入(包括通过支持浏览器的模块)<script type="module">
  • vuex.esm-bundler.js
    • 给打包工具使用的库,像 webpackrollupparcel
  • vuex.cjs.js
    • 用于在的 Node.js 服务器端呈现中 require()

声明 ComponentCustomProperties

Vuex 4 移除了 this.$store 在 Vue Component 的全局类型解决了一个 issue 。当配合 TypeScript 的时候,你必须声明你自己的模块扩充。

需要将下列的代码放入项目中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// vuex-shim.d.ts

import { ComponentCustomProperties } from 'vue'
import { Store } from 'vuex'

declare module '@vue/runtime-core' {
// Declare your own store states.
interface State {
count: number
}

interface ComponentCustomProperties {
$store: Store<State>
}
}

createLogger 从核心库中剥离出来

在 Vuex 3 中,createLogger 是从 vuex/dist/logger 导出的,现在它被包含到核心库了。

1
2
3
4
5
// vuex 3
import createLogger from "vuex/dist/logger"

// vuex4
import { createLogger } from 'vuex'

Vuex 小结

总的来说,Vuex 核心功能较稳定,只是一些使用 api 的变更。

评论

加载中,最新评论有1分钟延迟...