美文网首页
Vue路由全解

Vue路由全解

作者: YM雨蒙 | 来源:发表于2019-05-19 22:29 被阅读0次

路由基础

router-link

// 包装的 a 标签, router-link 组件
// to 属性
<router-link to="/about"></router-link>

router-view

// router-view 组件 视图渲染
<router-view></router-view>

router.js

// router.js
// 配置路由列表
import Home from './views/Home.vue'
export default [
  {
    path: '/',  // url 路径
    component: Home  // 路径对应渲染组件
  },
  {
    path: '/about',
    component: () => import('views/About.vue')  // 懒加载,优化
  }
]

动态路由匹配

import Home from './views/Home.vue'
export default [
  {
    path: '/',  // url 路径
    component: Home  // 路径对应渲染组件
  },
  {
    path: '/about',
    component: () => import('views/About.vue')  // 懒加载,优化
  },
  // 动态路由匹配
  {
    path: '/argu/:name',
    component: () => import('views/argu.vue')
  }
]

// argu.vue
<template>
  <div>
    {{ $route.params.name }}  // 当前加载的路由对象 参数 params 对象里的 name 动态路由参数
  </div>
</template>

// url
http://localhost:8080/argu/yym    // $route.params.name == yym

嵌套路由

// parent.vue
<template>
  <div>
    I am parent
    <router-view></router-view>  // 视图渲染
  </div>
</template>

// router.js
// 配置路由列表
import Home from './views/Home.vue'
export default [
  {
    path: '/',  // url 路径
    component: Home  // 路径对应渲染组件
  },
  {
    path: '/about',
    component: () => import('views/About.vue')  // 懒加载,优化
  },
  // 动态路由匹配
  {
    path: '/argu/:name',
    component: () => import('views/argu.vue')
  },
  {
    path: '/parent',
    component: () => import('views/parent.vue'),
    children: [
      {
        path: 'child',  // 不需要写斜杠, 在child 里自动补全
        component: () => import('views/child.vue') 
      }
    ]
  }
]

命名路由

// router.js
import Home from './views/Home.vue'
export default [
  {
    path: '/',  // url 路径
    name: 'home',  // 命名 设置 name 值
    component: Home  // 路径对应渲染组件
  },
  {
    path: '/about',
    name: 'about',   // 命名 设置 name 值
    component: () => import('views/About.vue')  // 懒加载,优化
  },
]

// App.vue
<template>
  <div>
    <router-link :to="{ name: 'home' }"></router-link>
    <router-link :to="{ name: 'about' }"></router-link>
  </div>
</template>

命名视图

// router.js
import Home from './views/Home.vue'
export default [
  {
    path: '/',  // url 路径
    name: 'Home',
    component: Home  // 路径对应渲染组件
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('views/About.vue')  // 懒加载,优化
  },
  {
    path: '/named_view',
    components: {  // 加s 命名多个视图
      default: () => import('views/child.vue'),
      email: () => import('views/email.vue'),
      tel: () => import('views/tel.vue')
    }
  }
]

// App.vue
<template>
  <div>
    <router-link :to="{ name: 'home' }"></router-link>
    <router-link :to="{ name: 'about' }"></router-link>

    <router-view/>
    <router-view name="email" />
    <router-view name="tel" />
  </div>
</template>

重定向

// router.js
import Home from './views/Home.vue'
export default [
  {
    path: '/',  // url 路径
    name: 'Home',
    component: Home  // 路径对应渲染组件
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('views/About.vue')  // 懒加载,优化
  },
  {
    path: '/main',  // 进入 /main 路径
    redirect: '/'  // 重定向到 home
  },
  {
    path: '/main',
    redirect: {  // 对象形式
      name: 'Home'
    }
  },
  {
    path: '/main',
    redirect: to => {  // 函数形式
      return {  // return 一个路径
        name: 'Home'
      }
    }
  },
  {
    path: '/main',
    redirect: to => {  // 函数形式
      return '/'
    }
  }    
]

别名

// router.js
import Home from './views/Home.vue'
export default [
  {
    path: '/',  // url 路径
    alias: '/home_page', // 别名
    name: 'Home',
    component: Home  // 路径对应渲染组件
  },
]

编程式导航

// 通过 js 来控制路由跳转
// Home.vue

<template>
  <div>
    <button @click="hanlderClick">返回</button>
  </div>
</template>

  
<script>
  export default {
    methods: {
      handlerClick () {
        this.$router.go(-1)  // 返回上一页
        this.$router.go(1)  // 前进一页
        this.$router.back()  // 返回上一页
        
        // 浏览历史中加入一个记录
        this.$router.push('/parent')  // 进入 parent
        this.$router.push({  // 命名
          name: 'parent',
          query: {  // query 参数 url:  /parent?name=yym
            name: 'yym'
          }
        })
        
        // 当前浏览历史 替换
        this.$router.replace({
          name: 'parent'
        })
      }
    }
  }
</script>

路由进阶

1. 路由传参

  • props: 布尔模式
// argu.vue
<template>
  {{ name }}
</template>
<script>
  export default {
    props: {
      name: {
        type: String,
        default: 'yym'
      }
    }
  }
</script>
import Home from './views/Home.vue'
export default [
  // 动态路由匹配
  {
    path: '/argu/:name',
    name: 'argu'
    component: () => import('views/argu.vue'),
    props: true
    // props: true , 会使用 router.params 作为组件的属性,  name 插入到组件中,
  }
]
  • props 对象模式
// about.vue
<template>
  {{ food }}  // banana
</template>

<script>
  export default {
    props: {
      food: {
        type: String,
        default: 'apple'
      }
    }
  }
</script>
import Home from './views/Home.vue'
export default [
  {
    path: '/about',
    name: 'about'
    component: () => import('views/about.vue'),
    props: {  // 对象模式传参
      food: 'banana'
    }
  }
]
  • props: 函数模式
// router.js
import Home from './views/Home.vue'
export default [
  {
    path: '/',  // url 路径
    name: 'Home',
    component: Home,  // 路径对应渲染组件
    props: route => ({
      food: route.query.food
    }) 
  },
]
// home.vue
// url:  /home?food=banana
<template>
  {{ food }}  // banana
</template>

<script>
  export default {
    props: {
      food: {
        type: String,
        default: 'apple'
      }
    }
  }
</script>

2. history 模式

// src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import routes from './router.js'
Vue.use(Router)
export default new Router({
  mode: 'hash',  // 默认 #/
  routes
})

// 有一个问题: 匹配不到页面静态资源, 匹配不到组件, 配置404
export default new Router({
  mode: 'history',  // 需要后端同学配合
  routes
})
// url:  /home/abc
// router.js
import Home from './views/Home.vue'
export default [
  {
    path: '/',  // url 路径
    name: 'Home',
    component: Home,  // 路径对应渲染组件
    props: route => ({
      food: route.query.food
    }) 
  },
  // 路由有优先级, 所以 404 放在最后不会影响其他路由的匹配
  {
    path: '*',
    component: () => import('views/error_404.vue')
  }
]

3. 导航守卫

  • 全局导航守卫
// src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import routes from './router.js'
Vue.use(Router)

const router =  new Router({
  routes
})

// 假设登录判断
const HAS_LOGIN = true

// 全局路由前置守卫
router.beforeEach((to, from, next) => {
  // to 即将跳转到的路由对象
  // from 将要离开的路由对象
  // next() 函数
  
  // 开始是否进入登录
  if (to.name !== 'login') {
    if (HAS_LOGIN) next()  // 如果登录了, 继续
    else next({
      name: 'login'
    })
  } else { // 如果跳转到登录页面
    if (HAS_LOGIN) next({name: 'home'}) // 登录了, 到主页
    else next()  // 没有登录 next()
  }
})


// 全局路由后置守卫
router.afterEach((to, from) => {
  // 可以设置 loading 的进度 为 false
})


export default router
  • 路由独享守卫
// router.js
import Home from './views/Home.vue'
export default [
  {
    path: '/',  // url 路径
    name: 'Home',
    component: Home,  // 路径对应渲染组件
    beforeEnter: (to, from, next) => {
      // ...
      next()
    }
  }
]
  • 组件内的钩子
// home.vue
<template>
  home
</template>

<script>
  export default {
    beforeRouteEnter (to, from, next) => {
      // 在渲染该组件的对应路由被 confirm 前调用
      // 不!能!获取组件实例 `this`
      // 因为当守卫执行前,组件实例还没被创建
      next(vm => {
        console.log(vm)
      })
    },
    // 用户编辑未保存离开, 可以询问是否离开
    beforeRouteLeave (to, from, next) {
      // 导航离开该组件的对应路由时调用
      // 可以访问组件实例 `this`
      const leave = confirm('您确认要离开吗')
      if (leave) next()
      else next(false)
    }
  }
</script>
// argu.vue
<template>
  argu
</template>

<script>
  export default {
    beforeRouteUpdate (to, from, next) {
      // 在当前路由改变,但是该组件被复用时调用
      // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
      // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
      // 可以访问组件实例 `this`
    },
  }
</script>
  • 完整的导航解析流程
  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 的回调函数。

4. 路由元信息

// router.js
import Home from './views/Home.vue'
export default [
  {
    path: '/',  // url 路径
    name: 'Home',
    component: Home,
    meta: {  // 路由元信息
      title: '主页'
    }
  },
]
// src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import routes from './router.js'
Vue.use(Router)

const router =  new Router({
  routes
})

// 全局路由前置守卫
router.beforeEach((to, from, next) => {
  // 元信息的判断
  if (to.meta && to.meta.title) {
    window.document.title = to.meta.title || 'admin'
  }
})

export default router

5. 过渡动效

  • 单个路由过渡
<template>
  <transition name="router">
    <router-view></router-view>
  </transition>
</template>


<style>
  .router-enter {
    // ...
  }
  .router-enter-active {
    // ...
  }
  .router-enter-to {
    // ...
  }
  .router-leave {
    // ...
  }
  .router-leave-active {
    // ...
  }
  .router-leave-to {
    // ...
  }
    
</style>
  • 动态过渡
<!-- 使用动态的 transition name -->
<transition :name="transitionName">
  <router-view></router-view>
</transition>
// 接着在父组件内
// watch $route 决定使用哪种过渡
watch: {
  '$route' (to, from) {
    const toDepth = to.path.split('/').length
    const fromDepth = from.path.split('/').length
    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
  }
}

相关文章

  • Vue路由全解

    路由基础 router-link router-view router.js 动态路由匹配 嵌套路由 命名路由 命...

  • Day1.Vue(基本使用和define.properties)

    基本使用(概念) 1.vue的三大核心core,vuex(状态管理),vue-Router(路由),也称为VUE全...

  • flutter 路由全解

    本教程前半部分属于入门,后半部分属于进阶 1.routes 和navigator 的关系 ? 大部分应用程序都包含...

  • Vue应用

    Vue项目 Vue结构 Vue项目打包与发布 Vue语法二 Vue网络请求 Vue路由 动态路由 编程式路由导航

  • 10个Vue开发技巧

    参考文章:10个Vue开发技巧 一、路由参数解耦 知道这个写法,但是没有使用过,可参考笔记vue-router五。...

  • vue路由参数解耦

    一般在组件内使用路由参数,大多数人会这样做: 在组件中使用 $route 会使之与其对应路由形成高度耦合,从而使组...

  • vue路由、自定义指令、脚手架

    *Vue vue-router 一、路由 一、导航式路由 路由路径由

  • Vue路由

    一、Vue路由基础用法: 二、Vue路由配置的抽出 三、路由动态传值: 四、路由的跳转方式: 五、路由的hash模...

  • 手写 Vue Router、手写响应式实现、虚拟 DOM 和 D

    Vue-Router 原理实现 一、Vue-Router 动态路由 二、Vue-Router 嵌套路由 三、Vue...

  • 2018-09-19 vue 八

    一 :路由路由:vue-router是Vue的工具库 vue-router.js下载:npm install ...

网友评论

      本文标题:Vue路由全解

      本文链接:https://www.haomeiwen.com/subject/pyqaaqtx.html