最近理解了一下vue,而后简略理解了一下vue-router,而后当初简略得写一个vue-router得简易版得源码解析.
这是vue-router得根本用法 vue-router根本用法
vue的生命周期官网给出的好棒
https://cn.vuejs.org/images/l... 安利一下
首先咱们要理解:插件,slot插槽,混入,render函数,运行时和完整版得vue
首先咱们用vue-cli创立一个我的项目,要应用带编译器得版本,因为要编译模板。
而后咱们找到对应得router/index.js,把官网得vue-router,替换成咱们本人新建得
//import VueRouter from 'vue-router'import VueRouter from '../../Vue-router'
路由界面配置
const routes = [ { path: '/', name: 'Index', component: Index }, { path: '/login', name: 'Login', // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import(/* webpackChunkName: "about" */ '../views/Login.vue') }, { path: '/detail/:id', name: 'Detail', props: true, component: () => import(/* webpackChunkName: "detail" */ '../views/Detail.vue') }]const router = new VueRouter({ routes})
app.vue界面咱们简略设置一下
而后开始思考Vue.use(VueRouter) 注册插件外部会调用传入对象得install办法
这一节得次要外围在vue-router文件上
次要得实现思路就是:
创立VueRouter类增加静态方法
- 判断插件是否加载了,不反复加载
- 记录vue得构造函数
- 当Vue加载得时候把传入得router对象挂载到vue原型上(只执行一次,应用混入的形式)
创立VueRouter里的具体方法
- 初始化,options,routeMap,data(以后路由,响应式数据)
- createRouteMap把路由信息生成一个映射放到routeMap中
- initComponent创立路由所应用得组件router-link,router-view
- initEvent监听浏览器的事件hash或history
上面是具体实现
let _Vue = nullclass VueRouter { static install (Vue) { // 1 判断以后插件是否被装置 if (VueRouter.install.installed) { return } VueRouter.install.installed = true // 已装置 // 2 把Vue的构造函数记录在全局 _Vue = Vue // 3 把最开始创立Vue的实例时传入的router对象,也就是实例化得VueRouter对象,应用混入的形式 // vue在实例化的时候会把router放到$options上,咱们取到它混入创立之前生命周期注入到Vue原型上 不便 // 所有得vue实例外部 应用 this.$router都能拜访到 _Vue.mixin({ beforeCreate () { if (this.$options.router) { console.dir(this) _Vue.prototype.$router = this.$options.router } } }) } constructor (options) { this.options = options // 把实例化路由时得参数储存起来 this.routeMap = {} // 路由对应得映射,component this.data = _Vue.observable({ // 创立一个observable被观察者,响应式数据 current: '/' }) this.init() // 初始化路由信息 } init () { this.createRouteMap()// 创立映射信息 this.initComponent(_Vue)// 创立应用得组件router-link router-view this.initEvent()// 监听浏览器 点击左右历史popstate事件 } createRouteMap () { // 遍历所有的路由规定 吧路由规定解析成键值对的模式存储到routeMap中 this.options.routes.forEach(route => { this.routeMap[route.path] = route.component // 值就是对应得组件 }) } initComponent (Vue) { // 创立路由组件 Vue.component('router-link', { props: { to: String // 设置router-link得props to 跳转地址 必须是字符串 }, render (h) { // 设置组件得render函数,不理解vue render何时执行得能够看下它的生命周期 return h('a', { // h函数生成虚构dom attrs: { // 设置属性 href: this.to }, on: { // 事件 click: this.clickhander } }, [this.$slots.default]) // 最初是组件里的子元素,咱们通过插槽获取 到 }, methods: { clickhander (e) { // 组件得办法 e.preventDefault() // 阻止默认跳转 history.pushState({}, '', this.to) // history模式扭转url地址,不发送申请 this.$router.data.current = this.to// 扭转observable对象得值,触发响应式观察者更新 } } }) const that = this Vue.component('router-view', { // 视图展现组件 render (h) { const cm = that.routeMap[that.data.current] // 取到路由对应得compoment return h(cm) // 传给h函数,会帮咱们转换为虚构dom } }) } initEvent () { // 初始化浏览器后退后退事件拦挡 window.addEventListener('popstate', () => { // 拦挡,要箭头函数应用this this.data.current = window.location.pathname // 扭转observable对象,触发router-view更新 }) }}export default VueRouter
次要的外围代码都在这个vue-router文件里了,这只是个简易版,简略模拟了一下,性能必定有很多有余,常识理解下原理,有趣味的能够拿下来,替换原始的vue-router跑一下,看看成果。