路由表是一个数组,包含每个路由的路径和对应的组件信息,还可以包括一些额外的配置,如嵌套路由、重定向、别名等。
const routes = [
{
path: '/',
component: HomeComponent,
children: [
{ path: 'profile', component: ProfileComponent }
]
},
{ path: '/about', component: AboutComponent },
{ path: '/contact', component: ContactComponent },
{ path: '/user/:id', component: UserComponent }
];
我们需要一个解析器来匹配当前的 URL 并找到对应的路由。可以使用正则表达式来处理动态路由参数。
function matchRoute(path, routes) {
for (let route of routes) {
const regex = new RegExp(`^${route.path.replace(/:\w+/g, '(\\w+)')}$`);
const match = path.match(regex);
if (match) {
return { ...route, params: extractParams(route.path, match) };
}
}
return null;
}
function extractParams(routePath, match) {
const keys = routePath.match(/:\w+/g);
const params = {};
if (keys) {
keys.forEach((key, index) => {
params[key.replace(':', '')] = match[index + 1];
});
}
return params;
}
在 Vue 应用中,我们使用一个根组件来动态渲染当前匹配的组件。
const App = {
data() {
return {
currentRoute: window.location.pathname,
currentComponent: null
};
},
created() {
this.updateRoute();
window.addEventListener('popstate', this.updateRoute);
},
methods: {
updateRoute() {
const match = matchRoute(this.currentRoute, routes);
if (match) {
this.currentComponent = match.component;
} else {
this.currentComponent = NotFoundComponent;
}
},
navigate(path) {
history.pushState(null, null, path);
this.currentRoute = path;
this.updateRoute();
}
},
render() {
return Vue.h(this.currentComponent);
}
};
导航守卫可以在路由切换之前或之后执行一些逻辑,如权限检查、数据获取等。可以在路由对象中定义 beforeEnter
钩子。
const routes = [
{
path: '/',
component: HomeComponent,
beforeEnter(to, from, next) {
// 执行一些逻辑
next();
}
},
{ path: '/about', component: AboutComponent }
];
function updateRoute() {
const match = matchRoute(window.location.pathname, routes);
if (match && match.beforeEnter) {
match.beforeEnter(match, currentRoute, () => {
currentComponent = match.component;
});
} else if (match) {
currentComponent = match.component;
} else {
currentComponent = NotFoundComponent;
}
}
嵌套路由允许在一个组件内部定义子路由。可以使用递归来渲染子路由。
const HomeComponent = {
template: '<div>Home <router-view></router-view></div>',
components: {
'router-view': {
render() {
const currentRoute = window.location.pathname.replace('/profile', '');
const match = matchRoute(currentRoute, routes[0].children);
return Vue.h(match ? match.component : NotFoundComponent);
}
}
}
};
命名视图:允许在同一路由中渲染多个视图。
动态路由:通过 URL 参数传递数据。
重定向和别名:支持重定向路径和别名路径。
const HomeComponent = {
template: '<div>Home <router-view></router-view></div>',
};
const ProfileComponent = {
template: '<div>Profile</div>',
};
const AboutComponent = {
template: '<div>About</div>',
};
const ContactComponent = {
template: '<div>Contact</div>',
};
const UserComponent = {
props: ['id'],
template: '<div>User {{ id }}</div>',
};
const NotFoundComponent = {
template: '<div>404 Not Found</div>',
};
const routes = [
{
path: '/',
component: HomeComponent,
children: [
{ path: 'profile', component: ProfileComponent }
]
},
{ path: '/about', component: AboutComponent },
{ path: '/contact', component: ContactComponent },
{ path: '/user/:id', component: UserComponent }
];
function matchRoute(path, routes) {
for (let route of routes) {
const regex = new RegExp(`^${route.path.replace(/:\w+/g, '(\\w+)')}$`);
const match = path.match(regex);
if (match) {
return { ...route, params: extractParams(route.path, match) };
}
}
return null;
}
function extractParams(routePath, match) {
const keys = routePath.match(/:\w+/g);
const params = {};
if (keys) {
keys.forEach((key, index) => {
params[key.replace(':', '')] = match[index + 1];
});
}
return params;
}
const App = {
data() {
return {
currentRoute: window.location.pathname,
currentComponent: null
};
},
created() {
this.updateRoute();
window.addEventListener('popstate', this.updateRoute);
},
methods: {
updateRoute() {
const match = matchRoute(this.currentRoute, routes);
if (match) {
this.currentComponent = match.component;
} else {
this.currentComponent = NotFoundComponent;
}
},
navigate(path) {
history.pushState(null, null, path);
this.currentRoute = path;
this.updateRoute();
}
},
render() {
return Vue.h(this.currentComponent);
}
};
const app = Vue.createApp(App);
app.mount('#app');
这个示例展示了如何设计和实现一个基本的 Vue 路由系统。我们定义了路由表,通过正则表达式解析 URL,匹配路由并渲染相应的组件。系统还支持嵌套路由、动态路由参数、导航守卫等功能。尽管这是一个简化的实现,但它展示了 Vue Router 的基本原理。实际应用中,完整的路由系统可能会更复杂,处理更多的场景和优化。