一、项目准备
创建vue项目
vue create projectName
进入项目
cd projectName
安装vue-router
vue add router
手写vue-router:在router文件夹中创建jvue-router.js文件。
将index.js文件中引入VueRouter地址改为jvue-router.js的地址
-
// import VueRouter from "vue-router";
-
import VueRouter
from
"./jvue-router";
二、手写vue-router源码
1在router/index.js中使用VueRouter时是new VueRouter(),所以要创建一个VueRouter类并暴露出来,同时vue插件都要有一个install进行初始化,install中的参数为vue,保存起来以便后面使用。
-
let Vue;
-
class VueRouter {
-
constructor() {}
-
}
-
-
VueRouter.install =
function(_vue) {
-
Vue = _vue;
-
}
-
-
export
default VueRouter;
2.在组件中,我们是直接使用<router-link>和<router-view>两个组件,所以install方法中注册这两个组件
-
let Vue;
-
class VueRouter {
-
constructor() {}
-
}
-
-
VueRouter.install =
function(_vue) {
-
Vue = _vue;
-
-
// 注册router-view和router-link
-
Vue.component(
'router-view', {
-
render(h) {
-
return h(
'div',
'router-view')
-
}
-
})
-
Vue.component(
'router-link', {
-
render(h) {
-
return h(
'a',
'router-link')
-
}
-
})
-
}
-
-
export
default VueRouter;
3.先分析router-link组件:
使用时我们会传入一个to属性表示链接路径:
<router-link to="/about">About组件</router-link>
编译后是一个a标签和href属性,href属性的值为上面to属性的值:
<a href="/about">About组件</a>
所以我们注册router-link组件时应先用props获取to属性值,用$slots获取插值文本
-
let Vue;
-
class VueRouter {
-
constructor() {}
-
}
-
-
VueRouter.install =
function(_vue) {
-
Vue = _vue;
-
-
// 注册router-view
-
Vue.component(
'router-view', {
-
render(h) {
-
return h(
'div',
'router-view')
-
}
-
})
-
// 注册router-link
-
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.分析router-view组件:
获取当前hash并将其设为响应式数据,监听url变化。由于是响应式数据,所以当hash变化时,相应的组件会重新渲染。
获取路由映射表,根据当前hash在映射表中找到对应的组件,并渲染。
由于组件中使用router时是this.$router形式,所以要将router挂载到Vue原型链上。此时可以在Vue组件中获取到router和routes。
因为VueRouter执行install时Vue实例还没有创建(详见main.js),所以要使用混入的方式,在beforeCreate时再挂载。
路由映射表是在创建路由实例时传入(./router/index.js):
-
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
-
});
对应代码:
-
// 设置vue以便后面使用
-
let Vue;
-
class VueRouter {
-
constructor(options) {
-
this.options = options;
-
-
// 初始化current,设置current为响应式数据,当current改变时重新渲染页面
-
Vue.util.defineReactive(
-
this,
-
"current",
-
window.location.hash.slice(
1) ||
"/"
-
);
-
console.log(Vue.util);
-
-
// 监听url变化,重置current
-
window.addEventListener(
"hashchange",
() => {
-
this.current =
window.location.hash.slice(
1);
-
console.log(
this.current);
-
});
-
}
-
}
-
-
// vue插件都要有install方法:注册router-link和router-view两个组件 使得我们在组件中使用时可以<router-view>,将router挂载到Vue原型链上,使得我们在组件中使用时可以this.$router
-
VueRouter.install =
function(_vue) {
-
Vue = _vue;
-
console.log(_vue);
-
-
// 将router挂载到Vue原型链上
-
// 因为VueRouter执行install时Vue实例还没有创建(详见main.js),所以要使用混入的方式,在beforeCreate时再挂载
-
Vue.mixin({
-
beforeCreate() {
-
// 判断当前组件是否为根组件,只有根组件有$router
-
// 因为根组件的vue实例创建时传入了vueRouter实例,vue组件中获取传入的参数可使用this.$options,所以获取传入的vueRouter实例可以用this.$options.router
-
if (
this.$options.router) {
-
Vue.prototype.$router =
this.$options.router;
-
}
-
}
-
});
-
// 注册router-view
-
// 根据当前hash找到对应component
-
// hash:window.location.hash.slice(1)
-
// 获取路由映射表:VueRouter在创建实例时传入了路由映射表,所以从VueRouter初始化中获取
-
Vue.component(
"router-view", {
-
render(h) {
-
const { current, options } =
this.$router;
-
let component =
null;
-
const route = options.routes.find(
route => route.path === current);
-
if (route) {
-
component = route.component;
-
}
-
return h(component);
-
}
-
});
-
// 注册router-link
-
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;
转载:https://blog.csdn.net/MiemieWan/article/details/116456199