vue-router4 一些常见配置的改动
创建路由实例方式改变
3版本的时候是通过new的方式创建路由实例,4版本是改用了createRouter
的方式:
import { createRouter } from 'vue-router'
const router = createRouter({
// ...
})
路由模式配置改变
3版本路由模式是由mode属性控制,值为字符串,现在通过import引入不同函数来创建不同的路由模式:
"history"
改为createWebHistory()
"hash"
改为createWebHashHistory()
"abstract"
:createMemoryHistory()
这里着重解释一下第三种模式!
abstract是一种在内存中模拟路由path地址的方式,适用于没有hash和history的情况下,router会自动使用该模式,听说在weex上有用到这个。
需要注意的是,如果使用了这个模式,页面刷新后会回到首页。
在4版本中,mode属性改为了history
:
import { createRouter, createWebHistory } from 'vue-router'
// 还有 createWebHashHistory 和 createMemoryHistory
createRouter({
history: createWebHistory(),
routes: [],
})
base配置
base的定义是基路径,默认是/
,如果我们应用最终会部署在某个域名的/app
下,那么直接通过域名去访问单页应用,会导致路由路径与真实的路径不一致,我们就需要改动base。
比如我们现在的域名是:www.mule.com
打包的应用存放的是该域名下的/app
文件夹下
这就导致我们需要通过:www.mule.com/app 才能访问到网页
那么我就需要将base设为"/app"
具体我测了下好像没啥效果,设不设都不影响使用,文件夹这种问题,一般处理资源路径就行了,设置这个个人没感觉出效果,如果以后了解到了再补充。
但是找到一个不错的用例,就是多语言处理。
通过动态的base来实现一个语言前缀:
function getBasePath() {
const path = location.pathname
const subs = path.substr(0,3)
if (subs == '/en') {
return '/en'
}
if (subs == '/fr') {
return '/fr'
}
}
const router = new VueRouter({
routes: routes,
base: getBasePath(),
mode: 'history'
})
这个方式我只在createWebHistory模式下有效果,他会自动在路由路径的前面加上对应的语言。
在3版本中base还是单独选项,在4版本中,base是作为模式函数的第一个参数使用的。
createWebHistory("/app")
删除了fallback属性
fallback在3版本的时候,是作为一个回退属性配置的,接受一个布尔值,默认为true,表示当浏览器不支持 history.pushState
控制路由是否应该回退到 hash
模式。
原因是因为vue所能支持的浏览器中全部都对history api支持了,所以没有必要回退到hash,而且vue3已经放弃了对ie的支持。
删除了*星号通配符路由
弃用了之前*
通配符匹配方式,改用了正则参数的方式。
比如我们希望一个404页面,一般会在路由数组的最后加上:
{
path: '/:pathMatch(.*)*',
name: '404',
component: () => import('./views/404'),
}
当我们访问链接:http://localhost/:8081/about
会被重定向到404页面,我们还可以通过this.$route.params.pathMatch
来获取正则匹配到的路径,此时输出的是:
["about"]
如果有多个路径:http://localhost/:8081/about/aaa/detail
["about", "aaa", "detail"]
如果我希望这个路由是以特定路径前缀来进行匹配,比如test,那么可以这样:
{
path: '/test:id(.*)',
component: () => import('./views/xxx'),
name: 'xxx',
}
id是动态参数,假设链接为:http://localhost/:8081/test0912
this.$route.params.id //得到0912
如果我们希望手动跳转到这个404路由页,且携带参数的话,注意参数必须如下写法:
router.push({
name: "404",
params: {
pathMatch: ["xx", "xxx"]
}
});
router.reslove()
在nuxt中我们可能会用到这个属性来进行页面的新建打开,比如我有一个路由页b,我希望用户点击按钮是新建一个页面打开这个路由b,那么我们就必须知道完整的href,而reslove方法,可以接受一个本地路由参数,和平时push传的参一样,它最终会返回一个RouteLocation
对象。
RouteLocation 可以包含重定向记录的解析的 RouteLocationRaw。除此之外,它还具有与 RouteLocationNormalized 相同的属性。
其中还包括一个包含任何现有 base
的 href
属性,我们通过获取href属性可以拿到完整的链接地址进行跳转。
const href = router.reslove({
name: "about",
params: {
id: 12
}
}).href;
onReady改为isReady
改方法用于判断当前路由是否完成初始化导航,也就是第一个路由是否已经加载成功。
// 将3版本的
router.onReady(onSuccess, onError)
// 替换成
router.isReady().then(onSuccess).catch(onError)
// 或者使用 await:
try {
await router.isReady()
// 成功
} catch (err) {
// 报错
}
scrollBehavior
原来我们3版本可能会这么写:
scrollBehavior (to, from, savedPosition) {
return { x: 0, y: 0 }
}
4版本中,将x改为left,y改为top。
scrollBehavior (to, from, savedPosition) {
return { left: 0, top: 0 }
}
、 和
transition
和 keep-alive
现在必须通过 v-slot
API 在 RouterView
内部使用:
<router-view v-slot="{ Component }">
<transition>
<keep-alive>
<component :is="Component" />
</keep-alive>
</transition>
</router-view>
这么改可能会感觉写的很啰嗦,但是是符合我们的逻辑思维的,因为我们使用transition或者keep-alive最终命中的目标并不是router-view,而是router-view对应渲染的那个vue组件,所以新版本将其作为插槽参数拆分出来,使得代码逻辑上更加准确。
移除router-link的append属性
append用于表示当前router-link的跳转是一个相对路径,相对于当前页面路径的跳转路径。
由于使用频率不高被移除,官方也有提供对应的办法,查看文档:append
通过自己实现一个拼接方法实现该功能。
删除 中的event 和 tag属性
<router-link>
中的 event
和 tag
属性都已被删除。你可以使用 v-slot
API 来完全定制 <router-link>
:
将
<router-link to="/about" tag="span" event="dblclick">About Us</router-link>
替换成
<router-link to="/about" custom v-slot="{ navigate }">
<span @click="navigate" @keypress.enter="navigate" role="link">About Us</span>
</router-link>
官方为了减少包体大小,毕竟这两个功能完全可以自己实现,通过插槽的方式更加方便自由。
删除 中的exact属性
exact之前在3版本常常用于路由的高亮必备属性,现在4版本移除了,因为4版本不会有3的那种嵌套路径也会高亮的问题,所以放心移除。
mixins中路由守卫将被忽略
mixins在vue3中弃用,所以对应的路由守卫也不会被支持
所有的导航现在都是异步的
所有的导航,包括第一个导航,现在都是异步的,这意味着,如果你使用一个 transition
,你可能需要等待路由 ready 好后再挂载程序:
app.use(router)
// 注意:在服务器端,你需要手动跳转到初始地址。
router.isReady().then(() => app.mount('#app'))
否则会有一个初始过渡,就像你提供了 appear
属性到 transition
一样,因为路由会显示它的初始地址(什么都没有),然后显示第一个地址。
请注意,如果在初始导航时有导航守卫,你可能不想阻止程序渲染,直到它们被解析,除非你正在进行服务器端渲染。否则,在这种情况下,不等待路由准备好挂载应用会产生与 Vue2 中相同的结果。
跳转不存在的路由
在3版本的时候,如果我们跳转到一个不存在的路由,我们的浏览器的地址会变成根路径,如:http://localhost:8080/
,然后页面变成空白显示,然后并不会报错。
这显然并不符合我们逻辑思维,按道理,如果跳转到一个不存在的路由他应该报错才对,所以在4版的时候,我们跳转到一个不存在的路由,实际上会报错的,我们可以try...catch
捕获,或者catch
接一下promise的错误返回。
然后就可以做自己的判断了。
空path的子路由,不再追加斜线/
以前我们访问一个默认的子路由的时候,也就是空path的子路由时,我们的页面地址会在后面加上一个斜线。
const routes = [
{
path: '/parent',
component: Parent,
children: [
{ path: '', component: Child },
],
},
]
当我们访问parent时,他会默认展示子路由Child
,地址显示如下:
http://localhost:8080/parent/
而我们4版本不再添加斜线,展示如下:
http://localhost:8080/parent
原因:这是为了使尾部的斜线行为保持一致:默认情况下,所有路由都允许使用尾部的斜线。可以通过使用 strict
配置和手动添加(或不添加)斜线来禁用它。
不添加斜线回来一些副作用:
当我们通过默认子路由重定向到另一个子路由的时候,注意,如果使用path作为redirect
重定向参数,那么就需要注意了,你的path最好是完整路径,否则就会导致跳转过去的地址作为一个非子路由来进行跳转了。
import { h } from "vue";
import { createRouter, createWebHistory, RouterView } from "vue-router";
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: "/parent",
component: {
render() {
return h(RouterView);
},
},
children: [
{
path: "",
name: "Parent",
redirect: "children",
},
{
path: "children",
name: "Children",
component: () => import("./views/Chint2.vue"),
},
],
},
],
});
当我们访问/parent
路由的时候,会被重定向到:
http://localhost:8080/children
这显然不是我们需要的,如果你非要使用path,那么就需要这么写:
redirect: "/parent/children"
我建议是使用name:
redirect: { name: "Children" }
这点还是需要大家注意。
$route属性编码行为
path、fullPath
现在路由的path
、fullPath
不再默认做解码操作了
举个例子:
我们拿上面那个子路由复用一下,我们在Children2.vue里面输出一个fullPath属性。
<script lang="ts">
import { defineComponent } from "vue";
import { useRoute } from "vue-router";
export default defineComponent({
setup() {
const route = useRoute();
console.log(route.fullPath);
return {};
},
});
然后我们的网址是:http://localhost:5173/parent/children?name=木灵鱼儿
按照以往的获取,我们拿到的fullPath
也一定是/parent/children?name=木灵鱼儿
。
这里我们就需要了解一个知识,就是我们的浏览器其实会将特殊字符进行转码,虽然看上去和我们自己输入内容一致,但是实际使用的是被转码的内容,不信的话,我们在浏览器地址重新复制一下网址,再去聊天界面粘贴,你会发现你粘贴的内容是这样的:
http://localhost:5173/parent/children?name=%E6%9C%A8%E7%81%B5%E9%B1%BC%E5%84%BF
这个转码我们使用js也能实现,就是encodeURI
这套函数,具体可以自行百度。
我们打印下route.fullPath
,得到一下内容:
/parent/children?name=%E6%9C%A8%E7%81%B5%E9%B1%BC%E5%84%BF
hash
hash
现在被解码了,这样就可以复制过来。router.push({ hash: $route.hash })
可以直接用于 scrollBehavior 的 el
配置中。
push、replace、resolve
当使用 push
、resolve
和 replace
并在对象中提供 string
地址或 path
属性时,必须进行编码(像以前的版本一样)。另一方面,params
、query
和 hash
必须以未编码的版本提供。
带斜线字符参数
斜线字符(/
)现在已在 params
内正确解码,同时仍在 URL 上产生一个编码版本:%2F
原因:这样,在调用 router.push()
和 router.resolve()
时,可以很容易地复制一个地址的现有属性,并使产生的路由地址在各浏览器之间保持一致。router.push()
现在是幂等的,这意味着调用 router.push(route.fullPath)
、router.push({ hash: route.hash })
、router.push({ query: route.query })
和router.push({ params: route.params })
不会产生额外的编码。
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据