ブラウザの自動更新を実装するReactサンプルコード

ブラウザの自動更新を実装するReactサンプルコード

シングルページ アプリケーションが今日非常に人気となっているため、かつては驚異的だったフロントエンド ルーティングが、主要なフレームワークの基本標準となっています。各フレームワークは強力なルーティング機能を提供するため、ルーティングの実装は複雑になります。ルーティングの内部実装を理解するのはまだ少し難しいですが、ルーティング実装の基本原則を理解するだけであれば比較的簡単です。本記事では、フロントエンドルーティング、ハッシュ、ヒストリーの主流の実装方法を対象に、ネイティブ JS/React/Vue の 6 つのバージョンを参考として提供します。各バージョンの実装コードは 25 行から 40 行程度です (空白行を含む)。

フロントエンドルーティングとは何ですか?

ルーティングの概念はサーバーから来ており、ルーティングは URL と処理機能間のマッピング関係を記述します。

Web フロントエンドのシングルページ アプリケーション SPA (シングル ページ アプリケーション) では、ルーティングは URL と UI 間のマッピング関係を表します。このマッピングは一方向です。つまり、URL を変更すると UI が更新されます (ページは更新されません)。

フロントエンドルーティングを実装するにはどうすればいいですか?

フロントエンド ルーティングを実装するには、次の 2 つの主要な問題に対処する必要があります。

ページを更新せずに URL を変更するにはどうすればよいですか? URL が変更されたことを検出するにはどうすればよいでしょうか?

次の 2 つの主要な質問には、それぞれハッシュと履歴の実装を使用して回答します。

ハッシュ実装

  • ハッシュは、ハッシュ ( # ) で始まりハッシュで終わる URL の部分です。ページ内を移動するためのアンカーとしてよく使用されます。URL のハッシュ部分を変更しても、ページは更新されません。
  • hashchange イベントを通じて URL の変更を監視します。URL を変更する方法はいくつかあります。ブラウザを前後に動かして URL を変更する、標簽改變URL、通過wind 、です。これらの変更により、hashchange イベントがトリガーされます。

歴史の実装

  • History には、pushState と replaceState という 2 つのメソッドがあります。これら 2 つのメソッドは、ページを更新せずに URL のパス部分を変更します。
  • history は hashchange イベントに似た popstate イベントを提供しますが、popstate イベントは多少異なります。popstate イベントは、ブラウザを前後に移動して URL が変更されたときにトリガーされ、 pushState/replaceStateまたは tags によって URL が変更されたときには popstate イベントはトリガーされません件。好在我們可以攔截pushState/r 、クリック イベントにラベルを付けて URL の変更を検出できるため、URL の変更を監視することは可能ですが、hashchange ほど便利ではありません。

フロントエンドルーティング実装のネイティブJSバージョン

前のセクションで説明した 2 つの実装方法に基づいて、ハッシュ バージョンと履歴バージョンのルーティングがそれぞれ実装されます。この例では、ネイティブ HTML/JS 実装を使用し、フレームワークに依存しません。

ハッシュベースの実装

操作効果:

cbbb0cd6008139afcd5158c5feadfdb5.png

HTML部分:

<本文>
  <ul>
ref=""> <!-- ルートを定義する -->
    <li><a href="#/home" rel="external nofollow" >ホーム</a></li>
    <li><a href="#/about" rel="external nofollow" >について</a></li>
 
ref=""> <!-- ルートに対応する UI をレンダリングします -->
    <div id="ルートビュー"></div>
  </ul>
</本文>

JavaScript部分:

// ページはロード後にハッシュ変更をトリガーしません。ここでは、ハッシュ変更イベントをアクティブにトリガーします。window.addEventListener('DOMContentLoaded', onLoad)
// ルートの変更をリッスンする window.addEventListener('hashchange', onHashChange)
 
// ルーティングビュー var routerView = null
 
関数onLoad(){
  ルータービュー = document.querySelector('#routeView')
  ハッシュ変更()
}
 
// ルートが変更されたら、ルートに応じて対応するUIをレンダリングします
関数onHashChange() {
  スイッチ (location.hash) {
    ケース '#/home':
      routerView.innerHTML = 'ホーム'
      戻る
    ケース '#/about':
      routerView.innerHTML = '概要'
      戻る
    デフォルト:
      戻る
  }
}

履歴ベースの実装

操作効果:

d1469967dcc98af85ee83cc40b039980.png

HTML部分:

<本文>
  <ul>
    <li><a href='/home'>ホーム</a></li>
    <li><a href='/about'>について</a></li>
 
    <div id="ルートビュー"></div>
  </ul>
</本文>

JavaScript部分:

// ページはロード後にハッシュ変更をトリガーしません。ここでは、ハッシュ変更イベントをアクティブにトリガーします。window.addEventListener('DOMContentLoaded', onLoad)
// ルートの変更をリッスンする window.addEventListener('popstate', onPopState)
 
// ルーティングビュー var routerView = null
 
関数onLoad(){
  ルータービュー = document.querySelector('#routeView')
  オンポップステート()
 
 href=""> //<a> タグのクリック イベントのデフォルトの動作をインターセプトします。クリックされると、pushState を使用して URL を変更し、手動 UI を更新することで、リンクをクリックしたときに URL と UI を更新する効果を実現します。
  var linkList = document.querySelectorAll('a[href]')
  linkList.forEach(el => el.addEventListener('click', 関数(e) {
    e.preventDefault()
    history.pushState(null, '', el.getAttribute('href'))
    オンポップステート()
  }))
}
 
// ルートが変更されたら、ルートに応じて対応するUIをレンダリングします
関数onPopState(){
  スイッチ (場所.パス名) {
    '/home'の場合:
      routerView.innerHTML = 'ホーム'
      戻る
    ケース '/about':
      routerView.innerHTML = '概要'
      戻る
    デフォルト:
      戻る
  }
}

フロントエンドルーティング実装のReactバージョン

ハッシュベースの実装

操作効果:

ceb8b03a3af741f98955d1fc1d5ea506.png

使用方法は react-router と似ています。

  <ブラウザルーター>
    <ul>
      <li>
        <Link to="/home">ホーム</Link>
      </li>
      <li>
        <Link to="/about">について</Link>
      </li>
    </ul>
 
    <Route path="/home" render={() => <h2>ホーム</h2>} />
    <Route path="/about" render={() => <h2>概要</h2>} />
  </ブラウザルーター>

ブラウザルータの実装

デフォルトのクラス BrowserRouter をエクスポートし、React.Component を拡張します {
  状態 = {
    現在のパス: utils.extractHashPath(window.location.href)
  };
 
  onHashChange = e => {
    const currentPath = utils.extractHashPath(e.newURL);
    console.log("onHashChange:", 現在のパス);
    this.setState({ currentPath });
  };
 
  コンポーネントマウント() {
    window.addEventListener("ハッシュ変更"、this.onHashChange);
  }
 
  コンポーネントのマウントを解除します(){
    window.removeEventListener("ハッシュ変更"、this.onHashChange);
  }
 
  与える() {
    戻る (
      <RouteContext.Provider 値 = {{currentPath: this.state.currentPath}}>
        {this.props.children}
      </ルートコンテキスト.プロバイダー>
    );
  }
}

ルートの実装

エクスポートデフォルト({パス、レンダリング})=>(
  <ルートコンテキスト.コンシューマー>
    {({currentPath}) => currentPath === パス && render()}
  </RouteContext.Consumer>
);

リンクの実装

export default ({ to, ...props }) => <a {...props} href={"#" + to} />;

履歴ベースの実装

操作効果:

537e863d46a6ae5d5380e909fd086752.png

使用方法は react-router と似ています。

  <履歴ルーター>
    <ul>
      <li>
        <Link to="/home">ホーム</Link>
      </li>
      <li>
        <Link to="/about">について</Link>
      </li>
    </ul>
 
    <Route path="/home" render={() => <h2>ホーム</h2>} />
    <Route path="/about" render={() => <h2>概要</h2>} />
  </履歴ルーター>

HistoryRouter 実装

デフォルトのクラス HistoryRouter をエクスポートし、React.Component を拡張します {
  状態 = {
    現在のパス: utils.extractUrlPath(window.location.href)
  };
 
  onPopState = e => {
    定数 currentPath = utils.extractUrlPath(window.location.href);
    console.log("onPopState:", 現在のパス);
    this.setState({ currentPath });
  };
 
  コンポーネントマウント() {
    window.addEventListener("popstate", this.onPopState);
  }
 
  コンポーネントのマウントを解除します(){
    window.removeEventListener("popstate", this.onPopState);
  }
 
  与える() {
    戻る (
      <RouteContext.Provider 値 = {{currentPath: this.state.currentPath, onPopState: this.onPopState}}>
        {this.props.children}
      </ルートコンテキスト.プロバイダー>
    );
  }
}

ルートの実装

エクスポートデフォルト({パス、レンダリング})=>(
  <ルートコンテキスト.コンシューマー>
    {({currentPath}) => currentPath === パス && render()}
  </RouteContext.Consumer>
);

リンクの実装

エクスポートデフォルト({to、...props})=>(
  <ルートコンテキスト.コンシューマー>
    {({ onPopState }) => (
      <a
        href=""
        {...小道具}
        onClick={e => {
          e.preventDefault();
          window.history.pushState(null, "", to);
          ポップステート();
        }}
      />
    )}
  </RouteContext.Consumer>
);

Vue バージョンのフロントエンドルーティング実装

ハッシュベースの実装

操作効果:

5cb30fe18eb6118acce1f1720efb50c9.png

使用方法は vue-router に似ています (vue-router はプラグイン メカニズムを通じてルートを挿入しますが、これにより実装の詳細が隠されます。コードを直感的に保つために、ここでは Vue プラグインのカプセル化は使用されません)。

    <div>
      <ul>
        <li><router-link to="/home">ホーム</router-link></li>
        <li><router-link to="/about">について</router-link></li>
      </ul>
      <ルータービュー></ルータービュー>
    </div>
 
定数ルート = {
  '/家': {
    テンプレート: '<h2>ホーム</h2>'
  },
  '/について': {
    テンプレート: '<h2>概要</h2>'
  }
}
 
constアプリ = 新しいVue({
  el: '.vue.hash',
  コンポーネント:
    'ルータービュー': ルータービュー、
    'ルーターリンク': ルーターリンク
  },
  作成前() {
    this.$routes = ルート
  }
})

ルータビューの実装:

<テンプレート>
  <コンポーネント:is="routeView" />
</テンプレート>
 
<スクリプト>
'~/utils.js' から utils をインポートします
エクスポートデフォルト{
  データ () {
    戻る {
      ルートビュー: null
    }
  },
  作成された(){
    this.boundHashChange = this.onHashChange.bind(this)
  },
  マウント前() {
    window.addEventListener('hashchange', this.boundHashChange)
  },
  マウントされた(){
    onHashChange() は、
  },
  破棄する前に() {
    window.removeEventListener('hashchange', this.boundHashChange)
  },
  メソッド: {
    ハッシュ変更() {
      定数パス = utils.extractHashPath(window.location.href)
      this.routeView = this.$root.$routes[path] || null
      console.log('vue:hashchange:', パス)
    }
  }
}
</スクリプト>

ルータリンクの実装:

<テンプレート>
  <a @click.prevent="onClick" href=''><スロット></スロット></a>
</テンプレート>
 
<スクリプト>
エクスポートデフォルト{
  小道具: {
    から: 文字列
  },
  メソッド: {
    クリック時(){
      window.location.hash = '#' + this.to
    }
  }
}
</スクリプト>

履歴ベースの実装

操作効果:

f4708d3c19db588f48ae4dbc686b2d2e.png

使用方法は vue-router と似ています。

    <div>
      <ul>
        <li><router-link to="/home">ホーム</router-link></li>
        <li><router-link to="/about">について</router-link></li>
      </ul>
      <ルータービュー></ルータービュー>
    </div>
 
定数ルート = {
  '/家': {
    テンプレート: '<h2>ホーム</h2>'
  },
  '/について': {
    テンプレート: '<h2>概要</h2>'
  }
}
 
constアプリ = 新しいVue({
  el: '.vue.history',
  コンポーネント:
    'ルータービュー': ルータービュー、
    'ルーターリンク': ルーターリンク
  },
  作成された(){
    this.$routes = ルート
    this.boundPopState = this.onPopState.bind(this)
  },
  マウント前() {
    window.addEventListener('popstate', this.boundPopState) 
  },
  破棄前() {
    window.removeEventListener('popstate', this.boundPopState) 
  },
  メソッド: {
    onPopState (...引数) {
      this.$emit('popstate', ...引数)
    }
  }
})

ルータビューの実装:

<テンプレート>
  <コンポーネント:is="routeView" />
</テンプレート>
 
<スクリプト>
'~/utils.js' から utils をインポートします
エクスポートデフォルト{
  データ () {
    戻る {
      ルートビュー: null
    }
  },
  作成された(){
    this.boundPopState = this.onPopState.bind(this)
  },
  マウント前() {
    this.$root.$on('popstate', this.boundPopState)
  },
  破棄する前に() {
    this.$root.$off('popstate', this.boundPopState)
  },
  メソッド: {
    onPopState (e) {
      定数パス = utils.extractUrlPath(window.location.href)
      this.routeView = this.$root.$routes[path] || null
      console.log('[Vue] popstate:', パス)
    }
  }
}
</スクリプト>

ルータリンクの実装:

<テンプレート>
  <a @click.prevent="onClick" href=''><スロット></スロット></a>
</テンプレート>
 
<スクリプト>
エクスポートデフォルト{
  小道具: {
    から: 文字列
  },
  メソッド: {
    クリック時(){
      history.pushState(null, '', this.to)
      this.$root.$emit('popstate')
    }
  }
}
</スクリプト>

まとめ

フロントエンド ルーティングのコア実装原理は非常にシンプルですが、特定のフレームワークと組み合わせると、フレームワークによって動的ルーティング、ルーティング パラメーター、ルーティング アニメーションなどの多くの機能が追加され、ルーティングの実装が複雑になります。この記事は、フロントエンドルーティングのコア部分の実装のみを分析し、ハッシュモードと履歴モードに基づくネイティブ JS/React/Vue の 3 つの実装、合計 6 つの実装バージョンを参考として提供します。お役に立てば幸いです。

すべての例は Github リポジトリで入手できます: https://github.com/whinc/web-router-principle

参照する

シングルページルーティングのいくつかの実装原則の詳細な説明

シングルページアプリケーションルーティングの実装原則: React-Routerを例に

これで、React でブラウザの自動更新を実装するためのサンプルコードに関するこの記事は終了です。React ブラウザの自動更新に関するより関連性の高いコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • JavaScript に基づいてブラウザが閉じられたか更新されたかを判断する (超正確)
  • JavaScriptはブラウザを更新せず、進むと戻る機能を実現しません。
  • WeChat ブラウザの Javascript が wi​​ndow.location.reload() を使用してページを更新できない問題の解決方法
  • ブラウザが閉じられているか更新されているかを判断するための Js インテリジェント コード
  • ブラウザのさまざまな更新ルールを深く理解する
  • ブラウザ更新データ消失問題を解決するvuex永続化プラグインの詳しい説明

<<:  VMware12.0 インストール Ubuntu14.04 LTS チュートリアル

>>:  SSDストレージを有効にしたMySQLインスタンスの詳細な説明

推薦する

MySQLデータベースを使い始めるための最初のステップはテーブルを作成することです

データベースを作成する右クリック - 新しいデータベースを作成ライブラリ名を入力し、文字セットと並べ...

Dockerコンテナでルート権限を取得する方法

まず、コンテナが稼働している必要がありますコンテナのCONTAINER IDは、sudo docke...

Angularルーティングサブルートの詳細な説明

目次1. サブルート構文2. 例1. 2つの新しいコンポーネントを作成し、その内容を変更する2. ル...

MySQL エラー コード 1862 の解決方法: パスワードの有効期限が切れています

ブロガーは 1 ~ 2 か月間 MySQL を使用していませんでしたが、今日この問題に遭遇しました。...

MySQL 5.6 から 5.7 にアップグレードする際のマスター スレーブ遅延問題のトラブルシューティング

最近、Zabbix データベースを MySQL 5.6 から 5.7 にアップグレードしたときに、マ...

flexとは何か、flexレイアウト構文の詳細なチュートリアル

フレックスレイアウトFlex は Flexible Box の略で、「柔軟なレイアウト」を意味します...

MySQL 最適化チュートリアル: 大規模なページングクエリ

目次背景制限の最適化最適化方法1. カバーインデックスを使用する2. サブクエリの最適化3. 遅延連...

Docker イメージに基づいて Go プロジェクトをデプロイする方法と手順

知識への依存Go クロスコンパイルの基礎Dockerの基礎Dockerfileカスタムイメージの基本...

6秒でMySQLに100万件のレコードを挿入する方法を教えます

1. アイデアMySQL に 1,000,000 件のレコードを挿入するのにたった 6 秒しかかかり...

seata docker 高可用性デプロイメントの詳細な紹介

バージョン1.4.2公式ドキュメントドッカーハブ起動する環境変数SEATA_CONFIG_NAMEを...

MySQLとNavicatプレミアムのインストールと設定の詳細な手順

前提条件: Mac、zsh がインストールされ、bash のときに mysql がダウンロードされ、...

IDEA 構成の Tomcat 起動エラーの問題を解決する

異なるサーブレット パスを構成するときに、次の 2 つのエラーが発生しました。 java.lang....

HTML 画像 img にハイパーリンクを追加した後の醜い青い境界線の問題を解決する

HTML画像にハイパーリンクを追加すると醜い青い枠線が表示される次のように:解決: CSS スタイル...

Alibaba Cloud Ubuntu 16.04 が IPSec サービスを構築

IPSec の概要IPSec (インターネット プロトコル セキュリティ): ネットワーク層と適用さ...

Linux での NVIDIA GPU 使用状況の監視の詳細な説明

TensorFlow をディープラーニングに使うとビデオメモリ不足がよく起こるので、GPU 使用状況...