1、Hash模式与History模式
二者的存在表现形式和原理上的区别
1、表现形式的区别
Hash:https://api.aibianxian.net/igameh5/#/detail/213?token=123,链接中带有#号
History: https://api.aibianxian.net/igameh5/detail/213/123
2、原理区别
Hash:基于锚点,以及onHashChange事件,通过锚点的值作为路由地址,当地址发生变化后,触发onHashChange事件,然后根据路径决定页面呈现的内容。
**History:**基于HTML5中的HistoryAPI
- history.pushState() 存在兼容模式,IE10以后才支持
- history.replaceState()
pushState与push方法的区别是:调用push的时候路径会发生变化,会向服务器发送请求,调用pushState的时候,不会向服务器发送请求,只会改变地址栏中的地址,并且将地址记录到历史记录中,可以实现客户端路由
3、History模式的使用
- History需要服务器的支持
- 单页应用中,服务端不存在某一个地址,会返回404页面
- 在服务端应该除了静态资源外都返回单页应用的index.html
2、Vue的构建版本
运行时版本和完整版
1、运行时版本
不支持template模板,需要打包的时候提前编译。可以使用render函数。vue-cli创建的项目默认是运行时版本,因为效率更高
Vue.component('router-link',{
props:{
to:String
},
render(h){
return h('a',{
attrs:{
href:this.to
}
},[this.$slots.default])
}
})
2、完整版
包含运行时编译器runtimeCompiler,体积比运行时版大10K左右,程序运行的时候会把模板转换为render函数,性能不如运行时版本。
3、手写Vue Router
配置文件
1、vue.config.js
module.exports = {
//加载完整版本的vue
runtimeCompiler:true
}
2、index.js
// index.js
let _Vue = null
export default class VueRouter {
static install(Vue) {
// 1、判断当前插件是否已经被安装
if (VueRouter.install.installed) {
return
}
VueRouter.install.installed = true
//2、把Vue构造函数记录到全局变量
_Vue = Vue
//3、把创建Vue实例时候传入的router对象注册到Vue实例上
_Vue.mixin({
beforeCreate() {
console.log(this.$options)
if (this.$options.router) {
console.log(123)
_Vue.prototype.$router = this.$options.router
this.$options.router.init()
}
}
})
}
constructor(options) {
this.options = options
this.routerMap = {
}
this.data = _Vue.observable({
current: "/"
})
}
init() {
this.createRouteMap()
this.initCommponents(_Vue)
this.initEvent()
}
createRouteMap() {
//作用:遍历所有的路由规则,将其解析为键值对存储到routeMap中
this.options.routes.forEach(route => {
this.routerMap[route.path] = route.component
})
}
initCommponents(Vue) {
console.log("注册")
// Vue.component('router-link', {
// props: {
// to: String
// },
// template: '<a :href="to"><slot></slot></a>'
// })
//运行时版本使用
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.routerMap[self.data.current]
return h(component)
}
})
}
//当我们前进或者后退的时候,没有重新加载组件,所以
initEvent(){
//popstate当历史发生变化的时候触发,调用pullState,replaState不会触发
window.addEventListener('popstate',()=>{
this.data.current = window.location.pathname
})
}
}