VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮

目录

 一、初识路由

1.1 什么是 Vue-Router

1.2 什么单页面应用

1.3 Vue-Router的使用步骤

1.4 什么是router-link?

1.5 创建路由的几种方式

1.6 组件可以分为哪两类

1.7 路由综合小案例

二、声明式导航

2.1 声明式导航基础使用

2.2 声明式导航跳转传值

 三、重定向和别名

3.1 重定向

3.2 给路由起别名

四、路由 404 设置

五、模式修改(History模式)

六、编程式导航

6.1 编程式导航基本使用

6.2 编程式导航传参

七、嵌套路由

八、命名视图

九、导航守卫

9.1 全局前置守卫(beforeEach)--跳转之前触发

9.2 全局解析守卫(beforeResolve)

9.3 全局后置钩子(afterEach)--跳转之后触发

9.4 路由独享的守卫(beforeEnter)

9.5 组件内的守卫

9.6 完整的导航解析流程

十、路由元信息

实现业务:

十一、导航高亮

11.1 初识导航高亮

11.2 示例


 一、初识路由

1.1 什么是 Vue-Router

路由是什么?

一种映射关系

Vue 中的路由是什么?

  • 路径和组件的映射关系
  • Vue-Router和v-if/v-show一样,是用来切换组件的显示的
  • v-if/v-show是标记来切换(true/false)
  • Vue-Router是用哈希来切换(#/xxx)
  • 比v-if/v-show强大的是Vue-Router不仅仅能够切换组件的显示,还能在切换的时候传递参数


1.2 什么单页面应用

单页面应用(SPA): 所有功能在同一个html页面上实现,网页不刷新

前端路由作用: 实现业务场景切换

优点:

  • 整体不刷新页面,用户体验更好
  • 数据传递容易, 开发效率高


缺点:

  • 开发成本高(需要学习专门知识)
  • 首次加载会比较慢一点。不利于seo

单页面如何切换场景:依赖路由切换显示


1.3 Vue-Router的使用步骤

  1. 导入Vue-Router
  2. 定义路由规则
  3. 根据路由规则创建路由对象
  4. 将路径对象挂载到Vue实例中
  5. 修改URL哈希值
  6. 通过渲染匹配的组件


1.4 什么是router-link?

通过a标签确实能够设置URL的hash,但是这种方式并不专业,在Vue-Router中专门提供了一个专门用于设置hash的标签-router-link

特点:

默认情况下Vue会将router-link渲染成a标签,但是我们可以通过tag来指定到底渲染成什么

给router-link设置选中样式:

默认情况下我们可以通过重写 router-link-active 类名来实现选中样式,但是我们也可以通过linkActiveClass来指定选中样式

重定向路由:

{path: '被重定向值',redirect: '重定向之后的值'}

注意点:

如果是通过router-link的方式来设置URL的hash值,那么不用写#,而是通过to属性来设置hansh值


1.5 创建路由的几种方式

a.直接下载 / CDN

    
    
    
    
    
切换到第一个界面 切换到第二个界面

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第1张图片


b.NPM--非手动下载

npm install vue-router --save

如果在一个模块化工程中使用它,必须要通过 Vue.use() 明确地安装路由功能:

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

如果使用全局的 script 标签,则无须如此 (手动安装),如上面的  a

使用  vue create xxx 创建  vue 项目

在src目录下新建router文件夹和views文件夹,然后分别新建index.js和About.vue、Home.vue文件

项目结构如下:

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第2张图片

示例:

Home.vue





About.vue





router/index.js

/**
 * 1.
 */
import Vue from 'vue'
import VueRouter from 'vue-router'

/**
 * 2.
 */
import Home from "../views/Home.vue"
import About from "../views/About.vue"

Vue.use(VueRouter)


/**
 * 3.
 */
const routes = [{
        path: "/",
        component: Home
    },
    {
        path: "/about",
        component: () =>
            import ("../views/About.vue")
    }
]


/**
 * 4. 创建 router 实例,然后传 `routes` 配置
 * 还可以传别的配置参数
 */
const router = new VueRouter({
    routes // (缩写) 相当于 routes: routes
});

export default router

main.js

import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import router from "./router"

Vue.config.productionTip = false


/**
 * 5.创建和挂载根实例--router
 */
new Vue({
    router,
    render: h => h(App),
}).$mount('#app')

App.vue







c.Vue CLI

如果你有一个正在使用 Vue CLI的项目,你可以以项目插件的形式添加 Vue Router。CLI 可以生成上述代码及两个示例路由。它也会覆盖你的 App.vue,因此请确保在项目中运行以下命令之前备份这个文件:

vue add router

 使用  vue create xxx 创建  vue 项目

然后在项目根目录下通过   vue add router   来进行安装路由:

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第3张图片

安装完成后会发现在src目录下自动新增了router和views两个文件夹以及分别多了index.js和About.vue、Home.vue文件:

 VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第4张图片

会发现router文件夹和views文件夹里面的文件的内容和上面手动创建的router文件夹和views文件夹里面的文件的内容差不多,最后运行效果如下:

 VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第5张图片

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第6张图片

 vue creat xxx 创建vue项目时勾选上路由演示:

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第7张图片

创建完成后,项目结构如下:

 VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第8张图片

 会发现在src目录下自动新增了router和views两个文件夹以及分别多了index.js和About.vue、Home.vue文件

router文件夹和views文件夹里面的文件的内容和上面手动创建的router文件夹和views文件夹里面的文件的内容差不多,最后运行效果如下:

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第9张图片

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第10张图片


d.构建开发版

如果你想使用最新的开发版,就得从 GitHub 上直接 clone,然后自己 build 一个 vue-router

git clone https://github.com/vuejs/vue-router.git node_modules/vue-router
cd node_modules/vue-router
npm install
npm run build


1.6 组件可以分为哪两类

.vue文件本质无区别, 方便大家学习和理解, 总结的一个经验

src/views文件夹:页面组件 - 页面展示 - 配合路由用

src/components文件夹:复用组件 - 展示数据/常用于复用

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第11张图片


1.7 路由综合小案例

前期准备:

通过 vue create xxx 创建vue项目,这里在创建时我们勾选上 router 选项,自动创建路由

将前面学习 axios 时封装的跨域配置,utils文件夹以及 vue.config.js文件分别放置在该项目的src目录和根目录下

通过 npm install axios --save 安装 axios

项目结构:

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第12张图片

 vue.config.js

module.exports = {
    devServer: {
        proxy: {
            '/api': {
                target: 'http://iwenwiki.com',
                changeOrigin: true,
                pathRewrite: { // 路径重写
                    "^/api": ""
                }
            }
        }
    }
}

 src/utils/request.js

import axios from "axios"
import qs from "querystring"

/**
 * 处理错误信息
 * status:状态吗
 * info:具体信息
 */

const errorHandle = (status,info) =>{
    switch(status){
        case 400:
            console.log("语义错误");
            break;
        case 401:
            console.log("服务器认证失败");
            break;
        case 403:
            console.log("服务器请求拒绝执行");
            break;
        case 404:
            console.log("请检查网路请求地址");
            break;
        case 500:
            console.log("服务器发生意外");
            break;
        case 502:
            console.log("服务器无响应");
            break;
        default:
            console.log(info);
            break;
    }
}


/**
 * 创建Axios对象
 */

const instance = axios.create({
    // 公共配置
    // baseURL:"http://iwenwiki.com",
    timeout:5000,
    // withCredentials: true
})


/**
 * 拦截器
 */

instance.interceptors.request.use(
    config =>{
        if(config.method === 'post'){
            // token:登陆信息凭证
            config.data = qs.stringify(config.data)
        }
        return config
    },
    error => Promise.reject(error)
)

instance.interceptors.response.use(
    // 完成了
    response => response.status === 200 ? Promise.resolve(response) : Promise.reject(response),
    error =>{
        // 错误信息的处理
        const { response } = error;
        if(response){
            errorHandle(response.status,response.info)
        }else{
            console.log("网络请求被中断了");
        }
    }
)

// get和post等请求方案

export default instance

App.vue




src/views/Home.vue




src/views/About.vue


src/views/NotFound.vue





src/views/Details.vue





components/ListView.vue





src/api/index.js

import axios from "../utils/request"

const base = {
    baseUrl: '/api',
    list: '/api/FingerUnion/list.php',
    details: '/api/FingerUnion/details.php'
};

const api = {
    /**
     * 获得 list 数据
     */
    getList() {
        return axios.get(base.baseUrl + base.list);
    },
    getDetails(params) {
        return axios.get(base.baseUrl + base.details, {
            params
        });
    }
}

export default api;

src/router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'

Vue.use(VueRouter)

const routes = [{
        path: '/',
        name: 'Home',
        component: Home
    },
    {
        path: '/about',
        name: 'About',
        component: () =>
            import ( /* webpackChunkName: "about" */ '../views/About.vue')
    },
    {
        path: '/details/:id',
        name: 'Details',
        component: () =>
            import ( /* webpackChunkName: "about" */ '../views/Details.vue')
    },
    {
        path: '*',
        name: 'NotFound',
        component: () =>
            import ( /* webpackChunkName: "about" */ '../views/NotFound.vue')
    }
]

const router = new VueRouter({
    mode: 'history',
    base: process.env.BASE_URL,
    routes
})

export default router

main.js

import Vue from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第13张图片

点击跳转:

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第14张图片 VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第15张图片


二、声明式导航

2.1 声明式导航基础使用

以前如何实现导航高亮效果?

有没有更简单的方式呢?

可用组件router-link来替代a标签:

vue-router提供了一个全局组件 router-link

router-link实质上最终会渲染成a链接 to属性等价于提供 href属性(to无需#)

 router-link提供了声明式导航高亮的功能(自带类名)

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第16张图片

main.js,

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

router/index.js,

import Vue from 'vue'
import VueRouter from 'vue-router'
import Find from '../views/Find.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/find',
    name: 'Find',
    component: Find
  },
  {
    path: '/my',
    name: 'My',
    component: () => import('../views/My.vue')
  },
  {
    path: '/part',
    name: 'Part',
    component: () => import('../views/Part.vue')
  }
]

const router = new VueRouter({
  routes
})

export default router

App.vue,




views/Find.vue,






views/My.vue,






views/Part.vue,






VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第17张图片


2.2 声明式导航跳转传值

在跳转路由时, 可以给路由对应的组件内传值

方式一:

在router-link上的to属性传值, 语法格式如下:

/path?参数名=值

对应页面组件接收传递过来的值:

$route.query.参数名

方式二:

在router-link上的to属性传值, 语法格式如下: 

/path/值 – 需要路由对象提前配置 path: “/path/参数名”

对应页面组件接收传递过来的值:

$route.params.参数名

main.js,

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

router/index.js,

import Vue from 'vue'
import VueRouter from 'vue-router'
import Find from '../views/Find.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/find',
    name: 'Find',
    component: Find
  },
  {
    path: '/my',
    name: 'My',
    component: () => import('../views/My.vue')
  },
  {
    path: '/part',
    name: 'Part',
    component: () => import('../views/Part.vue')
  },
  { // 传值方式二:动态路由
    path: '/part/:username',
    name: 'Part',
    component: () => import('../views/Part.vue'),
    props: true
  }
]

const router = new VueRouter({
  routes
})

export default router

App.vue,



views/Part.vue,






在router/index.js 里引入 NotFound.vue

  // 404 一定要在组最后
  {
    path: '*',
    name: 'NotFound',
    component: () => import('../views/NotFound.vue')
  }


五、模式修改(History模式)

路由的路径看起来不自然, 能否切成真正路径形式? 

如何切换路由模式呢?

在src/router/index.js文件中做如下修改:

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第20张图片

当使用 history 模式时,URL 就像正常的 url,例如 http://yoursite.com/user/id

不过这种模式要玩好,还需后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确配置,当用户在浏览器直接访问 http://oursite.com/user/id 就会返回 404

所以,要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面

推荐在开发时使用 hash 模式


六、编程式导航

除了使用 标签来定义导航链接,还可以借助 router 的实例方法,通过编写代码来实现 :--用JS代码来进行跳转

6.1 编程式导航基本使用

语法: path或者name任选一个

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第21张图片

注意点:虽然用 name 来进行跳转,但是 url 的 hash 值还是切换 path 路径值

index.js,

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = [
  {
    path: '/', // 默认 hash 值路径
    redirect: '/find', // 重定向到 /find
    // 浏览器 url 中 # 后的路径被修改成 /find-重新匹配规则
    component: () => import('../views/Find.vue')
  },
  {
    path: '/find',
    name: 'Find',
    component: () => import('../views/Find.vue')
  },
  {
    path: '/my',
    name: 'My',
    component: () => import('../views/My.vue')
  },
  {
    path: '/part',
    name: 'Part',
    component: () => import('../views/Part.vue')
  },
  // { // 传值方式二:动态路由
  //   path: '/part/:username',
  //   name: 'Part',
  //   component: () => import('../views/Part.vue')
  // },
  // 404 一定要在组最后
  {
    path: '*',
    name: 'NotFound',
    component: () => import('../views/NotFound.vue')
  }
]

const router = new VueRouter({
  routes
})

export default router

App.vue,





其余 .vue 省略

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第22张图片

应用场景 :

方便修改:name 路由名(在页面上不可见因此可以随便定义 name 对应的值)

path可以在 url 的 hash 值看到


6.2 编程式导航传参

JS跳转路由, 传参

语法: query或者params任选一个

注意: 使用path会忽略params,因此 path 和 params 不能一起使用

推荐:使用 name + query 方式传参

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第23张图片

 index.js,

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

// 解决报错:Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: xxx
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push (location) {
  return originalPush.call(this, location).catch(err => err)
}

const routes = [
  {
    path: '/', // 默认 hash 值路径
    redirect: '/find', // 重定向到 /find
    // 浏览器 url 中 # 后的路径被修改成 /find-重新匹配规则
    component: () => import('../views/Find.vue')
  },
  {
    path: '/find',
    name: 'Find',
    component: () => import('../views/Find.vue')
  },
  {
    path: '/my',
    name: 'My',
    component: () => import('../views/My.vue')
  },
  {
    path: '/part',
    name: 'Part',
    component: () => import('../views/Part.vue')
  },
  // { // 传值方式二:动态路由
  //   path: '/part/:username',
  //   name: 'Part',
  //   component: () => import('../views/Part.vue')
  // },
  // 404 一定要在组最后
  {
    path: '*',
    name: 'NotFound',
    component: () => import('../views/NotFound.vue')
  }
]

const router = new VueRouter({
  routes
})

export default router

App.vue,






Part.vue





VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第24张图片

注意点:如果不断地点击一个导航,例如不断地点击 “朋友--小智”,这个导航,可能会报如下错:

Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: xxx

解决措施:在 router/index.js 里加上:

const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push (location) {
  return originalPush.call(this, location).catch(err => err)
}

即可解决


七、嵌套路由

main.js,

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

router/index.js,

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

// 解决报错:Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: xxx
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push (location) {
  return originalPush.call(this, location).catch(err => err)
}

const routes = [
  {
    path: '/', // 默认 hash 值路径
    redirect: '/find', // 重定向到 /find
    // 浏览器 url 中 # 后的路径被修改成 /find-重新匹配规则
    component: () => import('../views/Find.vue')
  },
  {
    path: '/find',
    name: 'Find',
    component: () => import('../views/Find.vue'),
    children: [
      {
        path: 'ranking',
        component: () => import('../views/Ranking.vue')
      },
      {
        path: 'recommend',
        component: () => import('../views/Recommend.vue')
      },
      {
        path: 'songlist',
        component: () => import('../views/SongList.vue')
      }
    ]
  },
......
]

const router = new VueRouter({
  routes
})

export default router

Find.vue,





App.vue,





...

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第25张图片

 


八、命名视图

在一个路由上同时 (同级) 展示多个视图(页面),而不是嵌套展示

在App.vue中新增如下内容:

在src/views目录中新增  AD.vue文件:





在src/router/index.js文件中做如下修改:

新增,import AD from "../views/AD.vue"

在 path:'/about' 中做如下修改,

 path: '/about',
        name: 'About',
        // component: () =>
        //     import ( /* webpackChunkName: "about" */ '../views/About.vue'),
        components: {
            default: () =>
                import ( /* webpackChunkName: "about" */ '../views/About.vue'),
            ad: AD
        },

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第26张图片


九、导航守卫

主要用来通过跳转或取消的方式守卫导航

有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的

参数或查询的改变并不会触发进入/离开的导航守卫。你可以通过观察 $route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫

应用场景:需要对路由权限判断时

 语法: router.beforeEach((to, from, next)=>{//路由跳转"之前"先执行这里, 决定是否跳转})

 

9.1 全局前置守卫(beforeEach)--跳转之前触发

所有的路由跳转都会触发该函数

推荐写法:

// GOOD
router.beforeEach((to, from, next) => {
  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
  else next()
})

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

  • to: 要跳转到的路由 (路由对象信息)    目标

  • from: 从哪里跳转的路由 (路由对象信息)  来源

  • next: 函数体 - next()才会让路由正常的跳转切换, next(false)在原地停留, next("强制修改到另一个路由路径上");注意: 如果不调用next, 页面留在原地

    • next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。

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

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

    • next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

在src/router/index.js中添加如下内容:

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第27张图片

router.beforeEach((to, from, next) => {
    console.log(from);
    console.log(to);
    next(); //必须调用

})

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第28张图片

 


9.2 全局解析守卫(beforeResolve)

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

里面的参数都和 全局前置守卫 一样


9.3 全局后置钩子(afterEach)--跳转之后触发

和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:

在src/router/index.js中添加如下内容:

router.afterEach((to, from) => {
    console.log(from);
    console.log(to);
})

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第29张图片


9.4 路由独享的守卫(beforeEnter)

只有某一个路由在发生跳转时才会触发

在src/router/index.js中 about 里做如下修改:

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第30张图片


9.5 组件内的守卫

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

  • beforeRouteEnter
  • beforeRouteUpdate (2.2 新增)
  • beforeRouteLeave

在src/router/index.js中做如下修改:

在App.vue中做如下修改:

src/views/About.vue





进入,

 更新,

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第31张图片

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第32张图片

离开,

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第33张图片


9.6 完整的导航解析流程

  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 字段

实现业务:

  • 如果用户未登录, 可以进入首页, 但无法进入关于页面
  • 如果用于未登录, 若通过点击想进入关于页面, 我们要导向登录页面
  • 如果用户已登录, 则可以进入任何页面

在上面的基础之上,在src/views中新建Login.vue:





在src/router/index.js里const routes = []字段里增加如下内容:

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'

Vue.use(VueRouter)

const routes = [{
        path: '/',
        name: 'Home',
        component: Home
    },
    {
        path: '/about/:id',
        name: 'About',
        component: () =>
            import ('../views/About.vue'),
        /**
         * 路由独享导航守卫
         */
        beforeEnter: (to, from, next) => {
            next();
        },
        meta: {
            requiresAuth: true
        }
    },

    {
        path: '/login',
        name: 'Login',
        component: () =>
            import ('../views/Login.vue')
    },
]

const router = new VueRouter({
    mode: 'history',
    base: process.env.BASE_URL,
    routes
})

/**
 * 全局前置导航守卫
 */
router.beforeEach((to, from, next) => {
    // console.log(from);
    // console.log(to);

    //需要判断用户是否登录
    if (to.matched.some(record => record.meta.requiresAuth)) {
        //用户已经登录
        const token = false;
        // if (token) {
        //     next();
        // } else {
        //     next('/login');
        // } 或
        token ? next() : next('/login');

    } else {
        //无需要判断用户是否登录
        next();
    }
    next(); //必须调用

})

export default router

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第34张图片

点击“About”时,

VueRouter:初识路由、声明式导航、重定向和别名、404设置、模式修改(HTML5 History 模式)、编程式导航、嵌套路由、导航守卫、路由元信息、导航高亮_第35张图片


十一、导航高亮

11.1 初识导航高亮

router-link-exact-active:

(精确匹配) url中hash值路径, 与href属性值完全相同, 设置此类名   

例如:

 

 

router-link-active:

(模糊匹配) url中hash值, 包含href属性值这个路径,因此两者都会匹配

例如:

 


11.2 示例

在App.vue的style里面添加如下内容即可:

#nav a.router-link-exact-active {
  color: #42b983;
}

在src/router/index.js的const router = new VueRouter()字段里添加如下内容:

const router = new VueRouter({

    linkActiveClass: "active",

    linkExactActiveClass: "exact-active",

})

在 Home 字段变为Home,表示Home页导航默认为高亮显示

最后App.vue的style里面的 #nav a.router-link-exact-active 字段,便可直接用 .active替代


App.vue




src/views/Home.vue




src/views/About.vue





src/router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'

Vue.use(VueRouter)

const routes = [{
        path: '/',
        name: 'Home',
        component: Home
    },
    {
        path: '/about/:id',
        name: 'About',
        component: () =>
            import ('../views/About.vue'),
        /**
         * 路由独享导航守卫
         */
        beforeEnter: (to, from, next) => {
            next();
        },
        meta: {
            requiresAuth: true
        }
    },

    {
        path: '/login',
        name: 'Login',
        component: () =>
            import ('../views/Login.vue')
    },
]

const router = new VueRouter({
    mode: 'history',
    linkActiveClass: "active",
    linkExactActiveClass: "exact-active",
    base: process.env.BASE_URL,
    routes
})

/**
 * 全局前置导航守卫
 */
router.beforeEach((to, from, next) => {
    // console.log(from);
    // console.log(to);

    //需要判断用户是否登录
    if (to.matched.some(record => record.meta.requiresAuth)) {
        //用户已经登录
        const token = true;
        // if (token) {
        //     next();
        // } else {
        //     next('/login');
        // } 或
        token ? next() : next('/login');

    } else {
        //无需要判断用户是否登录
        next();
    }
    next(); //必须调用

})

/**
 * 全局后置导航守卫
 */
// router.afterEach((to, from) => {
//     // console.log(from);
//     // console.log(to);
// })

export default router

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