cisco路由器设置步骤图 router路由器设置怎么清除
Vue Router 基础让我们先来了解下Vue Router的简单使用吧,先了解怎么使用,之后再去想办法怎么去实现
1.简介路由:本质上是一种对应关系
分类分为前端路由和后端路由
后端路由比如node.js 的路由是 URL的请求地址和服务器上面的资源对应,根据不同的请求地址返回不同的资源
前端路由在SPA(单页应用)中根据用户所触发的事件改变了URL 在无需刷新的前提下 显示不同的页面内容,比如等下就要讲的Vue Router
2.Vue-Router最基础的使用步骤2.1.引入Vue-Router文件
<!-- 使用vue router前提 vue 必不可少 --><script src="https://www.cnfyg.com/shcs/js/vue.js"></script><!-- 引入vue-router文件 --><script src="https://www.cnfyg.com/shcs/js/vue-router_3.0.2.js"></script>
2.2.在页面上添加 router-link 和 router-view<!-- 添加路由 --><!-- 会被渲染为 <a href="https://www.cnfyg.com/shcs/#/home"></a> --><router-link to="/home">Home</router-link><router-link to="/login">Login</router-link><!-- 展示路由的内容 --><router-view></router-view>
2.3.创建路由组件//创建路由组件const home = { template: `<div>欢迎来到{{name}}</div>`,data() {return {name: '首页',}},}const login = { template: `<div>欢迎来到登录页</div>`,}
2.4.配置路由规则// 配置路由规则const router = new VueRouter({ routes: [//每一个路由规则都是一个对象//path 路由的 hash地址//component 路由的所展示的组件{path: '/',// 当访问 '/'的时候 路由重定向 到新的地址 '/home'redirect: '/home',},{path: '/home',component: home,},{path: '/login',component: login,},],})
2.5.挂载路由let vm = new Vue({ el: '#app', data: {}, methods: {},// 挂载到vue 上面 router, })
文章插图
3.嵌套路由
这里的嵌套路由是基于上面的例子继续写的3.1.在路由里面添加 子路由链接和 占位符
//创建路由组件const home = {template: `<div>欢迎来到首页<br><!-- 子路由链接 --><router-link to="/tab1">Tab1</router-link><router-link to="/tab2">Tab2</router-link><!-- 子路由展示 --><router-view></router-view></div>}复制代码
3.2.添加路由组件// 创建两个子路由组件const tab1 = {template: `<div>子路由1</div>`,}const tab2 = {template: `<div>子路由2</div>`,}复制代码
3.3.配置路由规则// 配置路由规则const router = new VueRouter({routes: [{path: '/home',component: home,//children 表示子路由规则children: [{ path: '/tab1', component: tab1 },{ path: '/tab2', component: tab2 },],},],})复制代码
文章插图
4.动态路由
path属性加上/:id 使用route对象的params.id获取动态参数比如现在有这么多个路由,如果自己也配置多个路由,岂不是有点 。。。多余
<div id="app"><!-- 添加路由 --><!-- 会被渲染为 <a href="https://www.cnfyg.com/shcs/#/home"></a> --><router-link to="/goods/1">goods1</router-link><router-link to="/goods/2">goods2</router-link><router-link to="/goods/3">goods3</router-link><router-link to="/goods/4">goods4</router-link><!-- 展示路由的内容 --><router-view></router-view></div>
然后这里就可以使用 动态路由来解决<script>//创建路由组件const goods = {// this.$route.parms.id 可以省略 thistemplate: `<div>欢迎来到商品 {{$route.params.id}}页</div>`,}// 配置路由规则const router = new VueRouter({routes: [{// 加上`/:id`path: '/goods/:id',component: goods,},],})let vm = new Vue({el: '#app',data: {},methods: {},// 挂载到vue 上面router,})</script>
文章插图
最后提一下还可以用query进行传参.
// 比如<router-link to="/goods?id=1">goods</router-link>复制代码
然后使用this.$route.query.id就可以在路由组件中获取到id添加动态路由使用 this.$router.addRoutes([]) 可以添加动态路由,里面传递是一个数组 和 routes里面一样
5.路由传参
我们可以使用 props 进行传值5.1.布尔值类型
为啥要用 props 进行传值,route不香了吗,确实route 不够灵活
props 值有三种情况
//创建路由组件const goods = {// 使用props接收props: ['id'],template: `<div>欢迎来到商品 {{id}}页</div>`,}// 配置路由规则const router = new VueRouter({routes: [{path: '/goods/:id',component: goods,//props为true, route.params将会被设置为组件属性props: true,},],})复制代码
5.2.对象类型但是这里就获取不到 id 了,会报错
这里的id 需要 $route.params.id 获取
const goods = {// 使用props接收props: ['name', 'info', 'id'],// 这里的 id 是获取不到的template: `<div>{{info}}来到{{name}} {{id}}页</div>`,}// 配置路由规则const router = new VueRouter({routes: [{path: '/goods/:id',component: goods,//props为对象 就会把这个对象传递的路由组件//路由组件使用props接收props: {name: '商品',info: '欢迎',},},],})复制代码
5.3.函数const goods = {// 使用props接收props: ['name', 'info', 'id'],template: `<div>{{info}}来到{{name}} {{id}}页</div>`,}// 配置路由规则const router = new VueRouter({routes: [{path: '/goods/:id',component: goods,//prop是一个函数的话 就可以组合传值props: (route) => {return {name: '商品',info: '欢迎',id: route.params.id,}},},],})复制代码
6.route 和 router在上面提到了route 那么和 router有什么区别呢
- route为当前router跳转对象里面可以获取path,params,hash,query,fullPath,matched,name
- router为VueRouter实例用 new VueRouter创建的实例,想要导航到不同URL,则使用router.push方法
- routes是router路由实例用来配置路由对象(顺带提一下)
//创建路由组件const goods = {// 使用props接收props: ['id'],template: `<div>商品{{id}}页</div>`,}复制代码
路由配置//配置路由const router = new VueRouter({routes: [{path: '/goods/:id',// 命名路由name: 'goods',component: goods,},],})复制代码
绑定 :to 通过name找到定义的路由 还可以使用 params 传递参数<router-link :to="{name: 'goods', params: { id: 1 } }">goods1</router-link><!-- 展示路由的内容 --><router-view></router-view>复制代码
8.编程式导航8.1.声明式导航既然提到了编程式导航,那么先简单说下声明式导航上面所展示的都是声明是导航 比如router-link
<router-link to=”/goods/1″>goods1</router-link>
还有a标签
<a href=https://www.cnfyg.com/shcs/”#/goods/1″>goods1
8.2.编程式导航
使用javaScript来控制路由跳转在普通的网页中使用 loaction.href window.open 等等进行跳转
现在我要介绍的是Vue Router中的编程式导航
我们平时都是用router.push() **router.go(n)**方法进行跳转
//字符串this.$router.push('/home')//对象this.$ruter.push({path:'/home'})//比如这个 /goods?id=1this.$router.push({path:'/goods',query:{id:'1'}})//命名路由 /goods/1this.$router.push({name:'goods',params:{id:1}})//后退this.$router.go(-1)复制代码
9.路由守卫9.1.全局守卫router.beforeEach 全局守卫 对所有的路由都起作用
router.beforeEach((to, from, next) => {next();//使用时,千万不能漏写next!!!}).catch(()=>{//跳转失败页面next({ path: '/error', replace: true, query: { back: false }})})复制代码
全局的守卫的三个参数to: 即将要进入的目标 路由对象
from: 当前导航正要离开 路由对象
next: 参数不同做的事也不同
next() 直接进入下一个钩子9.2.路由独享的守卫
next(false) 停止当前导航
next(‘/路径’) 跳转到path路由地址 当然这里面也可以写成对象形式 next({path : ‘/路径’}) next(error): 如果传入参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError()
beforeEnter 路由对象独享的守卫写在routes里面
const router = new VueRouter({routes: [{path: '/goods',component: goods,beforeEnter: (to, from, next) => {// 一样的用法}}]})复制代码
9.3.组件内的守卫(了解)组件内的守卫 写在组件内部 下面是官方介绍
- beforeRouteEnter 进入路由前,组件还没有被实例化所以这里无法获取到this
- beforeRouteUpdate (2.2) 这个阶段可以获取this,在路由复用同一个组件时触发
- beforeRouteLeave 这个阶段可以获取this,当离开组件对应的路由时,此时可以用来保存数据,或数据初始化,或关闭定时器等等
const goods = {template: `<div>goods</div>`,beforeRouteEnter (to, from, next) {// 具体逻辑},beforeRouteUpdate (to, from, next) {// 具体逻辑},beforeRouteLeave (to, from, next) {// 具体逻辑}}复制代码
10.组件缓存keep-alive页面重新加载会重新渲染页面比如回退的时候等等,我们有的组件它不是一个活动的(数据不变)不希望它被重新渲染,所以这里就可以使用 <keep-alive> </keep-alive> 包裹起来,这样就不会触发created钩子应用场景:获取一个商品的详情然后回退在前进的时候就使用缓存,提高性能
10.1.不使用 keep-alive例子
这里home 组件在created进行打印当前的时间
<div id="app"><router-link to="/home">home</router-link><router-link to="/login">login</router-link><router-view></router-view></div>复制代码
<script>const login = {template: `<div>Login</div>`,}const home = {template: `<div>Home</div>`,created() {console.log(new Date())},}const router = new VueRouter({routes: [{path: '/',redirect: '/home',},{path: '/home',component: home,},{path: '/login',component: login,},],})let vm = new Vue({el: '#app',data: {},methods: {},router,})</script>复制代码
文章插图
如上,每切换home 的路由 组件就会重新渲染,打印当前的时间
如果使用 keep-alive 会有什么效果呢
10.2.使用keep-alive
这里只需简单的包裹起来就行了
<div id="app"><router-link to="/home">home</router-link><router-link to="/login">login</router-link><keep-alive><router-view></router-view></keep-alive></div>复制代码
文章插图
可以看到的是只打印一次,说明切换了路由它并没有重新渲染组件
当然可以在 组件内取个name名字 keep-alive 标签里面添加 include 属性就可以对相应的组件进行缓存
const login = {name: login,template: `<div>Login</div>`,}const home = {name: home,template: `<div>Home</div>`,created() {console.log(new Date())},}复制代码
<div id="app"><router-link to="/home">home</router-link><router-link to="/login">login</router-link><keep-alive include="login,home"><router-view></router-view></keep-alive></div>复制代码
10.3.activated 和 deactivatedkeep-alive 生命周期执行顺序第一次访问路由时:
- created–>mounted –>activated
- deactivated在退出后触发
11.hash 和 history 模式11.1.hash模式
在vue-router中默认使用的是 hash 模式
hash是url中的锚点就是**#,通过锚点作为路由地址,我们通常改变的是改变#**后面部分,实现浏览器渲染指定的组件.,锚点发生改变会触发 onhashchange 事件
11.2.history模式
history 模式就是平时正常的地址,使用方面需要服务器支持
如果访问的路径资源没有 直接就是 404
在HTML5后新增了两个API
pushState(): IE10后支持
replaceState()
在vue-router中如果要使用 history 模式需要指定
【cisco路由器设置步骤图 router路由器设置怎么清除】
const router = new VueRouter({mode: 'history'})复制代码
实现一个基础 Vue Router复习上面的路由的基础那么我们不如来写个Vue Router吧实现的这个 Vue Router是基于 history模式
所有的步骤都放到代码的注释中,每一行都写个注释
这个简单的没有按照Vue Router源码来写主要是一些基础功能的实现
为后面的按照源码写打基础
1.注册全局Vue Router
首先就是先注册自己的 Vue Router
判断是否注册了组件
在Vue实例创建完成进行注册
// 保存一个全局变量 Vuelet _Vue = null// 默认导出自己写的 VueRouterexport default class MyVueRouter {// 实现install 注册 MyVueRouter vue提供install可供我们开发新的插件及全局注册组件等// 把Vue传进去static install(Vue) {// 定义一个标识判断是否注册了 MyVueRouter ,注册了就不用下一步了if (MyVueRouter.install.installed) return// 没有就进行下面的,把标识改变trueMyVueRouter.install.installed = true// 把全局变量 _Vue 保存_Vue = Vue// 为了获取Vue中的this执行这里使用 混入_Vue.mixin({// 在Vue实例创建好的时候进行操做beforeCreate() {// 判断是否是实例创建还是组件创建 ,可以判断是否挂载 了routerif (this.$options.router) {// 把router注册到 _Vue上_Vue.prototype.$router = this.$options.router}},})}}复制代码
2.实现 构造方法optoins 保存传入的规则
routerMap 确定地址和组件的关系
current 表示当前的地址是响应式的之后渲染组件和它相关
export default class MyVueRouter {...//实现构造constructor(optoins) {// 这个保存的是routesthis.optoins = optoins// routerMap 保存路由和 组件之间的关系this.routerMap = {}// 用来记录数据 这里面的数据都是 响应式this.data = https://www.cnfyg.com/shcs/_Vue.observable({// 当前路由的地址current:'/',})}}复制代码
3.解析路由规则传入的路由规则拿到一个对象里 地址 和 组件一一匹配
export default class MyVueRouter {...// 解析路由规则createRouterMap() {// 把之前构造函数的中的传入的 routes 规则进行遍历this.optoins.routes.forEach((item) => {// 把路由 和 组件的对应关系添加到 routerMap中this.routerMap[item.path] = item.component})}}复制代码
4.实现 router-link 组件router-link就是页面上所展示的路由链接
因为一般使用的基本都是运行版的Vue 所以自己把组件转为 虚拟DOM
还有就是链接会刷新的问题
自己写个函数进行跳转阻止默认事件
还得注意对应的路由所要渲染的组件
export default class MyVueRouter {...// 实现组件initComponents(Vue) {// 实现 router-link组件Vue.component('router-link', {props: {// router-link上面的to属性将访问的地址to: String,},// 由于运行版的Vue不能渲染template所以这里重新写个render 这里h 也是个函数// template: `<a :href="https://www.cnfyg.com/shcs/to"><slot></slot></a>`,render(h) {// 第一个参数是标签return h('a',// 第二个参数是对象是 tag 里面的属性{// 设置属性attrs: {href: this.to,},// 绑定事件on: {// 重新复写点击事件,不写的话会点击会向服务器发送请求刷新页面click: this.myClick,},},// 这个是标签里面的内容 这里渲染是 默认插槽[this.$slots.default])},methods: {//router-link的点击事件myClick(e) {// 因为我这里是模拟是 history的路由所以用pushState ,hash路由可以这里用 push// 使用history修改浏览器上面的地址// pushState 第一个参数是传递的参数,第二个是标题,第三个是链接history.pushState({}, '', this.to)// 渲染相应的组件// 渲染的页面也需要改变 data中的current是响应式的 router-view是根据current来渲染的this.$router.data.current = this.to// 阻止默认跳转事件e.preventDefault()},},})复制代码
5.实现 router-view 组件这里从之前解析的规则里面拿到当前的对应的组件进行转为虚拟DOM
最后router-view占位渲染到页面上
export default class MyVueRouter {...// 实现组件initComponents(Vue) {// 实现 router-view组件Vue.component('router-view', {render(h) {// 获取的当前路径所对应的组件// 因为当前this是Vue,this.$router才是MyVueRouterconst component = this.$router.routerMap[this.$router.data.current]// 转化为虚拟Domreturn h(component)},})}}复制代码
6.前进和后退在完成之前的编写还是不够的,因为在浏览器点后退和前进虽然改变了浏览器的地址,但是组件却没有刷新,下面就来解决这个问题
export default class MyVueRouter {...// 初始化事件initEvent() {// 监听浏览器地址的改变window.addEventListener('popstate', () => {// 改变VueRouter的当前的地址 重新渲染组件this.data.current = window.location.pathname})}}复制代码
7.在router挂载后进行初始化最后写个函数进行初始化
在router注册到Vue之后进行 初始化
export default class MyVueRouter {// 初始化init() {// 解析路由规则this.createRouterMap()// 初始化组件this.initComponents(_Vue)// 初始化事件this.initEvent()}static install(Vue) {if (MyVueRouter.install.installed) returnMyVueRouter.install.installed = true_Vue = Vue_Vue.mixin({beforeCreate() {if (this.$options.router) {_Vue.prototype.$router = this.$options.router// 注册完router后进行初始化this.$options.router.init()}},})}...}复制代码
8.放上完整的 index.js// 保存一个全局变量 Vuelet _Vue = nullexport default class MyVueRouter {// 实现install 注册 MyVueRouter vue提供install可供我们开发新的插件及全局注册组件等// 把Vue传进去static install(Vue) {// 定义一个标识判断是否注册了 MyVueRouter ,注册了就不用下一步了if (MyVueRouter.install.installed) return// 没有就进行下面的,把标识改变trueMyVueRouter.install.installed = true// 把全局变量 _Vue 保存_Vue = Vue// 为了获取Vue中的this执行这里使用 混入_Vue.mixin({// 在Vue实例创建好的时候进行操做beforeCreate() {// 判断是否是实例创建还是组件创建 ,可以判断是否挂载 了routerif (this.$options.router) {// 把router注册到 _Vue上_Vue.prototype.$router = this.$options.router// 注册完router后进行初始化this.$options.router.init()}},})// 判断是否挂载}// 实现构造方法constructor(optoins) {// 这个保存的是routesthis.optoins = optoins// routerMap 保存路由和 组件之间的关系this.routerMap = {}// 用来记录数据 这里面的数据都是 响应式this.data = https://www.cnfyg.com/shcs/_Vue.observable({// 当前路由的地址current:'/',})}// 解析路由规则createRouterMap() {// 把之前构造函数的中的传入的 routes 规则进行遍历this.optoins.routes.forEach((item) => {// routes中的每一项都是一个对象 { path: '/XXX', component: XXX}// 把路由 和 组件的对应关系添加到 routerMap中this.routerMap[item.path] = item.component})}// 实现组件initComponents(Vue) {// 实现 router-link组件Vue.component('router-link', {props: {// router-link上面的to属性将访问的地址to: String,},// 由于运行版的Vue不能渲染template所以这里重新写个render 这里h 也是个函数// template: `<a :href="https://www.cnfyg.com/shcs/to"><slot></slot></a>`,render(h) {// 第一个参数是标签return h('a',// 第二个参数是对象是 tag 里面的属性{// 设置属性attrs: {href: this.to,},// 绑定事件on: {// 重新复写点击事件,不写的话会点击会向服务器发送请求刷新页面click: this.myClick,},},// 这个是标签里面的内容 这里渲染是 默认插槽// 比如<router-link to="/">首页</router-link>// 插槽就是给首页两个字留位置,当前这只是个例子[this.$slots.default])},methods: {//router-link的点击事件myClick(e) {// 因为我这里是模拟是 history的路由所以用pushState ,hash路由可以这里用 push// 使用history修改浏览器上面的地址// pushState 第一个参数是传递的参数,第二个是标题,第三个是链接history.pushState({}, '', this.to)// 渲染相应的组件// 渲染的页面也需要改变 data中的current是响应式的 router-view是根据current来渲染的this.$router.data.current = this.to// 阻止默认跳转事件e.preventDefault()},},})// 实现 router-view组件Vue.component('router-view', {render(h) {// 获取的当前路径所对应的组件// 因为当前this是Vue,this.$router才是MyVueRouterconst component = this.$router.routerMap[this.$router.data.current]// 转化为虚拟Domreturn h(component)},})}// 初始化事件initEvent() {// 监听浏览器地址的改变window.addEventListener('popstate', () => {// 改变VueRouter的当前的地址 重新渲染组件this.data.current = window.location.pathname})}// 初始化init() {// 解析路由规则this.createRouterMap()// 初始化组件this.initComponents(_Vue)// 初始化事件this.initEvent()}}复制代码
到了这里基础的实现功能差不多了,上面的例子是为了下面打基础,所有的功能实现基本都是在一个文件下很不严谨,下面就严格按照Vue Router 源码来实现自己 Vue RouterVue Router实现
经过上面简单的实现,现在我们按照Vue Router源码的方式进行编写1.首先是Vue Router 构造
/* index.js */// 导出自己写的 VueRouterexport default class VueRouter {// 实现构造函数功能constructor(options) {// 获取options中的routes路由规则 没有就为空数组this._options = options.routes || []}// 初始化init(Vue) {}}复制代码
2.注册组件 install在 install.js 对自己写的Vue-Router进行全局的注册
之后还会在这里创建 router????router** **router????route
还有注册 router-link router-view
/* install.js */// 定义一个全局 的Vueexport let _Vue = null// 导出 install方法export default function install(Vue) {// 保存到全局的Vue_Vue = Vue// 混入_Vue.mixin({// Vue实例创建完毕之后操做beforeCreate() {// 这里是new Vueif (this.$options.router) {// 保存 Vuethis._routerRoot = this// 保存 Vue Router 的实例,以后可以通过Vue Router构造的一些方法this._router = this.$options.router// 调用Vue Router的init(Vue) 初始化操做this._router.init(this)} else {// 这里是创建 Vue的组件等等// 判断是否有父组件 ,有的话就把父组件的 _roterRoot(也就是Vue)给 子组件// 没有父组件就把 this 这是也是(Vue) 给子组件this._routerRoot = (this.$parent && this.$parent._routerRoot) || this}},})}复制代码
然后在 index.js中导入install 进行为构造添加 install// 导入 installimport install from './install'// 导出自己写的 VueRouterexport default class VueRouter {...}// 为VueRouter 添加 install方法VueRouter.install = install复制代码
3.编写 create-route-map.js这个主要的作用就是用来解析传递过来的路由 需要导出然后在 create-matcher.js进行使用
具体的细节都写了注释
/* create-route-map.js */// 导出具体的路由解析/** * * @param {*} routes 路由规则 * @param {*} oldPathList 路由列表 * @param {*} oldPathMap 路由和组件的对应关系 */export default function createRouteMap(routes, oldPathList, oldPathMap) {// 传入了就是添加动态路由 没有传入就默认为空const pathList = oldPathList || []const pathMap = oldPathMap || []// 遍历规则操作routes.forEach((route) => {// 记录路由 也是核心的解析路由 为了分工明确写的外面addRouteRecord(route, pathList, pathMap)})// 返回新的路由列表 和 路由对应关系return {pathList,pathMap,}}/** * * @param {*} route 路由规则 * @param {*} pathList 路由列表 * @param {*} pathMap 路由和组件之间的对应关系 * @param {*} parentRecord父路由 */function addRouteRecord(route, pathList, pathMap, parentRecord) {// 路由地址 判断是否存在父级的路由 有的话拼接父级路由和当前路由的path 没有就是当前route.pathconst path = parentRecord ? `${parentRecord.path}/${route.path}` : route.path// record作为一个路由记录 记录了路由地址,组件,父级路由用于路由对应关系去对应相对应的pathconst record = {path,component: route.component,parent: parentRecord,}// 判断是否在路由列表中 存在当前路由,不存在进行添加当前路由,更新路由列表if (!pathList[path]) {// 向路由列表中添加路由pathList.push(path)// 向路由对应关系中 添加path 相对应的记录pathMap[path] = record}// 判断当前的 路由是否有子路由,有的话进行递归if (route.children) {route.children.forEach((childRoute) => {// 就简单说下最后一个参数 就是父级路由记录addRouteRecord(childRoute, pathList, pathMap, record)})}}复制代码
4.编写 create-matcher.js这个模块的意义也是解析路由不过这个是个指挥家,上面实现的是具体解析操作
在这个模块里进行调用上面的具体解析路由的方法就行了
有了上面面具体的路由解析,这个create-matcher.js就容易实现了,只需要简单的调用它即可
这个模块返回了两个方法
match : 根据路由路径创建路由规则对象,之后就可以通过 规则对象获取到所有的路由信息然后拿到所有的组件进行创建
addRoutes : 添加动态路由
/* create-matcher.js */// 导入具体的路由解析规则import createRouteMap from './create-route-map'// 导出解析路由规则 传入的是规则export default function createMatcher(router) {// pathList 路由的列表pathMap 路由与组件的对应关系 nameMap这里没有考虑,先完成个简单的// 具体的解析规则是使用createRouteMapconst { pathList, pathMap } = createRouteMap(router)// match是 从pathMap 根据path获取 相应的路由记录function match(path) {//待实现}// 添加动态路由function addRoutes(router) {// 添加动态路由肯定也要解析路由规则createRouteMap(router, pathList, pathMap)}// 返回match 和 addRoutesreturn {match,addRoutes,}}复制代码
然后在index.js也就是Vue Router的构造中使用 createMatcher. 使用this.matcher接收
// 导入 installimport install from './install'// 导入解析路由import createMatcher from './create-matcher'// 导出自己写的 VueRouterexport default class VueRouter {// 实现构造函数功能constructor(options) {// 获取options中的routes路由规则 没有就为空数组this._routes = options.routes || []// 解析路由 传入规则 这里还返回了两个方法 match,addRoutes 用matcher接收一下之后有用this.matcher = createMatcher(this._routes)}// 初始化init(Vue) {}}// 为VueRouter 添加 install方法VueRouter.install = install复制代码
5.编写 createMatcher看见上面在 createMatcher中定义了 一个match了吗,
match是 从pathMap 根据path获取 相应的路由记录
上面还没有去实现,现在来实现它
需要实现它的话还需要编写个 createRoute 方法,我这里写在 uitl/route.js模块里
/* util/route.js */// 导出 createRoute/** * * @param {*} record 传过来的记录 * @param {*} path 路由地址 * @returns */export default function createRoute(record, path) {// 保存路由的记录 里面可能有多个路由 是这种模式保存 [parentRecord,childRecord]const matched = []// 判断是否是子路由// 下面 record = record.parent 在不断向上找parent有继续执行// 没有就直接return 下面的对象while (record) {// 循环得到的 record不断插入到 数组的最前面matched.unshift(record)// 把父记录给当前record 继续循环record = record.parent}// 返回path 和 matched 以便之后 router-view渲染return {path,matched,}}复制代码
上面编写了 createRoute方法我们就可以在 create-mathcer.js 调用 来获取到记录了
然后再 create-mathcer.js中继续 完善 match方法
/* create-matcher.js */// 导入具体的路由解析规则import createRouteMap from './create-route-map'// 导入 createRouteimport createRoute from './util/route'// 导出解析路由规则 传入的是规则export default function createMatcher(router) {// pathList 路由的列表pathMap 路由与组件的对应关系 nameMap这里没有考虑,先完成个简单的// 具体的解析规则是使用createRouteMapconst { pathList, pathMap } = createRouteMap(router)// match是 从pathMap 根据path获取 相应的路由记录function match(path) {// 取出path对应的记录const record = pathMap[path]// 判断记录是否存在if (record) {return createRoute(record, path)}return createRoute(null, path)}// 添加动态路由function addRoutes(router) {// 添加动态路由肯定也要解析路由规则createRouteMap(router, pathList, pathMap)}// 返回match 和 addRoutesreturn {match,addRoutes,}}复制代码
6.历史记录的处理 History在 history目录下新建一个 base模块用来编写 父类
这个父类有 hash 模式 和 history(html5) 模式共同的方法
这里就主要演示下 hash 模式的代码
/* history/base.js */// 导入 我们上面写好的 createRouteimport createRoute from '../util/route'// 导出 Historyexport default class History {// router 是路由对象 也就是 VUe-Router的一个实例constructor(router) {// 赋值给自己的 routerthis.router = router// 默认的的当前路径为 /this.current = createRoute(null, '/')}// 将要跳转的链接// path 是路由的地址, onComplete是一个回调transitionTo(path, onComplete) {// 获取当前的应该跳转的路由调用的是 Vue-Router中 this.matcher中收到的match方法// 在这里 this.router就是 Vue-Router的一个实例 所以写成// this.router.matcher.match(path)this.current = this.router.matcher.match(path)// 回调存在触发回调onComplete && onComplete()}}复制代码
编写 HashHistory 模式 继承 History
/* /history/hash */// 导入 base中的 Historyimport History from './base'// 继承了 Historyexport default class HashHistory extends History {constructor(router) {super(router)// 确保第一次访问的时候路由加上 #/ensuerSlash()}// 监听URL的改变 设置当前的currentsetUpListener() {// 监听 hash的变化window.addEventListener('hashchange', () => {// 改变 this.currentthis.transitionTo(this.getCurrentLocation())})}// 获取当前的URL的hash 当然这里要去除 #getCurrentLocation() {// 这里不建议写成这个 return window.location.hash.slice(1) 有兼容问题let href = https://www.cnfyg.com/shcs/window.location.hrefconst index = href.indexOf('#')// 当没有 #的时候 直接返回 空字符串if (index < 0) return ''// 获取 #后面的地址href = https://www.cnfyg.com/shcs/href.slice(index + 1)return href}}// 确保第一次加上 #/function ensuerSlash() {// 如果存在 hash的话就不行加 /if (window.location.hash) {return}// 如果没有hash值 只要给 hash 加上一个 / 它会自动加上 /#/window.location.hash ='/'}复制代码
关于 html5模式 这里 就没写了
然后回到 index.js 就是自己写的 Vue Router中继续编写模式判断
最后就是 初始化 init方法
/* index.js */// 导入 installimport install from './install'// 导入解析路由import createMatcher from './create-matcher'// 导入 HashHistoryimport HashHistory from './history/hash'// 导入 HTML5Historyimport HTML5History from './history/html5'// 导出自己写的 VueRouterexport default class VueRouter {// 实现构造函数功能constructor(options) {// 获取options中的routes路由规则 没有就为空数组this._routes = options.routes || []// 解析路由 传入规则 这里还返回了两个方法 match,addRoutes 用matcher接收一下之后有用this.matcher = createMatcher(this._routes)// 获取模式 没有就默认为 hash 模式this.mode = options.mode || 'hash'// 使用 if 或者 分支都行 根据不同的模式执行不同的路由跳转功能等等switch (this.mode) {case 'history':this.history = new HTML5History(this)breakcase 'hash':// 模式的实例使用 this.history接收等下用的上// 传入的this是 VueRouterthis.history = new HashHistory(this)breakdefault:throw new Error('该模式不存在')}}// 初始化init(Vue) {// 拿到模式的实例const history = this.history// 进行跳转第一个参数是path ,第二个是回调函数history.transitionTo(history.getCurrentLocation, () =>// 监听URL的改变 设置当前的 this.currenthistory.setUpListener())}}// 为VueRouter 添加 install方法VueRouter.install = install复制代码
7.定义一个响应值 _route渲染不同路由页面有个前提的就是需要一个表示 当前路由 响应式的属性
所以我们来到 install.js 添加一个响应式的 属性**_route**
和这个无关的代码 …省略
/* install.js */export let _Vue = nullexport default function install(Vue) {_Vue = VueVue.mixin({beforeCreate() {if (this.$options.router) {...// 创建一个代表当前路由 响应式的值_route// 其实不建议使用 defineReactive直接创建 。。// 第一个参数是绑定在谁身上,第二是值名称,第二个是值Vue.util.defineReactive(this, '_route', this._router.history.current)} else {...}},})}复制代码
然后得回到 history下面的 base 添加一个修改响应式 _route的值的回调 this.cb
/* history/base.js */import createRoute from '../util/route'export default class History {constructor(router) {...// cb 一个回调函数,它的作用就是修改 响应式路由的值_route ,对应的视图然后就刷新this.cb = null}// 通过 listen来修改 cb的值listen(cb) {this.cb = cb}transitionTo(path, onComplete) {...// cb 存在就修改响应式路由的值this.cb && this.cb(this.current)...}}复制代码
最后在 index.js 的 init 调用 listen 方法 传入回调修改 响应式值**_route**
/* index.js */...export default class VueRouter {...init(Vue) {...// 修改 响应式的 routehistory.listen((route) => {Vue._route = route})}}...复制代码
8.添加 $router 和 $route我们知道在 Vue Router 提供了 $router (这个是路由对象是**Vue Router**的实例) 还有 $route(路由规则对象)
我们自己可以来到 install.js 中进行 添加这两个属性
/* install.js */...export default function install(Vue) {...// 添加 $router 路由对象Object.defineProperty 参数分别是 为谁添加,属性名,属性值Object.defineProperty(Vue.prototype, '$router', {get() {// this._routerRoot代表的是 Vue ,他的_router是 Vue Router实例// 可以回过去看看第二点return this._routerRoot._router},})// 添加 $routeObject.defineProperty(Vue.prototype, '$route', {get() {// 他的_route是就是刚才添加 响应式 的当前 路由return this._routerRoot._route},})}复制代码
9.router-link基本的介绍就不多说了,之前也是有介绍的 。然后现在重新来实现下
在 components 文件下新建 link.js
/* ./components/link.js */// 导出 linkexport default {props: {to: {type: String,required: true,},},// 渲染render(h) {// 转化为虚拟DOMreturn h(// 标签名'a',// 标签属性{domProps: {href: '#' + this.to,},},// 标签里面的内容 这里是 默认插槽[this.$slots.default])},}复制代码
10.router-view在 components 文件下新建 view.js 具体步骤干了什么都写在注释里了
/* ./components/link.js */// 导出 viewexport default {render(h) {// 获取路由规则对象const route = this.$route// 定义一个变量,用来等下 取 matched 中的值let depth = 0// 该组件为 router-viewthis.routerView = true// 尝试去获取父组件let parent = this.$parent// 判断是否有父组件while (parent) {// 判断该组件是否为 routerViewif (parent.routerView) {depth++}// 继续向上判断还有无父组件parent = parent.$parent}// 这里的route是 this.$route 就是 _route 响应式值,也就是 current// 当初 current 是 调用了 match方法 获取到的 返回值是 matched 和 path// matched 里面是多个路由对象 是这种模式保存 [parentRecord,childRecord]// 通过 变量depth取出来 举个栗子 ['/login','/login/tab']// 因为使用的unshif添加后面的父组件添加到前面// depth 一直加 ,直接取出后面即可const record = route.matched[depth]// 没有记录直接渲染if (!record) {return h()}// 有的话就获取记录中的组件const component = record.component// 最后把组件渲染return h(component)},}复制代码
好了到了这里 Vue Router的第二次编写就完成了,虽然和官方的差距很大 。。额,因为这里是简化写的11.文件目录
忘了最后贴上文件的目录
文章插图
这个模拟Vue Router的demo 放在了 github,有需要的可以这里 MyVueRouter
到了这里也只是仅仅实现了 VueRouter的一小部分功能
但是大体上的功能都差不多实现了,嵌套路由 添加动态路由也实现了
其实我觉得到这里了也可以了,不过还是得继续加油学习
推荐阅读
- 华为路由器定时关闭后怎么再打开
- 和平精英灵敏度型号 怎么进行设置
- 电脑不显示桌面设置方法 显示屏桌面显示不全
- mac一键恢复出厂设置方法 如何mac清空所有数据
- 苹果x信任设置不见了恢复方法 苹果手机的设备管理在哪里找
- 教你把网址设置到可信任站点 添加网站为信任网站
- 微信怎么设置强提醒
- 领动怎样设置音效最好 不同音效不同介绍
- jquery设置滚动条位置 获取div高度的方法有哪些
- 5步设置qq来电铃声 qq来电铃声怎么设置