介绍
Vue-Router 是 Vue.js 官方的路由管理器,它和 Vue.js 核心深度集成,让构建单页面应用变得易如反掌。Vue-Router 提供了两种模式:Hash 模式和 History 模式。Hash 模式下,URL 中的 Hash 值(#)用来模拟传统意义上的路由,而在 History 模式下,使用了 HTML5 History API 中新增的 pushState() 和 replaceState() 来完成 URL 跳转而无须重新加载页面。
Vue-Router 内部具体是如何实现的呢?本篇文章就来告诉你如何深入了解 Vue-Router 原理并实现一个小 demo。
深入了解 Vue-Router 原理
Vue-Router 的实现主要是通过 Vue.js 的插件机制进行。Vue.js 的插件机制是通过 Vue.use(Plugin)
方法来注册插件,其内部实现是调用 Plugin 的 install
方法。所以 Vue-Router 要比 Vue.js 核心多提供一个 install
方法。通过如下代码生成一个 Vue-Router 的插件版:
let Vue;
class VueRouter {
constructor(options) {
this.$options = options;
}
}
VueRouter.install = function(_Vue) {
Vue = _Vue;
// 实现 VueRouter 的 $router 属性
Vue.mixin({
beforeCreate() {
if (this.$options.router) {
Vue.prototype.$router = this.$options.router;
}
}
});
};
export default VueRouter;
在以上代码中,生成了 VueRouter
类,并实现了 install
方法。在 install
方法中,通过 Vue.mixin()
方法来定义 beforeCreate
生命周期钩子函数,实现了在每个组件实例中添加 $router
属性的功能。
通过调用 Vue.use(VueRouter)
方法注册插件,Vue.js 的核心便会将 VueRouter 的 install
方法执行,从而让 $router
属性得以添加到每个组件实例中。
接着我们需要实现 Vue-Router 的核心功能:路由映射表和路由匹配。在 Vue-Router 中,通过 router.map()
来定义路由映射表。路由映射表的格式如下:
const routes = [
{
path: "/home",
component: Home
},
{
path: "/about",
component: About
}
];
在以上代码中,routes
数组中包含了两个路由配置对象,分别定义了 /home
和 /about
两个路由。
然后我们需要在 Vue-Router 插件的 install
方法中实现路由映射表的解析和路由匹配功能:
class VueRouter {
constructor(options) {
this.$options = options;
// 路由映射表解析
this.routeMap = {};
this.$options.routes.forEach(route => {
this.routeMap[route.path] = route.component;
});
// 监听浏览器 URL 变化
window.addEventListener("popstate", () => {
this.current = window.location.pathname;
});
}
// 路由匹配
get currentComponent() {
return this.routeMap[this.current];
}
}
VueRouter.install = function(_Vue) {
Vue = _Vue;
// 实现 VueRouter 的 $router 属性
Vue.mixin({
beforeCreate() {
if (this.$options.router) {
Vue.prototype.$router = this.$options.router;
}
}
});
// 实现 VueRouter 的 $route 属性
Object.defineProperty(Vue.prototype, "$route", {
get() {
return {
current: router.current
};
}
});
// 实现 VueRouter 的 router-link 组件
Vue.component("router-link", {
props: {
to: String
},
render(h) {
return h("a", { attrs: { href: "#" + this.to } }, this.$slots.default);
}
});
};
export default VueRouter;
在以上代码中,我们在 VueRouter
的构造函数中,实现了路由映射表的解析,并通过 window.addEventListener("popstate", ...)
监听了浏览器 URL 变化。
在 get currentComponent()
中,我们通过 this.routeMap[this.current]
获取当前 URL 对应的组件。
接着我们在 Vue-Router 的 install
方法中,实现了 $route
属性的定义和 router-link
组件的定义。其中,$route
属性是通过 Object.defineProperty()
方法实现的,而 router-link
组件是通过 Vue.component()
方法实现的。
Vue-Router 的核心功能:路由映射表和路由匹配就介绍到这里,接下来我们可以通过以上代码实现一个小 demo。
实现一个小 demo
我们先通过 Vue.js 创建一个 SPA 应用程序:
<div id="app">
<router-link to="/home">首页</router-link>
<router-link to="/about">关于我们</router-link>
<router-view></router-view>
</div>
在以上代码中,使用了 Vue-Router 的 router-link
和 router-view
组件,分别对应 URL 跳转和组件渲染的功能。
然后我们实例化 Vue.js:
import Vue from "vue";
import App from "./App.vue";
import VueRouter from "./router";
Vue.config.productionTip = false;
const routes = [
{
path: "/home",
component: () => import("./views/Home.vue")
},
{
path: "/about",
component: () => import("./views/About.vue")
}
];
const router = new VueRouter({
routes
});
new Vue({
router,
render: h => h(App)
}).$mount("#app");
在以上代码中,我们引入了 Vue.js、App 组件和 Vue-Router,定义了路由映射表 routes
,然后实例化了 Vue.js,并将路由管理器 router
作为参数传入 Vue.js 实例,通过 $mount("#app")
将 Vue.js 实例挂载到 #app
节点中。
接着,我们需要实现 Vue-Router 的跳转和组件渲染功能:
class VueRouter {
constructor(options) {
this.$options = options;
// 路由映射表解析
this.routeMap = {};
this.$options.routes.forEach(route => {
this.routeMap[route.path] = route.component;
});
// 监听浏览器 URL 变化
window.addEventListener("popstate", () => {
this.current = window.location.pathname;
});
// 初始化 URL
this.current = window.location.pathname;
}
// 跳转方法
push(url) {
window.history.pushState({}, "", url);
this.current = url;
}
// 路由匹配
get currentComponent() {
return this.routeMap[this.current];
}
}
VueRouter.install = function(_Vue) {
Vue = _Vue;
// 实现 VueRouter 的 $router 属性
Vue.mixin({
beforeCreate() {
if (this.$options.router) {
Vue.prototype.$router = this.$options.router;
}
}
});
// 实现 VueRouter 的 $route 属性
Object.defineProperty(Vue.prototype, "$route", {
get() {
return {
current: router.current
};
}
});
// 实现 VueRouter 的 router-link 组件
Vue.component("router-link", {
props: {
to: String
},
render(h) {
return h("a", { attrs: { href: "#" + this.to } }, this.$slots.default);
}
});
// 实现 VueRouter 的 router-view 组件
Vue.component("router-view", {
render(h) {
const component = router.currentComponent;
return h(component);
}
});
};
在以上代码中,我们分别实现了 push()
方法和 router-view
组件的渲染。在 push()
方法中,我们使用了 HTML5 History API 中的 pushState()
方法,实现了 URL 的跳转。在 router-view
组件的 render
方法中,则是通过 router.currentComponent
获取当前 URL 对应的组件,然后通过 h(component)
函数将组件渲染出来。
最后我们可以在组件中使用 Vue-Router 提供的 $router
和 $route
属性:
<template>
<div class="home">
<h1>这里是首页</h1>
</div>
</template>
<script>
export default {
mounted() {
console.log(this.$router); // VueRouter {$options: {…}, routeMap: {…}, current: "/home"}
console.log(this.$route.current); // "/home"
}
};
</script>
在以上代码中,我们在 Home 组件中使用了 $router
和 $route
属性。
至此,我们通过以上代码实现了一个简单的 Vue-Router 插件,实现了路由映射表、路由匹配、URL 跳转和组件渲染等核心功能。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:深入了解vue-router原理并实现一个小demo - Python技术站