手写vue-router源码
发布日期:2021-05-13 22:21:39 浏览次数:21 分类:精选文章

本文共 4595 字,大约阅读时间需要 15 分钟。

手写Vue Router源码实现

一、项目准备

1. 创建Vue项目

使用vue create命令创建一个新的Vue项目:

vue create projectName

进入项目目录:

cd projectName

2. 安装Vue Router

使用vue add router命令安装Vue Router:

vue add router

3. 手写Vue Router源码

router文件夹中创建jvue-router.js文件。

let Vue;
class VueRouter {
constructor(options) {
this.options = options;
this.current = window.location.hash.slice(1) || "/";
Vue.util.defineReactive(this, "current", this.current);
this.match();
window.addEventListener("hashchange", () => {
this.current = window.location.hash.slice(1);
this.matched = [];
this.match();
});
}
match() {
const routes = this.options.routes || [];
let matched = [];
for (const route of routes) {
if (route.path === "/" && this.current === "/") {
matched.push(route);
return;
}
if (route.path !== "/" && this.current.indexOf(route.path) !== -1) {
matched.push(route);
if (route.children) {
this.match(route.children);
}
return;
}
}
this.matched = matched;
}
}
VueRouter.install = function(_vue) {
Vue = _vue;
Vue.mixin({
beforeCreate() {
if (this.$options.router) {
Vue.prototype.$router = this.$options.router;
}
}
});
Vue.component("router-view", {
render(h) {
this.$vnode.data.routerView = true;
let depth = 0;
let parent = this.$parent;
while (parent) {
const vnodeData = parent.$vnode && parent.$vnode.data;
if (vnodeData && vnodeData.routerView) {
depth++;
}
parent = parent.$parent;
}
const route = this.$router.matched[depth];
return h(route ? route.component : "div");
}
});
Vue.component("router-link", {
props: {
to: {
type: String,
required: true
}
},
render(h) {
return h("a", { attrs: { href: "#" + this.to } }, this.$slots.default);
}
});
};
export default VueRouter;

4. 路由组件注册

index.js中引入自定义的Vue Router:

// import VueRouter from "vue-router";
import VueRouter from "./jvue-router";

5. 嵌套路由实现

router/index.js中添加嵌套路由:

const routes = [
{
path: "/",
name: "Home",
component: Home
},
{
path: "/about",
name: "About",
component: () => import("../views/About.vue"),
children: [
{
path: "/about/intro",
name: "Intro",
component: {
render: h => h("div", "intro page")
}
}
]
}
];
const router = new VueRouter({ routes });

views/About.vue中添加router-view组件:

6. 嵌套路由优化

jvue-router.js中优化路由匹配逻辑:

class VueRouter {
constructor(options) {
this.options = options;
this.current = window.location.hash.slice(1) || "/";
Vue.util.defineReactive(this, "current", this.current);
this.matched = [];
this.match();
window.addEventListener("hashchange", () => {
this.current = window.location.hash.slice(1);
this.matched = [];
this.match();
});
}
match() {
const routes = this.options.routes || [];
let matched = [];
for (const route of routes) {
if (route.path === "/" && this.current === "/") {
matched.push(route);
return;
}
if (route.path !== "/" && this.current.indexOf(route.path) !== -1) {
matched.push(route);
if (route.children) {
this.match(route.children);
}
return;
}
}
this.matched = matched;
}
}
VueRouter.install = function(_vue) {
Vue = _vue;
Vue.mixin({
beforeCreate() {
if (this.$options.router) {
Vue.prototype.$router = this.$options.router;
}
}
});
Vue.component("router-view", {
render(h) {
this.$vnode.data.routerView = true;
let depth = 0;
let parent = this.$parent;
while (parent) {
const vnodeData = parent.$vnode && parent.$vnode.data;
if (vnodeData && vnodeData.routerView) {
depth++;
}
parent = parent.$parent;
}
const route = this.$router.matched[depth];
return h(route ? route.component : "div");
}
});
Vue.component("router-link", {
props: {
to: {
type: String,
required: true
}
},
render(h) {
return h("a", { attrs: { href: "#" + this.to } }, this.$slots.default);
}
});
};
export default VueRouter;

路由使用说明

1. 简单路由示例

2. 嵌套路由示例

3. 路由参数传递

可以通过to属性传递额外的路由参数:

上一篇:手写vuex源码
下一篇:redux和react-redux

发表评论

最新留言

哈哈,博客排版真的漂亮呢~
[***.90.31.176]2025年04月08日 13时12分03秒