大家好,歡迎來到程序視點!
今天跟大家簡單聊聊Router的實現(xiàn)原理,以及我們?nèi)绾稳崿F(xiàn)這樣一個插件。
Vue Router
是Vue.js
官方的路由管理器。它和 Vue.js 的核心深度集成,讓構(gòu)建單頁面應(yīng)用變得易如反掌。關(guān)于Vue Router
的使用就不做過多介紹了,大家可以前往Vue Router
官網(wǎng)去學(xué)習(xí)哦~
vue-router插件的基本使用
import?Vue?from?'vue'
import?Router?from?'vue-router'
Vue.use(Router)
const?router?=?new?Router({routes:[]})
export?default?router
import?router?from?'./route'
new?Vue({
????render:?h?=>?h(APP),
????router
})
從上述代碼可以看出,router
也是作為一個插件去使用的,所以在進行原理實踐時候,我們開發(fā)的就是一個插件。
插件開發(fā)思路
定義一個Router
類,用來進行所有的router操作。定義一個install方法,將router掛載到Vue的實例上去。注冊全局組件router-link
和router-view
,router-link
組件解析為一個a標(biāo)簽,router-view
解析為一個div標(biāo)簽,內(nèi)容為當(dāng)前路由對應(yīng)的component。
監(jiān)聽hashchange
事件來改變當(dāng)前路由對應(yīng)的component,監(jiān)聽load
事件做同樣的事情。
對于嵌套路由而言,在渲染router-view
時候,先去判斷當(dāng)前router-view
的深度,即當(dāng)前router-view
是處在哪個層級,然后在解析routes時候判斷當(dāng)前路由。
如果當(dāng)前路由和routes中某個路由都為'/'根路由,則直接放到路由渲染數(shù)組中,如果當(dāng)前路由不是根路由,并且routes中的某個路由包含當(dāng)前路由,則意味著routes數(shù)組中的這個路由要么是當(dāng)前路由的父路由,要么就是當(dāng)前路由。
然后把routes數(shù)組中的這個路由放到路由渲染數(shù)組中去,放完之后如果還有childrens,遞歸去做就行。
最后得到了一個路由匹配數(shù)組,這個數(shù)組里面包含當(dāng)前路由和當(dāng)前路由的父路由,并且數(shù)組中子路由的下標(biāo)與之前router-view
的層級下標(biāo)相等,這樣就能正確的將子路由的component正確的渲染到對應(yīng)的router-view
中去了。
譬如當(dāng)前路由表如下:
routes:[
????{
????????path:?'/',
????????component:?()?=>?import?('../views/index.vue')
????},
????{
????????path:?'/second',
????????component:?()?=>?import?('../views/second.vue'),
????????childrens:?[
????????????{
????????????????path:?'/seconde/article',
????????????????component:?import?('../view/article.vue')
????????????}
????????]
????}
]
此時second組件下有一個router-view
,用來渲染子路由——article組件,在app下還有一個父router-view
,用來渲染index、second組件,所以此時second組件下的router-view
的層級是1(初始化為0)。
如果此時瀏覽器訪問路由 /second/article 時候,觸發(fā)我們的路由匹配方法,遍歷routes數(shù)組和當(dāng)前路由對比,當(dāng)前路由不是根路由,并且包含 /second 路由,所以path為 /second 的選項被push進入路由渲染數(shù)組中,然后此路由還有childrens,進行遞歸,好家伙,當(dāng)前路由和 /second/article 完全相等,所以也被push到了渲染數(shù)組中。
最后我們得到了一個數(shù)組,包含兩個路由選項,父路由下標(biāo)0,子路由下標(biāo)1,之前我們也將router-view
做了層級標(biāo)記,這樣就能得到子router-view
對應(yīng)渲染的component了。~nice
插件開發(fā)
先來一個cRouter文件夾,下面搞一個index.js,里面就是我們傳統(tǒng)的router使用,上面有,然后再搞一個crouter.js:
import?Link?from?'./cLink'
import?View?from?'./cView'
var?Vue
class?cRouter?{
??constructor(options)?{
????????this.$options?=?options
????this.courrentRoute?=?window.location.hash.slice(1)?||?'/'
????//定義一個響應(yīng)式的路由渲染數(shù)組
????????Vue.util.defineReactive(this,'routeMap',[])
????????//?遍歷匹配路由
????this.initRouterMap()
????//?初始化route改變事件
????this.initRouteChange()
??}
?
??initRouterMap(route)?{
????????let?routes?=?route?||?this.$options.routes
????????for?(const?routeItem?of?routes)?{
????????????if?(this.courrentRoute?===?'/'?&&?routeItem.path?===?'/')?{
????????????????this.routeMap.push(routeItem)
????????????????return
????????????}
????????????if?(
????????????routeItem.path?!==?'/'
????????????&&?
????????????this.courrentRoute.indexOf(routeItem.path)?!==?-1)?{
????????????????this.routeMap.push(routeItem)
????????????????if?(routeItem.childrens?&&?routeItem.childrens.length?>?0)?{
????????????????????this.initRouterMap(routeItem.childrens)
????????????????}
????????????????return
????????????}
????????}
??}
??initRouteChange()?{
????window.addEventListener('hashchange',?this.routeChange.bind(this))
????window.addEventListener('load',?this.routeChange.bind(this))
??}
??routeChange()?{
????????this.courrentRoute?=?window.location.hash.slice(1)
????????this.routeMap?=?[]
????this.initRouterMap()
??}
}
function?install(_Vue)?{
??Vue?=?_Vue
??Vue.mixin({
????beforeCreate()?{
??????if?(this.$options.crouter)?{
????????Vue.prototype.$crouter?=?this.$options.crouter
??????}
????},
??})
??Vue.component('router-link',?Link)
??Vue.component('router-view',?View)
}
export?default?{
??cRouter,
??install,
}
cview.js用來渲染router-view
export?default?{
????render(h)?{
????????//?將自身標(biāo)記為一個router-view,避免和其他元素搞混
????????this.$vnode.data.routerView?=?true
????????let?parent?=?this.$parent
????????//默認(rèn)自己層級為0
????????let?routeDeep?=?0
????????while(parent)?{
????????????//?判斷是否存在父元素并且父元素有值
????????????const?vodeData?=?parent.$vnode?&&?parent.$vnode.data
????????????if?(vodeData)?{
????????????????//?如果父router-view是true,則自身層級增加
????????????????if?(vodeData.routerView)?{
????????????????????routeDeep++
????????????????}
????????????}
????????????//繼續(xù)尋找父元素,進行遞歸
????????????parent?=?parent.$parent
????????}
????????let?component?=?null
????????const?route?=?this.$crouter.routeMap[routeDeep]
????????if?(route)?{
????????????component?=?route.component
????????}
????????return?h(component)
????}
}
cLink.js用來渲染router-link
export?default?{
????props:?{
????????to:?{
????????????type:?String,
????????????default:?'/',
????????},
????},
????render(h)?{
????????return?h(
????????????'a',
????????????{?attrs:?{?href:?`#${this.to}`?}?},
????????????this.$slots.default
????????)
????}
}
文章到這里,我們簡單實現(xiàn)了類似vue aouter
路由的功能~文章來源:http://www.zghlxwxcb.cn/news/detail-617998.html
我想說的是:如今開源框架大大方便了我們的開發(fā)效率,但是單純的使用三方框架并不能讓我們學(xué)到更多知識我們應(yīng)該是研究去探索他的實現(xiàn)原理以及設(shè)計理念,去思考如果讓我們設(shè)計一個框架,我們需要掌握哪些知識,該如何設(shè)計? 我想,這樣的學(xué)習(xí)才能學(xué)到更多的知識~文章來源地址http://www.zghlxwxcb.cn/news/detail-617998.html
到了這里,關(guān)于深度解析Vue Router原理:實戰(zhàn)指南與實用技巧的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!