简单实现一个Vue-Router

Hash与History模式的区别

大致区别:

  1. Hash模式是基于锚点,以及onhashchange事件
  2. Hash模式会先判断当前浏览器是否支持window.pushState()方法,否则通过window.location
  3. History模式是基于HTML5中的History API
    当调用history.push方法的时候会向服务器发送请求
    • history.pushState() IE10以后才支持 ,不会向服务器发送请求,只会记录路径,等于是在客户端完成的,不涉及服务端
    • history.replaceState()

History模式的使用

  • history需要服务器的支持
  • 单页应用中,服务器不存在http://test.xxxx.com/login这样的地址会返回找不到该页面
  • 在服务器端除了静态资源外都返回单页应用的index.html(Vue-cli自带的服务器已经配置好了)
    配置完了的服务器,当刷新http://test.xxxx.com/login时,服务器会返回index.html内容,index.html会判断login下面的内容,于是展现页面

自实现vue-router

要想自己实现vue-router之前,先了解一下vue-router的大致流程

// router/index.js
//注册插件
Vue.use(VueRouter)
//创建路由对象
const router = new VueRouter({
	routes: [
		{ name: 'Home', path: '/', component: homeComponent }
	]
})
// main.js
// 创建vue实例,注册router对象
new Vue({
	router,
	render: h => h(App)
}).$mount('#app')

VueRouter类所包含内容↓

在这里插入图片描述
options: 传递给VueRouter的router对象
data:data中有一个current属性对应当前的路由地址(因此data是响应式的对象)
routeMap:路由地址和组件的对应关系,路由规则解析到routeMap中

install():VueRouter的静态方法(不对外暴露),用来实现插件机制
Constructor():构造函数,初始化上述三个属性
initEvent():用来注册pushState()方法,用来监听浏览器历时的变换
createRouteMap():用来初始化routeMap属性,把传入的构造规则转换成键值对的形式,键就是路由地址,值就是对应组件,存储在routeMap中
initComponents(Vue):用来创建router-link跟router-view这两个组件
init():调用createRouteMap(),initEvent(),initComponents(Vue)

具体实现

install()方法:

  1. 判断当前插件已经被安装
  2. 把Vue构造函数记录到全局变量中,因为install是静态方法,但是在VueRouter的实例中还会用到Vue构造函数
  3. 把创建Vue实例时传入的router对象注入到所有的Vue实例上
static install (Vue) {
    //1. 判断当前插件已经被安装
    if (VueRouter.install.installed) {
        return
    }
    VueRouter.install.installed = true
    // 2. 把Vue构造函数记录到全局变量中,因为install是静态方法,但是在VueRouter的实例中还会用到Vue构造函数
    _Vue = Vue
    // 3. 把创建Vue实例时传入的router对象注入到所有的Vue实例上
    // 混入, 在beforeCreate钩子中获取Vue实例时传入的router
    _Vue.mixin({
        beforeCreate () {
            // 如果是vue实例则将router注入,如果是组件则不注入,不然会注入好多次重复的
            if (this.$options.router) {
                _Vue.prototype.$router = this.$options.router
            }
        }
    })
}

构造函数

constructor (options) {
    this.options = options
    this.routeMap = {}
    this.data = _Vue.observable({
        current: '/' //用来存储当前的路由地址
    })
}

createRouteMap

createRouteMap () {
   // 遍历所有的路由规则,把路由规则解析成键值对的形式存储到routeMap中
    this.options.routes.forEach(route => {
        this.routeMap[route.path] = route.component
    })
}

initComponents
方法1:
由于vue-cli默认是不带编译器版本的,也就是说不支持template选项,所以要创建vue.config.js,然后在这个文件开启runtimeCompiler配置。详细参考官方文档

initComponents (Vue) {
    Vue.component('route-link', {
        props: {
            to: String
        },
        template: '<a :href="to"><slot></solt></a>'
    })
}

方法2:
使用运行时版本的vue,组件会通过render函数进行一个虚拟dom的转换,所以实现render就能编译组件

initComponents (Vue) {
   Vue.component('route-link', {
        props: {
            to: String
        },
        render (h) {
            return h('a', {
                attrs: {
                    href: this.to
                }
            }, [this.$slots.default])
        }
    })
}

这里采用的是方法2

initComponents (Vue) {
  Vue.component('router-link', {
     props: {
         to: String
     },
     render (h) {
         return h('a', {
             attrs: { //对应的组件属性
                 href: this.to
             },
             on: { //对应的事件
                 click: this.clickHandler
             }
         }, [this.$slots.default])
     },
     methods: {
         clickHandler (e) {
             history.pushState({}, '', this.to)
             this.$router.data.current = this.to
             e.preventDefault()
         }
     }
 })

 const self = this
 Vue.component('router-view', {
     render (h) {
         const component = self.routeMap[self.data.current]
         return h(component)
     }
 })
}

initEvent
当浏览器点击返回、前进按钮的时候,页面并没有加载组件

initEvent () {
    window.addEventListener('popstate', () => {
        this.data.current = window.location.pathname
    })
}

完整代码参考这里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值