实现简易路由前置知识点
路由模式
hash模式
- 通过锚点(也就是hash)进行跳转
- 带
#号 - URL会更改
- 浏览器可以前进后退,当时浏览器不会刷新
- 不合服务端交流
-
history模式
无锚点 无hash
- 无
# - 是一个正常URL
- 会和服务端交流
- 路径名保存在
location.pathname上路由信息
$router
路由实例对象
可读可写
路由信息保存再History下的对象current中$route
只读,路由信息对象,数据是从$router.history.current下的数据的数据路由组件
router-link
组件支持用户在具有路由功能的应用中router-view
渲染路径匹配到的视图组件路由的切换//页面的跳转
hash模式
页面的跳转也就是hash的改变
可以监听hashchange事件 该事件会再hash改变时触发
当一次打开页面视图组件啥都不显示
此时需要使用DomcontentLoaded事件(该事件会在dom内容加载完毕时触发)将其hash值修改为首页的hash值原理
就是监听hashchange事件当页面改变通过获取hash值来找到对应的组件来渲染页面注意
当为a元素时,直接添加将路径添加到href上就行啦
当不是a元素时,通过监听单击事件来改变hash值history模式
所有的元素都是通过单击事件来触发页面的跳转
触发单击事件时使用history.pushState()来实现页面的跳转
history的路径信息是存储在location.pathname中
但是页面的前进关于回退会失效
可是使用popstate事件(当浏览器前进与后退时触发)将location.pathname中的值修改
当一次打开页面视图组件啥都不显示
此时需要使用DomcontentLoaded事件(该事件会在dom内容加载完毕时触发)将其location.pathname值修改为首页的hash值原理
同过元素的单击事件时将其路由路径传入,通过history.pushState()来实现的页面的跳转,在通过popstate来实现也面的前进与后退,第一次代开页面 通过DomcontentLoaded来渲染首页use方法
如上面代码Vue.use(VueRouter)
use 方法是干嘛的
use方法就是桥梁,开发一个在vue上使用的工具或插件它必须要使用vue的构造函数或vue类,通过use将vue传递给这个工具或插件,在被使用的类上必须要用一个install方法,只要被vue.use(类)就会自然而然的去调用类中的install方法
利用代码实现简易路由
app.vue
<template><div id="app"><div class="nav-box"><div class="logo">zxt</div><div class="nav-list"><router-link tag="div" to="/">首页</router-link><router-link tag="div" to="/learn">课程学习</router-link><router-link tag="div" to="/show">学员展示</router-link><router-link tag="div" to="/about">关于</router-link><router-link tag="div" to="/community">社区</router-link></div></div><div class="content"><router-view></router-view></div></div></template><script>export default {name: 'App',components: {},}</script><style>#app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;}.nav-box{width: 100%;height: 60px;display: flex;justify-content: space-around;align-items: center;background: rgba(0, 0, 200, .5);}.logo{color: #fff;font-size: 30px;font-weight: bold;}.nav-list{display: flex;width: 60%;justify-content: space-between;align-items: center;}.nav-list a{text-decoration: none;color: #000;font-size: 18px;}.nav-list a.router-link-exact-active{font-weight: bold;color: #fff;}.content{margin-top: 40px;font-size: 20px;}</style>
main.js
import Vue from 'vue'import App from './App.vue'import router from './router'new Vue({// 挂载路由router,render: h => h(App),}).$mount('#app')
route.js
import Vue from 'vue'import VueRouter from './vue-router'// 桥梁// 想要别vue使用的工具或插件必须通过use方法// use方法会调用要被vue使用的工具或插件上的instal方法,同时会将vue传递过去// 毕竟要被vue使用的工具或插件要用的vueVue.use(VueRouter)Vue.config.productionTip = false// 定义路由// 路由表 将其当做router的配置参数const routes = [{path: '/',// 异步加载组件,当标签被点击才会加载组件component: () => import('./components/views/Home.vue')},{path: '/learn',component: () => import('./components/views/Learn.vue')},{path: '/show',component: () => import('./components/views/Show.vue')},{path: '/about',component: () => import('./components/views/About.vue')},{path: '/community',component: () => import('./components/views/community.vue')},]// 创建实例export default new VueRouter({mode: 'history',routes,})
vue-router 的代码
idnex.js
import History from './history'import install from './install'class VueRouter {constructor(option){//接受路由表this.routes = option.routes;// 将其路由表格式成容易操作的对象// key : 路径// value: 子组件this.routeMap = this.createRouterMap(this.routes) || []this.history = new History()this.mode = option.mode || 'hash'this.init()}/*** 将其路由表格式化为对象* 格式为: {路径:子组件 ...}* @param { Array } routes 路由表* @returns 返回一个对象*/createRouterMap(routes){let routeMap = {}for (let i = 0; i < routes.length; i++) {let routesItem = routes[i]routeMap[routesItem.path] = routesItem.component}return routeMap}init(){if(this.mode === 'hash'){location.hash ? '' : location.hash = '/'// 第一次页面加载的时候视图是空的document.addEventListener('DOMContentLoaded', () => {this.history.current.path = location.hash.slice(1)})// 监听hash是否改变window.addEventListener('hashchange', () => {this.history.current.path = location.hash.slice(1)})}else{// 第一次页面加载的时候视图是空的document.addEventListener('DOMContentLoaded', () => {this.history.current.path = location.pathname})// 修复浏览器无法前进与后退window.addEventListener('popstate',() =>{this.history.current.path = location.pathname})}}}// use 会默认调用函数中的install方法VueRouter.install = install;export default VueRouter
history.js
/**** $route中存放当前路由信息来自$.router.history下的current* 同时$router上也存放着*/class History {constructor() {this.current = {path:null,}}}export default History
install.js
import link from './link';import view from './view'export default function install(Vue) {Vue.mixin({beforeCreate(){// console.log(this.$options.router)/*** 找到根实例上的router*/if(this.$options.router){this._router = this.$options.router// this._route = this._router.history.current;// 一旦属性值改变啦页面就会进行重新渲染Vue.util.defineReactive(this,'_route',this._router.history.current)}}})/*** Object.defineProperty(Vue.prototype, '$router', {}* 中的this指向 由于有属性描述get会将this传入,那吗他的this 就指向Vue的实例*/Object.defineProperty(Vue.prototype, '$router', {get() {return this.$root._router;}})Object.defineProperty(Vue.prototype,'$route',{get(){return this.$root._route;}})// 会显示找不到router-link 与 router-view 两个组件Vue.component('router-link', link )Vue.component('router-view', view )}
link.js
/*** 等效于* Vue.component('router-link',{})*/export default {// 接受元素传递过来的hash路径,以及元素名字props: {to:{type: String,required: true,},tag:{type:String,default:'a'}},methods:{handleClick(){const mode = this.mode;if(mode === 'hash'){location.hash = this.to;}else{history.pushState(null,null,this.to)this.$router.history.current.path = this.to;}}},// 渲染render(h) {const to = this.to;const tag = this.tag;const data = {}const mode = this.mode;// 当为其a元素时 使用的hash来修改的路由,// 当不是a元素时,通过history模式(就是当触发单击事件时,将其路由修改)if(tag === 'a' && mode === 'hash'){const href = '#' + todata.attrs = { href }}else{data.on = { click: this.handleClick }}// 渲染元素, 特性, 以及需要显示的信息return h(this.tag, data, this.$slots.default)}}
view.js
/*** 函数是组件* 通过父级找到存放路由信息的对象* 通过路径找到需要渲染的组件* 将其渲染*/export default {functional: true,render(h, {parent}) {let routeMap = parent.$router.routeMap;let path = parent.$route.pathreturn h(routeMap[path])}}
思维导图
做的不怎嘛滴
vue-router.xmind
vue-router.xmind
