什么是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
? ? })
? }
}
?
|