创建一个router类
class VueRouter {
constructor(){
}
}
router作为插件,在使用的时候调用的是Vue.use(),也就是会调用插件的install方法,所以实现一下VueRouter的install方法
VueRouter.install = function (Vue) {
// 存储一下当前的Vue 减少当前引入Vue造成这里的Vue被打包
_Vue = Vue
// 挂载$router在全局的vue实例上
Vue.mixin({
beforeCreate(){
if (this.$options.router) {
Vue.prototype.$router = this.$options.router
}
}
})
}
这里的mixin挂在全局Vue上,会在每个vue实例的beforeCreate钩子都执行这个代码,除非当前vue实例有自己定义的beforeCreate钩子函数 所以这里混入的顺序是 执行main里面的
import router from './router'
之后进入router文件夹下的index.js执行
Vue.use(Router)
也就是会执行VueRouter的install方法,这个时候就开始定义好了beforeCreate的默认方法
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/home',
name: 'home',
component: ()=>import('../components/home')
}
]
})
抛出路由实例,并且回到main.js执行new Vue
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
这个时候规格的路由实例作为参数传给我们整个项目的根实例 进入到beforeCreate拿到参数判断到了是根实例将$router挂载在vue实例的原型上
这个时候再回到构造函数上,我们这个时候构造的实例已经被挂在vue实例上也就是每个vue实例都能拿到了,我们需要存储一个当前的hash值,并且当这个哈希值发生变化的时候触发路由容器的刷新
class VueRouter {
constructor(options){
// 保存一下路由配置
this.$options = options
// 保存当前路由
let defaultHash = window.location.hash.slice(1) || '/'
// 改变当前路由变量为一个响应式变量,这样调用到这个变量的vue实例会执行render函数重新渲染
_Vue.util.defineReactive(this,'currenRoute',defaultHash)
window.addEventListener('hashchange',this.hashChange.bind(this))
window.addEventListener('load',this.hashChange.bind(this))
}
hashChange(){
this.currenRoute = window.location.hash.slice(1) || '/'
}
}
这里注意一下render函数中的craterElement方法可以直接传一个组件进行渲染,也可以进行标签渲染,其中标签渲染的时候三个参数分别为:1、标签名 2、标签配置 3、childs数组
再在install方法里实现路由容器组件
// router-view
Vue.component('router-view',{
render(h){
// 获取到路由映射表,拿到当前的路由哈希值对应的组件
let component = null
let route = this.$router.$options.routes.find(item => item.path===this.$router.currenRoute)
if (route) {
component = route.component
}
return h(component)
}
})
实现路由跳转标签
Vue.component('router-link',{
props:{
to:{
type: String,
required: true
}
},
render(h){
return h('a',{attrs:{href:'#'+this.to}},this.$slots.default)
}
})
实现全部代码
将路由文件改成我们自己的路由文件
import Vue from 'vue'
// 改成自己的文件
import Router from './vue-router'
import HelloWorld from '@/components/HelloWorld'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'HelloWorld',
component: HelloWorld
},
{
path: '/home',
name: 'home',
component: ()=>import('../components/home')
}
]
})
实现路由文件
let _Vue
class VueRouter {
constructor(options){
// 保存一下路由配置
this.$options = options
// 保存当前路由
let defaultHash = window.location.hash.slice(1) || '/'
// 改变当前路由变量为一个响应式变量,这样调用到这个变量的vue实例会执行render函数重新渲染
_Vue.util.defineReactive(this,'currenRoute',defaultHash)
window.addEventListener('hashchange',this.hashChange.bind(this))
window.addEventListener('load',this.hashChange.bind(this))
}
hashChange(){
this.currenRoute = window.location.hash.slice(1) || '/'
}
}
VueRouter.install = function (Vue) {
// 存储一下当前的Vue 减少当前引入Vue造成这里的Vue被打包
_Vue = Vue
// 挂载$router在全局的vue实例上
Vue.mixin({
beforeCreate(){
if (this.$options.router) {
Vue.prototype.$router = this.$options.router
}
}
})
// 实现一下路由的两个全局组件
// router-view
Vue.component('router-view',{
render(h){
// 获取到路由映射表,拿到当前的路由哈希值对应的组件
let component = null
let route = this.$router.$options.routes.find(item => item.path===this.$router.currenRoute)
if (route) {
component = route.component
}
return h(component)
}
})
// router-link
Vue.component('router-link',{
props:{
to:{
type: String,
required: true
}
},
render(h){
return h('a',{attrs:{href:'#'+this.to}},this.$slots.default)
}
})
}
export default VueRouter