vue-router实现
vue-router在vue开发中是我们最常接触到的,但对于其实现还是比较陌生的
vue-router最常见的用法:
首先在main.js中引入
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App)
}).$mount('#app')
接着定义路由文件
router/index.js
import Vue from 'vue'
// import VueRouter from 'vue-router'
import VueRouter from '../vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = new VueRouter({
routes
})
export default router
最后,在App.vue中使用
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
</div>
</template>
分析一下vue-router
首先vue-router是一个vue插件,所以需要实现插件方法install
接着我们需要记录vue的路由配置,最好能形成一个map,键为路由的路径,值为路径对应的component
然后我们需要实现路由组件router-link、router-view
最后我们要让组件能响应浏览器的前进后退按钮
先来完成第一步
let Vue;
export default class VueRouter{
static install(_Vue) {
if(VueRouter.installed) {
return
}
VueRouter.installed = true;
Vue = _Vue
Vue.mixin({
beforeCreate() {
if(this.$options.router) {
Vue.prototype.$router = this.$options.router
//执行初始化函数
this.$options.router.init()
}
}
})
}
init() {}
}
//解释一下
//变量Vue记录vue的构造函数,让我们能够用mixin、component等全局函数
//install方法会传入vue的构造函数
//用一个installed变量记录是否已经挂载了vue-router插件
//使用mixin给所有vue实例都挂在一个beforeCreate方法,但只有具有router属性的实例,也就是main函数中的实例才具有router,才能为vue原型添加router,其他组件实例找到的是构造函数原型上的实例
new Vue({
router,
render: h => h(App)
}).$mount('#app')
完成第二步,
export default class VueRouter{
static install(_Vue) {
//some code
}
constructor(options) {
this.options = options; //记录路由配置信息,也就是router/index.js中的路由配置
this.routerMap = {}; //路由map
this.data = Vue.observable({ //这是vue提供的api,能让一个对象变为响应式
current: '/' //记录当前路径
})
}
initRouteMap() { //初始化routerMap
this.options.forEach(item => {
this.routerMap[item.path] = item.component
})
}
init() {
this.initRouteMap()
}
}
接下来实现router-link,router-view
export default class VueRouter{
static install(_Vue) {
//some codes
}
constructor(options) {
// some codes
}
initRouteMap() { //初始化routerMap
//some codes
}
initComponent(Vue) {
// router-link实现
Vue.component('router-link', {
props: {
to: String
},
render(h) {
return h(
"a",
{
attrs: {
href: this.to
},
on: {
click: this.clickHandler
}
},
[this.$slots.default]
)
},
methods: {
clickHandler(e) {//我们这里实现使用的是history模式,这里使用了pushstate方法
history.pushState({}, "", this.to);
this.$router.data.current = this.to;//记录当前路径
e.preventDefault();//阻止a标签默认事件
}
},
})
//router-view实现
const self = this;
Vue.component('router-view', {
render(h) {
const component = self.routeMap[self.data.current]//获取当前路径对应的组件
return h(component)
},
})
}
init() {
this.initRouteMap()
this.initComponent(Vue)
}
}
//注意要阻止默认a标签事件,因为a标签默认事件会跳转刷新网页
完成最后一步
export default class VueRouter{
static install(_Vue) {
//some codes
}
constructor(options) {
// some codes
}
initRouteMap() { //初始化routerMap
//some codes
}
initComponent(Vue) {
//some codes
}
//初始化事件
initEvent() {
window.addEventListener("popstate", () => { //history提供了popstate用来监听路由变化
this.data.current = window.location.pathname
})
}
//初始化
init() {
this.initRouteMap();
this.initComponent(Vue);
this.initEvent()
}
}
//我们已经将this.data转变为了一个响应式对象,当路径发生改变时就会触发dom重新渲染
完整代码
let Vue;
export default class VueRouter {
static install(_Vue) {
if(VueRouter.installed) { //1.是否已安装VueRouter
return
}
VueRouter.install.installed = true;
Vue = _Vue //2.缓存Vue构造函数
Vue.mixin({ //3.将VueRouter混入到所有Vue实例中
beforeCreate() {
if(this.$options.router) {
Vue.prototype.$router = this.$options.router;
this.$options.router.init()
}
},
})
}
constructor(options) {
this.options = options; //路由配置
this.routeMap = {}; //路径和组件对应配置表
this.data = Vue.observable({ //是一个响应式对象
current: '/' //该属性记录当前路由地址
})
}
//初始化路由配置
initRouteMap() {
this.options.routes.forEach(item => {
this.routeMap[item.path] = item.component;
})
}
//初始化路由组件
initComponent(Vue) {
Vue.component('router-link', {
props: {
to: String
},
render(h) {
return h(
"a",
{
attrs: {
href: this.to
},
on: {
click: this.clickHandler
}
},
[this.$slots.default]
)
},
methods: {
clickHandler(e) {
history.pushState({}, "", this.to);
this.$router.data.current = this.to;
e.preventDefault();
}
},
})
const self = this;
Vue.component('router-view', {
render(h) {
const component = self.routeMap[self.data.current]
return h(component)
},
})
}
//初始化事件
initEvent() {
window.addEventListener("popstate", () => {
this.data.current = window.location.pathname
})
}
//初始化
init() {
this.initRouteMap();
this.initComponent(Vue);
this.initEvent()
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?