WeChatアプレットシングルページアプリケーションルーティングを徹底的に理解するための10分

WeChatアプレットシングルページアプリケーションルーティングを徹底的に理解するための10分

シングルページアプリケーションの特徴

「前提:」Web ページには、クリックするとサイト内の他のページにジャンプできるボタンがあります。

「マルチページ アプリケーション:」 ボタンをクリックして HTML リソースを再読み込みし、ページ全体を更新します。

「シングルページ アプリケーション:」 ボタンをクリックすると、新しい HTML リクエストは発生せず、部分的な更新のみが発生するため、シルクのようにスムーズなネイティブに近いエクスペリエンスを実現できます。

SPA シングルページ アプリケーションがほとんど更新不要で済むのはなぜですか? SP(シングルページ)だから。アプリケーションに初めてアクセスすると、HTML ページとそのパブリック静的リソースのみが返されます。その後のいわゆる「ジャンプ」では、サーバーから HTML ファイルを取得することはなくなり、シミュレートされた DOM 置換操作のみになります。

では、js はどのようにしてコンポーネントの切り替えのタイミングをキャプチャし、更新せずにブラウザの URL を変更するのでしょうか?ハッシュと HTML5History に依存します。

ハッシュルーティング

特徴

  • www.xiaoming.html#bar と同様に、ハッシュ ルートです。# の後のハッシュ値が変更されると、サーバーにデータが要求されません。hashchange イベントを通じて URL の変更を監視し、DOM 操作を実行してページ ジャンプをシミュレートできます。
  • サーバーの協力は不要
  • SEOフレンドリーではない

原理

ハッシュ

HTML5履歴ルーティング

特徴

  1. 履歴モードは HTML5 の新機能です。ハッシュ ルーティングよりも直感的で、次のようになります: www.xiaoming.html/bar。ページ ジャンプをシミュレートするには、history.pushState(state, title, url) を使用してブラウザー ルートを更新します。ルートが変更されると、popstate イベントがリッスンされて DOM が操作されます。
  2. リダイレクトにはバックエンドの協力が必要
  3. SEOに比較的優しい

原理

HTML5の歴史

Vue-router ソースコード解釈

Vue のルーター vue-router を例に、そのソースコードを見てみましょう。

ヒント: この記事の焦点はシングルページ ルーティングの 2 つのモードを説明することであるため、主に次の内容を説明するいくつかのキー コードのみを以下にリストします。

  1. プラグインの登録
  2. VueRouterのコンストラクタはルーティングモードを区別します
  3. コンポーネントをグローバルに登録する
  4. ハッシュ / HTML5History モードのプッシュおよびリッスン メソッド
  5. transitionTo メソッド

プラグインの登録

まず、プラグインとして、Vue が使用できるようにインストール メソッドを意識的に公開する必要があります。

ソースコードの install.js ファイルでは、プラグインを登録してインストールするための install メソッドが定義されており、このメソッドは各コンポーネントのフック関数にミックスされ、beforeCreate フックの実行時にルートが初期化されます。

Vue.mixin({
 作成前() {
 if (isDef(this.$options.router)) {
 this._routerRoot = これ
 this._router = this.$options.router
 this._router.init(これ)
 Vue.util.defineReactive(this, '_route', this._router.history.current)
 } それ以外 {
 this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
 }
 インスタンスを登録します(これ、これ)
 },
 // テキスト全体を通じて、... は省略されたメソッドを示すために使用されます...
});

区別モード

次に、index.js からプラグイン全体の基本クラス VueRouter を見つけます。モードに応じてコンストラクターで異なるルーティングインスタンスが使用されていることは簡単にわかります。

...
'./install' から {install} をインポートします。
'./history/hash' から {HashHistory} をインポートします。
'./history/html5' から {HTML5History} をインポートします。
...
デフォルトクラスVueRouterをエクスポートします。
 静的インストール: () => void;
 コンストラクタ(オプション:RouterOptions = {}){
 if (this.fallback) {
 モード = 'ハッシュ'
 }
 ブラウザ内で
 モード = '抽象'
 }
 this.mode = モード
  
 スイッチ(モード){
 ケース「履歴」:
 this.history = 新しい HTML5History(this、options.base)
 壊す
 ケース 'ハッシュ':
 this.history = 新しい HashHistory(this、options.base、this.fallback)
 壊す
 ケース「抽象」:
 this.history = 新しい AbstractHistory(this、options.base)
 壊す
 デフォルト:
 process.env.NODE_ENV !== 'production' の場合 {
 assert(false, `無効なモード: ${mode}`)
 }
 }
 }
}

ルータリンクコンポーネントをグローバルに登録する

この時点で、次のような疑問が湧くかもしれません。vue-router を使用する場合、共通の <router-link/> と <router-view/> はどこで導入されるのでしょうか?

install.js ファイルに戻ると、router-view および router-link コンポーネントをインポートしてグローバルに登録します。

'./components/view' から View をインポートします。
'./components/link' から Link をインポートします。
...
Vue.component('RouterView', ビュー);
Vue.component('RouterLink', リンク);

./components/link.js では、クリック イベントはデフォルトで <router-link/> コンポーネントにバインドされており、クリックによってハンドラー メソッドがトリガーされ、対応するルーティング操作が実行されます。

定数ハンドラ = e => {
 ガードイベントの場合(e)
 (これを置き換える){
 router.replace(場所、noop)
 } それ以外 {
 router.push(場所、noop)
 }
 }
};

冒頭で述べたように、VueRouter コンストラクターはモードごとに異なる History インスタンスを初期化するため、router.replace と router.push のメソッドも異なります。次に、これら 2 つのモードのソース コードをそれぞれプルダウンします。

ハッシュモード

history/hash.js ファイルでは、history/base.js の History 基本クラスから継承する HashHistory クラスが定義されています。
push メソッドはプロトタイプで定義されています。HTML5History モードをサポートするブラウザー環境 (supportsPushState が true) では、ブラウザー アドレスを変更するために history.pushState が呼び出されます。その他のブラウザー環境では、location.hash = path が直接使用され、新しいハッシュ アドレスが置き換えられます。

実は、これを最初に読んだときは少し疑問に思いました。すでにハッシュ モードになっているのに、なぜ supportsPushState を判断する必要があるのでしょうか? scrollBehavior をサポートするために、history.pushState はキー パラメータを渡すことができ、各 URL 履歴にキーが与えられ、そのキーを使用して各ルートの位置情報を保存することがわかりました。

同時に、プロトタイプにバインドされた setupListeners メソッドは、ハッシュの変更のタイミングをリッスンする役割を担います。HTML5History モードをサポートするブラウザー環境では、popstate イベントをリッスンし、その他のブラウザーでは、hashchange をリッスンします。変更を監視した後、handleRoutingEvent メソッドがトリガーされ、親クラスの transitionTo ジャンプ ロジックが呼び出され、DOM 置換操作が実行されます。

'../util/push-state' から { pushState、replaceState、supportsPushState } をインポートします。
...
エクスポートクラスHashHistoryはHistoryを拡張します{
 セットアップリスナー() {
 ...
 const ハンドルルーティングイベント = () => {
 定数 current = this.current
 if (!ensureSlash()) {
  戻る
 }
 // 親クラス History のジャンプメソッドは transitionTo によって呼び出され、ジャンプ後にパスがハッシュ化されます this.transitionTo(getHash(), route => {
  スクロールをサポートする場合
  handleScroll(this.router, ルート, 現在の, true)
  }
  プッシュ状態をサポートする場合
  ハッシュを置換(ルート.fullPath)
  }
 })
 }
 const eventType = supportsPushState ? 'popstate' : 'hashchange'
 ウィンドウにイベントリスナーを追加します(
 イベントタイプ、
 ルーティングイベントの処理
 )
 this.listeners.push(() => {
 window.removeEventListener(イベントタイプ、handleRoutingEvent)
 })
 }
 
 プッシュ (場所: RawLocation、onComplete?: Function、onAbort?: Function) {
 const { current: fromRoute } = this
 this.transitionTo() は、
 位置、
 ルート => {
 pushHash(ルート.fullPath)
 handleScroll(this.router, ルート, fromRoute, false)
 onComplete && onComplete(ルート)
 },
 中止時
 )
 }
}
...

// 受信したパスをハッシュ化された URL に処理します
関数 getUrl (パス) {
 定数 href = window.location.href
 定数 i = href.indexOf('#')
 定数基数 = i >= 0 ? href.slice(0, i) : href
 `${base}#${path}` を返します
}
...

// ハッシュを置き換える
関数pushHash(パス){
 (PushStateをサポートする)の場合{
 pushState(getUrl(パス))
 } それ以外 {
 window.location.hash = パス
 }
}

//util/push-state.js ファイル内のメソッド export const supportsPushState =
 ブラウザ内 &&
 (関数 () {
 定数 ua = window.navigator.userAgent

 もし (
 (ua.indexOf('Android 2.') !== -1 || ua.indexOf('Android 4.0') !== -1) &&
 ua.indexOf('モバイルSafari') !== -1 &&
 ua.indexOf('Chrome') === -1 &&
 ua.indexOf('Windows Phone') === -1
 ){
 偽を返す
 }
 window.history を返します && typeof window.history.pushState === 'function'
 })()

HTML5履歴モード

同様に、HTML5History クラスは history/html5.js で定義されています。

プッシュ プロトタイプ メソッドを定義し、history.pusheState を呼び出してブラウザー パスを変更します。

同時に、プロトタイプの setupListeners メソッドは popstate イベントを監視し、タイムリーに DOM の置換を行います。

'../util/push-state' から {pushState、replaceState、supportsPushState} をインポートします。
...
エクスポートクラス HTML5History は History を拡張します {

 セットアップリスナー() {

 const ハンドルルーティングイベント = () => {
 現在の状態を定数で表す。
 定数 location = getLocation(this.base);
 if (this.current === START && location === this._startLocation) {
 戻る
 }

 this.transitionTo(場所、ルート => {
 スクロールをサポートする場合
 handleScroll(ルーター、ルート、現在、true)
 }
 })
 }
 window.addEventListener('popstate', handleRoutingEvent)
 this.listeners.push(() => {
 window.removeEventListener('popstate', handleRoutingEvent)
 })
 }
 プッシュ (場所: RawLocation、onComplete?: Function、onAbort?: Function) {
 const { current: fromRoute } = this
 this.transitionTo(場所、ルート => {
 pushState(cleanPath(this.base + route.fullPath))
 handleScroll(this.router, ルート, fromRoute, false)
 onComplete && onComplete(ルート)
 }, 中止時)
 }
}

...

//util/push-state.js ファイルのメソッドエクスポート function pushState (url?: string, replace?: boolean) {
 スクロール位置を保存します。
 定数履歴 = window.history
 試す {
 (置換)の場合{
 const stateCopy = extend({}, history.state)
 stateCopy.key = getStateKey()
 history.replaceState(stateCopy, ''、url)
 } それ以外 {
 history.pushState({ キー: setStateKey(genStateKey()) }, '', url)
 }
 } キャッチ (e) {
 window.location[replace ? 'replace' : 'assign'](url)
 }
}

transitionToはルート変更ロジックを処理します

上記の 2 つのルーティング モードはどちらも、リッスン時に this.transitionTo をトリガーします。これは何ですか?これは実際には history/base.js 基本クラスで定義されたプロトタイプ メソッドであり、ルーティング変更ロジックを処理するために使用されます。

まず、const route = this.router.match(location, this.current) を使用して、渡された値と現在の値を比較し、対応するルート オブジェクトを返します。次に、新しいルートが現在のルートと同じかどうかを判断します。同じ場合は、直接返します。同じでない場合は、this.confirmTransition でコールバックを実行してルート オブジェクトを更新し、ビュー関連の DOM を置き換えます。

エクスポートクラス履歴{
 ...
 遷移先 (
 場所: RawLocation、
 onComplete?: 関数、
 onAbort?: 関数
 ){
 const ルート = this.router.match(場所、this.current)
 this.confirmTransition() は、
 ルート、
 () => {
 定数 prev = this.current
 this.updateRoute(ルート)
 onComplete && onComplete(ルート)
 this.ensureURL()
 this.router.afterHooks.forEach(フック => {
  フック && フック(ルート、前)
 })

 準備ができたら
  this.ready = true
  this.readyCbs.forEach(cb => {
  cb(ルート)
  })
 }
 },
 エラー => {
 中止の場合
  中止(エラー)
 }
 もしエラーなら、this.ready です。
  this.ready = true
  // https://github.com/vuejs/vue-router/issues/3225
  if (!isRouterError(err, NavigationFailureType.redirected)) {
  this.readyErrorCbs.forEach(cb => {
  cb(エラー)
  })
  } それ以外 {
  this.readyCbs.forEach(cb => {
  cb(ルート)
  })
  }
 }
 }
 )
 }
 ...
}

やっと

さて、以上はシングルページルーティングに関するちょっとした知識です。始めから諦めずに続けられるといいですね~~

これで、WeChatミニプログラムシングルページアプリケーションルーティングを10分で徹底的に理解する方法に関する記事は終了です。より関連性の高いミニプログラムシングルページアプリケーションルーティングコンテンツについては、123WORDPRESS.COMで以前の記事を検索するか、次の関連記事を引き続き閲覧してください。今後とも123WORDPRESS.COMを応援してください。

以下もご興味があるかもしれません:
  • Android開発WeChatアプレットルーティングジャンプ方法
  • WeChatアプレット学習ノート: ページ構成とルーティング
  • ミニプログラムのカプセル化ルーティング ファイルとルーティング方法 (5 つの完全な分析)
  • WeChatアプレット開発ルーティング切り替えページリダイレクトの問題
  • WeChatアプレットルーティングジャンプ2つの方法の例の分析

<<:  Linux デュアル ネットワーク カード バインディング スクリプト メソッドの例

>>:  MySQLは既存のコンテンツを保持し、後でコンテンツを追加します

推薦する

Tomcat9 のダウンロード、インストール、設定 + Eclipse への統合に関する詳細なチュートリアル

トムキャット公式サイトtomcatはローカルサーバーと同等であり、Webページを開くことができます設...

IEのクラッシュバグ

コードをコピーコードは次のとおりです。 <スタイル タイプ="text/css&qu...

Node.jsをゼロから学ぶ

目次URL モジュール1. 解析メソッド2. フォーマット方法3. 解決方法イベントモジュール(イベ...

シンプルな HTML ビデオ プレーヤーを実装する方法

この記事では、シンプルな HTML ビデオ プレーヤーを実装する方法を紹介し、皆さんと共有します。詳...

CSSはリストのスタイルを設定し、ナビゲーションメニューの実装コードを作成します。

1. リストシンボルを設定するlist-style-type: attribute; //リストの...

この記事はPReact10.5.13のソースコードを理解するのに役立ちます

目次render.js 部分create-context.js 部分差分部分Reactのソースコード...

CSS の Flex レイアウトを使用してシンプルな縦棒グラフを作成する方法

以下は、Flex レイアウトを使用した棒グラフです。 HTML: <div class=&qu...

Vue の下部ナビゲーション バー TabBar を実装するための非常に詳細なチュートリアル

目次プロジェクト紹介:プロジェクトディレクトリ: TabBar 効果のプレビュー: TabBar 実...

nginx を使用して静的リソース サーバーを構築する方法

Windows を例にとると、Linux も実際には同じです。静的リソースサーバーを構築するパソコン...

JavaScript のコールバック関数の理解と使用

目次概要コールバックまたは高階関数とは何ですか?コールバック関数はどのように機能しますか?コールバッ...

Linux /etc/network/interfaces 設定インターフェース方法

Linux の /etc/network/interfaces ファイルは、ネットワーク インターフ...

MySQL 接続クエリを本当に学びましたか?

1. 内部結合クエリの概要内部結合は、アプリケーションで非常に一般的な結合操作であり、通常はデフォ...

最もよく使われるHTMLエスケープシーケンス

HTML では、<、>、& などは特別な意味を持ち (<、> はリン...