vue基础四(路由)

路由

  • 起步
  • 使用路由
  • 动态路由匹配(传参)
  • 使用props 接收路由参数
  • 路径参数与查询参数
  • this.$route的fullpath和path
  • 响应路由参数的变化
  • 匹配所有路径
  • 匹配优先级
  • 嵌套路由
  • 声明式导航
  • 编程式导航
    • $router.push()
    • $router.replace()
    • $router.go(n)
      • $router.go(n)简写方法
  • 命名路由
  • 命名视图
  • 重定向
  • 别名
  • 路由组件传参
  • History 模式
  • $router 和 $route
  • 导航守卫
    • 全局前置守卫
      • next 函数的3 种调用方式
    • 全局解析守卫
    • 全局后置钩子
    • 路由独享的守卫
    • 组件内的守卫
  • 完整的导航解析流程
  • 路由元信息
  • 过渡效果
  • 滚动行为

使用 Vue.js ,可以通过组合组件来组成应用程序,
把 Vue Router 添加进来,要将组件 (components) 映射到路由 (routes),然后告诉 Vue Router 在哪里渲染它们。

起步

脚手架路由实例

index.js

//导入创建路由对象方法和hash 模式路径方法
import { createRouter, createWebHashHistory } from 'vue-router
//创建路由表
const routes = [
{
    path: '/',
    name: 'Home',
    component: () => import('../views/Home.vue'),
},  //path  和  component 必须有
{
    path: '/about/:id/:name',
    name: 'About',
    component: () => import('../views/About.vue')
},
]
//创建路由对象
const router = createRouter({
  history: createWebHashHistory(),//hash模式路径
  routes//路由表
})
//导出路由对象
export default router

使用路由

路由连接
路由视图

App.vue

//to属性指定路由路径
Home |
About
//router-view为路由视图

动态路由匹配(传参)

动态路由指的是:

把Hash 地址中可变的部分定义为参数项,从而提高路由规则的复用性。在vue-router 中使用英文的冒号(:)来定义路由的参数项。

我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。

例如,我们有一个About 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。

那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”来达到这个效果:

index.js 路由表

import About from '../views/About.vue'
{
	// 在about组件中,希望根据id和name值展示组件不同的信息
    path: '/about/:id/:name', //动态传参
    name: 'About',
    component: About,
 }

App.vue

About
About

当匹配到一个路由时,参数值会被设置到 this.$route.params,可以在每个组件内通过this.$route.params.xxx使用路由上的参数。

可以在About组件中输出用户的id和name:

About.vue


使用props 接收路由参数

为了简化路由参数的获取形式,vue-router 允许在路由规则中开启props 传参

    // 可以为路由规则开启 props 传参,从而方便的拿到动态参数的值
    { path: '/movie/:mid', component: Movie, props: true }
    
	 // 接收 props 动态参数的数据
	 props: ['mid'],
	 
   //可以直接使用props里接收的数据
    <h3>Movie 组件 --- {{ $route.params.mid }} --- {{ mid }}</h3>

路径参数与查询参数

在hash地址中,/后的参数项,叫做路径参数
在路由的参数对象中,需要使用this.$route.params获取参数

<router-link to="/about/001/zhangsan">About</router-link>

在hash地址中,后的参数项,叫做查询参数
在路由的参数对象中,需要使用this.$route.query获取参数

<router-link to="/about/001/zhangsan?age=22">About</router-link>

this.$route的fullpath和path

this.$route.fullpath表示#后的完整路径

/about/001/zhangsan?age=22&color=red

this.$route.path表示#后的除去查询参数的路径

/about/001

响应路由参数的变化

当使用路由参数时,例如从 /user/foo 导航到 /user/bar,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。
不过,这也意味着组件的生命周期钩子不会再被调用。

复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch (监测变化) $route 对象:

App.vue

watch: {
    //时刻监听路由的变化
    $route(to, from) {
      console.log(to);
      console.log(from);
    },
  },

匹配所有路径

常规参数只会匹配被 / 分隔的 URL 片段中的字符。如果想匹配任意路径,vue2使用* , vue3使用/:pathMatch(.*)

const routes = [
  { 
  	//path:"*", //vue2匹配所有路径
  	path: ' /:pathMatch(.*) ',  //vue3 当遇到不认识的路径
    name: '404',
    component: ()=>import('../views/404.vue')  //404路由
  },
]

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

404.vue


匹配优先级

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

嵌套路由

在项目中,我们的路由可能会更加复杂,
例如在Home路由中嵌套子路由,分别为HomeA,HomeB三个子模块,则就需要为Home路由添加children属性,并创建Home模块的路由视图。

index.js

//为Home路由添加children属性,添加子路由
const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home,
    children:[
      {path:'/homea',component:()=>import('../views/HomeA.vue')},
      {path:'/homeb',component:()=>import('../views/HomeB.vue')}
    ]
  },
]

Home.vue


声明式导航

在浏览器中,点击链接实现导航的方式,叫做声明式导航。

例如:普通网页中点击 链接、vue 项目中点击 都属于声明式导航

编程式导航

在浏览器中,调用API 方法实现导航的方式,叫做编程式导航。

例如:普通网页中调用location.href 跳转到新页面的方式,属于编程式导航

除了使用 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。

$router导航对象,包含许多导航的api方法

$router.push()

在 Vue 实例内部,你可以通过 $ router 访问路由实例。 使用this.$router.push(hash地址)

跳转到指定hash 地址,并增加一条历史记录

App.vue



注意:如果提供了 path,params 会被忽略.

$router.replace()

跟 router.push 很像,会跳转到指定地址,唯一的不同就是,它不会向 history 添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录

this.$router.replace(hash地址)

this.$router.replace({name:'About',params:{id:'001',name:'zhangsan'}});
	 //push换为replace,不会添加新的历史记录,将上一个记录替换为现有记录

$router.go(n)

这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似 window.history.go(n)。

this.$router.go(数值n)

this.$router.go(0); //刷新
this.$router.go(1); //前进
this.$router.go(-1); //后退

如果后退的层数超过上限,则会原地不动

$router.go(n)简写方法

在实际开发中,一般只会前进和后退一层页面。

因此vue-router 提供了如下两个便捷方法:

$router.back() 在历史记录中,后退到上一个页面

$router.forward()在历史记录中,前进到下一个页面

注意:在行内使用编程式导航的方法时,this必须要省略,否则会报错。

<!-- 在行内使用编程式导航跳转的时候,this 必须要省略,否则会报错! -->
    <button @click="$router.back()">back 后退</button>
    <button @click="$router.forward()">forward 前进</button>

命名路由

通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者是执行一些跳转的时候。你可以在创建 Router 实例的时候,在 routes 配置中给某个路由设置名称。

About

命名视图

想同时 (同级) 展示多个视图.
在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。
如果 router-view 没有设置名字,那么默认为 default。

//APP.vue



//路由表
components:{
  default:Home,
  a:()=>import('../views/HomeA.vue'),
  b:()=>import('../views/HomeB.vue')
},

重定向

重定向也是通过 routes 配置来完成.
“重定向”的意思是,当用户访问 /a时,URL 将会被替换成 /b,然后匹配路由为 /b.

从/about/:id/:name 重定向到 /

{
    path: '/about/:id/:name', 
    name: 'About',
    redirect:'/ ',   //重定向 redirect:'/ '
 }

重定向的目标也可以是一个命名的路由

{
    path: '/about/:id/:name', 
    name: 'About',
    redirect:{name:'Home'},   //重定向 redirect:'/ '
 }

别名

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

{
path: ‘/about/:id/:name’, //必须传入一个id和name值
name: ‘About’,
alias:‘/ab/:id/:name’, //别名,访问localhost:8081/#/ab/:id/:name时相当于访问about
component: () => import( ‘…/views/About.vue’),
}

路由组件传参

在组件中使用 $route 会使之与其对应路由形成高度耦合,从而使组件只能在某些特定的 URL 上使用,限制了其灵活性。

使用$route

路由实例


通过props解耦

路由实例



路由表

{
    path: '/about/:id/:name', //必须传入一个id和name值
    name: 'About',
    //另外一种导入路由所需模块的方式(导入需要时使用)
    component: () => import( '../views/About.vue'),
    props:true, //开启props传参模式 布尔模式
    props:{id:456,name:'lisi'}, //开启props传参模式 对象模式 静态传参 id值不能改变,一直为456
    props:route=>({id:'$'+route.params.id,name:route.params.name}), //函数模式 可以对收到的参数做处理
  },
  • 布尔模式
    如果 props 被设置为 true,route.params 将会被设置为组件属性
  • 对象模式
    如果 props 是一个对象,它会被按原样设置为组件属性。当 props 是静态的时候有用。
  • 函数模式
    你可以创建一个函数返回 props。这样你便可以将参数转换成另一种类型,将静态值与基于路由的值结合等等。

History 模式

vue-router 默认 hash 模式(路径带#) —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。
如果不想要很丑的 hash,我们可以用路由的 history 模式,需要后台配合。

$router 和 $route

this.$route 是路由的参数对象,可以拿到参数。
this.$router 是路由的导航对象。

router是VueRouter的一个对象,通过Vue.use(VueRouter)和VueRouter构造函数得到一个router的实例对象,这个对象中是一个全局的对象,他包含了所有的路由,包含了许多关键的对象和属性。

route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象,可以获取对应的name,path,params,query等。

导航守卫

导航守卫可以控制路由的访问权限。

全局前置守卫

每次发生路由的导航跳转时,都会触发全局前置守卫

因此,在全局前置守卫中,程序员可以对每个路由进行访问权限的控制

使用 router.beforeEach 注册一个全局前置守卫

index.js

const router = new VueRouter({...})

// 为 router 实例对象,声明全局前置导航守卫
// 只要发生了路由的跳转,必然会触发 beforeEach 指定的 function 回调函数
router.beforeEach(function(to, from, next) {
  // to 表示将要访问的路由的信息对象
  // from 表示将要离开的路由的信息对象
  // next() 函数表示放行的意思
  // 分析:
  // 1. 要拿到用户将要访问的 hash 地址
  // 2. 判断 hash 地址是否等于 /main。
  // 2.1 如果等于 /main,证明需要登录之后,才能访问成功
  // 2.2 如果不等于 /main,则不需要登录,直接放行  next()
  // 3. 如果访问的地址是 /main。则需要读取 localStorage 中的 token 值
  // 3.1 如果有 token,则放行
  // 3.2 如果没有 token,则强制跳转到 /login 登录页
  if (to.path === '/main') {
    // 要访问后台主页,需要判断是否有 token
    const token = localStorage.getItem('token')
    if (token) {
      next()
    } else {
      // 没有登录,强制跳转到登录页
      next('/login')
    }
  } else {
    next()
  }
})

	//以判断用户是否登录为例
	router.beforeEach((to, from, next) => {
	   if(cookie.get('login'))
	   next()
	   else{
	    if (to.path !== "/login") {
	      next({ path: "/login" });
	    } else {
	      next();
	    }
	   }   
	})

每个守卫方法接收三个参数

to: Route: 即将要进入的目标 路由对象
from: Route: 当前导航正要离开的路由
next: Function: 执行效果依赖 next 方法的调用参数。表示允许放行。一定要调用一次next()

next 函数的3 种调用方式

  • 当前用户拥有后台主页的访问权限,直接放行:next()

  • 当前用户没有后台主页的访问权限,强制其跳转到登录页面:next('/login')

  • 当前用户没有后台主页的访问权限,不允许跳转到后台主页:next(false)(强制处于当前页面)

全局解析守卫

用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。

全局后置钩子

注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身,导航被确认后,全局后置钩子被调用

router.afterEach((to, from) => {
  // ...
})

路由独享的守卫

在路由配置上直接定义 beforeEnter 守卫,在全局前置守卫触发后, beforeEnter 守卫被调用

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})

组件内的守卫

可以在路由组件内直接定义以下路由导航守卫

beforeRouteEnter(to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
  },
  beforeRouteUpdate(to, from, next) {
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
  },
  beforeRouteLeave(to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  }

完整的导航解析流程

  1. 导航被触发。
  2. 在失活的组件里调用 beforeRouteLeave 守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  5. 在路由配置里调用 beforeEnter。
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter。
  8. 调用全局的 beforeResolve 守卫 (2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

路由元信息

定义路由的时候可以配置 meta 字段。
一个路由匹配到的所有路由记录会暴露为 $route 对象的 $route.matched 数组。
需要遍历 $route.matched 来检查路由记录中的 meta 字段。

//路由表
meta: { requiresAuth: true }
//About.vue
{{$route.matched[0].meta}}

过渡效果

//app.vue


  


//CSS
#nav a.router-link-exact-active{color:#42b983;}
.fade-enter-active,.fade-leave-active{transition: opacity .5s;}
.fade-enter,.fade-leave-to{opacity: 0;}

滚动行为

scrollBehavior (to, from, savedPosition) {  
      return { left: 0, top: 0 }
    //vue2  {x:0,y:0}
}

你可能感兴趣的:(vue,vue.js,前端,javascript)