1. vue-router的使用
第一步:引入vue-router,并使用Vue.use加载
import Router from 'vue-router'
Vue.use(Router)
第二步:创建Router实例
export default new Router({routes: [{path: '/', component: Home}]})
第三步:在根组件上添加该实例,main.js
import router from './router'
new Vue({
router,
...
}).$mount("#app");
第四步:使用路由视图
<!--导航-->
<router-link to="/">Home</router-link>
<!--路由出口-->
<router-view></router-view>
2.需求分析
根据vue-router的使用方法,我们需要做的事情有以下几点:
1.实现VueRouter类
- 保存传入的路由列表
- 监控url变化
- 响应url的变化
2.实现install方法给Vue.use调用
- 在Vue上挂载一个$router对象
3.创建两个全局组件
- router-link
- router-view
3.然后开始写代码
在写之前,先用vue-router写一个正常工作的页面,然后在src/router下面创建一个myrouter.js文件,最后改一下src/router/index.js文件,不引用vue-router,直接引用自己写的myrouter,这样做页面肯定报错,等写完myrouter.js,它又能正常运行,任务就完成了。
// import Router from 'vue-router'
import Router from './myrouter'
myrouter.js代码如下,思路顺序在注释中:
// 11 创建router-link
// 它是这样使用的:<router-link to="/">Home</router-link>
// 我们知道其实它是一个a标签,接收一个to属性,还有一个默认插槽
const Link = {
// 接收to
props: {
to: {
type: String,
required: true
}
},
// h是createElement方法,这个方法有三个参数,分别提供标签名,标签相关属性,标签内部的html内容 ,返回一个虚拟DOM
// render方法可以使用JSX语法,但需要Babel plugin插件
render (h) {
return h('a', {
attrs: {
href: '#' + this.to
}
}, [this.$slots.default])
}
}
// 12 创建router-view
const View = {
// h方法还可以接收一个vue组件,在路由配置选项的routes中,所有需要渲染的路由组件都写在里面,
// 在src/router/index.js中可以看到,在new Router的时候会传递进来,所以我们去构造方法中去保存一下路由
// 14 拿到组件放到h中
render(h) {
let component = null
if(this.$router.routerMap[this.$router.currentPath]) {
component = this.$router.routerMap[this.$router.currentPath].component
}
return h(component)
}
}
// 3 定义一个Vue,用来保存install中传入的Vue构造方法
let Vue
// 1 写一个class
export default class VueRouter{
constructor(options) {
// 6 获取当前url来对应路由里的path, 这里只做hash模式
let currentPath = window.location.hash.slice(1) || '/'
// 7 将currentPath做成响应式的,Vue.util.defineReactive(obj, key,...)的做用是将obj上的key弄成响应式的
Vue.util.defineReactive(this, 'currentPath', currentPath)
// 8 监听url变化,这里需要绑定一下this,不然就指到window上去了
window.addEventListener('hashchange', this.onHashChange.bind(this))
// 9 首次进入页面不会触发hashchange,需要用load来触发
window.addEventListener('load', this.onHashChange.bind(this))
// 13 保存一下options,它里面的值大概是这样的形式{routes: [{path: '/', component: Home}]}
this.$options = options
// 14 为了方便查找,做一个routerMap,不然每次找对应的组件都要循环routes
this.routerMap = {}
this.$options.routes.forEach(route => {
this.routerMap[route.path] = route
})
// 16 调用一下
this.createComponents()
}
// 10 url变化时,拿到hash值给currentPath
onHashChange() {
this.currentPath = window.location.hash.slice(1)
}
// 15 注册全局组件
createComponents() {
Vue.component('router-link', Link )
Vue.component('router-view', View)
}
}
// 2 在VueRouter上挂install方法
VueRouter.install = function(_Vue) {
// 4 保存Vue ,从使用中可以看出,先是Vue.use(Router),然后才是new Router()
// 所以是先执行install方法,后执行constructor,在这里保存Vue,构造函数中就可以使用Vue了
Vue = _Vue
// 5 挂载$router,使用全局混入,在main.js中,创建Vue时会传入router,其它组件是不会传入router的
// 如果你其它的组件也放个router,这里就还需要判断一下Vue.prototype.$router是否已存在,因为根实例会先执行
Vue.mixin({
beforeCreate () {
// 这里的this是Vue实例
if(this.$options.router) { // 根组件
Vue.prototype.$router = this.$options.router
}
}
})
// _15 在这里注册全局组件也是ok的
// Vue.component('router-link', Like)
// Vue.component('router-view', View)
}
再看下浏览器,是不是正常运行了?