先看两个问题:
router-link、router-view是什么,有什么作用?url变化时,是如何拿到对应的页面进行渲染的?
路由工作流程图:
vue-router 使用方式:
- step1:引入
vue和vue-router
import Vue from 'vue'
import VueRouter from './vue-router'
- step2:使用 VueRouter
// 可知VueRouter是插件,会暴露install方法,供Vue调用
Vue.use(VueRouter)
- step3:定义路由配置项
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About
}
]
- step4:创建
router对象并导出
const router = new VueRouter({
routes // 将配置项传入
})
export default router
- step4:在
main.js中导入router对象
import router from './router'
- step5:在根组件初始化中传入
router对象
new Vue({
// 传入router对象
router,
render: h => h(App)
}).$mount('#app')
- step6:在
vue组件中,可以通过this.$router拿到路由器对象
实现自己的 vue-router,取名 mvue-router😁
- 创建
MVueRouter类:
// MVue保存Vue类,因为在做path响应式时要用到
let MVue
class MVueRouter {
// 使用:new MVueRouter({routes})
constructor(options) {
// 将传入的配置项保存,options里有路由配置项:routes
this.$options = options
// 将url中的path解析出来,根据路由配置项,可以通过path找到对应的component
// 比如:当前window.location.hash是 "#/about",initPath为 "/about",对应的组件是 About
const initPath = window.location.hash.slice(1) || '/'
// 利用Vue的工具方法,将initPath设置成响应式数据,取名currentPath,当currentPath改变时,触发对应组件渲染更新
MVue.util.defineReactive(this, 'currentPath', initPath)
// 因为vue实例的data选项就是响应式的,也可以直接初始化一个vue实例,在使用的时候,用this.app.currentPath即可:
// this.app = new Vue({data: () => return {currentPath: initPath})
// 监听事件,更新最新的currentPath
// 页面path改变
window.addEventListener('hashchange', this.onHashChange.bind(this))
// 首次加载页面
window.addEventListener('load', this.onHashChange.bind(this))
// 缓存路由映射关系,处理成下面的格式,方便后面使用
// {
// '/about/': {path: '/about', component: About}
// }
this.routeMap = {}
this.$options.routes.forEach(route => {
this.routeMap[route.path] = route
})
}
onHashChange() {
// 拿到最新的path,注:因为currentPath是响应式的,当它改变时,会触发router-view更新
this.currentPath = window.location.hash.slice(1)
}
}
// 实现install方法
MVueRouter.install = Vue => {
// 保存Vue,为什么要这样设计,而不是直接引入vue呢?
// 不能要求router的使用者去安装vue啊😆
MVue = Vue
// 通过全局混入的方式,将根组件中的router对象挂载到原型上
Vue.mixin({
beforeCreate() {
// 判断当前组件的选项中是否存在router,存在router的,就是根组件
if (this.$options.router) {
// 所以Vue组件都可以通过this.$router拿到路由器实例
Vue.prototype.$router = this.$options.router
}
}
})
// 实现router-link组件,实际上就是对a标签的封装
// 使用:<router-link to="/about">关于</router-link>
Vue.component('router-link', {
props: {
to: {
type: String,
required: true
}
},
render(h) {
return h(
'a',
{
attrs: {
href: '#' + this.to
}
},
this.$slots.default
)
}
})
// 实现router-view
// router-view就是一个容器,路由对应的组件渲染在这里进行
Vue.component('router-view', {
render(h) {
// 因为通过混入了router,所以组件上能拿到router对象
// 将router对象中的路由信息和当前path解构出来
const { routeMap, currentPath } = this.$router
// 取出当前path对应的组件
const comp = routeMap[currentPath]
? routeMap[currentPath].component
: null
return h(comp)
}
})
}
vue学习项目:重学vue,欢迎pr。