最近理解了一下 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 = null
class 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 跑一下,看看成果。