vue-router使用手册

官网:https://router.vuejs.org/zh/installation.html

安装

npm i vue-router

配置

// router/index.js
import Vue from 'vue';
import VueRouter from 'vue-router'
import Home from '@/buyCars/Home.vue'
import About from '@/buyCars/About.vue'
import Detail from '@/buyCars/Detail.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'home',
    component: Home
  },
  // 路由与子路由
  {
    path: '/about',
    name: 'about',
    component: About,
    children: [
      {
        // 访问/about时,默认访问的页面
        path: '',
        name: 'detail',
        component: AboutPage
      },
      {
        // 注意子路由前不要加/,否则会被认为是根目录那一级的路由;不加/会自动默认嵌套在父路由下/about/cart
        path: 'cart',
        name: 'cart', 
        component: Cart
      }
    ]
  },
  {
    // 配置动态路由
    path: '/detail/:id',
    // name: 'detail',
    component: Detail
  }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.Base_URL,
  routes
})
export default router;

// main.js
import router from './router'
new Vue({
  router, // 注意key是小写,写成大写会报错
  render: h => h(App),
}).$mount('#app')

// App.vue
// 嵌套的子路由的视图,记录也要添加router-view标签

路由跳转



  {{item.goods}}

// 方法2
this.$router.push({name: 'detail', params: {id: item.id}})

跨域代理配置

vue cli官网 - 配置参考: https://cli.vuejs.org/zh/config/

// vue.conifg.js
module.exports = {
  // vue2的配置代理
  devServer: {
    proxy: {
      '/api': {
        target: "http://localhost:7777",
        pathRewrite: {
          "^/api": ""
        }
      }
    }
  }
};

$router和$route

  • $router:本质上也就是我们创建的路由对象:
const router = new VueRouter({
  mode: 'history',
  base: process.env.Base_URL,
  routes
})

  • $route是经过处理的,当前页面的一些路由信息对象:
this.$route === {
  fullPath: "/"
  hash: ""
  matched: [{…}]
  meta: {}
  name: "home"
  params: {}
  path: "/"
  query: {}
}

// 获取动态路由
let id = this.$route.params.id

它们其实就是由插件的形式,绑定在Vue实例上的

import Vue from 'vue';
import VueRouter from 'vue-router'
Vue.use(VueRouter)

路由守卫

使用场景,举个栗子:当购物车改变排序(比如金额从低到高)的参数时,要通过queryString方式记录,以便分享给他人记录此排序
如果只是queryString(?sort=asc或?sort=desc)改变的话,路由组件会复用,而不是销毁重建,所以组件中初始请求并不会再次发送。这时要监听路由参数的变化,去重新请求的话,有两种方式:

1. 通过watch去监听路由变化

 watch: {  
   //  to是要跳转的路由信息,from是跳转之前的信息
   $route(to, from) {
     console.log('$route', to, from);
     const sort = to.query.sort;
     this.getGoods(sort)  // 参数改变后,重新请求后台数据
   }
 }

2. 通过路由守卫完成

路由守卫的钩子

  • beforeRouteEnter: 在地址栏输入url,按下enter时调用
  • beforeRouteUpdate: 在当前路由改变,但是该组件被复用时调用,比如像这种只改变queryString的路由
  • beforeRouteLeave: 离开当前路由时被调用

它们有参数是一样的:

  • to: 目标路由的$route对象
  • from: 跳转前的$route对象
  • next: 路由确认回调函数,类似Promise中的resolve函数,一定要调用next函数,才能保证后续导航行为继续
    1. next(): 继续进入管道中的下一个钩子
    2. next(false): 中断当前导航。如果浏览器url改变了(可能用户手动或浏览器后退),那么url地址会重置到from路由对应的地址
    3. next('/')或next({path: '/'}): 跳转到另一个路由。当前导航被中断,并跳到指定地址

单个vue组件中的使用

 create() {},
 // 在地址栏输入url,按下enter时,调用,相当于一个拦截器,必须调用next()才能正常访问路由,否则会被拦截
 beforeRouteEnter(to, from, next) {
   //  这里是在beforeCreate之前,不能调用组件实例this,只能处理跟data无关的操作
   console.log("beforeRouterEnter");
  //  如果非要操作实例中的数据,只能在next回调函数中处理
   next(vm => {
    //  处理和vue实例相关的操作
    console.log(1111, vm);
   }) 
 },
//  在当前路由改变,但是该组件被复用时调用,比如像这种只改变queryString的路由
 beforeRouteUpdate(to, from, next) {
   console.log("beforeRouterUpdate");
   console.log(to.query.sort);
   this.getGoods(to.query.sort);
   next()
 },
// 离开当前路由时被调用
 beforeRouteLeave() {
   console.log("beforeRouterLeave");
   next() 
 }

路由独享的守卫,在配置路由时设置beforEnter

在访问某个地址时,就会执行beforEnter中的操作,这种应用不多

// router/index.js
const routes = [
  {
    path: '/',
    name: 'home',
    beforeEnter: (to, from, next) => {
      // ...
    }
  }
]

全局路由守卫

参考:https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%85%A8%E5%B1%80%E5%89%8D%E7%BD%AE%E5%AE%88%E5%8D%AB

  • beforeEach:当一个导航触发时,全局前置守卫按照创建顺序调用
  • beforeResolve:在所有组件内守卫和异步路由组件被解析之后被调用
  • afterEach: 导航被确认后调用
// router/index.js
const routes = [{...}]
const router = new VueRouter({
  mode: 'history',
  routes
})

// 设置全局路由守卫
router.beforeEach((to, from, next) => {
  // 如果没有登录,且要跳转的路由不是登录页,就跳转到登录页
  if(!isLogin && to.name !== 'login') {
    next({name: 'login'})
  }else {
    next()
  }
})

props路由传递

有些子页面可以接收父组件的props参数,确无法接收到父组件的路由params参数。为了解决这个问题,可以在路由配置中将props设置true,这样路由参数会和父组件的props做个合并,传给子组件
当有些页面既是路由组件,同时又是一个组件的子组件(比如一些详情面,既是单独的路由详情页,又是某些页面的弹出窗组件),那么这时候就可以设置params为true,这样就能统一在props中接收动态参数

// router/index.js
const routes = [
  // 默认将所有route.params参数放在父组件给子组件中的props中
  {
    path: '/',
    name: 'home',
    component: Home,
    props: true
  },
  // 也可以有选择性表示放置哪些参数在props中,但是这个值是事先定好的,不能指定参数
  {
    path: '/aa/:id',
    name: 'home',
    component: Home,
    // 对象方式,只能传指定值的对象
    // props: {id: 2},
    // 要想使用参数,要使用函数方式
    porps(route) {
      return {
        a: 1,
        b: 2,
        id: route.params.id
      }
    }
  },
]

// 父组件

// 子组件中,要设置接收的动态参数名称,注意要和路由设置的名称保持一致;父组件中,也是同样传入同名的参数
props: ['id']

跳转页面,获取数据的方式

跳转页面后获取数据

也就是先跳到详情页,然后再在详情页的created()中获取到数据后,再渲染页面

跳转前获取数据

我们知道,当进入一个页面时,会调用beforeRouteEnter钩子,当在其中调用next()后,才会真正跳转到那个路由,可以利用这一点,进行先获取数据,再进入路由跳转;
但这个可能比较少用,因为它不适用单独一个组件的传参,更适合路由组件

async beforeRouteEnter(to, from, next) {
   console.log("进入" + to.name + "页面前");
  //  可以使用to.params来获取路由参数
   let res = await getGoodsDetail(to.params.id)
   const { data, msg } = res.data
   next(vm => {
     vm.showDetail = msg === 'ok' ? true: false
     vm.info = data
   })
 },
 methods: {
   getDetail() {
    //  $route.params.
     getGoodsDetail(this.id).then(res => {
       console.log(res.data.data);
       const {data, msg} = res.data
       this.showDetail = msg === 'ok' ? true: false
       this.info = data
     })
   }
 }

路由动画

进度条 NProgress.js

官网: https://ricostacruz.com/nprogress/
是一个独立js库,用于在页面加载时添加进度条显示

主要包括以下四个方法:

  • NProgress.start() : 设置一个开始进度条
  • NProgress.set(0.4) :设置40%的进度条
  • NProgress.inc() :将进度条进度往前一点点
  • NProgress.done() : 进度条完成
  1. vue中安装: npm i nprogress
    我们可以在全局路由守卫中给页面加载时,添加进度条:
// router/index.js

import NProgress from 'nprogress'
import 'nprogress/nprogress.css'

router.beforeEach((to, from, next) => {
  NProgress.start()
  next()
})

router.afterEach((to, from, next) => {
  NProgress.done()
})

离开,进入时的动画

可以参考trasition的使用


  

.fade-enter-active, .fade-leave-active {
  transition: opacity 3s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
  opacity: 0;
}

路由滚动位置记录

new VueRouter配置中,有一项是scrollBehavior函数,它接收三个参数:

  • to:同路由守卫中$route对象
  • from:同路由守卫中$route对象
  • savedPositon:记录的滚动条位置

当使用浏览器的回退和前进功能时,scrollBehavior中的savedPosition参数会记录上次用户浏览到的滚动位置; 但如果是用户点击跳转a标签等方式,savedPosition则不会记录,而是为Null
scrollBehavior返回是一个对象{x: 0, y:0},表示当前滚动条要滚动的位置(已作废)

const router = new VueRouter({
  mode: 'history',
  base: process.env.Base_URL,
  routes,
  scrollBehavior(to, from, savedPosition) {
    console.log("当使用:", savedPosition);
        console.log("当使用:", savedPosition);

    // vue-router 不再支持return 方式
    if(savedPosition) {
      console.log("回退到原来位置:", savedPosition);      
    }else {
      return {x:0, y: 0}
    }

    // 路由滚动一直都不生效,后续等解决....
    document.body.srcollTop = 50
    document.documentElement.scrollTop = 50
    window.scrollTo(0, 50)
  }
})

路由懒加载

静态方式:

// router/index.js
// 1. 静态方式
import Home from '@/buyCars/Home.vue'
import Detail from '@/buyCars/Detail.vue'
const routes = [
  {
    path: '/',
    name: 'home',
    component: Home
  },
  {
    path: '/about',
    name: 'about',
    component: About
  }
]

// 生成的dist包:会将所有静态路由都打包一个包,chunk-verdors.js,这样体积会比较大,且一次加载时间也会比较长

// 2. 动态加载(懒加载)方式
const routes = [
  {
    path: '/',
    name: 'home',
    component: () => import('@/buyCars/Home.vue')
  },
  {
    path: '/about',
    name: 'about',
    component: () => import(/* webpackChunkName: "about" */ '@/buyCars/Detail.vue'),
    children: [
      {
        path: '/',
        name: 'home',
        component: () => import(/* webpackChunkName: "about" */ '@/buyCars/Home.vue')
      },
      {
        path: '/',
        name: 'home',
        component: () => import(/* webpackChunkName: "about" */ '@/buyCars/Home.vue')
      }
    ]
  }
]

// 生成的dist包,会打包成多个(一般一个懒加载对应一个)chunk-verdors.js文件
// 但是,往往一个级联路由,会将这一个模块的路由组件都打成一个包,以便当成一个整体模块,通过注释 /* webpackChunkName: "about" */ 说明包的名称,包名称一致webpack会将其打包成一个包

router.addRoutes动态加载路由

// login.vue

methods: {
  login() {
    // 如果已经登录,且为管理员
    if(this.$store.isLogin && this.$store.username === 'admin') {
      // 动态加载后台管理权限
      this.$router.addRoutes([
        {
          path: '/admin',
          name: 'admin',
          component: () => import(/*webpackChuckName: "admin" */ '@/views/admin.vue')
        }
      ])
      this.$router.push({ name: 'admin'})
    }
  }
}

你可能感兴趣的:(vue-router使用手册)