前言
最近在研究vue的源码,打算自己着手实现一些简单的功能,加深一下对框架的了解,于是准备实现一个简单的vue-router。
准备工作
先用vue-cli创建一个包含vue-router的demo,然后把项目引入的vue-router注释掉,改成自己写的js。
hash模式和history模式的区别
- 表现形式的区别
- hash模式
- history模式
- 原理的区别
- hash模式
- history模式
history.pushState({}, "", "bar.html") // 往浏览器添加历史记录 history.replaceState({}, "", "bar.html") // 往浏览器修改当前的历史纪录 history.go() // 跳转指定页面
实现思路
- 创建一个VueRouter类,有一个静态方法install,判断此插件是否加载过,只需加载一次。当Vue加载时,把传入的router对象挂载到Vue实例上(只执行一次)。
- 在构造函数中,初始化,把传入的参数options放到自己的this上;创建一个routerMap对象,用来记录路由和组件的映射关系;利用Vue提供的 observable 方法创建一个响应式数据,记录当前的路由。
- 创建initEvent事件,利用popstate事件监听history模式下路由的变化,利用hashchange事件监听hash模式下的变化。
- 创建initRouterMap事件,循环传入的routes路由配置信息,把路由和组件的映射关系记录到routerMap对象中。
- 创建initComponent事件,创建router-link和router-view两个组件。
- 当路径改变时,通过routerMap找到对应的组件,渲染到router-view中。
- 插件初始化时,执行initEvent、initRouterMap、initComponent事件。
代码演示
// my-Router.js
let _Vue = null;
class VueRouter {
static install(Vue) {
// 判断此插件是否安装过
if(VueRouter.prototype.installed) {
return
}
VueRouter.prototype.installed = true
_Vue = Vue;
// 把当前路由对象挂载到vue实例上
_Vue.mixin({
beforeCreate() { // 为什么在这里挂载,因为这里的this才是vue实例
if(this.$options.router) {
_Vue.prototype.$router = this.$options.router
}
}
})
}
constructor(options) {
// 传入的对象
this.options = options;
// 所有路由
this.routerMap = {};
// 当前路由
this.data = _Vue.observable({
current: "/",
});
this.init();
}
init() {
//监听浏览器地址变化
this.initEvent()
// 把所有的路由添加到routerMap中
this.initRouterMap();
// 初始化全局的路由组件
this.initComponent(_Vue);
}
initRouterMap() {
for (let item of this.options.routes) {
this.routerMap[item.path] = item.component;
}
}
initEvent() {
if(this.options.mode == 'history') {
window.addEventListener('popstate', ()=>{
this.data.current = window.location.pathname
})
}else {
window.addEventListener('hashchange', ()=>{
this.data.current = window.location.hash.substr(1)
})
}
}
initComponent(Vue) {
let that = this;
Vue.component("router-link", {
props: {
to: String,
},
render(h) {
return h(
"a",
{
attrs: {
href: this.to,
},
on: {
click: this.clickhander,
},
},
[this.$slots.default]
);
},
methods: {
clickhander(e) {
e.preventDefault();
if(that.options.mode == 'history') {
history.pushState({}, "", this.to);
}else{
history.pushState({}, "", '#' + this.to);
}
that.data.current = this.to;
},
},
});
Vue.component("router-view", {
render(h) {
let app = that.routerMap[that.data.current];
return h(app);
},
});
}
}
export default VueRouter;
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!