实现一个简单的vue-router
所有项目的源代码都放在我的github上,欢迎大家start: https://github.com/Jasonwang911/my-vue-router
首先来看下vue-router的使用:
import Vue from 'vue';
import VueTouter from 'vue-router';
// VueRouter 是一个类,用来new 一个实例 // 注册vue-router
Vue.use(VueRouter); new VueRouter({
mode: 'hash', // hash 或者是 history
routes: [
{path: '/home', component: Home },
]
})
vue项目的入口文件中:
import Vue from "vue";
import App from "./App.vue";
// 引入配置好的router
import router from "@/router"; Vue.config.productionTip = false; new Vue({
//将路由注入根组件
router,
render: h => h(App)
}).$mount("#app");
同时视图文件展示在全局组件 router-view 上,并使用全局组件 router-link 进行跳转 , 并且在所有组件上都会有一个 $route 的属性集和 一个 $router 的方法集
<router-view></router-view> // 用来显示路由组件的视图组件,需要注册 Vue.use(VueRouter);vue-router还区分两种路由模式 mode: hash模式和history模式
<router-link to="/home"></router-link> // 链接全局组件,包括一些属性 eg: to
this.$route 属性集
this.$router 方法集
1.hash模式的基本原理是在页面加载完和hash发生变化的时候获取 location.hash, 代码放在我的github上: https://github.com/Jasonwang911/my-vue-router/blob/master/static/hash.html
<body>
<!-- hash -->
<a href="#/home">首页</a>
<a href="#/about">关于我们</a>
<div id="html"></div> <script>
window.addEventListener('load', () => {
html.innerHTML = location.hash.slice(1);
})
window.addEventListener('hashchange', () => {
html.innerHTML = location.hash.slice(1);
})
</script>
2.history的基本原来是使用浏览器的 history API 演示代码放在我的github上: https://github.com/Jasonwang911/my-vue-router/blob/master/static/history.html
<body>
<a onclick="go('/home')">首页</a>
<a onclick="go('/about')">关于</a>
<div id="html"></div> <script>
function go(pathname) {
// 传入的数据 标题null 真正的路径 --- 页面不会刷新,后退按钮有问题
history.pushState({}, pathname, pathname);
html.innerHTML = pathname;
}
// 浏览器的后退按钮
window.addEventListener('popstate', () => {
go(location.pathname);
})
</script>
简单介绍一下注册插件 vue.use 这个方法: vue要求在插件上添加一个 install 的方法,这个方法接收两个参数,第一个参数是vue, 第二个参数是options, options用来给插件传值
import Vue from 'vue';
import VueRouter from '@/router/vue-router.js'; // 注册组件
Vue.use(VueRouter, {name: 'jason', age: 18}); // VueRouter 的类 (/router/vue-router.js)
class VueRouter { } // 使用vue.use 就会调用 install 方法, 方法上有一个参数是vue实例
VueRouter.install = function(Vue, options) {
console.log(Vue, options);
} export default VueRouter;
根据上面的思路来简单实现一下vue-router(只实现了部分功能和一层组件,如果需要实现子路由请自行递归):
import Vue from 'vue';
// 路由的history属性类
class HistoryRoute {
constructor() {
this.current = null;
}
} // VueRouter 的类
class VueRouter {
// options 中包含 mode 和 routes
constructor(options) {
this.mode = options.mode || 'hash';
this.routes = options.routes || [];
// 把routes改成 路径:组件 的键值对对象,方便拿到路径直接渲染组件
this.routesMap = this.createMap(this.routes);
console.log('收敛后的路由表===>',this.routesMap);
// 路由中history属性存放当前路径 创建一个history类,方便扩展属性 {currnet: null}
this.history = new HistoryRoute;
// 初始化操作
this.init();
} init() {
console.log('执行了初始化的操作')
// 判断路由模式
if(this.mode === 'hash') {
// 先判断用户打开时有没有hash,没有就跳转到 #/
location.hash ? '' : location.hash = '/';
// 页面加载完成当前路径写入this.history
window.addEventListener('load', () => {
this.history.current = location.hash.slice(1);
});
// 监听 hash 变化并把当前路径存入 this.history
window.addEventListener('hashchange', () => {
this.history.current = location.hash.slice(1);
});
}else if(this.mode === 'history'){
// 判断用户打开页面的 pathname
location.pathname ? '' : location.pathname = '/';
// 页面加载完成当前路径写入this.history
window.addEventListener('load', () => {
this.history.current = location.pathname;
});
// 监听 history 变化并把当前路径存入 this.history
window.addEventListener('popstate', () => {
this.history.current = location.pathname;
});
}else {
throw new Error(`vue-router mode error, can no font router mode: ${this.mode}`);
}
} // 收敛路由表 this.routes
createMap(routes) {
return routes.reduce((prev, next, index, arr) => {
prev[next.path] = next.component;
return prev;
}, {});
}
} // 使用vue.use 就会调用 install 方法, 方法上有一个参数是vue实例
VueRouter.install = function(Vue) {
// 混合到每个组件中路由属性和路由方法 每个组件都有 this.$router / this.$toute this是当前的组件 组件中所有属性都在 this.$options上
Vue.mixin({
beforeCreate () {
// this.$router 是 vue-router 的实例, 即 VueRouter, 在 main.js中实例化vue的时候传入的 vue-router 实例,需要在所有组件中拿到这个路由实例
// vue 组件是从上到下渲染的
if(this.$options && this.$options.router) {
// 根组件
this._root = this;
this._router = this.$options.router;
// vue.util.defineReactive 是vue的一个核心库, 接收三个参数, 监听谁,第二个参数是一个别名,第三个参数如果是对象会深度监听,给对象中的每个属性加上set方法
// hostoryzhong de current发生变化会令视图发生变化
Vue.util.defineReactive(this, 'xxx' , this._router.history );
}else {
this._root = this.$parent._root;
}
Object.defineProperty(this, '$router', {
get() {
return this._root._router;
}
});
// this.$route 是路由实例的属性
Object.defineProperty(this, '$route', {
get() {
return {
current: this._root.history.current
}
}
});
}
});
// 注册全局组件
Vue.component('router-link', {
props: {
to: {
type: String,
default: ''
},
tag: String
},
methods: {
// <tag on-click={this.handleClick.bind(this)}></tag>
handleClick() { }
},
// h 表示 createElement
render(h) {
let mode = this._self._root._router.mode;
let tag = this.tag;
// return h('a', {}, '首页');
return <a href={mode === 'hash' ? `#${this.to}` : this.to}>{this.$slots.default}</a>
}
});
// 根据当前的状态 history.current 匹配 收敛后的路由表
Vue.component('router-view', {
// this 是 proxy
// h 表示 createElement
render(h) {
// console.log(this); 先注册组件然后才页面加载完成执行 onload , 需要 currnet 变化 视图更新 --- vue 双向绑定 Object.defineProperty
console.log('====>', this._root)
let current = this._root._router.history.current;
let routeMap = this._self._root._router.routesMap;
console.log(current)
return h(routeMap[current]);
}
});
} export default VueRouter;
所有项目的源代码都放在我的github上,欢迎大家start: https://github.com/Jasonwang911/my-vue-router
实现一个简单的vue-router的更多相关文章
- 搭建Vue.js环境,建立一个简单的Vue项目
基于vue-cli快速构建 Vue是近年来比较火的一个前端框架,所以搭建Vue.js环境,要装webpack,vue-cli,Vue 安装webpack命令如下 $ cnpm install webp ...
- 手把手教你从零写一个简单的 VUE
本系列是一个教程,下面贴下目录~1.手把手教你从零写一个简单的 VUE2.手把手教你从零写一个简单的 VUE--模板篇 今天给大家带来的是实现一个简单的类似 VUE 一样的前端框架,VUE 框架现在应 ...
- 一个简单的 vue.js 实践教程
https://segmentfault.com/a/1190000006776243?utm_source=tuicool&utm_medium=referral 感觉需要改善的地方有: ( ...
- 实现一个简单的Vue插件
我们先看官方文档对插件的描述 插件通常会为 Vue 添加全局功能.插件的范围没有限制--一般有下面几种: 1.添加全局方法或者属性,如: vue-custom-element 2.添加全局资源:指令/ ...
- mvvm实现一个简单的vue
vue,基于mvvm模式下的一个前端框架 mvvm模式下简单的实现数据代理,数据劫持 1.是用Object.defineProperty 实现数据代理 2.使用发布订阅者模式,配合 Object.de ...
- 60行代码实现一个迷你版Vue Router
这是一个超级精简版的VueRouter,实现hash模式下,hash改变组件切换的功能,原理就是利用了 Vue.js 的响应式机制触发router-view组件的重新渲染. 代码 https://gi ...
- 一个简单的Vue.js组件开发示例
//创建属于自己的vue组件库 (function(Vue, undefined) { Vue.component("my-component", { template: '< ...
- 记录一个简单的vue页面实现
<template> <div class="userView"> <!-- 页眉颜色统一 --> <div class="bu ...
- Vue-cli安装步骤,搭建一个完整的 Vue 项目
安装node环境下载 node.js 官网地址:https://nodejs.org/en/ 下载完成后打开然后一路next安装完成后打开 dos 窗口输入命令:node -v 回车会输出node的版 ...
- VSCode配置简单的vue项目
VSCode配置简单的vue项目 https://www.cnblogs.com/wnxyz8023/p/9989447.html 由于最近要使用的项目框架为前后端分离的,采用的是vue.js+web ...
随机推荐
- echo 转义字符的使用
man echo 查看 echo 的使用文档 -n 不尾随换行符 -e 启用解释反斜杠的转义功能 -E 禁用解释反斜杠的转义功能(默认) --help 显示此帮助信息并退出 --version 显示版 ...
- [uboot] (第五章)uboot流程——uboot启动流程
http://blog.csdn.net/ooonebook/article/details/53070065 以下例子都以project X项目tiny210(s5pv210平台,armv7架构)为 ...
- Unity3D中的生命周期函数
生命周期函数:需要继承 MonoBehaviour 类才能使用.生命周期函数全部都是由系统定义好的,系统会自动调用,且调用顺序和我们在代码里面的书写顺序无关. 常用的生命周期函数: Awake():唤 ...
- android-基础编程-ScrollView
滚动视图(ScrollView)是指当拥有很多内容,屏幕显示不完时,需要通过滚动来显示完整的视图.包括水平滚动视图(HorizontalScrollView)和垂直滚动视图(ScrollView) 基 ...
- 利用树莓派3和RTL-SDR V3搭建一个低成本的QRP小功率监测点
TUTORIAL: SETTING UP A LOW COST QRP (FT8, JT9, WSPR ETC) MONITORING STATION WITH AN RTL-SDR V3 AND R ...
- ORACLE 日期加减操作
无论是DATE还是timestamp都可以进行加减操作. 可以对当前日期加年.月.日.时.分.秒,操作不同的时间类型,有三种方法: 1 使用内置函数numtodsinterval增加小时,分钟和秒2 ...
- 第十节:详细讲解一下Java多线程,随机文件
前言 大家好,给大家带来第十节:详细讲解一下Java多线程,随机文件的概述,希望你们喜欢 多线程的概念 线程的生命周期 多线程程序的设计 多线程的概念 多线程的概念:程序是静态的,进程是动态的.多进程 ...
- 算法入门:最大子序列和的四种算法(Java)
最近再学习算法和数据结构,推荐一本书:Data structures and Algorithm analysis in Java 3rd 以下的四种算法出自本书 四种最大子序列和的算法: 问题描述 ...
- 机器学习技法笔记:08 Adaptive Boosting
Roadmap Motivation of Boosting Diversity by Re-weighting Adaptive Boosting Algorithm Adaptive Boosti ...
- PCA历程详细python代码(原创)
#PCA主成分分析,原文为文末的链接,代码为自己亲自手码 def cov_out1(dx,dy): #第一步:求解x,y各自的均值 mean_x=0 mean_y=0 for i in range(l ...