经过上篇,咱们知道前端理由的两种实现方法,Hash 路由与 History 路由,而且用它们分别实现了一个前端路由。html
接下来咱们就将 Vue 与 Hash 路由结合,实现一个很是简单的 vue-router 吧。前端
想象一下,若是本身实现了一个 vue-router,会怎么去使用呢?参考 vue-router 官方的使用方式,看看 html 的使用:vue
<div id="app">
<p>
<router-link to="#/">home</router-link>
<router-link to="#/book">book</router-link>
<router-link to="#/movie">movie</router-link>
</p>
<router-view></router-view>
</div>
复制代码
这里会有 router-link
和 router-view
两个组件须要咱们来实现。再来看 js 的:git
const Home = { template: '<div>home</div>' };
const Book = { template: '<div>book</div>' };
const Movie = { template: '<div>movie</div>' };
const routes = [
{ path: '/', component: Home },
{ path: '/book', component: Book },
{ path: '/movie', component: Movie }
];
const router = new VueRouter(Vue, {
routes
});
new Vue({
el: '#app'
});
复制代码
这里会有咱们本身定义的组件 Home、Book 和 Movie,而且有它们各自对应的路由。咱们实现的 VueRouter 跟官方的有些区别,在 VueRouter 被 new 时是将 Vue 做为参数传入,而不是注入挂载到根实例下。github
接下来就是 VueRouter 的实现了。vue-router
要怎么来实现 VueRouter 呢,先提供一下实现的思路:app
hashchange
事件,实现前端路由;router-view
会响应更新;router-link
和 router-view
组件。先建立一个 VueRouter:ui
class VueRouter {
constructor (Vue, options) {
this.$options = options;
}
}
复制代码
给 VueRouter 添加一个绑定事件的方法,一旦路由发生改变,会触发 onHashChange
方法。this
constructor (Vue, options) {
this.init();
}
// 绑定事件
init () {
window.addEventListener('load', this.onHashChange.bind(this), false);
window.addEventListener('hashchange', this.onHashChange.bind(this), false);
}
复制代码
将传入的 options 设置成一张路由映射表,以便于经过路由查找到对应的组件。spa
constructor (Vue, options) {
this.$options = options;
this.routeMap = {};
this.createRouteMap(this.$options);
}
// 路由映射表
createRouteMap (options) {
options.routes.forEach(item => {
this.routeMap[item.path] = item.component;
});
}
复制代码
options 之中,路由与组件的关系:
const routes = [
{ path: '/', component: Home },
{ path: '/book', component: Book },
{ path: '/movie', component: Movie }
];
复制代码
生成的路由映射表:
this.routeMap = {
'/': Home,
'/book': Book,
'/movie': Movie
};
复制代码
咱们须要 new 一个新的 Vue 实例,将当前路由 current
储存在其 data 之中,当修改了 current
时,router-view
就会本身去更新视图。
constructor (Vue, options) {
this.app = new Vue({
data: {
current: '#/'
}
});
}
// 获取当前 hash 串
getHash () {
return window.location.hash.slice(1) || '/';
}
// 设置当前路径
onHashChange () {
this.app.current = this.getHash();
}
复制代码
只要在 router-view
里使用到了 this.app.current
,一旦更新它,便会更新。
router-link
实际上就是一个 <a> 标签,点击它便能触发 hashchange
。router-view
会实现一个 render 方法,将当前路由对应的组件取出,进行渲染。
constructor (Vue, options) {
this.initComponent(Vue);
}
// 注册组件
initComponent (Vue) {
Vue.component('router-link', {
props: {
to: String
},
template: '<a :href="to"><slot></slot></a>'
});
const _this = this;
Vue.component('router-view', {
render (h) {
var component = _this.routeMap[_this.app.current];
return h(component);
}
});
}
复制代码
至此,一个简单的 vue-router 就出来了,所有代码是这样的:
class VueRouter {
constructor (Vue, options) {
this.$options = options;
this.routeMap = {};
this.app = new Vue({
data: {
current: '#/'
}
});
this.init();
this.createRouteMap(this.$options);
this.initComponent(Vue);
}
// 绑定事件
init () {
window.addEventListener('load', this.onHashChange.bind(this), false);
window.addEventListener('hashchange', this.onHashChange.bind(this), false);
}
// 路由映射表
createRouteMap (options) {
options.routes.forEach(item => {
this.routeMap[item.path] = item.component;
});
}
// 注册组件
initComponent (Vue) {
Vue.component('router-link', {
props: {
to: String
},
template: '<a :href="to"><slot></slot></a>'
});
const _this = this;
Vue.component('router-view', {
render (h) {
var component = _this.routeMap[_this.app.current];
return h(component);
}
});
}
// 获取当前 hash 串
getHash () {
return window.location.hash.slice(1) || '/';
}
// 设置当前路径
onHashChange () {
this.app.current = this.getHash();
}
}
复制代码
将 Vue 与 Hash 路由结合,监听了 hashchange
事件,再经过 Vue 的 响应机制
和 组件
,便有了上面实现好了一个 vue-router。
所有源码参考 这里。