Vue:vue-routerの基本原則
I.はじめに
- ほとんどのVueアプリケーションはシングルページアプリケーションであり、シングルページアプリケーションを実装するための最も重要なツールはルーターです。ルーターの最下層はブラウザーの履歴クラスをカプセル化するため、ブラウザーが新しいページを要求する必要はありません。ページが切り替わります。
第二に、vue-routerの基本的な知識
1.vue-routerの3つのモード
-
Vue-routerには、HTML5 History、HashHistory、AbstractHistory(一時的に展開されない)の合計3つのモードがあります。
-
履歴モード:
-
例:http://test.com/abc
-
popstateイベント:
定義:同じドキュメントの閲覧履歴(履歴オブジェクト)が変更されると、popstateイベントがトリガーされます。
注意:
-
このイベントは、pushStateメソッドまたはreplaceStateメソッドを呼び出すだけではトリガーできません。ユーザーがブラウザーの進むボタンまたは戻るボタンをクリックしたとき、またはhistory.back / forward / goメソッドが使用されたときにのみトリガーされます。
- 同じドキュメントの場合のみ、閲覧履歴の切り替えによって異なるドキュメントが切り替えられると、イベントはトリガーされません。
使用法:を使用する場合、popstateイベントのコールバック関数を指定できます。このコールバック関数のパラメーターはイベントイベントオブジェクトであり、その状態属性はpushStateメソッドとreplaceStateメソッドの最初のパラメーター(つまり、状態オブジェクト)を指します。 URLの)。
-
-
-
ハッシュモード:
-
例:http://test.com/#/abc
-
リダイレクトリンクまたはブラウザ履歴リダイレクトをクリックすると、hashchangeイベントがトリガーされ、URLを解析することで対応するルーティングルールが照合され、abcページにジャンプします。
-
hashchangeイベントのトリガー条件:
ブラウザのアドレスを直接変更し、最後に#hashを追加または変更します
location.hrefまたはlocation.hashの値を変更する
ドットの付いたリンクをクリックする
ハッシュの値が異なる場合、ブラウザの前後でハッシュが変更される可能性があります
-
-
手動で更新した場合、ブラウザはサーバーにリクエストを送信しませんが、hashchangeイベントをトリガーしません。loadイベントを使用してURLを解析し、対応するルーティングルールを照合して、abcページにジャンプできます。
-
ハッシュモードでは、dom置換を使用してページコンテンツを変更します。
-
-
抽象モード:保留中
2.ハッシュルーティングの主要な実装
-
まず、タグ、タグ内のハッシュ値を含むindex.htmlページを作成すると、ページジャンプを実行できます。
-
リンクのリダイレクトであるブラウザのデフォルトの動作を防止します。
-
タグのコンテンツをハッシュ値としてキャプチャします。
-
ブラウザのハッシュジャンプを実行します。
-
Vueソースコードの実装ロジック:
$ router.push()=>
hashHistory.push()=>
History.transitionTo()=>
History.updateRoute()=>
{app._route = route} =>
vm.render()
-
キーコードの実装:
// 捕获hash document.querySelectorAll('a').forEach(item=>{ item.addEventListener('click',e=>{ e.preventDefault(); let link = item.textContent; location.hash = link; },false); }) // 监听路由 window.addEventListener('hashchange',e=>{ console.log({ location : location.href, hash : location.hash }); // 根据hash,进行dom操作 })
3.履歴ルーティングの主要な実装
-
まず、タグを含むindex.htmlページと、ページにジャンプするために使用できるタグ内のターゲットパスを作成します。
-
リンクのリダイレクトであるブラウザのデフォルトの動作を防止します。
-
タグのコンテンツをターゲットパスとしてキャプチャします。
-
history.pushStateメソッドを使用して、ページの状態を変更します。
-
キーコード:
// 捕获路径 document.querySelectorAll('a').forEach(item=>{ item.addEventListener('click',e=>{ e.preventDefault(); let link = item.textContent; if(!!window.history %% history.pushState){ window.history.pushState({ name : 'history'},link,link); }else{ // 不支持,安装polyfill补丁 } },false); }) // 监听路由 window.addEventListener('popstate',e=>{ console.log({ location : location.href, state : e.state }); // 根据路径,进行dom操作 })
4.ナビゲーションガード
-
機能:名前が示すように、
vue-router
提供されているナビゲーションガードは、主にジャンプまたはキャンセルによってナビゲーションを保護するために使用されます。素人の用語では、ルートジャンププロセスの特定の変更を検出することです。ルーティングおよびナビゲーションプロセスに組み込まれる機会はたくさんあります。グローバル、単一ルートの排他的、またはコンポーネントレベルです。 -
3種類のナビゲーションガード:グローバルガード、ルートガード、コンポーネントガード
-
グローバルガードは、ルーティングインスタンスオブジェクトが登録されるときに使用されます:beforeEach、beforeResolve、afterEach
-
ルートガードは、ルート構成アイテムで定義されています:beforeEnter
-
コンポーネントガードは、コンポーネントのプロパティで定義されています:beforeRouteEnter、beforeRouteUpdate、beforeRouterLeave
-
各ガードメソッドは、次の3つのパラメータを受け取ります。
to:Route、入力するルートオブジェクト
from:ルート、現在のナビゲーションが出発しようとしているルート
next:関数。最後に、このフックを解決するには、このメソッドを呼び出す必要があります。実行効果は、次のメソッドの呼び出しパラメーターによって異なります。
1. next() : 进行管道中的下一个钩子。如果全部执行完了,则导航的状态就是comfirmded。 2. next(false) : 终端当前的导航。若浏览器的url改变了,那么url地址会重置到from路由对应的地址; 3. next('/')或者next({path : '/'}) : 跳转到一个不同的地址,当前的导航被中断,然后执行一个新的导航。可以向next转递任意位置的对象,且允许设置`replace: true`、`name: 'home'` 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。 4. next(error) : (2.4.0+)若传入next的参数是一个Error实例,则导航会被终止且该错误会被传递给router.onError()注册过的回调函数。
-
完全なナビゲーション分析プロセス:
- ナビゲーショントリガー;
- 非アクティブ化されようとしているコンポーネントのコール
beforeRouteLeave
ガード - グローバル
beforeEach
ガードを呼び出します。 - ペットコンポーネントの
beforeRouteUpdate
警備員を呼び出します; - ルーティング構成で
beforeEnter
ガードを呼び出します; - 非同期ルーティングコンポーネントを解決します。
- 次にアクティブ化されたコンポーネントで
beforeRouteEnter
ガードを呼び出します; - グローバル
beforeResolve
ガードを呼び出します。 - ナビゲーションが確認されました。
- グローバル
afterEach
フックを呼び出します。 - DOMの更新をトリガーします。
beforeRouteEnter
ガードでnextに渡されたコールバック関数を呼び出すと、作成されたコンポーネントインスタンスがコールバック関数のパラメーターとして渡されます。
第三に、vue-routerのソースコード分析
1.ソースコード分析
-
まず、vue-routerのコンストラクターを見てください
constructor (options: RouterOptions = { }) { this.app = null this.apps = [] this.options = options this.beforeHooks = [] this.resolveHooks = [] this.afterHooks = [] this.matcher = createMatcher(options.routes || [], this) let mode = options.mode || 'hash' this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false if (this.fallback) { mode = 'hash' } if (!inBrowser) { mode = 'abstract' } this.mode = mode switch (mode) { case 'history': this.history = new HTML5History(this, options.base) break case 'hash': this.history = new HashHistory(this, options.base, this.fallback) break case 'abstract': //非浏览器环境下 this.history = new AbstractHistory(this, options.base) break default: if (process.env.NODE_ENV !== 'production') { assert(false, `invalid mode: ${ mode}`) } } }
-
1つ目は、コンストラクターから渡されたモード値を取得することです。モードが履歴であり、ブラウザーがこのモードをサポートしていない場合、モードは強制的にハッシュされます。履歴がサポートされている場合、モードはモードに従って選択されます。
-
モードを取得した後、ルートが初期化されます。initメソッドを見てください。
init (app: any /* Vue component instance */) { // .... const history = this.history if (history instanceof HTML5History) { history.transitionTo(history.getCurrentLocation()) }else if (history instanceof HashHistory) { const setupHashListener = () => { history.setupListeners() } history.transitionTo( history.getCurrentLocation(), setupHashListener, setupHashListener ) } history.listen(route => { this.apps.forEach((app) => { app._route = route }) }) } // .... // VueRouter类暴露的以下方法实际是调用具体history对象的方法 push (location: RawLocation, onComplete?: Function, onAbort?: Function) { this.history.push(location, onComplete, onAbort) } replace (location: RawLocation, onComplete?: Function, onAbort?: Function) { this.history.replace(location, onComplete, onAbort) } }
-
上記のソースコードからわかるように、transitionTo関数は両方のモードで使用されます。
-
ハッシュモードの場合
HashHistory.push()
:push (location: RawLocation, onComplete?: Function, onAbort?: Function) { this.transitionTo(location, route => { pushHash(route.fullPath); onComplete && onComplete(route); }, onAbort) } function pushHash (path) { window.location.hash = path }
-
HashHistory.push
メソッドの主要部分は、場所のハッシュに値を割り当てることであり、ハッシュの変更はブラウザのアクセス履歴に自動的に追加されます。 -
ビューの更新には、次の
TransitionTo
機能が含まれます。transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) { // 调用 match 得到匹配的 route 对象 const route = this.router.match(location, this.current) this.confirmTransition(route, () => { this.updateRoute(route) ... }) } updateRoute (route: Route) { this.cb && this.cb(route) } listen (cb: Function) { this.cb = cb }
-
ルートが変更されると、Historyのthis.cbメソッドが呼び出され、
History.listen
メソッドによって設定されます。VueRouterクラスの定義に戻り、initメソッドを見つけましょう。init (app: any /* Vue component instance */) { this.apps.push(app) history.listen(route => { this.apps.forEach((app) => { app._route = route }) }); }
-
コード内のアプリはVueインスタンスを参照し、app._routeは
Vue.use(Router)
、vue-routerプラグインをロードするときのVue.mixin
メソッドによるグローバル登録の混合であり、登録後に各Vueインスタンスに影響します。この混合は、beforeCreated
フックでのVue.util.defineReactive
応答を定義します。スタイル_route。ルートが変更されるとVue.render
、ビューを更新するために自動的に呼び出されます。vm.render
ルートに対応するコンポーネントは、現在の_routeのパス、名前、およびその他の属性に基づいてレンダリングされます。
2.更新を表示するためのルーティング変更のプロセス
1. this.$router.push(path)
2. HashHistory,push
3. History.transitionTo()
4. const route = this.$router.match(location,this.current) // 进行地址匹配,得到当前地址的route对象
5. History.updateRoute(route)
6. app._route = route
7. vm.render() // 在<router-view></router-view>中渲染
8. window.location.hash = route.fullpath // 浏览器地址栏显示新的地址