vue-router使用笔记

基本使用

  • 目录结构

image.png

  • 示例代码
// 示例代码:src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from "./router";

new Vue({
  // 将router挂载到vue实例
  // 从而让整个应用都有路由功能
  router,
  // main入口渲染的时App组件,在App组件模板中提供路由跳转链接
  render: h => h(App),
}).$mount('#app')

复制代码
// 示例代码:src/App.vue
<template id="app">
  <div>
    <h1>我是App组件的主页</h1>

    <!-- 使用 router-link 组件来导航. -->
    <!-- 通过传入 `to` 属性指定链接. -->
    <!-- router-link 默认会被渲染成一个 `<a>` 标签 -->
    <router-link to="/home">Go to Home</router-link>
    <br />
    <router-link to="/about">Go to About</router-link>

    <!-- 路由匹配到的组件将渲染在这里 -->
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  template: '#app'
}
</script>

复制代码
// 示例代码: src/router/index.js
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "../components/Home.vue";
import About from "../components/About.vue";

// 0. 如果使用模块化机制编程,导入Vue和VueRouter,要调用 Vue.use(VueRouter)安装插件

// 1. 通过Vue.use(插件) 安装插件
Vue.use(VueRouter);

// 2. 配置一组路由route映射
const routes = [
    { path: '/home', component: Home },
    { path: '/about', component: About },
]

// 3. 生成路由实例
const router = new VueRouter({
    routes
})

// 4. 导出路由实例用于挂载到vue实例
export default router;
复制代码
// 示例代码: src/components/Home.vue
<template id="home">
  <div>
    <h1>我是home页</h1>
  </div>
</template>
<script>
export default {
  template: '#home'
}
</script>
复制代码
  • 结果展示

image.png

路由的两种模式

一般单页面应用是(SPA)不会请求页面而是只更新视图. vue-router提供了两种方式来实现前端路由:Hash模式和History模式,可以用mode参数来决定使用哪一种方式

// 示例:
const router = new VueRouter({
    //mode指定history模式;如果这里不写,路由默认为hash模式
    mode: 'history', 
    routes: [...]
})
复制代码

1. Hash模式

vue-router默认使用Hash模式。使用url的hash来模拟一个完整的url.此时url变化时,浏览器是不会重新加载的。Hash(即#)是url的锚点,代表的是网页中的一个位置,仅仅改变#后面部分,浏览器只会滚动对应的位置,而不会重新加载页面.仅仅只是对浏览器进行指导,而对服务端是完全没有作用的!它不会被包括在http请求中,故也不会重新加载页面.同时hash发生变化时,url都会被浏览器记录下来,这样你就可以使用浏览器的后退了.

总而言之: Hash模式就是通过改变#后面的值,实现浏览器渲染指定的组件.

2. History模式

这种模式利用了HTML5 History新增的pushState()和replaceState()方法. 除了之前的back,forward,go方法,这两个新方法可以应用在浏览器历史记录的增加替换功能上.使用History模式,通过历史记录修改url,但它不会立即向后端发送请求.

注意点: 虽然History模式可以丢掉不美观的#,也可以正常的前进后退,但是刷新f5后,此时浏览器就会访问服务器,在没有后台支持的情况下,此时就会得到一个404!官方文档给出的描述是:”不过这种模式要玩好,还需要后台配置支持.因为我们的应用是单个客户端应用,如果后台没有正确的配置,当用户直接访问时,就会返回404.所以呢,你要在服务端增加一个覆盖所有情况的的候选资源;如果url匹配不到任何静态资源,则应该返回同一个index.html页面.”

总而言之:History模式就是通过pushState()方法来对浏览器的浏览记录进行修改,来达到不用请求后端来渲染的效果.不过建议,实际项目还是使用history模式.

路由的默认路径

默认情况下,进入网站的首页,我们希望渲染出首页的内容

// 示例:默认路由配置
const routes = [
    // 配置默认路由, 访问`根路径/`时直接重定向跳转到`/Home组件`
    { path: '/', redirect: '/Home' },
    { path: '/home', component: Home },
]
复制代码

router-link

  1. to:指定跳转的路径
  2. tag<router-link>默认是渲染成<a>标签组件,可以使用tag指定<router-link>渲染成什么组件。
<!-- 示例: -->
<!-- 默认首页两个字展示是a标签 -->
<router-link to="/home">首页</router-link>
<!-- 这里tag指定首页两个字出现在button标签上 -->
<router-link to="/home" tag="button">首页</router-link>
复制代码
  1. replace:不会留下history记录,不能通过浏览器的后退按钮回到上一步
<router-link to="/home" tag="button" replace>首页</router-link>
复制代码
  1. active-class:默认点击router-link会出现活跃class属性为router-link-active,可以根据这个活跃class设置活跃标签的样式,但是router-link-active太长了,可以使用active-class在标签上人为重新命名简短的活跃class属性;但是当标签很多的时候每个都需要指定active-class,很繁琐,我们可以在
<router-link to="/home" tag="button" replace
active-class="active" >首页</router-link>
复制代码
// 示例:
const router = new VueRouter({
    // mode不写默认为hash模式
    mode: 'history',
    routes,
    // linkActiveClass指定所有的router-link的活跃class属性名都叫active,就可以通过.active给活跃router-link设置样式
    linkActiveClass: 'active'
})

复制代码

h5的history

代码控制跳转路由

  • this.$router:每个路由实例都有一个$router的属性,表示的是整个router路由实例对象。
<template id="app">
  <div>
    <h1>我是App组件的主页</h1>
    <!-- <router-link to="/home">Go to Home</router-link>
         <router-link to="/about">Go to About</router-link> -->

    <div @click="clickHome">首页</div>
    <div @click="clickAbout">关于</div>
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  template: '#app',
  methods: {
    clickHome () {
        // 每个组价都会有个`$router`属性
        // push方法提供一个路由路径
        // push 方法设置的路由是可以通过浏览器回退按钮前进后退切换的,如果不需要切换,可以通过
        // this.$router.replace('/home')
      this.$router.push('/home')
    },
    clickAbout () {
        // this.$router.replace('/about')
      this.$router.push('/about')
    }
  }

}
</script>
复制代码

动态路由

// 路由属性介绍:
1. $route.path:string类型;对应当前路由的路径,总是解析为绝对路径,如 "/foo/bar"
2. $route.params:object类型;一个 key/value 对象,包含了动态片段和全匹配片段,如果没有路由参数,就是一个空对象
3. $route.query:object类型;一个 key/value 对象,表示 URL 查询参数。例如,对于路径 /foo?user=1,则有 $route.query.user == 1,如果没有查询参数,则是个空对象。
4. $route .name:当前路由的名称,如果有的话。这里建议最好给每个路由对象命名,方便以后编程式导航.不过记住name必须唯一!
5. $route.hash:string类型;当前路由的 hash 值 (带 #) ,如果没有 hash 值,则为空字符串。
6. $route.fullPath:string类型;完成解析后的 URL,包含查询参数和 hash 的完整路径。
7. $route.matched:Array<RouteRecord>类型;一个数组,包含当前路由的所有嵌套路径片段的路由记录 。路由记录就是 routes 配置数组中的对象副本 (还有在 children 数组)。	
8. $route.redirectedFrom:如果存在重定向,即为重定向来源的路由的名字
复制代码
// `$route.matched`: 一个包含路由记录的数组。

// router/index.js
const routes = [
    {
        path: '/home',
        component: Home,
        children: [
            {
                path: 'news',
                component: HomeNews,
            }
        ]
    },
    { path: '/about', component: About },
]

// HomeNews.vue
export default {
  template: '#news',
  activated () {
    //  当HomeNews活跃时,this.$route.matched控制台输出为下面的值
    // this.$route.matched: [
    //   0下标: { path: "/home", ... },
    //   1下标: { path: "/home/news", ...}
    // ]
    console.log(this.$route);
  }
}

复制代码

1. 动态路由基本使用

<!-- App.vue -->
<template id="app">
  <div>
    <router-link to="/home">首页</router-link>
    <!-- 采用v-bind将userId绑定到跳转路由,还有注意 使用单引号将'/user/'包裹,告知vi-bind /user/是个字符串而不是变量;这样用户就可以 访问 /user/xiaoming了 -->
    <router-link v-bind:to=" '/user/' + userId ">用户</router-link>
    <!-- 路由匹配到的组件将渲染在这里 -->
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  template: '#app',
  data () {
    return {
      userId: ''
    }
  }
}
</script>
复制代码
// router/index.js
const routes = [
    { path: '/home', component: Home },
    // 从App.vue组件的router-link的 :to=" '/user/' + userId "跳转来
    // 动态路径参数 以冒号开头 userId 就是动态路由,接收到用户传递来/user/xiaoming的xiaoming
    { path: '/user/:userId', component: User },
]
复制代码
// User.vue
export default {
  template: '#user',
  computed: {
    userName () {
      // User.vue组件 通过this.$route.params.userId获取到传递的参数值
      return this.$route.params.userId
    }
  }
}
复制代码

响应路由参数变化

由于路由参数对组件实例是复用的.例如:/user/foo/user/bar在使用路由参数时,复用的都是User组件.此时组件的生命周期钩子不会再被调用。如果你想路径切换时,进行一些初始化操作时,可以用以下两种解决办法:

// 方式1:在组件内 watch $route 对象:
const User = {
 template: '...',
 watch: {
   '$route' (to, from) {
     // 对路由变化作出响应...
   }
 }
}

// 方式2:使用2.2版本中的 beforeRouteUpdate 路由守卫
const User = {
  template: '...',
  beforeRouteUpdate (to, from, next) {
	// react to route changes...
	// don't forget to call next()
  }
}
复制代码

匹配优先级

  • 同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:谁先定义的,谁的优先级就最高。

嵌套路由

  • 案例:在home组件中嵌套messages组件和news组件
  • 思想理解:将嵌套的孩子路由展示在父路由的模板中,父路由的模板给一个子嵌套路由的出口router-view
// router/index.js
// 通过children配置孩子嵌套路由
const routes = [
    {
        path: '/home',
        component: Home,
        children: [
            {
                // 嵌套的孩子组件的path不需要写`/`,当访问/home/news,这里会自动添加
                path: 'news',
                component: HomeNews,
            },
            {
                path: 'messages',
                component: HomeMessages,
            }
        ]
    },
    { path: '/about', component: About },
]
复制代码
<!-- HomeNews.vue组件 -->
<template id="news">
  <div id="app">
    <h2>我是news组件</h2>
  </div>
</template>
<script>
export default {
  template: '#news'
}
</script>
复制代码
<!-- Home.vue组件 -->
<!-- 方式1:页面渲染出home组件后,不会显示嵌套的孩子组件,需要我们人为在地址栏输入`/Home/news` 才会访问到-->
<template id="home">
  <div>
    <h1>我是home页</h1>
    <!-- 在父路由Home的模板中嵌套子路由的渲染出口 -->
    <router-view></router-view>
  </div>
</template>
<script>
export default {
  template: '#home'
}
</script>

<!-- Home.vue组件 -->
<!-- 方式2:在home组件中,提供了跳转链接,通过跳转链接代替手动在地址栏输入 -->
<template id="home">
  <div>
    <h1>我是home页</h1>
    <!-- tips:这里需要写全路径,就相当于代替了手动在地址栏输入 -->
    <router-link to="/home/news">新闻</router-link>
    <router-link to="/home/messages">消息</router-link>
    <router-view></router-view>
  </div>
</template>
<script>
export default {
  template: '#home'
}
</script>
复制代码

路由传参

1. params传参方式

  • params传参之后,参数最终也会出现在地址栏
  • this.$route.params***$route表示的是当前活动路由组件,this.$route.params可以获取到当前活动路由接收到的参数。
  • 一个路径参数使用冒号 : 标记。当匹配到一个路由时,参数值会被设置到this.$route.params,可以在每个组件内使用
模式 匹配路径 $route.params
/user/:username /user/evan { username: ‘evan’ }
/user/:username/post/:post_id /user/evan/post/123 { username: ‘evan’, post_id: ‘123’ }
// 示例
{ path: '/user/:userId', component: User }
访问路径:/user/xiaoming
通过 this.$route.params.userId 可以获取值 xiaoming
复制代码

2. query传参方式

  • 在项目里我们可以通过上面提到的params进行传参.同时也可以用query进行传参.举个例子:<router-link to="/user?id=foo">foo</router-link>vue-route会自动将?后的id=foo封装进this.route.query.此时,在组件里this.route.query里. 此时,在组件里this.route.query.id值为’foo’.
  • 当通过query传参之后,参数最终也会出现在地址栏
  • 除了通过router-linkto属性. query也可以通过后面讲到的编程式导航进行传参
<!-- App.vue -->
<router-link to="/about">关于</router-link>
<router-link :to="{ path: '/about' }">关于2</router-link>
<!-- query传参,to可以bind一个对象,在对象中配置path跳转和query传参 -->
<router-link
    :to="{ path: '/profile', query: {name: 'lisi',age: 18} }"
>档案</router-link>
复制代码
// Profile.vue
<script>
export default {
  template: '<h1>我是profile组件 {{ this.$route.query }}</h1>',
}
</script>

// router/index.js
{ path: '/profile', component: Profile },
复制代码

3. 路由参数不通过router-link

  • 通过this.$router.push( String | Object )
      1. this.$router.push('/user/' + this.userId)
      1. this.$router.push({ path: '/profile', query: {sex: 'girl'} })
<!-- App.vue -->
<!-- 不通过router-link路由 -->
<button @click="userClick">用户1</button>
<button @click="profileClick">档案1</button>
methods: {
    userClick () {
        this.$router.push('/user/' + this.userId)
    },
    profileClick () {
        this.$router.push({
        path: '/profile',
        query: {
            sex: 'girl'
        }
        })
    }
}
复制代码
// Profile.vue
<h1>我是profile组件 {{ this.$route.query }}</h1>

// User.vue
<h2>我是user组件{{this.$route.params}}</h2>
复制代码

导航守卫

  • 导航守卫: 主要的作用是在路由跳转过程中进行操作控制
  • 导航解析思想:当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中。也就是说钩子函数会按照顺序在管道中排队等待,导航钩子函数中的next()就是为了执行管道中的下一个钩子函数。如果队列中的钩子函数全部执行完了,则导航的状态就是confirmed
  • 每个守卫方法接收三个参数
1. to: Route: 即将要进入的目标 路由对象
2. from: Route: 当前导航正要离开的路由
3. next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
    - next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。

    - next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。

    - next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: 'home' 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。

    - next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。
复制代码
    // 对函数及next()的详细使用说明
    router.beforeEach((to, from, next) => { 
	//首先to和from 其实是一个路由对象,所以路由对象的属性都是可以获取到的(具体可以查看官方路由对象的api文档).
	//例如:我想获取获取to的完整路径就是to.path.获取to的子路由to.matched[0].
      next();//使用时,千万不能漏写next!!!

	//next()  表示直接进入下一个钩子.
	//next(false)  中断当前导航
	//next('/path路径')或者对象形式next({path:'/path路径'})  跳转到path路由地址
	//next({path:'/shotcat',name:'shotCat',replace:true,query:{logoin:true}...})  这种对象的写法,可以往里面添加很多.router-link 的 to prop 和 router.push 中的选项(具体可以查看api的官方文档)全都是可以添加进去的,再说明下,replace:true表示替换当前路由地址,常用于权限判断后的路由修改.
    //next(error)的用法,(需2.4.0+) 
    }).catch(()=>{
        //跳转失败页面
        next({ path: '/error', replace: true, query: { back: false }})
    })

//如果你想跳转报错后,再回调做点其他的可以使用 router.onError()
router.onError(callback => { 
    console.log('出错了!', callback);
});

复制代码

1. 全局守卫

  • 全局守卫:异步执行,每个路由跳转都会按顺序执行.
// 1. 全局前置守卫: 在路由跳转之前回调
router.beforeEach((to, from, next)=>{
    next()
}): 
// 2. 全局解析守卫(2.5.0+) 在beforeRouteEnter调用之后调用.
router.beforeResolve

// 3. 全局后置钩子:在路由跳转之后回调 注意:不支持next();只能写成这种形式
router.afterEach((to, from) => {});
复制代码
  • 代码示例
router.beforeEach((to, from, next) => {
    // 从from跳转到to
    // document.title = to.meta.title;
    document.title = to.matched[0].meta.title;

    // from和to都是route路由对象
    // next必须被调用
    next()  
})
复制代码

2. 路由独享守卫

  • 路由独享守卫:路由对象独享的守卫
// 1. 路由只独享这一个钩子函数,在rutes里配置,在配置路由跳转之前执行
beforeEnter: (to, from, next) => {
    next()
}

复制代码
  • 代码示例
const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]
})
复制代码

3. 组件内的守卫

  • 组件内的守卫: 写在组件内部的路由导航守卫
1. beforeRouteEnter 进入路由前,此时实例还没创建,无法获取到zhis
2. beforeRouteUpdate (2.2) 路由复用同一个组件时
3. beforeRouteLeave 离开当前路由,此时可以用来保存数据,或数据初始化,或关闭定时器等等
复制代码
  • 代码示例
const Foo = {
  template: `...`,
  beforeRouteEnter (to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`. 因为当守卫执行前,组件实例还没被创建
  },
  beforeRouteUpdate (to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
  },
  beforeRouteLeave (to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  }
}
复制代码
  • 注意点beforeRouteEnter 是支持给 next 传递回调的唯一守卫。对于 beforeRouteUpdate 和 beforeRouteLeave 来说,this 已经可用了,所以不支持传递回调,因为没有必要了。
// 可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数
beforeRouteEnter (to, from, next) {
  next(vm => {
    // 通过 `vm` 访问组件实例
  })
}
复制代码

3. 完整的导航解析流程

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 的回调函数,创建好的组件实例会作为回调函数的参数传入。
复制代码

keep-alive

1. keep-alive基本使用

  • 背景:比如点击首页(首页下有两个子组件,News新闻组件和Messages消息组件),默认展示的是首页下的新闻/home/news,接着我们点击消息组件,展示的是/home/messages,这时候我们点击首页组件的兄弟组件关于组件/home/about, 然后我们再点击下首页组件,此时首页组件并不是停在我们去about组件之前的状态messages消息组件,而是首页组件默认渲染的news新闻组件,说明之前的状态没有被保留。其实从about组件切换到home组件,其实是重新创建了home组件,并重新渲染。

  • keep-alive:是Vue的内置组件,可以使被包裹的组件保留状态,或者避免重新渲染。也就是说再次切回到该组件时,该组件不会重新创建和渲染

  • router-view:是vue-router的内置组件,如果被直接包裹在keep-alive里面,所有路径匹配到的视图组件都会被缓存。

  • activated&deactivated:这两个生命周期函数只有在keep-alive包裹组件时才有效。切换路由组件时,当切换到被包裹的组件时,被包裹组件则处于活跃状态会调用activated,切换到其他组件时,该包裹的组件则处于不活跃状态会调用deactivated函数。

  • 解决背景问题

<!--  -->
<!-- App.vue:修改渲染home组件的出口 -->
<keep-alive>
    <router-view />
</keep-alive>
复制代码
// Home.vue
export default {
  template: '#home',
  data () {
    return {
      // 将嵌套路由中配置的home首页默认显示news组件的route删除,在home组件中配置path为默认显示的子组件路径
      path: '/home/news'
    }
  },
  // activated是一个生命周期函数,当组件活跃时调用。只有在keep-alive包裹组件时才有效;
  activated () {
    // 第一次执行时默认是显示的时this.path是news新闻组件的内容;
    this.$router.push(this.path).catch(err => { err })
  },
  // 组件内导航守卫钩子函数表示离开该组件的对应路由时调用。
  beforeRouteLeave (to, from, next) {
    //  将离开本组件时的path记录到 this.path中,这样下次组件再活跃时,会调用activated展示离开之前组件的状态
    this.path = this.$route.path
    next()
  }
}
复制代码

image.png

2. keep-alive其他属性

keep-alive默认是被包裹的组件全部缓存

  • include:字符串或者正则表达式,只有匹配的组件才会被缓存。需要关联组件的name属性结合使用
  • exclude:字符串或者正则表达式,任何匹配的组件都不会被缓存。需要关联组件的name属性结合使用
// 问题1:比如不想缓存其中的一个组件,可以使用exclude

// App.vue:因为出口都是从App.vue被keep-alive包裹的router-view出,所以相当于默认渲染的全部组件都是被缓存了,
<keep-alive >
    <router-view />
</keep-alive>

// 解决问题1:exclude="Profile,User" 指定Profile和User组件不需要被缓存;exclude中指定的字符串组件关联的是组件的name属性。注意这里逗号连接的组件两边都不能有空格
// App.vue
<keep-alive exclude="Profile,User">
    <router-view />
</keep-alive>

// Profile.vue
export default {
  template: '#profile',
  name: 'Profile',
}
// User.vue
export default {
  template: '#user',
  name: 'User',
}
复制代码

命令路由

  • 给route配置name属性,在其他跳转的地方可以使用name替代path的路径,就不用写那么长的路径了
// 示例:
// /router/index.js
const router = new VueRouter({
  routes: [
    {
      path: '/user/:userId',
    //   name属性配置命令路由
      name: 'user',
      component: User
    }
  ]
})

// 两种方式都会把路由导航到 `/user/123`,注意to是前面的冒号绑定
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
router.push({ name: 'user', params: { userId: 123 }})
复制代码

命名视图

  • 命名视图:有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar (侧导航) 和 main (主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果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>
复制代码

一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件

const router = new VueRouter({
  routes: [
    {
      path: '/',
      components: {
        default: Foo,
        a: Bar,
        b: Baz
      }
    }
  ]
})
复制代码

重定向和别名

  • 重定向:当用户访问/a时,URL将会被替换成/b,然后匹配路由为/b
  • 别名/a的别名是/b,意味着,当用户访问/b 时,URL 会保持为/b,但是路由匹配则为/a,就像用户访问/a 一样。
// 重定向也是通过 routes 配置来完成,下面例子是从 /a 重定向到 /b
const router = new VueRouter({
  routes: [
    { path: '/a', redirect: '/b' }
  ]
})

// 重定向的目标也可以是一个命名的路由:
const router = new VueRouter({
  routes: [
    { path: '/a', redirect: { name: 'foo' }}
  ]
})

// 甚至是一个方法,动态返回重定向目标
const router = new VueRouter({
  routes: [
    { path: '/a', redirect: to => {
      // 方法接收 目标路由 作为参数
      // return 重定向的 字符串路径/路径对象
    }}
  ]
})
复制代码
// 示例:别名:两个路径对应一个路由
const router = new VueRouter({
//这时,路径'/fxxksky'和'/two-dogs' 都会跳转到A
  routes: [
    { path: '/fxxksky', component: A, alias: '/two-dogs' }
	//当有多个别名时,alias也可以写成数组形式.  alias: ['/two-dogs', 'three-dogs','four-dogs','five-dogs'] 
  ]
})
复制代码

路由元信息

  • 可以把一些信息存储起来,比如用户登录验证。
// 示例:
const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      children: [
        {
          path: 'bar',
          component: Bar,
          // a meta field
          meta: { requiresAuth: true }
        }
      ]
    }
  ]
})


router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requiresAuth)) {
	//数组some方法,如果meta.requiresAuth为ture,则返回true.此时,说明进入该路由前需要判断用户是否已经登录 
    if (!auth.loggedIn()) {   //如果没登录,则跳转到登录页
      next({
        path: '/login',
        query: { redirect: to.fullPath }  //官方例子的这个小细节很好,通过query将要跳转的路由路径保存下来,待完成登录后,就可以直接获取该路径,直接跳转到登录前要去的路由
      })
    } else {
      next()
    }
  } else {
    next() // 确保一定要调用 next()
  }
})
复制代码

HTML5的history模式

History 接口允许操作浏览器的曾经在标签页或者框架里访问的会话历史记录

  • 常用属性和方法
    • History.length:当前窗口访问过的网址数量(包括当前网页)
    • History.back():前往上一页, 用户可点击浏览器左上角的返回按钮模拟此方法. 等价于 history.go(-1)
    • History.forward():在浏览器历史记录里前往下一页,用户可点击浏览器左上角的前进按钮模拟此方法. 等价于 history.go(1)
    • History.go():通过当前页面的相对位置从浏览器历史记录( 会话记录 )加载页面。比如:参数为-1的时候为上一页,参数为1的时候为下一页

H5新增方法history.pushState()

history.pushState(state, title, url); 添加一条历史记录,不刷新页面

  • history.pushState(state, title[, url]):向当前浏览器会话的历史堆栈中添加一个状态(state)。
  • 参数
state : 一个于指定网址相关的状态对象,popstate事件触发时,该对象会传入回调函数中。如果不需要这个对象,此处可以填nulltitle : 新页面的标题,但是所有浏览器目前都忽略这个值,因此这里可以填nullurl : 新的网址,必须与前页面处在同一个域。浏览器的地址栏将显示这个网址。
复制代码
// 浏览器没有刷新加载demo.html,只是更改浏览器地址栏地址
// index.html
history.pushState(null, null,'./demo.html')
history.pushState(null, null,'./inexistence.html')

// 应用--添加hash值,页面只局部加载
// index.html
history.pushState(null, null,'#one')
复制代码

H5新增方法history.replaceState()

history.replaceState(state, title, url); 替换当前的历史记录,不刷新页面

//demo.html
history.replaceState(null, null,'?one')

当前的历史记录 http://localhost/class/demo.html
被替换为 http://localhost/class/demo.html?one
复制代码
1.popstate 事件:历史记录发生改变时触发,调用history.pushState()或者history.replaceState()不会触发popstate事件
2.hashchange 事件:当页面的hash值改变的时候触发,常用于构建单页面应用。
复制代码

路由懒加载

路由组件的懒加载的实现:结合Vue的异步组件Webpack的代码分割功能

当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。

// 下面这种方式就是定义了能够被 Webpack 自动代码分割的异步组件
const Foo = () => import('./Foo.vue')
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享