Vue-Router核心實現原理


vue-router的實現原理簡介
如何在vue中使用vue-router?
1.Vue使用插件,即調用Vue的use方法;

// router.js 
Vue.use(Router);

2.實例化router,並配置router的配置對象,含routes路由;

// router.js 
export default new Router({
    mode:"hash",
    routes:[
        {
            path:"/hello",
            component:HelloWorld
        },
        {
            path:"/",
            component:VuexTest
        },
        {
            path:"/form",
            component:Form
        }
    ]
})

3.在vue實例上配置router實例;

// main.js
import router from "./config/router";
new Vue({
  router,
  render: h => h(App),
}).$mount('#app')

4.使用

<template>
  <div id="app">
    <router-link to="/">home</router-link>|
    <router-link to="/form">form</router-link>|
    <router-link to="/hello">HelloWorld</router-link>
    <router-view></router-view>
  </div>
</template>

5.效果
點擊home,form,helloWorld可以切換路由頁面。

以上的幾個步驟,vue-router內部都做了什么?
我們需要明白的是,router-link和router-view是兩個Vue全局組件,必定是在vue-router中實現了全局定義兩個組件,他們分別用來跳轉路由和展示路由對應的組件內容。

我們點擊了router-link時導致路由變了,vue-router內部必然是在監聽路由變化,根據路由規則找到匹配的組件,然后在router-view中渲染。

所以,路由切換最終是頁面的不同組件的展示,而沒有真正去刷新頁面。

那么接下來說vue-router核心實現原理:

目標:
1.實現一個靜態install方法,因為作為插件都必須有這個方法,給Vue.use()去調用;
2.可以監聽路由變化;
3.解析配置的路由,即解析router的配置項routes,能根據路由匹配到對應組件;
4.實現兩個全局組件router-link和router-view;(最終落地點)

核心代碼實現簡版:

let Vue;
class KVueRouter {
    constructor(options){
        this.$options=options;
        this.$routerMap={};//{"/":{component:...}}
        // url 響應式,當值變化時引用的地方都會刷新
        this.app = new Vue({
            data:{
                current:"/"
            }
        });
    }
    // 初始化
    init(){
        // 監聽事件
        this.bindEvent();
        // 解析路由
        this.createRouteMap();
        // 聲明組件
        this.initComponent();
    }
    bindEvent(){
        window.addEventListener('hashchange',this.onHashchange.bind(this));
    }
    onHashchange(){
        this.app.current = window.location.hash.slice(1) || "/";
    }
    createRouteMap(){
        this.$options.routes.forEach(route=>{
            this.$routerMap[route.path]=route;
        })
    }
    initComponent(){
        Vue.component('router-link',{
            props:{
                to:String,
            },
            render(h){
                return h('a',{attrs:{href:'#'+this.to}},[this.$slots.default])
            }
        });
        Vue.component('router-view',{
            render:(h)=>{
              //這里使用了data中的 this.app.current,根據vue相應式原理,當變化 this.app.current時
              //這里會監聽並發生變化
                const Component = this.$routerMap[this.app.current].component;
                return h(Component)
            }
        });
    }
}
// 參數是vue構造函數,Vue.use(router)時,執行router的install方法並把Vue作為參數傳入
KVueRouter.install = function(_vue){
    Vue = _vue;
    //全局混入
    Vue.mixin({
        beforeCreate(){//拿到router的示例,掛載到vue的原型上
            if (this.$options.router) {
                Vue.prototype.$router=this.$options.router;
                this.$options.router.init();
            }
        }
    })
}
export default KVueRouter;

解讀如下:

Vue.use(Router)時,會調用router的install方法並把Vue類傳入,混入beforeCreate方法,即在Vue實例化后掛載前在vue原型上掛個$router方法(因為這樣后面才能用this.$router.push()...但此處沒有實現哦),然后調用router實例的init方法;

在init中把三件事情都干了,監聽路由,解析路由(路由mapping匹配),定義組件;

需要注意的是,存儲當前路由的變量this.app.current非一般的變量,而是借用Vue的響應式定義的,所以當路由變化時只需要給這個this.app.current賦值,而router-view組件剛好引用到這個值,當其改變時所有的引用到的地方都會改變,則得到的要展示的組件也就響應式的變化了

====

作者:變態的小水瓶
鏈接:https://www.jianshu.com/p/d59971198082
來源:簡書


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM