Vue:vue-routerの基本原則

Vue:vue-routerの基本原則

I.はじめに

  • ほとんどのVueアプリケーションはシングルページアプリケーションであり、シングルページアプリケーションを実装するための最も重要なツールはルーターです。ルーターの最下層はブラウザーの履歴クラスをカプセル化するため、ブラウザーが新しいページを要求する必要はありません。ページが切り替わります。

第二に、vue-routerの基本的な知識

1.vue-routerの3つのモード

  • Vue-routerには、HTML5 History、HashHistory、AbstractHistory(一時的に展開されない)の合計3つのモードがあります。

  • 履歴モード:

    • 例:http://test.com/abc

    • popstateイベント:

      定義:同じドキュメントの閲覧履歴(履歴オブジェクト)が変更されると、popstateイベントがトリガーされます。

      注意:

      1. このイベントは、pushStateメソッドまたはreplaceStateメソッドを呼び出すだけではトリガーできません。ユーザーがブラウザーの進むボタンまたは戻るボタンをクリックしたとき、またはhistory.back / forward / goメソッドが使用されたときにのみトリガーされます。

        1. 同じドキュメントの場合のみ、閲覧履歴の切り替えによって異なるドキュメントが切り替えられると、イベントはトリガーされません。

      使用法:を使用する場合、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()注册过的回调函数。
    
  • 完全なナビゲーション分析プロセス:

    1. ナビゲーショントリガー;
    2. 非アクティブ化されようとしているコンポーネントのコールbeforeRouteLeaveガード
    3. グローバルbeforeEachガードを呼び出します。
    4. ペットコンポーネントのbeforeRouteUpdate警備員を呼び出します;
    5. ルーティング構成でbeforeEnterガードを呼び出します;
    6. 非同期ルーティングコンポーネントを解決します。
    7. 次にアクティブ化されたコンポーネントでbeforeRouteEnterガードを呼び出します;
    8. グローバルbeforeResolveガードを呼び出します。
    9. ナビゲーションが確認されました。
    10. グローバルafterEachフックを呼び出します。
    11. DOMの更新をトリガーします。
    12. 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 // 浏览器地址栏显示新的地址

おすすめ

転載: blog.csdn.net/yivisir/article/details/109305952