VUE学习笔记---初识VueRouter

前言

Vue Router啥用呢,其实就是前端来更改页面路径的一个玩意,一般来说,网页的跳转都是要后台来控制的,现在有了它,前端自己就可以定义路由。当然,后台得提供一个默认渲染页面index.html,所以有了这玩意,做个单页面应用就很方便。

正文

实现原理

Vue的思想就是一切皆组件,那么开发单页面应用的时候,它在加载页面的时候不会加载整个页面,而只加载指定的组件,那么当页面路径的改变的时候,并不是去更新页面,而是更新里面的组件。它的实现有两种模式:Hash模式History模式,这个下面再讲。

基本例子

HTML

Go to Foo //name 为路由的名称,params为参数

//留坑,加载路径下默认组件

JavaScript

import Foo from "@/components/Foo"
const routes = [
  {
    path: '/foo',
    component: Foo
  }
]
export default new VueRouter({
  routes
})

全局注册

//main.js
import router from "./router"
new Vue({
  el: '#app',
  router,
  components: { App },
  template: ''
})

动态路由匹配

模式 路径 $route.params
/user/:username /user/evan { username: 'evan' }
/user/:username/post/:post_id /user/evan/post/123 { username: 'evan', post_id: '123' }

在组件中访问路由的参数方法:this.$router.params,此外还有this.$router.query(获取查询参数),this.$router.hash(获取hash值)

嵌套路由

是最顶层的出口,当它匹配到的组件中还包含那么就要用到嵌套路由,children就要出场了。

routes : [
  {
    path : '/user/:id',
    component : User,
    children : [
      {
        path : 'profile',
        component : UserProfile
      }
    ]
  }
]

编程式的导航

啥意思呢,上面的内容是讲怎么在html里面放一个a标签,下面要讲的是,怎么用js实现链接跳转。

router.push()

this.$router.push({name: 'user',params: {userId: 123}})
// 也可以简写一下
// 这个也适用于router-link的to属性
const userId = 123
this.$router.push({path: `user/${userId}` })

router.replace()

router.push()类似,区别就是,router.replace()不会向History添加新纪录,意思就是说不能通过go(-1)返回上一个路由

router.go()

跟原生JS的window.history.go()一个意思

命名视图

加载的是路由下默认的组件,当一个路由下有好多个组件的时候,就需要给加一个name属性,让它对应相应的组件。


import Bar form '@/component/Bar'
routes: [
  {
    path: '/',
    components: {
      default: Foo,
      a: Bar
    }
  }
]

重定向

routes: [
  {
    path: '/a',
    redirect: '/b'  //重定向到/b
  },
  {
    path: '/a',
    redirect: {
      name: 'foo'   //重定向到一个命名的路由
    }
  },
  {
    path: '/a',
    redirect: to => {
      const { hash, params, query} = to;
      //根据hash  query.to  params.id 判断
      //最后 return 一个路径
    }
  }
]

别名

如果要实现路径不变,但是访问的是另外一个路由的东西,那么就要用到别名alias

{path: '/a',alias: '/b'}

/b/a的别名,当访问/b或者/a时候,路径不会改变,但是访问的视图都是/a路由下的视图

高级一点用法就是嵌套路由

{
  path: '/home',
  children: [
    {
      {
        path: 'foo',
        alias: ['/foo',foolis]
      }
    }
  ]
}

上面的代码中,当输入路径为/foo或者home/foolis或者home/foo渲染的都是相同的视图

路由传参

前面提到可以通过parms={}传递参数,在组件中获取参数

{{ $route.params.id }}

这种方式会形成高度耦合,更高明的方式就是用props

{path: '/user/:id',props: true}

props设置为true时,route.params将会变成组件属性,组件中就可以直接使用{{ id }}获取参数id

{path: '/user/:id',props: {name: 'world'}}

传给组件一个对象

props也可以用函数模式(获取查询参数的id)

const router = new VueRouter({
    routes: [
      {path: '/user/:id',props: (route) => ({ query: route.query.id })}
    ]
})

导航守卫

啥是导航守卫呢,就好比假如每一个url路径代表一扇门,那么就有很多个门,有一个人穿过这些门,每两个门中间的路上有那么一个摄像头,那么摄像头就是导航守卫,它就能知道这个人从哪扇门过来的,准备去哪扇门。

参数和查询改变并不需要去另外一扇门,所以摄像头就看不到,遇到这种情况就需要用到beforeRouteUpdate

全局守卫

const router = new VueRouter({})
router.beforeEach((to, from, next) => {
  // 不管函数体内作何判断,最终都必须调用next()
})

上面注册了一个全局前置守卫,一旦有一个导航被出发的时候,它就会调用。next()可以传递参数,当传递一个路由的时候就会中断当前的导航转向去另外一个导航,当参数为false时,返回from的路由。

与全局前置守卫对应的还有一个后置守卫afterEach(),但是后置守卫是没有next参数的

路由独享的守卫

可以直接在路由配置上定义一个beforeEnter守卫

routes: [
  {
    path: '/foo',
    beforeEnter((to,from,next) => {

    })
  }
]

组件内的守卫

export default{
  data() {
    return {}
  },
  beforeRouteEnter(to, from, next) {
    //渲染组件前调用
    //不!能!使用this,因为实例还没创建呢
  },
  beforeRouteUpdate(to, from, next) {
    // 路由更变但是视图没咋变的时候调用
    // 比如参数或者查询内容的变化
    // 可以使用this,因为组件被复用了
  },
  beforeRouteLeave(to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以使用this
    // 主要用来防止用户未保存就离开页面
  }
}

beforeRouteEnter 虽然不能访问this,但是可以传一个回调next来访问实例

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

beforeRouteEnter是唯一一个可以回调的守卫

完整的导航流程

  1. 全局的beforeEach守卫
  2. 重用组件中的beforeRouteUpdate守卫
  3. 路由配置里面的beforeEnter守卫
  4. 解析异步路由组件
  5. 在被激活的组件里调用beforeEnter
  6. 调用全局的beforeResolve守卫
  7. 导航被确认
  8. 调用全局的afterEach

路由元信息

{
  path: '/foo',
  meta: {
    requireIsLogin: true
  }
}

meta字段就是元信息,它的值可以随便定义,它有啥用,主要是给页面加了一个验证,假如有一些页面需要登录权限,那么就可以根据这个元字段来标识这些页面。下面用代码来实现

router.beforeEach((to, from, next) => {
  if(to.match.some(record => record.meta.requireIsLogin)) {
    if(!isLogin) {
      next({
          path: '/login',
          query: { redirect: to.fullPath }
      })
    }else{
      next()
    }
  }else{
    next()  // 一定要调用next()
  }
})

滚动行为

使用前端路由,当切换到新路由后,页面默认保持的的是原来的滚动位置,如果想让它滚动到顶部就像重新加载的一样,就需要用到scrollBehavior

const router = new VueRouter({
    routes:[],
    scrollBehavior(to, from, savedPosition) {
      if(savedPosition) {
        return savedPosition
      }else{
        return {x: 0, y: 0}
      }
    }
})

第三个参数savedPosition仅且仅当是通过浏览器的前进/后退按钮触发的才可用。

如果返回一个falsy(不是false),或者一个空对象,那么不会发生滚动。

如果要模拟滚动到锚点

scrollBehavior(to, from, savedPosition) {
  if(to.hash) {
    return {
      selector: to.hash
    }
  }
}

当然也可以延迟滚动,用Promise来实现

scrollBehavior(to, from, savedPosition) {
  return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve({x: 0, y: 0})
      },500)
  })
}

你可能感兴趣的:(VUE学习笔记---初识VueRouter)