1.路由总结
基础知识点是必须掌握的,无论在业务开发过程中还是准备面试复习,都需要扎实掌握。
手写路由插件-基础版
1.初始化一个vue项目
新建一个vuerouter文件夹,在文件夹中创建一个index.js文件,我们的vue插件就写在index中。
2.VueRouter的使用方式
vue-router的基本使用方式:
import Router from ‘vue-router’
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [
//路由规则
]
})
main.js
import router from './router'
new Vue({
router,
render : h => h(app)
}).$mount('#app')
清楚了vue-router的使用方式,我们开始实现自己的vue-router功能
3.查看Vue.use()源码
/* @flow */
import { toArray } from '../util/index'
export function initUse (Vue: GlobalAPI) {
Vue.use = function (plugin: Function | Object) {
const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
if (installedPlugins.indexOf(plugin) > -1) {
return this
}
// additional parameters
const args = toArray(arguments, 1)
args.unshift(this) //在第一个位置插入了Vue实例
if (typeof plugin.install === 'function') {
plugin.install.apply(plugin, args)
} else if (typeof plugin === 'function') {
plugin.apply(null, args)
}
installedPlugins.push(plugin)
return this
}
}
可以看到如果是对象就必须有install方法。
4.构建VueRouter
Vue.use() 方法中传入参数为函数或者对象,因此我们创建的VueRouter可以是函数也可以是对象,那么我们就以对象来创建。此次构建为history模式的路由。
let _Vue = null //设置全局保存Vue
export default class VueRouter {
static install(Vue) {
if(Vue.install.installed){ //判断是否以及安装了VueRouter
return;
}
Vue.install.installed = true
_Vue = Vue //全局保存,方便后面的代码调用
//通过Vue的mixin 混入在Vue的原型上挂载VueRouter实例
_Vue.mixin({
beforeCreate() {
// this.$options.router 是 new Vue({
// router 此处传递的router
// })
if(this.$options.router){ //如果存在 表示是通过 new Vue({router}) 来初始化的
//组件初始化时不需要再次执行该代码
_Vue.prototype.$router = this.$options.router
//调用初始化函数
this.$router.init()
}
}
})
}
constructor(options) {
this.$options = options;
this.routeMap = {}; //路由映射关系
this.data = _Vue.observable({ //设置该变量为响应式数据
current: '/' //设置初始的路径
})
}
//设置路由映射表
createRouteMap() {
this.$options.routes.forEach((route)=>{
this.routeMap[route.path] = route.component //路由路径和组件对应
})
}
//注册全局的组件 router-link
//router-link的使用:
//<router-link to="/">首页</router-link>
//因此需要to这个属性
//并且内容自定义,需要使用slot插槽
initComponent(Vue) {
const self = this //保存 当前的this指向(指向的时VueRouter实例)
Vue.component('router-link', {
props: {
to: {
type: String,
required: true
}
},
//注意这里需要使用render函数来编译生成虚拟DOM
//如果使用template 模板 在vue默认的版本中会出现报错,提示没有compiler
//解决方法1.使用render函数创建组件,
//2.在vue.config.js 中配置 runtimeCompiler: true 即可解决
render(h) {
// 默认使用a标签作为元素
return h('a', {
attrs: { //设置a标签的属性
href: this.to //使用时传递的路径内容
},
//点击事件
on: {
click: this.clickHander
}
}, [this.$slots.default]) //通过$slots.default方法获取默认插槽中的内容
},
methods: {
clickHander(e) { //点击事件
//这里需要阻止a标签的默认事件,禁止点击时刷新页面,因为单页面路由是不需要请求后端的
e.preventDefault()
//通过history 提供的pushState()方法来控制路由
history.pushState({}, "", this.to) //三个参数 state对象,标题,路径,前两个不需要管,只需要添加我们要去的路径即可
//然后更新我们的响应式数据data中的current
this.$router.data.current = this.to //注意该this代表的是 vue 实例因此有$router
}
}
})
//注册组件 router-view
Vue.Component('router-view', {
render(h) {
return h(self.routeMap[self.data.current]) //此处就体现了该响应式数据的作用了,响应式就能让页面更新,当路径变化时就能更新视图,显示对应的组件
}
})
}
initEvent() {
//监听window的popstate事件 //MDN: 当活动历史记录条目更改时,将触发popstate事件
//当我们点击前进或者后退时 会触发popstate事件
window.addEventListener('popstate', ()=> { //此处需要使用箭头函数保证this指向为VueRouter
this.data.current = window.location.pathname
})
}
//设置初始化函数,负责调用上面的三个方法
init() {
this.createRouteMap()
this.initComponent(_Vue)
this.initEvent()
}
}
5.使用自定义的VueRouter
首先创建两个组件
然后创建router.js文件
import Vue from "vue";
import Router from './components/vuerouter'
import Login from './components/login'
import Home from './components/home'
Vue.use(Router)
export default new Router({
mode: 'history',
routes: [
{path: '/', component: Home},
{path: '/login', component: Login},
]
})
在main.js中使用
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
router,
render: h => h(App),
}).$mount('#app')
App.vue
最后启动程序,页面如下:
点击login后
一个基础版本的VueRouter就创建成功了。后面会继续完善,比如路由嵌套等等。
路漫漫其修远兮,点个赞吧大哥