Maison  >  Article  >  interface Web  >  Connaissances de base et principes de fonctionnement de vue-router

Connaissances de base et principes de fonctionnement de vue-router

亚连
亚连original
2018-05-29 17:18:421779parcourir

Cet article présente principalement les connaissances de base liées à vue-router et le principe de fonctionnement de l'application monopage. Les amis dans le besoin peuvent s'y référer

Préface

On m'a posé des questions sur le routage dynamique de Vue lors de l'interview d'aujourd'hui, et je n'ai même pas répondu. Je ne pensais pas que c'était une question rare. Je n'ai pas lu la documentation de vue-router depuis longtemps, et beaucoup d'éléments et de concepts utilisés ne correspondent pas. Quand je suis revenu et que j'ai vu ce qu'était le routage dynamique, j'ai été abasourdi. Il semble qu'il soit nécessaire de résumer les connaissances pertinentes de vue-router. C'est tellement embarrassant.

Le principe de fonctionnement d'une application monopage

Le principe de fonctionnement d'une application monopage est que le changement de hachage après le # dans l'URL du navigateur entraînera la page à modifier. Divisez la page en différents petits modules, puis modifiez le hachage pour que la page affiche le contenu que nous souhaitons voir.

Alors pourquoi les hachages sont-ils différents et pourquoi cela affecte-t-il l'affichage de la page ? Que fait le navigateur ici ? Dans le passé, le contenu après # était généralement utilisé comme ancre, mais il était positionné à un certain endroit sur une page. Comment cela se fait-il. En quoi est-ce différent de notre routage actuel ? (J'imagine que l'affichage d'un itinéraire masquera d'autres itinéraires, est-ce vrai ?) J'y jetterai un œil et j'écrirai sur ce doute plus tard. Le plus important maintenant est de vous familiariser avec les concepts de base.

Texte

Lorsque vous souhaitez ajouter vue-router, ce que nous devons faire est de mapper les composants aux routes ( routes), puis dites à vue-router où les rendre

Démarrer

//*** router-link 告诉浏览器去哪个路由
//*** router-view 告诉路由在哪里展示内容
<p id="app">
 <h1>Hello App!</h1>
 <p>
 <!-- 使用 router-link 组件来导航. -->
 <!-- 通过传入 `to` 属性指定链接. -->
 <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
 <router-link to="/foo">Go to Foo</router-link>
 <router-link to="/bar">Go to Bar</router-link>
 </p>
 <!-- 路由出口 -->
 <!-- 路由匹配到的组件将渲染在这里 -->
 <router-view></router-view>
</p>
// 1. 定义(路由)组件。
// 可以从其他文件 import 进来
const Foo = { template: &#39;<p>foo</p>&#39; }
const Bar = { template: &#39;<p>bar</p>&#39; }
// 2. 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
// 我们晚点再讨论嵌套路由。
const routes = [
 { path: &#39;/foo&#39;, component: Foo },
 { path: &#39;/bar&#39;, component: Bar }
]
// 3. 创建 router 实例,然后传 `routes` 配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({
 routes // (缩写)相当于 routes: routes
})
// 4. 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({
 router
}).$mount(&#39;#app&#39;)
// 现在,应用已经启动了!

La correspondance d'itinéraire dynamique

est équivalente au même composant, car différents paramètres affichent différents contenus de composant. En fait, il est utilisé dans le chemin de routage de vue-router Dynamic. paramètres du chemin 

const router = new VueRouter({
 routes: [
 // 动态路径参数 以冒号开头
 { path: &#39;/user/:id&#39;, component: User }
 ]
})

Ensuite, lorsque nous entrons

et uesr/001 , ils entrent en fait dans le même itinéraire. Nous pouvons modifier le contenu en fonction du. différents paramètres. Les pages affichent un contenu différent. Scénarios généralement applicables : liste, contrôle d'autorisation user/002

est utilisé lors de la définition : Indique le routage dynamique


Utilisez

pour obtenir le contenu des paramètres de cet itinéraire {{ $route.params.id }}

Lors de l'utilisation de paramètres d'itinéraire, tels que la navigation de /user/foo à /user/bar, l'instance du composant d'origine sera réutilisée. Étant donné que les deux routes restituent le même composant, la réutilisation est plus efficace que la destruction et la recréation. Cependant, cela signifie également que le hook de cycle de vie du composant ne sera plus appelé.

Lors de la réutilisation de composants, si vous souhaitez répondre aux modifications des paramètres de routage, vous pouvez simplement regarder (surveiller les modifications) l'objet $route

const User = {
 template: &#39;...&#39;,
 watch: {
 &#39;$route&#39; (to, from) {
  // 对路由变化作出响应...
 }
 }
}


Parfois, un même chemin peut correspondre à plusieurs itinéraires. Dans ce cas, la priorité de correspondance est basée sur l'ordre dans lequel les itinéraires sont définis : celui qui le définit en premier aura la priorité la plus élevée. .

Routage imbriqué

Imbriquer un itinéraire à l'intérieur d'un itinéraire

//路由里面也会出现 <router-view> 这是嵌套路由展示内容的地方
const User = {
 template: `
 <p class="user">
  <h2>User {{ $route.params.id }}</h2>
  <router-view></router-view>
 </p>
 `
}
//定义路由的时候在 加children 子路由属性
const router = new VueRouter({
 routes: [
 { path: &#39;/user/:id&#39;, component: User,
  children: [
  {
   // 当 /user/:id/profile 匹配成功,
   // UserProfile 会被渲染在 User 的 <router-view> 中
   path: &#39;profile&#39;,
   component: UserProfile
  },
  {
   // 当 /user/:id/posts 匹配成功
   // UserPosts 会被渲染在 User 的 <router-view> 中
   path: &#39;posts&#39;,
   component: UserPosts
  }
  ]
 }
 ]
})

Définissez un itinéraire vide, et le contenu de l'itinéraire vide sera affiché lorsqu'aucun itinéraire n'est spécifié

const router = new VueRouter({
 routes: [
 {
  path: &#39;/user/:id&#39;, component: User,
  children: [
  // 当 /user/:id 匹配成功,
  // UserHome 会被渲染在 User 的 <router-view> 中
  { path: &#39;&#39;, component: UserHome },
  ]
 }
 ]
})

Navigation par programmation

Déclaratif : 327e3535b9e0e9f12607bd1fd4e603ad

Programmatique : router.push(...)

On peut imaginer que le push programmatique peut être compris comme l'insertion d'un nouveau hachage dans l'historique du navigateur, provoquant le changement de l'itinéraire

router.replace() Modifie l'itinéraire mais n'existe pas dans l'historique

router.go(n) est un peu comme le window.history.go(n)

Named Routing de JS consiste à définir un nom pour chaque itinéraire.

Vues nommées

Parfois, vous souhaitez afficher plusieurs vues en même temps (frères) au lieu d'un affichage imbriqué, par exemple, créez une mise en page avec barre latérale (navigation latérale ) Il existe deux vues : et main (contenu principal). À ce stade, nommer la vue est pratique. Au lieu d'avoir une seule prise, vous pouvez avoir plusieurs vues nommées individuellement dans votre interface. Si router-view ne définit pas de nom, la valeur par défaut est la valeur par défaut.

<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>


Une vue est rendue à l'aide d'un seul composant, donc pour le même itinéraire, plusieurs vues nécessitent plusieurs composants. Assurez-vous d'utiliser correctement la configuration des composants (avec s) :

const router = new VueRouter({
 routes: [
  {
   path: &#39;/&#39;,
   components: {
    default: Foo,
    a: Bar,
    b: Baz
   }
  }
 ]
})


redirection et La redirection d'alias

se fait également via la configuration des routes. L'exemple suivant redirige de /a vers /b :

const router = new VueRouter({
 routes: [
  { path: &#39;/a&#39;, redirect: &#39;/b&#39; }
 ]
})
<.>


Généralement, la page d'accueil peut être redirigée vers d'autres endroits

La cible de redirection peut également être une route nommée :

const router = new VueRouter({
 routes: [
  { path: &#39;/a&#39;, redirect: { name: &#39;foo&#39; }}
 ]
})


Même une méthode qui renvoie dynamiquement la cible de redirection :

const router = new VueRouter({
 routes: [
  { path: &#39;/a&#39;, redirect: to => {
   // 方法接收 目标路由 作为参数
   // return 重定向的 字符串路径/路径对象
  }}
 ]
})


« Redirection » signifie que lorsque l'utilisateur accède à /a, l'URL sera remplacée par /b, puis la route correspondante est /b, puis « l'alias » est Qu'est-ce que c'est ?

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

上面对应的路由配置为:

const router = new VueRouter({
 routes: [
  { path: &#39;/a&#39;, component: A, alias: &#39;/b&#39; }
 ]
})


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

HTML5 History 模式

ue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。

如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。

const router = new VueRouter({
 mode: &#39;history&#39;,
 routes: [...]
})

当你使用 history 模式时,URL 就像正常的 url,例如 http://yoursite.com/user/id,也好看!

不过这种模式要玩好,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问 http://oursite.com/user/id 就会返回 404,这就不好看了。

所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。

给个警告,因为这么做以后,你的服务器就不再返回 404 错误页面,因为对于所有路径都会返回 index.html 文件。为了避免这种情况,你应该在 Vue 应用里面覆盖所有的路由情况,然后在给出一个 404 页面。

const router = new VueRouter({
 mode: &#39;history&#39;,
 routes: [
  { path: &#39;*&#39;, component: NotFoundComponent }
 ]
})

或者,如果你使用 Node.js 服务器,你可以用服务端路由匹配到来的 URL,并在没有匹配到路由的时候返回 404,以实现回退。

导航守卫

我的理解 就是组件或者全局级别的 组件的钩子函数

正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的。

记住参数或查询的改变并不会触发进入/离开的导航守卫。你可以通过观察 $route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫。

全局守卫

const router = new 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: true、name: ‘home' 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。

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

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

全局后置钩子

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

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

路由独享的守卫

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

const router = new VueRouter({
 routes: [
  {
   path: &#39;/foo&#39;,
   component: Foo,
   beforeEnter: (to, from, next) => {
    // ...
   }
  }
 ]
})

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

组件内的守卫

最后,你可以在路由组件内直接定义以下路由导航守卫:

beforeRouteEnter 
beforeRouteUpdate (2.2 新增) 
beforeRouteLeave

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

beforeRouteEnter 守卫 不能 访问 this,因为守卫在导航确认前被调用,因此即将登场的新组件还没被创建。

完整的导航解析流程

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

路由元信息

我的理解就是 他可以把路由的父路径都列举出来,完成一些任务,比如登录,user 组件需要登录,那么user下面的foo组件也需要,那么可以通过这个属性 来检测这个路由线上 的一些状态。

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

const router = new VueRouter({
 routes: [
  {
   path: &#39;/foo&#39;,
   component: Foo,
   children: [
    {
     path: &#39;bar&#39;,
     component: Bar,
     // a meta field
     meta: { requiresAuth: true }
    }
   ]
  }
 ]
})

首先,我们称呼 routes 配置中的每个路由对象为 路由记录。路由记录可以是嵌套的,因此,当一个路由匹配成功后,他可能匹配多个路由记录

例如,根据上面的路由配置,/foo/bar 这个 URL 将会匹配父路由记录以及子路由记录。

一个路由匹配到的所有路由记录会暴露为 $route 对象(还有在导航守卫中的路由对象)的 $route.matched 数组。因此,我们需要遍历 $route.matched 来检查路由记录中的 meta 字段。

下面例子展示在全局导航守卫中检查元字段:

router.beforeEach((to, from, next) => {
 if (to.matched.some(record => record.meta.requiresAuth)) {
  // this route requires auth, check if logged in
  // if not, redirect to login page.
  if (!auth.loggedIn()) {
   next({
    path: &#39;/login&#39;,
    query: { redirect: to.fullPath }
   })
  } else {
   next()
  }
 } else {
  next() // 确保一定要调用 next()
 }
})

数据获取

我的理解就是在哪里获取数据,可以再组件里面,也可以在组件的守卫里面,也就是组件的生命周期里面。

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

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

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

从技术角度讲,两种方式都不错 —— 就看你想要的用户体验是哪种。

导航完成后获取数据

当你使用这种方式时,我们会马上导航和渲染组件,然后在组件的 created 钩子中获取数据。这让我们有机会在数据获取期间展示一个 loading 状态,还可以在不同视图间展示不同的 loading 状态。

假设我们有一个 Post 组件,需要基于 $route.params.id 获取文章数据:

<template>
 <p class="post">
  <p class="loading" v-if="loading">
   Loading...
  </p>

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

  <p v-if="post" class="content">
   <h2>{{ post.title }}</h2>
   <p>{{ post.body }}</p>
  </p>
 </p>
</template>
export default {
 data () {
  return {
   loading: false,
   post: null,
   error: null
  }
 },
 created () {
  // 组件创建完后获取数据,
  // 此时 data 已经被 observed 了
  this.fetchData()
 },
 watch: {
  // 如果路由有变化,会再次执行该方法
  &#39;$route&#39;: &#39;fetchData&#39;
 },
 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))
  })
 },
 // 路由改变前,组件就已经渲染完了
 // 逻辑稍稍不同
 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
   }
  }
 }
}

在为后面的视图获取数据时,用户会停留在当前的界面,因此建议在数据获取期间,显示一些进度条或者别的指示。如果数据获取失败,同样有必要展示一些全局的错误提醒。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

Angular使用操作事件指令ng-click传多个参数示例

JavaScript代码实现txt文件的上传预览功能

Angularjs实现控制器之间通信方式实例总结

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn