vue-router

vue-router

官网讲解
简述参考

安装

  • npm install vue-router --save-dev 2.x
  • vue add vue-router 3.x

router 和route的区别

  1. router是VueRouter的一个对象,通过Vue.use(VueRouter)和VueRouter构造函数得到一个router的实例对象,这个对象中是一个全局的对象。举例:history对象
  • $router.push({path:'home'});本质是向history栈中添加一个路由
  • $router.replace({path:'home'});替换路由,没有历史记录
  1. route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象,可以获取对应的name,path,params,query等
  • $route.path
    字符串,等于当前路由对象的路径,会被解析为绝对路径,如 "/home/news" 。
  • $route.params
    对象,包含路由中的动态片段和全匹配片段的键值对
  • route.query 对象,包含路由中查询参数的键值对。例如,对于 /home/news/detail/01?favorite=yes ,会得到route.query.favorite == 'yes' 。
  • $route.router
    路由规则所属的路由器(以及其所属的组件)。
  • $route.matched
    数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。
  • $route.name
    当前路径的名字,如果没有使用具名路径,则名字为空。

功能点

功能包括:

  • 嵌套路由/视图映射
  • 模块化,基于组件的路由器配置
  • 路线参数,查询,通配符
  • 查看由Vue.js过渡系统提供支持的过渡效果
  • 细粒度的导航控制
  • 与自动活动CSS类的链接
  • HTML5历史模式或散列模式,在IE9中具有自动回退功能
  • 可自定义的滚动行为

要点

  1. 匹配任何东西,用'*'
{
  // will match everything
  //通常用于404客户端
  path: '*'
}
{
  // will match anything starting with `/user-`
  path: '/user-*'
}
  1. 单击<router-link :to="...">相当于调用router.push(...)

  2. params和query

// literal string path
router.push('home')

// object
router.push({ path: 'home' })

// named route
router.push({ name: 'user', params: { userId: '123' } })

// with query, resulting in /register?plan=private
router.push({ path: 'register', query: { plan: 'private' } })
  1. name和path
const userId = '123'
router.push({ name: 'user', params: { userId } }) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// This will NOT work
router.push({ path: '/user', params: { userId } }) // -> /user
  1. router.replace(location, onComplete?, onAbort?):作用就像router.push,唯一的区别是它导航时没有按下新的历史记录条目,顾名思义 - 它取代了当前的条目。

  2. router.go(n):指示在历史堆栈中前进或后退的步数,类似于window.history.go(n)

// go forward by one record, the same as history.forward()
router.go(1)

// go back by one record, the same as history.back()
router.go(-1)

// go forward by 3 records
router.go(3)

// fails silently if there aren't that many records.
router.go(-100)
router.go(100)
  1. 重定向和别名
//三种重定向的方式
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 => {
      // the function receives the target route as the argument
      // return redirect path/location here.
      return '/b'
    }}
  ]
})
//别名
const router = new VueRouter({
  routes: [
    { path: '/a', component: A, alias: '/b' }
  ]
})
  1. props ???
routes:[
  path:'/home/:id',
  props:true,
]

export default{
  props:['id'],
  mounted(){
    console.log(this.id)
  }
}
  1. mode: 'history', 路由中去掉#号,利用history.pushStateAPI实现URL导航而无需重新加载页面。mode: 'hash',

响应路由参数的变化

当路由参数发生变化时,复用组件实例。两种方式:

const User = {
  template: '...',
  watch: {
    '$route' (to, from) {
      // react to route changes...
    }
  }
}

const User = {
  template: '...',
  beforeRouteUpdate (to, from, next) {
    // react to route changes...
    // don't forget to call next()
  }
}
  1. 路由样式
    exact 精确匹配
linkExactActiveClass: 'active-exact',
linkActiveClass: 'active',

历史操纵

You may have noticed that router.push, router.replace and router.go are counterparts of window.history.pushState, window.history.replaceState and window.history.go, and they do imitate the window.history APIs.

命名视图(插座)

<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
      }
    }
  ]
})

导航守卫 Navigation Guards

导航守卫有点类似 中间件,进入 路由 前 先通过守卫,来判断是否可以通过,进而到达页面。

每个守卫功能都有三个参数:

  • to: Route:导航到的目标Route对象。

  • from: Route:当前路线被导航离开。

  • next: Function:必须调用此函数来解析钩子。该操作取决于提供给的参数next:

    • next():继续前进到管道中的下一个钩子。如果没有留下挂钩,则确认导航。

    • next(false):中止当前导航。如果浏览器URL已更改(由用户手动或通过后退按钮),则会将其重置为from路径的URL 。

    • next('/')或next({ path: '/' }):重定向到其他位置。当前导航将中止,并将启动一个新导航。你可以通过任何位置对象next,它允许您指定类似的选项replace: true,name: 'home'在使用任何选项router-link的to道具或router.push

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

确保始终调用该next函数,否则永远不会解析挂钩。

全局守卫(在定义router的地方定义)


//全局钩子
//使用router.beforeEach注册一个全局 前置守卫
router.beforeEach((to, from, next) => {
  // some every  路由元信息
  const needLogin = to.matched.some(route => route.meta && route.meta.login);
  if (needLogin) {
    // 检验
    const isLogin = document.cookie.includes('login=true');
    if (isLogin) {
      next();
      return;
    }
    const toLoginFlag = window.confirm('该页面需要登录后访问,要去登陆吗?');

    if (toLoginFlag) {
      next('/login');
    }

    return;
  }
  next();
})

//使用router.beforeResolve注册一个全局解析守卫
//在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用
router.beforeResolve((to, from, next) => {
  console.log('beforeResolve');
  next();
})

//router.beforeResolv注册全局后置钩子
//不会接受 next 函数也不会改变导航本身
router.afterEach(() => {
  console.log('afterEach');
})

路由独享的守卫(在路由内定义)

routes:[
  {
    path:
    name:
    component:
    beforeEnter:(to,from,next)=>{
      console.log('路由内的守卫导航')
    }
  }
]

组件内的守卫(在组件内定义)

注意 beforeRouteEnter 是支持给 next传递回调的唯一守卫。对于 beforeRouteUpdatebeforeRouteLeave 来说,this 已经可用了,所以不支持传递回调,因为没有必要了。

beforeRouteEnter(to,from,next){
  next(vm=>{
    //通过'vm'访问组件实例
  })
}

beforeRouteUpdate(to,from,next){
  //使用this
  this.name = to.params.name
  next()
}

// 这个离开守卫通常用来  禁止用户在还未保存修改前突然离开  。该导航可以通过 next(false) 来取消。
 beforeRouteLeave(to,from,next){
   const answer = window.confirm('leave?save?')
   answer?next():next(false) 
 }

进入某一个路径时,执行顺序

  • beforeEach -> beforeEnter -> beforeRouteEnter -> beforeResolve -> afterEach

完整的导航解析流程

  • 导航被触发。
  • 在失活的组件里调用离开守卫。
  • 调用全局的 beforeEach 守卫。
  • 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  • 在路由配置里调用 beforeEnter。
  • 解析异步路由组件。
  • 在被激活的组件里调用 beforeRouteEnter。
  • 调用全局的 beforeResolve 守卫 (2.5+)。
  • 导航被确认。
  • 调用全局的 afterEach 钩子。
  • 触发 DOM 更新。
  • 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。

路由元信息 Route Meta Fields

  • 存储路由信息 meta = {}

过渡动效 Transitions

<!-- use a dynamic transition name -->
<transition :name="transitionName">
  <router-view></router-view>
</transition>
// then, in the parent component,
// watch the `$route` to determine the transition to use
watch: {
  '$route' (to, from) {
    const toDepth = to.path.split('/').length
    const fromDepth = from.path.split('/').length
    this.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
  }
}

数据提取

  • 导航完成之后获取:先完成导航,然后在接下来的组件生命周期钩子中获取数据。在数据获取期间显示“加载中”之类的指示。
<template>
  <div class="post">
    <div v-if="loading" class="loading">
      Loading...
    </div>

    <div v-if="error" class="error">
      {{ error }}
    </div>

    <div v-if="post" class="content">
      <h2>{{ post.title }}</h2>
      <p>{{ post.body }}</p>
    </div>
  </div>
</template>
export default {
  data () {
    return {
      loading: false,
      post: null,
      error: null
    }
  },
  created () {
    //组件创建后完成获取数据
    //此时的data已经被observed
    this.fetchData()
  },
  watch: {
    //如果路由有变化,会再次执行该方法
    '$route': 'fetchData'
  },
  methods: {
    fetchData () {
      this.error = this.post = null
      this.loading = true
      // replace `getPost` with your data fetching util / API wrapper
      getPost(this.$route.params.id, (err, post) => {
        this.loading = false
        if (err) {
          this.error = err.toString()
        } else {
          this.post = post
        }
      })
    }
  }
}
  • 在导航之前获取:导航完成前,在路由进入的守卫中获取数据,在数据获取成功后执行导航。
//过这种方式,我们在导航转入新的路由前获取数据。我们可以在接下来的组件的 beforeRouteEnter守卫中获取数据,当数据获取成功后只调用 next 方法。
export default {
  data () {
    return {
      post: null,
      error: null
    }
  },
  beforeRouteEnter (to, from, next) {
    getPost(to.params.id, (err, post) => {
      next(vm => vm.setData(err, post))
    })
  },
  // when route changes and this component is already rendered,
  // the logic will be slightly different.
  beforeRouteUpdate (to, from, next) {
    this.post = null
    getPost(to.params.id, (err, post) => {
      this.setData(err, post)
      next()
    })
  },
  methods: {
    setData (err, post) {
      if (err) {
        this.error = err.toString()
      } else {
        this.post = post
      }
    }
  }
}

滚动行为

const router = new VueRouter({
  routes: [...],
  scrollBehavior (to, from, savedPosition) {
    // return desired position
  }

  scrollBehavior (to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition
    } else {
      return { x: 0, y: 0 }
    }
  }

  scrollBehavior (to, from, savedPosition) {
    if (to.hash) {
      return {
        selector: to.hash
        // , offset: { x: 0, y: 10 }
      }
    }
  }
})

懒加载路由

//webpack会将具有相同块名称的任何异步模块分组到同一个异步块中。
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,104评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,816评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,697评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,836评论 1 298
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,851评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,441评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,992评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,899评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,457评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,529评论 3 341
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,664评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,346评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,025评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,511评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,611评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,081评论 3 377
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,675评论 2 359

推荐阅读更多精彩内容