vue-Router有两种模式 Hash 与 History
- Hash 模式是基于锚点,以及 onhashchange 事件
- HIstory模式是基于 HTML5 中 History API
- history.pushState() IE10以后支持 (history.push()会向服务器发送请求 history.pushState()记录地址,改变并记录地址 不会向服务器发送请求)
- history.replaceState()
History 模式的使用
- History需要服务器的支持
- 单页应用中,服务不存在就会返回找不到页面
- 在服务端应该除了静态资源外都返回单页应用的 index.html
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
try_files $uri $uri/ /index.html; //nginx 配置history模式
}
}
VueRouter实现原理
Hash模式
- URL中#后面的内容作为路径地址
- 监听 hashchange事件
- 根据当前路由地址找到对应组件重新渲染
- 调用push方法先判断浏览器是否支持window.history.pushState方法 支持则直接调用 不支持则通过window.location改变地址栏
History模式 - 通过 history.pushState() 方法改变地址栏
- 监听popstate 事件,可以监听到浏览器地址操作变化,记录改变后的地址
- 根据当前路由地址找到对应组件重新渲染
- window.history.pushState 不会触发 popstate事件,当历史状态被激活的时候 才会触发 popstate事件
//实现VueRouter
let _Vue = null
export default class VueRouter {
constructor(options) {
this.options = options
this.routeMap = {} //键值对存储 路由地址:对应组件
this.data = _Vue.observable({
current: '/' //存储当前路由地址
})
}
static install(Vue) {
//1.判断插件是都已经安装
if (VueRouter.install.installed) return
VueRouter.install.installed = true
//2.Vue构造函数记录在全局变量中
_vue = Vue
//3.把创建Vue实例时传入的router对象注册到Vue实例中
//混入
_Vue.mixin({
beforeCreate() {
if (this.$options.router) {
_Vue.prototype.$router = this.$options.router
this.$options.routerinit()
}
}
})
}
init() {
this.createRouteMap()
this.initComponents(_Vue)
this.initEvent()
}
//解析路由规则 存储到routeMap中
createRouteMap() {
this.options.routes.forEach(route => {
this.routeMap[route.path] = route.component
})
}
initComponents(Vue) {
Vue.component('router-link', {
props: {
to: String
},
// template: '<a :href="to"><slot></slot></a>'
render(h) { //h创建一个虚拟dom
//三个参数 1.选择器 2.设置属性 3.生成元素的子元素
return h('a', {
attrs: {//设置dom对象属性
href: this.to
},
on: {
click: this.clickHandler
}
}, [this.$slots.default])
},
methods: {
clickHandler(e) {
//三个参数 1.data 2.网页标题 3.地址
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)//将组件处理为虚拟dom
}
})
}
//注册popstate事件
initEvent() {
window.addEventListener('popstate', () => {
this.data.current = window.location.pathname
})
}
}
Vue的构建版本
运行版本:不支持template模板,需要打包的时候提前编译
完整版:包含运行时和编译器,体积比运行版大10kb左右,程序运行的时候把模板转换成 render 函数
//vue.config.js
module.exports = {
runtimeCompiler:true
}