Heim > Web-Frontend > js-Tutorial > Hauptteil

Grundkenntnisse und Arbeitsprinzipien des Vue-Routers

亚连
Freigeben: 2018-05-29 17:18:42
Original
1777 Leute haben es durchsucht

In diesem Artikel werden hauptsächlich die Grundkenntnisse im Zusammenhang mit dem Vue-Router und dem Funktionsprinzip der Einzelseitenanwendung vorgestellt

Vorwort

Ich wurde heute im Interview nach dem dynamischen Routing von Vue gefragt und habe nicht einmal geantwortet. Es schien, als wäre das keine seltene Frage. Ich habe die Dokumentation von vue-router schon lange nicht mehr gelesen und viele der verwendeten Dinge und Konzepte stimmen nicht überein. Als ich zurückkam und sah, was dynamisches Routing ist, war ich sprachlos. Es scheint, dass es notwendig ist, das relevante Wissen über Vue-Router zusammenzufassen. Es fühlt sich so peinlich an.

Das Funktionsprinzip einer Single-Page-Anwendung

Das Funktionsprinzip einer Single-Page-Anwendung besteht darin, dass die Hash-Änderung nach dem # in der Browser-URL bewirkt wird Teilen Sie die Seite in verschiedene kleine Module auf und ändern Sie dann den Hash, damit die Seite den Inhalt anzeigt, den wir sehen möchten.

Warum unterscheiden sich die Hashes und warum wirkt sich das auf die Anzeige der Seite aus? Was macht der Browser hier? In der Vergangenheit wurde der Inhalt nach # im Allgemeinen als Anker verwendet, aber er wurde an einer bestimmten Stelle auf einer Seite positioniert. Wie unterscheidet sich das von unserem aktuellen Routing? (Ich kann mir vorstellen, dass die Anzeige einer Route andere Routen verbirgt, stimmt das?) Ich werde später einen Blick darauf werfen und über diesen Zweifel schreiben. Das Wichtigste ist jetzt, sich mit den Grundkonzepten vertraut zu machen.

Text

Wenn Sie einen Vue-Router hinzufügen möchten, müssen wir Komponenten Routen (Routen) zuordnen und dann Sagen Sie Vue-Router, wo sie gerendert werden sollen

Start

//*** 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;)
// 现在,应用已经启动了!
Nach dem Login kopieren

Dynamischer Routenabgleich

entspricht derselben Komponente, da unterschiedliche Parameter unterschiedliche Komponenteninhalte anzeigen. Tatsächlich wird im Routing-Pfad von vue ein „dynamischer Pfad“ verwendet. Router-Parameter 

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

Wenn wir dann uesr/001 und user/002 eingeben, können sie tatsächlich die gleiche Route auf der Inhaltsseite anzeigen auf unterschiedliche Inhalte. Allgemein anwendbare Szenarien: Liste, Berechtigungskontrolle

wird verwendet bei der Definition von: Zeigt dynamisches Routing an

Verwenden Sie {{ $route.params.id }} , um den Inhalt der Parameter in dieser Route abzurufen

Bei der Verwendung von Routenparametern, z. B. beim Navigieren von /user/foo nach /user/bar, wird die ursprüngliche Komponenteninstanz wiederverwendet. Da beide Routen dieselbe Komponente rendern, ist die Wiederverwendung effizienter als die Zerstörung und Neuerstellung. Dies bedeutet jedoch auch, dass der Lifecycle-Hook der Komponente nicht mehr aufgerufen wird.

Wenn Sie bei der Wiederverwendung von Komponenten auf Änderungen der Routing-Parameter reagieren möchten, können Sie einfach das $route-Objekt

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


< 🎜 beobachten (Änderungen überwachen). >

Manchmal kann derselbe Pfad mit mehreren Routen übereinstimmen. In diesem Fall basiert die Übereinstimmungspriorität auf der Reihenfolge der Routendefinition: Wer ihn zuerst definiert, hat die höchste Priorität.

Verschachteltes Routing

Eine Route innerhalb einer Route verschachteln

//路由里面也会出现 <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
  }
  ]
 }
 ]
})
Nach dem Login kopieren

Legen Sie eine leere Route fest und der leere Routeninhalt wird angezeigt, wenn keine Route angegeben ist

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

Programmatische Navigation

Deklarativ:

Programmatisch: router.push(...)

Das kann sein Stellen Sie sich vor, dass programmatischer Push so verstanden werden kann, dass ein neuer Hash in den Browserverlauf verschoben wird, wodurch sich die Route ändert

router.replace() Die Route ändern, aber sie existiert nicht im Verlauf

router.go (n) Ein bisschen wie das window.history.go(n)

benannte Routing von JS besteht darin, einen Namen für jede Route zu definieren.

Benannte Ansichten

Manchmal möchten Sie statt einer verschachtelten Anzeige mehrere Ansichten gleichzeitig anzeigen (Geschwisteransichten), zum Beispiel erstellen Sie ein Layout mit Seitenleiste (Seitennavigation). ) Es gibt zwei Ansichten: und main (Hauptinhalt). Anstelle nur einer einzigen Steckdose können Sie in Ihrer Benutzeroberfläche mehrere individuell benannte Ansichten haben. Wenn router-view keinen Namen festlegt, wird standardmäßig der Standardwert verwendet.

<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>
Nach dem Login kopieren


Eine Ansicht wird mit einer Komponente gerendert, sodass für dieselbe Route mehrere Ansichten mehrere Komponenten erfordern. Stellen Sie sicher, dass Sie die Komponentenkonfiguration korrekt verwenden (mit s):

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


Redirects and Aliases

Die Umleitung erfolgt auch über die Routenkonfiguration. Das folgende Beispiel leitet von /a nach /b um:

const router = new VueRouter({
 routes: [
  { path: &#39;/a&#39;, redirect: &#39;/b&#39; }
 ]
})
Nach dem Login kopieren


Generell kann die Homepage an andere Orte weitergeleitet werden

Das Weiterleitungsziel kann auch eine benannte Route sein:

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


ist sogar eine Methode, die das Weiterleitungsziel dynamisch zurückgibt:

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


„Umleiten“ bedeutet, dass, wenn der Benutzer auf /a zugreift, die URL durch /b ersetzt wird und die passende Route dann /b ist. Was ist also der „Alias“?

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

上面对应的路由配置为:

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


『别名』的功能让你可以自由地将 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: [...]
})
Nach dem Login kopieren

当你使用 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 }
 ]
})
Nach dem Login kopieren

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

导航守卫

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

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

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

全局守卫

const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
 // ...
})
Nach dem Login kopieren


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

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) => {
 // ...
})
Nach dem Login kopieren

路由独享的守卫

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

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

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

组件内的守卫

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

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`
 }
}
Nach dem Login kopieren

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 }
    }
   ]
  }
 ]
})
Nach dem Login kopieren

首先,我们称呼 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()
 }
})
Nach dem Login kopieren

数据获取

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

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

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

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

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

导航完成后获取数据

当你使用这种方式时,我们会马上导航和渲染组件,然后在组件的 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
    }
   })
  }
 }
}
Nach dem Login kopieren

在导航完成前获取数据

通过这种方式,我们在导航转入新的路由前获取数据。我们可以在接下来的组件的 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
   }
  }
 }
}
Nach dem Login kopieren

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

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

相关文章:

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

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

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

Das obige ist der detaillierte Inhalt vonGrundkenntnisse und Arbeitsprinzipien des Vue-Routers. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!