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
來源:簡書