vue从入门到进阶:vue-router路由功能九

基本使用

html:

<script src="https://unpkg.com/vue/dist/vue.js"></script>
="https://unpkg.com/vue-router/dist/vue-router.js">

div id="app">
  h1>Hello App!</p>
    <!-- 使用 router-link 组件来导航. -->
     通过传入 `to` 属性指定链接.  <router-link> 默认会被渲染成一个 `<a>` 标签 router-link to="/foo">Go to Foorouter-link="/bar">Go to Bar 路由出口 -->
   路由匹配到的组件将渲染在这里 router-viewdiv>

JavaScript:

// 0. 如果使用模块化机制编程,導入Vue和VueRouter,要调用 Vue.use(VueRouter)

 1. 定义(路由)组件。
// 可以从其他文件 import 进来
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }

 2. 定义路由 每个路由应该映射一个组件。 其中"component" 可以是 通过 Vue.extend() 创建的组件构造器, 或者,只是一个组件配置对象。 我们晚点再讨论嵌套路由。
const routes = [
  { path: '/foo',component: Foo },{ path: '/bar' 3. 创建 router 实例,然后传 `routes` 配置 你还可以传别的配置参数,不过先这么简单着吧。
const router = new VueRouter({
  routes  (缩写)相当于 routes: routes
})

 4. 创建和挂载根实例。 记得要通过 router 配置参数注入路由, 从而让整个应用都有路由功能
const app =  Vue({
  router
}).$mount('#app')

 现在,应用已经启动了!

通过注入路由,我们可以用 this.$router 来访问它,就像在任何组件里用 this.$router 访问当前路有一样。

export default {
  computed: {
    username () {
       我们很快就会看到 `params` 是什么
      return this.$route.params.username
    }
  },methods: {
    goBack () {
      window.history.length > 1
        ? this.$router.go(-1)
        : this.$router.push('/')
    }
  }
}

路由的命名

const router =  VueRouter({
  routes: [
    {
      path: '/user/:userId'

要链接到一个命名路由,可以给 router-linkto 属性传一个对象:

:to="{ name: 'user',params: { userId: 123 }}">User>

这跟代码调用 router.push() 是一回事:

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

这两种方式都会把路由导航到 /user/123 路径。

重定向和别名

const router =  VueRouter({
  routes: [
    { path: '/a',redirect: '/b' }
  ]
})

重定向的目标也可以是一个命名的路由:

const router =  }}
  ]
})

甚至是一个方法,动态返回重定向目标:

const router =  {
       方法接收 目标路由 作为参数
       return 重定向的 字符串路径/路径对象
    }}
  ]
})

别名:/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样。

const router =  }
  ]
})

『别名』的功能让你可以自由地将 UI 结构映射到任意的 URL,而不是受限于配置的嵌套路由结构。

路由组件传参props

方式一:

const User = {
  template: '<div>User {{ $route.params.id }}</div>'
}
const router =  VueRouter({
  routes: [
    { path: '/user/:id'
const User = {
  props: ['id'],template: '<div>User {{ id }}</div>' VueRouter({
  routes: [
    { path: '/user/:id',component: User,props: true }, 对于包含命名视图的路由,你必须分别为每个命名视图添加 `props` 选项:
    {
      path: '/user/:id': User,sidebar: Sidebar },props: { default: true,sidebar: false }
    }
  ]
})

如果 props 被设置为 trueroute.params 将会被设置为组件属性。

HTML5 History 模式

const router =  VueRouter({
  mode: 'history'
const router = 

路由元信息meta

定义路由的时候可以配置 meta 字段:

const router =  VueRouter({
  routes: [
    {
      path: '/foo' a meta field
          meta: { requiresAuth:  }
        }
      ]
    }
  ]
})

路由过渡动效

<transition>
  <router-view></router-view>
</transition>

上面的用法会给所有路由设置一样的过渡效果,如果你想让每个路由组件有各自的过渡效果,可以在各路由组件内使用 <transition> 并设置不同的 name。

const Foo = {
  template: `
    <transition name="slide">
      <div class="foo">...</div>
    </transition>
  `
}

const Bar = {
  template: `
    <transition name="fade">
      <div class="bar">...</div>
    </transition>
  `
}

active-class

设置 链接激活时使用的 CSS 类名。默认值可以通过路由的构造选项 linkActiveClass 来全局配置。

<router-link class="uilink" :to="{name:'orgList'}" active-class="active">成员</router-link>

嵌套路由

const router =  当 /user/:id/profile 匹配成功,
           UserProfile 会被渲染在 User 的 <router-view> 中
          path: 'profile' 当 /user/:id/posts 匹配成功
           UserPosts 会被渲染在 User 的 <router-view> 中
          path: 'posts'
 字符串
router.push('home' 对象
router.push({ path: 'home' })

 命名的路由
router.push({ name: 'user',params: { userId: 123 }})

 带查询参数,变成 /register?plan=private
router.push({ path: 'register',query: { plan: 'private' }})

注意:如果提供了 pathparams 会被忽略,上述例子中的 query 并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name 或手写完整的带有参数的 path

const userId = 123
router.push({ name: 'user',params: { userId }})  -> /user/123
router.push({ path: `/user/${userId}` })  -> /user/123 这里的 params 不生效
router.push({ path: '/user',1)"> -> /user

router.go(n)

 在浏览器记录中前进一步,等同于 history.forward()
router.go(1 后退一步记录,等同于 history.back()
router.go(-1 前进 3 步记录
router.go(3 如果 history 记录不够用,那就默默地失败呗
router.go(-100)
router.go(100)

命名视图

有时候想同时(同级)展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar(侧导航) 和 main(主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default

router-view class="view one"="view two" name="a"="view three"="b">

一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components 配置(带上 s):

const router =  VueRouter({
  routes: [
    {
      path: '/': Foo,a: Bar,b: Baz
      }
    }
  ]
})

导航守卫

全局守卫

你可以使用 router.beforeEach 注册一个全局前置守卫:

const router =  VueRouter({ ... })

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

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

  • to: Route: 即将要进入的目标 路由对象

  • from: Route: 当前导航正要离开的路由

  • next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。

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

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

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

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

确保要调用 next 方法,否则钩子就不会被 resolved。

全局后置钩子

你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:

router.afterEach((to,from) => ...
})

路由独享的守卫

你可以在路由配置上直接定义 beforeEnter 守卫:

const router =  {
         ...
      }
    }
  ]
})

这些守卫与全局前置守卫的方法参数是一样的。

组件内的守卫

const Foo = {
  template: `...`,beforeRouteEnter (to,next) {
     在渲染该组件的对应路由被 confirm 前调用
     不!能!获取组件实例 `this`
     因为当守卫执行前,组件实例还没被创建
  },beforeRouteUpdate (to,1)"> 在当前路由改变,但是该组件被复用时调用
     举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
     由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
     可以访问组件实例 `this`
 导航离开该组件的对应路由时调用
      }
}

数据获取

有时候,进入某个路由后,需要从服务器获取数据。例如,在渲染用户信息时,你需要从服务器获取用户的数据。我们可以通过两种方式来实现:

  • 导航完成之后获取:先完成导航,然后在接下来的组件生命周期钩子中获取数据。在数据获取期间显示『加载中』之类的指示。

  • 导航完成之前获取:导航完成前,在路由进入的守卫中获取数据,在数据获取成功后执行导航。

导航完成后获取数据

<template>
  <div class="post">
    <div class="loading" v-if="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  {
  data () {
    return {
      loading: null
    }
  },created () {
     组件创建完后获取数据,
     此时 data 已经被 observed 了
    .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) =>false
        if (err) {
          this.error = err.toString()
        } else {
          this.post = post
        }
      })
    }
  }
}

在导航完成前获取数据

通过这种方式,我们在导航转入新的路由前获取数据。我们可以在接下来的组件的 beforeRouteEnter 守卫中获取数据,当数据获取成功后只调用 next 方法。

export  {
      post:  {
      next(vm => vm.setData(err,post))
    })
  },1)"> 路由改变前,组件就已经渲染完了
   逻辑稍稍不同
  beforeRouteUpdate (to,1)">
    getPost(to.params.id,1)">.setData(err,post)
      next()
    })
  },methods: {
    setData (err,post) {
       (err) {
         err.toString()
      }  post
      }
    }
  }
}

滚动行为

使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。 vue-router 能做到,而且更好,它让你可以自定义路由切换时页面如何滚动。

注意: 这个功能只在支持 history.pushState 的浏览器中可用。

当创建一个 Router 实例,你可以提供一个 scrollBehavior 方法:

const router =  VueRouter({
  routes: [...],scrollBehavior (to,savedPosition) {
     return 期望滚动到哪个的位置
  }
})

scrollBehavior 方法接收 tofrom 路由对象。第三个参数 savedPosition 当且仅当 popstate 导航 (通过浏览器的 前进/后退 按钮触发) 时才可用。

这个方法返回滚动位置的对象信息,长这样:

  • { x: number,y: number }
  • { selector: string,offset? : { x: number,y: number }} (offset 只在 2.6.0+ 支持)

如果返回一个 falsy (译者注:falsy 不是 false参考这里)的值,或者是一个空对象,那么不会发生滚动。

举例:

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

对于所有路由导航,简单地让页面滚动到顶部。

返回 savedPosition,在按下 后退/前进 按钮时,就会像浏览器的原生表现那样:

 (savedPosition) {
     savedPosition
  }  {
     }
  }
}

如果你要模拟『滚动到锚点』的行为:

 (to.hash) {
     {
      selector: to.hash
    }
  }
}

 

相关文章

https://segmentfault.com/a/1190000022018995 https://www....
ES6 (ECMAScript 6)中的模块是一个包含 JavaScript 代码的...
from https://mp.weixin.qq.com/s/-rc1lYYlsfx-wR4mQmIIQQ V...
D:\Temp&gt;npm init vite@latest vue3study --temp...
文章浏览阅读1.2k次。最近自己从零撸起的甘特图组件需要子组...
文章浏览阅读3.3k次,点赞3次,收藏16次。静默打印是什么?简...