Vue3.0全家桶最全入门指南 - vue-router@4.x和vuex@4.x (3/4)
Posted coderkey
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue3.0全家桶最全入门指南 - vue-router@4.x和vuex@4.x (3/4)相关的知识,希望对你有一定的参考价值。
三、vue-router@4.x和vuex@4.x
vue-router@4.x和vuex@4.x
vue2.x使用的是vue-router@3.x和vuex@3.x,vue3.x使用的是vue-router@4.x和vuex@4.x,这里要避免跟vue3.x的版本号混合了,其实vue3.x使用的router和vuex都是4.x。
这里为了方便理解,统一使用vue2.x router、vue3.x router代替vue-router@3.x和vue-router@4.x,统一使用vue2.x vuex、vue3.x vuex代替vuex@3.x和vuex@4.x。
1、vue-router@4.x
创建实例
// vue2.x router
import Vue from 'vue'
import Router from 'vue-router'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
Vue.use(Router)
const router = new Router({
base: process.env.BASE_URL,
mode: 'history',
scrollBehavior: () => ({ y: 0 }),
routes
})
export default router
// vue3.x router
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router
scrollBehavior滚动行为
vue3.x router弃用了vue2.x router中的 { selector, x, y, offset },使用{ el, left, top, behavior }代替,新的api语义更接近原生DOM
// vue2.x router
const router = new Router({
base: process.env.BASE_URL,
mode: 'history',
scrollBehavior: () => ({ x: 0, y: 0 }),
routes
})
// vue3.x router
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
scrollBehavior(to, from, savedPosition) {
// scroll to id `#app` + 200px, and scroll smoothly (when supported by the browser)
return {
el: '#app',
top: 0,
left: 0,
behavior: 'smooth'
}
}
})
路由组件跳转
vue2.x使用路由选项redirect设置路由自动调整,vue3.x中移除了这个选项,将在子路由中添加一个空路径路由来匹配跳转
// vue2.x router
[
{
path: '/',
component: Layout,
name: 'WebHome',
meta: { title: '平台首页' },
redirect: '/dashboard', // 这里写跳转
children: [
{
path: 'dashboard',
name: 'Dashboard',
meta: { title: '工作台' },
component: () => import('../views/dashboard/index.vue')
}
]
}
]
// vue3.x router
[
{
path: '/',
component: Layout,
name: 'WebHome',
meta: { title: '平台首页' },
children: [
{ path: '', redirect: 'dashboard' }, // 这里写跳转
{
path: 'dashboard',
name: 'Dashboard',
meta: { title: '工作台' },
component: () => import('../views/dashboard/index.vue')
}
]
}
]
捕获所有路由:/:catchAll(.*)
捕获所有路由 ( /* ) 时,现在必须使用带有自定义正则表达式的参数进行定义:/:catchAll(.*)
// vue2.x router
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '/user/:a*' },
]
})
// vue3.x router
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/user/:a:catchAll(.*)', component: component },
]
})
当路由为 /user/a/b 时,捕获到的 params 为 {“a”: “a”, “catchAll”: “/b”}
router.resolve
router.match 与 router.resolve 合并在一起为 router.resolve,但签名略有不同
// vue2.x router
...
resolve ( to: RawLocation, current?: Route, append?: boolean) {
...
return {
location,
route,
href,
normalizedTo: location,
resolved: route
}
}
// vue3.x router
function resolve(
rawLocation: Readonly<RouteLocationRaw>,
currentLocation?: Readonly<RouteLocationNormalizedLoaded>
): RouteLocation & { href: string } {
...
let matchedRoute = matcher.resolve(matcherLocation, currentLocation)
...
return {
fullPath,
hash,
query: normalizeQuery(rawLocation.query),
...matchedRoute,
redirectedFrom: undefined,
href: routerHistory.base + fullPath,
}
}
获取当前路由
删除 router.getMatchedComponents,可以从 router.currentRoute.value.matched 中获取router.getMatchedComponents 返回目标位置或是当前路由匹配的组件数组 (是数组的定义/构造类,不是实例)。通常在服务端渲染的数据预加载时使用。
[{
aliasOf: undefined
beforeEnter: undefined
children: []
components: {default: {…}, other: {…}}
instances: {default: null, other: Proxy}
leaveGuards: []
meta: {}
name: undefined
path: "/"
props: ƒ (to)
updateGuards: []
}]
使用
如果使用 ,则可能需要等待 router 准备就绪才能挂载应用程序
app.use(router)
// Note: on Server Side, you need to manually push the initial location
router.isReady().then(() => app.mount('#app'))
一般情况下,正常挂载也是可以使用 的,但是现在导航都是异步的,如果在路由初始化时有路由守卫,则在 resolve 之前会出现一个初始渲染的过渡,就像给 提供一个 appear 一样
在服务端渲染 (SSR) 中,需要传递合适的 history mode
const history = isServer ? createMemoryHistory() : createWebHistory()
const router = createRouter({ routes, history })
// on server only
router.push(req.url) // request url
router.isReady().then(() => {
// resolve the request
})
push 或者 resolve 一个不存在的命名路由时,将会引发错误,而不是导航到根路由 “/” 并且不显示任何内容
在 vue2.x router 中,当 push 一个不存在的命名路由时,路由会导航到根路由 “/” 下,并且不会渲染任何内容。浏览器控制台只会打印警告,并且 url 会跳转到根路由 / 下。
const router = new VueRouter({
mode: 'history',
routes: [{ path: '/', name: 'foo', component: Foo }]
}
this.$router.push({ name: 'baz' })
在 vue3.x router 中,同样做法会引发错误。
const router = createRouter({
history: routerHistory(),
routes: [{ path: '/', name: 'foo', component: Foo }]
})
...
import { useRouter } from 'vue-next-router'
...
const router = userRouter()
router.push({ name: 'baz' })) // 这行代码会报错
获取路由
网上一些教程会告诉你通过ctx访问router和store对象,但是其实这种方式只能在develement模式有效,在production环境编译后,ctx在develement下看到的属性都无法访问,容易误导大家。
错误示例:
import { getCurrentInstance } from 'vue'
export default {
setup () {
const { ctx } = getCurrentInstance()
console.log(ctx)
console.log(ctx.$router.currentRoute.value)
const userId = computed(() => ctx.$store.state.app.userId)
return {
userId
}
}
}
正确使用:
import { getCurrentInstance } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useStore } from 'vuex'
export default {
setup () {
const { ctx } = getCurrentInstance()
console.log(ctx)
const router = useRouter()
const route = useRoute()
const store = userStore()
console.log(router, route, store)
console.log(router.currentRoute.value)
const userId = computed(() => store.state.app.userId)
return {
userId
}
}
}
2、vuex@4.x
vuex4.x很少breaking change,整体改动较少
创建实例
// vue2.x vuex
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {},
mutations: {},
actions: {},
getters: {},
modules: {}
}
// vue3.x vuex
import Vuex from 'vuex'
export default Vuex.createStore({
state: {},
mutations: {},
actions: {},
getters: {},
modules: {}
})
获取store
// vue3.x vuex
import { getCurrentInstance } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useStore } from 'vuex'
export default {
setup () {
const { ctx } = getCurrentInstance()
console.log(ctx)
const router = useRouter()
const route = useRoute()
const store = userStore()
console.log(router, route, store)
console.log(router.currentRoute.value)
const userId = computed(() => store.state.app.userId)
return {
userId
}
}
}
以上是关于Vue3.0全家桶最全入门指南 - vue-router@4.x和vuex@4.x (3/4)的主要内容,如果未能解决你的问题,请参考以下文章
Vue3.0全家桶最全入门指南 - 3.x跟2.x的其他差异 (4/4)
Vue3.0全家桶最全入门指南 - vue-router@4.x和vuex@4.x (3/4)