1.hash 模式的实现原理
最早期的前端路由的实现就是基于 location.hash 来实现的。其实现原理很简单,location.hash 的值就是 URL 中# 后面的内容。比如下面这个网站,它的 location.hash 的值为 #search:
hash 路由模式的实现主要是基于下面几个特性:
- URL 中 hash 值只是客户端的一种状态,也就是说当向服务器端发送请求时,hash部分不会被发送。
- hash 值的改变,都会在浏览器的访问历史中添加一个记录。因此我们能通过浏览器的回退、前进按钮控制 hash 的切换。
- 可以通过 a 标签,并设置 herf 属性,当用户点击这个标签后,URL 的 hash 值会发生改变;或者使用 Javascript 来对 location.hash 进行赋值,改变 URL 的 hash 值。
- 我们可以使用 hashChange 事件来监听 hash 值的变化,从而对页面进行跳转(渲染)。
2.history 模式的实现原理
HTML5 提供了 History API 来实现 URL 的变化。其中做主要的 API 有以下两个:
history.pushState() 和 history.repalceSate()。这两个 API 可以在不进行刷新的情况下,操作浏览器的历史记录。唯一不同的是,前者是新增一个历史记录,后者是直接替换当前的历史记录,如下所示
window.history.pushState(null,null,path) window.history.replaceState(null,null,path)
history 路由模式的实现主要基于存在下面几个特性:
- pushState 和 replaceState 两个 API 来操作 URL 的变化。
- 我们可以使用 popstate 事件来监听 URL 的变化,从而对页面进行跳转(渲染)。
- history.pushState() 或 history.replaceState() 不会触发 popstate 事件,这时需要我们手动触发页面跳转(渲染)。
3.history 的问题
History 路由模式虽然好看,但是这种模式要完好,需要后台配置。因为我们的应用是个页面客户端应用,如果后台没有配置,当用户在浏览器直接访问 http://oursite.com/user/id 就会返回404,这样就不好看了。
所以呢,你要在服务器增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。
4.简单实现 Vue Router
Vue Router 核心是,通过 Vue.use 注册插件,在插件 install 方法中获取用户配置的 router 对象。当浏览器地址发生变化的时候,根据 router 对象匹配相应的路由,获取组件,并将组件渲染到视图上。
(1)如何 install 方法中获取 Vue 实例上的 router 属性
可以利用 Vue.mixin 混入生命周期函数 beforeCreated ,在 beforeCreated 函数中可以获取到 Vue 实例上的属性并赋值到 Vue 原型链上。
_Vue.mixin({ beforeCreate(){ if(this.$options.router){ _Vue.prototype.$router = this.$options.router } } })
(2)如何触发更新
hash 模式下:
- 通过 location.hash 修改 hash 值,触发更新。
- 通过监听 hashchange 时间监听浏览器前进或者后退,触发更新。
history 模式下:
- 通过 history.pushState 修改浏览器地址,触发更新。
- 通过监听 popstate 时间监听浏览器前进或者后退,触发更新。
- 如何渲染 router-view 组件。
- 通过 Vue.observable 在 router 实例上创建一个保存当前路由的监控对象 current。
- 当浏览器地址变化的时候,修改监控对象 current。
- 在 router-view 组件中监控对象 current 的变化,当 current 对象变化后,获取用户注册的相应component,并利用 h 函数将 component 渲染成 vnodes ,进而更新页面视图。