什么是vueRouter
VueRouter是前端路由,当路径发生改变,在浏览器端判断当前路径,并加载当前路径对应的组件。
hash模式和history模式的简单介绍
hash模式
1. url中#后面作为路由地址
2. 可以直接通过location.url来切换浏览器中的地址,如果只是修改了#后面的内容,浏览器不会向服务器请求该地址,但是会记录到浏览器访问历史中。
3. 当hash发生变化时会触发hashChange事件监听hash变化作相应的处理
4. 监听hashChange事件,在该事件中会记录当前路由地址,根据地址找到对应的组件重新渲染
history模式
1. 就是一个普通的url
2. 通过history.pushState()方法改变地址栏,并把当前地址记录到浏览器的访问历史中,不会真正的跳转到指定路径(浏览器不会向服务器发送请求)
3. 监听popState事件,可以监听到浏览器历史操作的变化,记录改变后的地址。(当调用 pushState 和 replaceState 的时候并不会触发该事件,当点击浏览器的前进/后退时或者调用back/forward方法时,该事件才会被触发)
4. 当地址发生改变,根据当前路由地址找到对应组件重新渲染
hash和history模式的区别
相同点:
客户端路由的实现方式,当路径发生变化不会向服务器发送请求, 是用js监视路径的变化,使用不同的地址渲染不同的内容。当需要服务端内容的话通过发送ajax来获取。
不同点:
表现形式的区别:
hash地址url上面带着 # 和 ? 很丑,#后面的是路由地址,通过控制路由地址进入不同的页面
history模式就是正常的url
原理上的区别:
hash模式基于锚点 和 onHashChange 事件。通过锚点的值作为路由地址,当地址发生变化时触发onHashChange事件,根据路径决定页面呈现内容
history模式基于 h5中的 historyAPI: history.pushState()(实现客户端路由,IE10才支持,有兼容问题) history.replaceState()
history.pushState() 和 history.push() 方法的区别
push路径发生变化会向服务器发送请求
pushState路径发生变化,会记录到历史记录里面,但是不会向服务器发送请求。
history模式怎么使用
需要服务端的支持,当刷新浏览器,会向服务器端发送请求,会返回404
在服务端应该除了静态资源外都返回单页应用的index.html
vueRouter的基本使用
1. 安装vueRouter插件
2. 导入vue、vue-router
3. 通过vue.use()方法注册路由组件
- Vue.use() 可以传入对象或者方法,相当于直接调用这个对象或者方法中的install方法
- Vue.use(VueRouter) // 注册插件
4. 定义路由规则
5. 创建路由对象,将路由规则传进去
6. 创建Vue实例的时候将路由对象注册进去
7. 通过<router-link></router-link>标签创建链接,通过<router-view></router-view>创建路由组件的占位,替换为当前路由对应的组件
import VueRouter from 'vue-router'
// 定义路由规则
const routes= [// 路由规则
{
name: 'home',
path: '/',
component: Home
}
]
// 创建路由实例
const router = new VueRouter({
routes
})
// 创建Vue实例,注册路由实例对象
new Vue({
router,
render: h => h(App)
}).$mount('#app)
vueRouter实现分析
Vue.use() 注册 vue-router 插件, 里面可以传入函数或者对象。如果传入函数会直接执行这个函数,如果是一个对象,会调用这个对象里面的install方法。
<router-view> 创建路由组件的占位符,当路径发生变化会加载对应的组件替换掉router-view这个位置
$route:存放当前的路由规则
$router:存放路由实例对象(跟路由相关的方法)
动态路由:通过一个占位来匹配动态变化的位置
路由懒加载:当用户访问路由的时候才会去加载对应的组件,提高程序的性能
获取动态路由传递的参数:
1. 通过当前路由规则,获取数据: $route.params.id (缺点:强依赖于路由)
2. 在路由规则中开启props:会把URL中的参数传递给组件,在组件中通过 props 来接收 URL 参数
let _Vue = null
// 通过Vue.use()注册 vue-router 插件, 里面可以传入函数或者对象。如果传入函数会直接执行这个函数,如果是一个对象,会调用这个对象里面的install方法。这里我们通过定义一个class类来实现,里面定义一个静态的install方法
export default class VueRouter {
constructor(options) {
this.options = options
this.routeMap = {}
this.data = _Vue.observable({
current: '/'
})
}
static install(Vue) {
// 判断当前插件是否已经安装,已经安装直接返回:在VueRouter静态方法中定义一个变量状态来判断插件是否已经安装
if (VueRouter.install.installed) {
return
}
VueRouter.install.installed = true
// 将vue构造函数记录在全局
_Vue = Vue
// 通过混入的方式将创建的vue实例传入的router对象注入到vue实例上面
_Vue.mixins({
beforeCreate() {
if (this.$options.router) {
_Vue.prototype.$router = this.$options.router
}
}
})
}
init() {
this.createRouteMap() // 解析路由规则
this.initComponent(_Vue) // 初始化 router-view 和 router-link 组件
this.initEvent() // 初始化事件
}
// 遍历所有的路由规则,将解析后的路由规则存放到routeMap中
createRouteMap() {
this.options.forEach(route => {
this.routeMap[route.path] = route.component
})
}
initComponent(Vue) {
const self = this
// 注册router-link组件
Vue.component('router-link', {
props: {
to: String
},
render(h) {
return h('router-link', {
attrs: {
href: self.to
},
on: {
click: self.handleClick
}
}, [this.$solts.default])
},
methods: {
// 当点击router-link标签时更改当前地址栏的地址为this.to,同时将this.to赋值给this.data响应式对象中的current属性,并阻止a链接的默认事件
handleClick(e) {
history.pushState({}, '', this.to)
this.$router.data.current = this.to
e.preventDefault()
}
}
})
// 注册router-view组件
Vue.component('router-view', {
render(h) {
// 当前路由地址对应的组件
const cm = this.routeMap[self.data.current]
// 通过h()函数创建虚拟DOM,并将该虚拟DOM返回
return h(cm)
}
})
}
// 初始化事件,监听地址栏的变化替换掉VueRouter响应式对象Data中的current值
initEvent() {
window.addEventListener('popstate', () => {
this.data.current = window.location.pathname
})
}
}