あなたが知らないかもしれないVuejs-カスタムルートの実現


by yugasun from yugasun.com/post/you-ma...本文は全文転載できますが、原作者と出典を残しておく必要があります.
単一ページの応用に対して、フロントエンドのルートは不可欠であり、公式も私たちの便利な実現のためにvue-routerライブラリを提供していますが、もしあなたのアプリケーションが非常に簡単であれば、ルートライブラリ全体を導入する必要はありません.VuejsダイナミックにレンダリングされたAPIを通じて実現できます.
私たちは、コンポーネントがtemplateを通じてテンプレートを指定できることを知っています.単一ファイルコンポーネントについては、templateタグでテンプレートを指定できます.それ以外に、Vueはまた、カスタムレンダリングコンポーネントを提供しています.
これから先のルートを実現します.
簡易実現
私たちはまずrenderコマンドを実行して、私たちのプロジェクトを初期化します.
まず、vue init webpack vue-router-demoディレクトリでsrcファイルを作成し、ページのテンプレートとして使用します.コードは以下の通りです.
<template>
  <div class="container">
    <ul>
      <li><a :class="{active: $root.currentRoute === '/'}" href="/">Homea>li>
      <li><a :class="{active: $root.currentRoute === '/hello'}" href="/hello">HelloWorda>li>
    ul>

    <slot>slot>
  div>
template>
<script>
export default {
  name: 'Layout',
};
script>
<style scoped>
.container {
  max-width: 600px;
  margin: 0 auto;
  padding: 15px 30px;
  background: #f9f7f5;
}
a.active {
  color: #42b983;
}
style>
layout/index.vuecomponents/HelloWorld.vueに移動させ、そのコードを修正し、上記で作成されたページテンプレートパッケージを使用する.
<template>
  <layout>
      
  layout>
template>

<script>
import Layout from '@/layout';

export default {
  name: 'HelloWorld',
  components: {
    Layout,
  },
  // ...
};
script>

もちろん、ユーザが存在しないルートを入力するときのインターフェースを充実させるために、src/pagesを追加する必要がある.
最後に、私たちの最も重要なステップです.404 を書き換えて、ページmain.jsに従ってレンダリングコンポーネントを動的に切り替えます.
1.ルーティングマッピングを定義します.
// url -> Vue Component
const routes = {
  '/': 'Home',
  '/hello': 'HelloWorld',
};
2.urlを追加して属性を計算し、必要なコンポーネントをVueComponentに従って導入する.
const app = new Vue({
  el: '#app',
  data() {
    return {
      //     
      currentRoute: window.location.pathname,
    };
  },
  computed: {
    ViewComponent() {
      const currentView = routes[this.currentRoute];
      /* eslint-disable */
      return (
        currentView
          ? require('./pages/' + currentView + '.vue')
          : require('./pages/404.vue')
      );
    },
  },
});
3.レンダリングロジックを実現し、レンダー関数は、VNodeを生成する関数であるパラメータwindow.location.pathnameを提供し、直接にコンポーネントをそれに動的に導入してレンダリングを実行することができる.
const app = new Vue({
  // ...
  render(h) {
    //        es module       ,
    //        this.ViewComponent.default       
    return h(this.ViewComponent.default);
  }
});
最終実現コード
historyモード
簡易バージョンは、フロントエンドのルーティングが実現されていません.ページ切り替えをクリックして、グローバルリフレッシュを再開し、createElementに従って、それぞれのコンポーネントを初期化してレンダリングするだけです.
次に、フロントエンドルーティングのwindow.location.pathnameモードを実現する.ページURLの変更を実現するには、ページを更新しないと、history.pusState()の方法が必要となります.この方法により、ページURLを動的に変更できます.ページは更新されません.この方法には三つのパラメータがあります.一つの状態オブジェクト、一つのタイトル(現在は無視されています.)、及び任意のURLアドレスが実行されると、historyイベントがトリガされます.
では、上記のように直接にタブpopstateを通してページを切り替えることはできません.aタグをクリックすると、デフォルトイベントを無効にし、aを実行してページhistory.pushState()を修正し、URLを更新して、私たちが欲しいapp.currentRoute属性を変更する必要があります.
まず、汎用VueComponentコンポーネントを作成し、上記のrouter-linkタグクリックロジックを実現し、aを追加します.コードは以下の通りです.
<template>
  <a
    :href="href"
    :class="{active: isActive}"
    @click="go"
  >
    <slot>slot>
  a>
template>
<script>
import routes from '@/routes';

export default {
  name: 'router-link',
  props: {
    href: {
      type: String,
      required: true,
    },
  },
  computed: {
    isActive() {
      return this.href === this.$root.currentRoute;
    },
  },
  methods: {
    go(e) {
      //         
      e.preventDefault();
      //          
      this.$root.currentRoute = this.href;
      window.history.pushState(
        null,
        routes[this.href],
        this.href,
      );
    },
  },
};
script>
components/router-link.vueファイルについては、実際には何かの修正が必要ではなく、src/main.jsオブジェクトをモジュールに変更して導入すればいいです.以下のとおりです
import Vue from 'vue';

//     routes            
import routes from './routes';

Vue.config.productionTip = false;

/* eslint-disable no-new */
const app = new Vue({
  el: '#app',
  data() {
    return {
      currentRoute: window.location.pathname,
    };
  },
  computed: {
    ViewComponent() {
      const currentView = routes[this.currentRoute];
      /* eslint-disable */
      return (
        currentView
          ? require('./pages/' + currentView + '.vue')
          : require('./pages/404.vue')
      );
    },
  },
  render(h) {
    //        es module       ,
    //        this.ViewComponent.default       
    return h(this.ViewComponent.default);
  },
});
はい、私達のroutesモードのルートはすでに修正されました.頭のリンクをクリックして、ページの内容が変わりました.そしてページは更新されませんでした.
しかし、問題があります.ブラウザhistoryボタンをクリックすると、ページのURLが変わりましたが、ページの内容は変わっていません.これはどういうことですか?私たちはブラウザ / ボタンをクリックすると、 / は変更されていませんが、それがpopstateイベントをトリガするので、私たちはapp.currentRouteイベントを傍受し、popstateを修正すればいいです.
傍受が必要なら、直接コードを追加しましょう.app.currentRouteファイルの末尾に下記のコードを追加します.
window.addEventListener('popstate', () => {
  app.currentRoute = window.location.pathname;
});
このように私達は今ページの中でリンクをクリックして切り替えますか?それともブラウザsrc/main.jsボタンをクリックして、私達のページはすべてルートによって切り替えることができます.
最終実現コード
hashモード / を実現した以上、どうしてhistory を少なくできましたか?このようにお聞きしましたので、ご苦労をいとわず、皆様を連れて実現させていただきます.
URL hashとは何ですか?MDNの説明を見に来ました.
Is a DOMString containing a's'followwid by the fragment identifer of the URL.
つまり、ページURLのうちhash で始まる文字列である.また、変化が発生すると、#イベントがトリガされる.hashchangeと同じようにモニターすればいいです.history に対して、ここで必要な修正はhistory のルーティングマッピングにほかならないです.
export default {
  '#/': 'Home',
  '#/hello': 'HelloWorld',
};
src/routes.jsへのリンクは、全部src/layout/index.vueプレフィックスを追加し、#src/main.jsイベントを傍受する.もちろん、hashchangewindow.location.hashに値付けする必要がある.
window.addEventListener('hashchange', () => {
  app.currentRoute = window.location.hash;
});
最後にもう一つの問題があります.単一の面が初期化された時、app.currentRoute値が空です.そうすると、ルートマップが見つからないです.したがって、ページ初期化の際には、判断を追加する必要があり、window.location.hashが空であれば、デフォルトはwindow.location.hashに変更され、これで全部完了します.
最終実現コード
異なるモード切替バージョン
実際の開発では、プロジェクトのニーズに応じて、異なるルート方式を使うことができます.ここでは#/パラメータを追加して、ルートの切り替えを実現する必要があります.ここでは説明をしません.興味のある読者は自分で試してみてください.
締め括りをつける
実際には、完全なルーティングライブラリは、上で示したコードだけではなく、多くの問題を考慮する必要がありますが、プロジェクトが非常に簡単で、複雑なルーティングメカニズムが必要ではなく、自分で実行してもいいです.やはり需要によって違います.
本を尽くして、本がないほうがいいです.modeに直面する時、多くの自主的な思考と実践を注文して、直接に使うことを受け入れるより役に立ちます.
特定のテーマ
You-My-Not-Know-Vuejs