Vue Router【详解】含路由配置、路由定义、路由跳转、路由传参、自动注册路由、路由守卫、页面滚动、监听路由、$route、$router、路由过渡动画等

简介: Vue Router【详解】含路由配置、路由定义、路由跳转、路由传参、自动注册路由、路由守卫、页面滚动、监听路由、$route、$router、路由过渡动画等

Vue Router简介

Vue Router 官网  https://router.vuejs.org/zh/guide/#html

Vue Router 用于对vue项目中的路由进行管理,每个路由对应的页面,通过<router-view></router-view> 进行渲染,可以配合 <transition><keep-alive> 使用。

<transition>
  <keep-alive>
    <router-view></router-view>
  </keep-alive>
</transition>


Vue Router安装

npm install vue-router --save—dev

Vue Router配置

src/main.js 引入插件

// 插件-路由管理 vue-router
import VueRouter from 'vue-router'
Vue.use(VueRouter)
import {routes} from "./routes";
 
const router = new VueRouter({
    routes
})
 
new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

src/routes.js中定义路由(新建的文件)

export const routes = [
    {path: '/', name: '首页',component: resolve => require(['@/page/index'], resolve)},
    {path: '/dic',name: '速查手册', component: resolve => require(['@/projects/dic/index'], resolve)},
    {path: '/404',component: resolve => require(['@/page/404.vue'], resolve),},
    // 未匹配到的路由,重定向到 /404
    {path: '*', redirect: '/404'},
]

自动注册路由

page目录下的vue组件自动完成路由注册,路由为 /vue文件名

require.context('./page', true, /\.vue$/).keys().forEach(fileName => {
    let componentName = fileName.replace(/^\.\//, '').replace(/\.vue$/, '');
    let temp = {
        path: '/' + componentName,
        component: resolve => require(["@/page/" + componentName], resolve)
    }
    routes.push(temp)
});


路由模式 mode(通常用默认的hash模式)

浏览器时,默认为 hash 模式(url上有/#) —— 使用 URL 的 hash 来模拟一个完整的 URL,当 URL 改变时,页面不会重新加载。

Node.js 环境时,默认为abstract模式 —— 如果发现没有浏览器的 API,路由会自动强制进入这个模式。


可以改为 history 模式 ,但需要后端配合,详见 https://router.vuejs.org/zh/guide/essentials/history-mode.html#后端配置例子

const router = new VueRouter({
  // 不用mode: 'history'时,页面url地址后面会加上一个“#”
  // mode: 'history',
  routes
})

路由基路径 base

默认值: "/" ,如果整个单页应用服务在 /app/ 下,然后 base 就应该设为 "/app/"

const router = new VueRouter({
  base:'/app/',
  routes
})

<router-link> 默认的激活的 class—— linkActiveClass

默认值: "router-link-active"

<router-link> 默认的精确激活的 class —— linkExactActiveClass

默认值: "router-link-exact-active"

页面滚动 scrollBehavior

通过scrollBehavior 方法可以控制路由跳转后页面的滚动行为,和最终滚动条的位置。

兼容性:只在支持 history.pushState 的浏览器中可用

const router = new VueRouter({
  routes: [...],
  scrollBehavior (to, from, savedPosition) {
    // return 期望滚动到哪个的位置
  }
})


scrollBehavior 方法的参数

  • to —— 数据类型:路由 —— 即将进入的路由
  • from —— 数据类型:路由 —— 即将离开的路由
  • savedPosition —— 当且仅当 popstate 导航 (通过浏览器的 前进/后退 按钮触发) 时才可用。

scrollBehavior 方法的返回值 —— 滚动位置(数据类型:对象)

{ x: number, y: number }

{ selector: string, offset? : { x: number, y: number }}

滚动到顶部

scrollBehavior (to, from, savedPosition) {
  return { x: 0, y: 0 }
}

保持原滚动条的位置

scrollBehavior (to, from, savedPosition) {
  if (savedPosition) {
    return savedPosition
  } else {
    return { x: 0, y: 0 }
  }
}

滚动到锚点

scrollBehavior (to, from, savedPosition) {
  if (to.hash) {
    return {
      selector: to.hash
    }
  }
}

更高级的例子,参考 https://github.com/vuejs/vue-router/blob/dev/examples/scroll-behavior/app.js

异步滚动

// 返回一个 Promise 来得出预期的位置描述:
scrollBehavior (to, from, savedPosition) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({ x: 0, y: 0 })
    }, 500)
  })
}

平滑滚动

添加  behavior: 'smooth' 即可

scrollBehavior (to, from, savedPosition) {
  if (to.hash) {
    return {
      selector: to.hash,
      behavior: 'smooth',
    }
  }
}


平滑滚动的兼容性参考  https://developer.mozilla.org/en-US/docs/Web/API/ScrollToOptions/behavior

定义路由

路由匹配 path

路由定义得越早,优先级就越高。

{
  // 会匹配所有路径
  path: '*'
}
{
  // 会匹配以 `/user-` 开头的任意路径
  path: '/user-*'
}


//  "?" 可选参数
{ path: '/optional-params/:foo?' },
 
//  "?" 可选路由
{ path: '/optional-group/(foo/)?bar' }
 
// 对参数添加正则校验(限制id必须为数字)
{ path: '/params-with-regex/:id(\\d+)' },

含有通配符的路由应该放在最后,路由 { path: '*' } 通常用于客户端 404 错误。

{path: '/404',component: resolve => require(['@/page/404.vue'], resolve),},
// 未匹配到的路由,重定向到 /404
{path: '*', redirect: '/404'},


更多高级匹配方式,可以参考插件 path-to-regexp 的官方文档  https://github.com/pillarjs/path-to-regexp/tree/v1.7.0#parameters

  // 2.6.0+
  caseSensitive?: boolean, // 匹配规则是否大小写敏感?(默认值:false)
  pathToRegexpOptions?: Object // 编译正则的选项

路由命名 name

name属性为自定义的路由名称

推荐在路由跳转时,使用命名路由,这样即便path改变,也无需修改各页面中的path

{
      path: '/user/:userId',
      name: 'user',
      component: User
}

路由元信息 meta

 通过meta可以为路由添加更多自定义的配置信息

        {
          path: 'bar',
          component: Bar,
          meta: { requiresAuth: true }
        }

路由重定向 redirect

当用户访问 /a时,URL 将会被替换成 /b,然后匹配路由为 /b

{ path: '/a', redirect: '/b' }
{ path: '/redirect-with-params/:id', redirect: '/with-params/:id' },
{ path: '/a', redirect: { name: 'foo' }}
    { path: '/dynamic-redirect/:id?',
      redirect: to => {
        const { hash, params, query } = to
        if (query.to === 'foo') {
          return { path: '/foo', query: null }
        }
        if (hash === '#baz') {
          return { name: 'baz', hash: '' }
        }
        if (params.id) {
          return '/with-params/:id'
        } else {
          return '/bar'
        }
      }
    },

路由别名 alias

/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样。

 { path: '/home', component: Home,
      children: [
        // 绝对路径  别名
        { path: 'foo', component: Foo, alias: '/foo' },
        // 相对路径  别名 (/home/bar-alias)
        { path: 'bar', component: Bar, alias: 'bar-alias' },
        // 多个别名  —— 数组
        { path: 'baz', component: Baz, alias: ['/baz', 'baz-alias'] },
        // 默认别名 “”
        { path: 'default', component: Default, alias: '' },
        // 嵌套路由的别名  /home/nested-alias/foo 会访问 /home/nested/foo)
        { path: 'nested', component: Nested, alias: 'nested-alias',
          children: [
            { path: 'foo', component: NestedFoo }
          ]
        }
     ]
}


路由懒加载

{
  path:'./about',
  name:'About',
  component:() => import('../views/Aboout.vue')
}

更多详情见 https://blog.csdn.net/weixin_41192489/article/details/116610836

路由嵌套 children

    {
      path: '/user/:id',
      component: User,
      children: [
 
        {
          // 当 /user/:id/profile 匹配成功,
          // UserProfile 会被渲染在 User 的 <router-view> 中
          path: 'profile',
          component: UserProfile
        },
        {
          // 当 /user/:id/posts 匹配成功
          // UserPosts 会被渲染在 User 的 <router-view> 中
          path: 'posts',
          component: UserPosts
        },
          // 匹配其他子路由
        { path: '', component: UserHome }
      ]
    }


动态路由 : (路由传参)

模式 匹配路径 $route.params
/user/:username /user/evan { username: 'evan' }
/user/:username/post/:post_id /user/evan/post/123 { username: 'evan', post_id: '123' }

路由参数转为props传入组件

将组件和路由参数解耦,避免  $route.params 的使用,使组件在没有路由参数传入时,仍可正常复用。

方式一 布尔值

{ path: '/hello/:name', component: Hello, props: true }

访问 /hello/朝阳   相当于给组件传入props  { name:"朝阳"}

方式二 对象

{ path: '/static', component: Hello, props: { name: 'world' }}

访问 /static   就会向组件传入props  { name:"world"}

方式三 函数

尽可能保持 props 函数为无状态的,因为它只会在路由发生变化时起作用。如果你需要状态来定义 props,请使用包装组件,这样 Vue 才可以对状态变化做出反应。

 {
      path: '/search',
      component: SearchUser,
      props: route => ({ query: route.query.q })
}


/search?q=vue 会将 {query: 'vue'} 作为属性传递给 SearchUser 组件。

{ path: '/dynamic/:years', component: Hello, props: dynamicPropsFn }
function dynamicPropsFn (route) {
  const now = new Date()
  return {
    name: (now.getFullYear() + parseInt(route.params.years)) + '!'
  }
}

响应路由参数的变化

路由不变,只改变路由参数时,如从 /user/foo 导航到 /user/bar原来的组件实例会被复用,组件的生命周期钩子不会再被调用

此时,需要监听路由的变化,或使用路由守卫。

按组打包

把某个路由下的所有组件都打包在同个异步块 (chunk) 中。只需要使用 命名 chunk (opens new window),一个特殊的注释语法来提供 chunk name (需要 Webpack > 2.4)。

const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')

Webpack 会将任何一个异步模块与相同的块名称组合到相同的异步块中。

监听路由的变化

  watch: {
    $route(to, from) {
      // 对路由变化作出响应...
    }
  }

路由守卫

https://blog.csdn.net/weixin_41192489/article/details/117409477

路由跳转

<router-link> 标签

<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>

to 属性的使用方式与.push相同

当目标路由成功激活时,链接元素自动设置一个表示激活的 CSS 类名。

相关属性

replace —— 点击<router-link> 时默认调用 router.push()方法,增加此属性则调用 router.replace()

<router-link :to="{ path: '/abc'}" replace></router-link>

tag —— 默认<router-link> 会渲染成带有正确链接的 <a> 标签,指定tag 属性可以改成其他标签

<router-link to="/foo" tag="li">foo</router-link>
<!-- 渲染结果 -->
<li>foo</li>

active-class —— 指定链接激活时的样式名,默认为"router-link-active"。(通过路由的构造选项 linkActiveClass 可以全局配置默认值)

exact ——  使用“精确匹配模式”,避免模糊匹配上的路由都显示激活样式

<!-- 这个链接只会在地址为 / 的时候被激活 -->
<router-link to="/" exact></router-link>

event —— 默认通过点击触发跳转(默认值 click),可以修改为其他事件(一个字符串或是一个包含字符串的数组)


exact-active-class —— 链接被精确匹配时激活的 class


.push

会向 history 栈添加一个新的记录

this.$router.push('/login')

提供了 path后params 会被忽略

// 字符串 —— 没有/时会自动加/
router.push('home')
等同于
router.push('/home')
 
// 对象
router.push({ path: 'home' })
 
// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})
 
// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
const userId = '123'
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
  • 第二个可选参数——回调函数onComplete——导航成功完成时调用 (在所有的异步钩子被解析之后)

控制台报错提示跳转到重复路由时,可以将第二个可选参数设为空的箭头函数来解决。

this.$router.push('/login',()=>{})
  • 第三个可选参数——回调函数onAbort——导航终止时调用 (导航到相同的路由、或在当前导航完成之前导航到另一个不同的路由)

.replace

不会向 history 栈添加新的记录,参数规则与.push相同

this.$router.replace('/login')

.go

参数是一个整数,用于history 记录中向前或者后退多少步,类似 window.history.go(n)

// 在浏览器记录中前进一步,等同于 history.forward()
router.go(1)
 
// 后退一步记录,等同于 history.back()
router.go(-1)
 
// 前进 3 步记录
router.go(3)
 
// 如果 history 记录不够用,则失败,不会跳转
router.go(-100)

.back()

后退——跳转到上一路由(若浏览器存在history 记录)

router.back()

.forward()

前进——跳转到下一路由(若浏览器存在history 记录)

router.forward()

路由跳转——实战范例

// 返回到上一页面    
goBack() {
      window.history.length > 1 ? this.$router.go(-1) : this.$router.push('/')
}

当前路由 this.$route

$route为当前路由对象,用于获取当前路径,路由中的动态片段,路径中的查询参数等信息

  • $route.path— 字符串 —当前路由的绝对路径,定义路由时的path值,如"/foo/bar"
  • $route.fullPath— 字符串 —当前路由的完整路径,含查询参数和 hash ,如"/stock?name=朝阳#hello"
  • $route.query —对象——当前路由中查询参数的键值对

在路由“ /test/1?name=朝阳 中,$route.query的值为 { "name": "朝阳" }

  • $route.name— 字符串 —当前路由的名称,如“测试”
    {name:'测试', path: '/test/:id', component: resolve => require(['@/components/test/index'], resolve)},
  • $route.params —对象 —— 当前路由中动态片段的键值对
    {path: '/test/:id', component: resolve => require(['@/components/test/index'], resolve)},

在路由 /test/1 中,$route.params的值为 { "id": "1" }

使用一个通配符时,$route.params 内会自动添加一个名为 pathMatch 参数。它包含了 URL 通过通配符被匹配的部分:

// 给出一个路由 { path: '/user-*' }
this.$router.push('/user-admin')
this.$route.params.pathMatch // 'admin'
// 给出一个路由 { path: '*' }
this.$router.push('/non-existing')
this.$route.params.pathMatch // '/non-existing'


  • $route.hash — 字符串 — 当前路由的hash值,如http://localhost:8080/#/stock#hello 的hash值为"#hello"
  • $route.redirectedFrom —— 字符串 —— 重定向来源的路由的名字(如果存在重定向),如由name为a的路由,重定向到name为b的路由,则$route.redirectedFrom值为a
  • $route.matched — 数组 — 路由匹配到的所有已定义的路由会存入 $route.matched 数组中,包含定义路由时的嵌套路由数组children

使用范例:在全局导航守卫中检查元字段

router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requiresAuth)) {
    // this route requires auth, check if logged in
    // if not, redirect to login page.
    if (!auth.loggedIn()) {
      next({
        path: '/login',
        query: { redirect: to.fullPath }
      })
    } else {
      next()
    }
  } else {
    next() // 确保一定要调用 next()
  }
})

路由器 this.$router

$router 对象是全局路由的实例,用于实现路由的跳转,有以下属性:

  • app ——  路由对应的vue实例
  • mode ——  路由模式
  • currentRoute —— 当前路由对象,即 $route

使用 this.$router 进行路由跳转的范例

this.$router.push({name:'测试',params:{id:1}}); //会向 history 栈添加一个新的记录

跳转到名称为测试,动态片段为1的页面,即/test/1

this.$router.push({path:'/test/1',query:{name:'朝阳'}}); //会向 history 栈添加一个新的记录

跳转到路径为/test/1,查询参数为name=朝阳,即“ /test/1?name=朝阳

this.$router.go(-1); // 回到上一页
this.$router.replace('/'); // 使用 / 路由对应的页面,替换当前页面,不会向 history 栈添加一个新的记录

同时展示多个视图(命名视图)

如果 router-view 没有设置名字,那么默认为 default

<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>
 {
      path: '/',
      components: {
        default: Foo,
        a: Bar,
        b: Baz
      }
    }

路由过渡动画

全局路由动画

<transition>
  <router-view></router-view>
</transition>

局部路由动画

在指定路由的组件外,加上<transition>

    <transition name="slide">
      <div class="foo">...</div>
    </transition>

动态路由动画

<transition :name="transitionName">
  <router-view></router-view>
</transition>
// 父组件内 _ 根据路由层级决定过渡动画为左滑/右滑
watch: {
  '$route' (to, from) {
    const toDepth = to.path.split('/').length
    const fromDepth = from.path.split('/').length
    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
  }
}

目录
相关文章
|
7月前
|
资源调度 JavaScript 前端开发
路由管理:Vue Router的使用和配置技巧
【10月更文挑战第21天】路由管理:Vue Router的使用和配置技巧
167 3
|
6月前
|
JavaScript UED
"Vue实战技巧大揭秘:一招解决路由跳转页面不回顶部难题,让你的单页面应用用户体验飙升!"
【10月更文挑战第23天】在Vue单页面应用中,点击路由跳转时,默认情况下页面不会自动滚动到顶部,这可能影响用户体验。本文通过一个新闻网站的案例,介绍了如何使用Vue-router的全局前置守卫和`scrollBehavior`方法,实现路由跳转时页面自动滚动到顶部的功能,提升用户浏览体验。
268 0
|
1月前
|
JavaScript
vue实现任务周期cron表达式选择组件
vue实现任务周期cron表达式选择组件
142 4
|
15天前
|
人工智能 自然语言处理 JavaScript
用 CodeBuddy 搭建Vue框架 像呼吸一样简单
本文介绍如何借助 CodeBuddy 快速创建 Vue 项目。CodeBuddy 是一款支持自然语言编程的工具,能根据用户需求自动生成代码,降低开发门槛。文章详细说明了通过 CodeBuddy 创建 Vue 项目的步骤,包括解决项目创建失败的问题、自动补全代码功能以及启动开发服务器的方法。无论开发者经验如何,CodeBuddy 都能显著提升效率,让开发更专注创意实现。
|
5月前
|
JavaScript
vue使用iconfont图标
vue使用iconfont图标
243 1
|
26天前
|
缓存 JavaScript 前端开发
Vue 基础语法介绍
Vue 基础语法介绍
|
2月前
|
JavaScript 前端开发 算法
vue渲染页面的原理
vue渲染页面的原理
146 56
|
2月前
|
SQL JavaScript 前端开发
Vue实现动态数据透视表(交叉表)
Vue实现动态数据透视表(交叉表)
198 13
|
2月前
|
数据采集 资源调度 JavaScript
极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图
本文介绍了使用 Vue Flow 绘制流程图的方法与技巧。Vue Flow 是一个灵活强大的工具,适合自定义复杂的流程图。文章从环境要求(Node.js v20+ 和 Vue 3.3+)、基础入门案例、自定义功能(节点与连线的定制、事件处理)到实际案例全面解析其用法。重点强调了 Vue Flow 的高度灵活性,虽然预定义内容较少,但提供了丰富的 API 支持深度定制。同时,文中还分享了关于句柄(handles)的使用方法,以及如何解决官网复杂案例无法运行的问题。最后通过对比 mermaid,总结 Vue Flow 更适合需要高度自定义和复杂需求的场景,并附带多个相关技术博客链接供进一步学习。
|
3月前
|
移动开发 JavaScript API
Vue Router 核心原理
Vue Router 是 Vue.js 的官方路由管理器,用于实现单页面应用(SPA)的路由功能。其核心原理包括路由配置、监听浏览器事件和组件渲染等。通过定义路径与组件的映射关系,Vue Router 将用户访问的路径与对应的组件关联,支持哈希和历史模式监听 URL 变化,确保页面导航时正确渲染组件。