将前端实验室设为星标精品文章第一时间阅读
大家好,我是前端实验室的大师兄!
今天大师兄跟大家简单聊聊Router的实现原理,以及我们如何去实现这样一个插件。
Vue Router
是Vue.js
官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。关于Vue Router
的使用就不做过多介绍了,大家可以前往Vue Router
官网去学习哦~
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
也是作为一个插件去使用的,所以在进行原理实践时候,我们开发的就是一个插件。
插件开发思路
定义一个Router
类,用来进行所有的router操作。定义一个install方法,将router挂载到Vue的实例上去。
注册全局组件router-link
和router-view
,router-link
组件解析为一个a标签,router-view
解析为一个div标签,内容为当前路由对应的component。
监听hashchange
事件来改变当前路由对应的component,监听load
事件做同样的事情。
对于嵌套路由而言,在渲染router-view
时候,先去判断当前router-view
的深度,即当前router-view
是处在哪个层级,然后在解析routes时候判断当前路由。
如果当前路由和routes中某个路由都为’/’根路由,则直接放到路由渲染数组中,如果当前路由不是根路由,并且routes中的某个路由包含当前路由,则意味着routes数组中的这个路由要么是当前路由的父路由,要么就是当前路由。
然后把routes数组中的这个路由放到路由渲染数组中去,放完之后如果还有childrens,递归去做就行。
最后得到了一个路由匹配数组,这个数组里面包含当前路由和当前路由的父路由,并且数组中子路由的下标与之前router-view
的层级下标相等,这样就能正确的将子路由的component正确的渲染到对应的router-view
中去了。
譬如当前路由表如下:
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 时候,触发我们的路由匹配方法,遍历routes数组和当前路由对比,当前路由不是根路由,并且包含 /second 路由,所以path为 /second 的选项被push进入路由渲染数组中,然后此路由还有childrens,进行递归,好家伙,当前路由和 /second/article 完全相等,所以也被push到了渲染数组中。
最后我们得到了一个数组,包含两个路由选项,父路由下标0,子路由下标1,之前我们也将router-view
做了层级标记,这样就能得到子router-view
对应渲染的component了。~nice
插件开发
先来一个cRouter文件夹,下面搞一个index.js,里面就是我们传统的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) || '/'
//定义一个响应式的路由渲染数组
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) {
// 将自身标记为一个router-view,避免和其他元素搞混
this.$vnode.data.routerView = true
let parent = this.$parent
//默认自己层级为0
let routeDeep = 0
while(parent) {
// 判断是否存在父元素并且父元素有值
const vodeData = parent.$vnode && parent.$vnode.data
if (vodeData) {
// 如果父router-view是true,则自身层级增加
if (vodeData.routerView) {
routeDeep++
}
}
//继续寻找父元素,进行递归
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
)
}
}
文章到这里,我们简单实现了类似vue aouter
路由的功能,赶紧公众号回复「vue-router」获取相关示例源码哦~
大师兄想说的是:如今开源框架大大方便了我们的开发效率,但是单纯的使用三方框架并不能让我们学到更多知识
我们应该是研究去探索他的实现原理以及设计理念,去思考如果让我们设计一个框架,我们需要掌握哪些知识,该如何设计? 我想,这样的学习才能学到更多的知识~
文章来源于互联网:vue-router原理分析与实践
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.shuli.cc/?p=17214,转载请注明出处。
评论0