木灵鱼儿

木灵鱼儿

阅读:197

最后更新:2022/08/21/ 17:57:34

vue-router4 一些常见配置的改动

创建路由实例方式改变

3版本的时候是通过new的方式创建路由实例,4版本是改用了createRouter的方式:

import { createRouter } from 'vue-router'

const router = createRouter({
  // ...
})

路由模式配置改变

3版本路由模式是由mode属性控制,值为字符串,现在通过import引入不同函数来创建不同的路由模式:

  1. "history"改为createWebHistory()
  2. "hash"改为createWebHashHistory()
  3. "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 相同的属性。

其中还包括一个包含任何现有 basehref 属性,我们通过获取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 }
}

<router-view>、<keep-alive> 和 <transition>

transitionkeep-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

通过自己实现一个拼接方法实现该功能。

删除 <router-link>中的event 和 tag属性

<router-link> 中的 eventtag 属性都已被删除。你可以使用 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>

官方为了减少包体大小,毕竟这两个功能完全可以自己实现,通过插槽的方式更加方便自由。

删除 <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

现在路由的pathfullPath不再默认做解码操作了

举个例子:

我们拿上面那个子路由复用一下,我们在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 }) 可以直接用于 scrollBehaviorel 配置中。

push、replace、resolve

当使用 pushresolvereplace 并在对象中提供 string 地址或 path 属性时,必须进行编码(像以前的版本一样)。另一方面,paramsqueryhash 必须以未编码的版本提供。

带斜线字符参数

斜线字符(/)现在已在 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 }) 不会产生额外的编码。

版权申明

本文系作者 @木灵鱼儿 原创发布在木灵鱼儿 - 有梦就能远航站点。未经许可,禁止转载。

关于作者

站点职位 博主
获得点赞 1
文章被阅读 197

相关文章