实现效果如下:
1. 准备好环境
使用 vue/cil 初始化项目配置:
npm install -g @vue/cli //全局安装@vue/cli
vue create demo-vue //创建项目
yarn add vue-router
安装vue-router创建一个router文件夹并使用:
2. 实现目的
router/index.js
内容如下:(我们的目的将引入自写的vue-router实现vue路由跳转功能)
import vue from 'vue'
//import vueRouter from 'vue-router' //使用官方 vue-router 插件
import vueRouter from './my-vue-router' //使用我们直接实现的 vue-router 插件
vue.use(vueRouter) //此时执行 my-vue-router 内 install 方法
const routes = [
{
path: '/',
redrect: '/a'
},
{
path: '/a',
name: 'a',
component: () => import('../views/a.vue')
},
{
path: '/b',
name: 'b',
component: () => import('../views/b.vue')
}
]
const router = new vueRouter({
mode: 'hash', //哈希路由
routes
})
export default router //main.js 引入实例化的 router 添加至 this.$options.router 中
3. 实现原理
router/my-vue-router.js
实现过程如下:
let Vue //声明一个变量用来存储install内接收的vue实例 给 constructor 内调用
class vueRouter {
constructor(options) {
this.$options = options //用于通过全局 this.$options.router.$options 获取
const initail = window.location.hash.slice(1) || '/'
Vue.util.defineReactive(this, 'current', initail) //监听数据响应式渲染页面
window.addEventListener('hashchange', () => { //监听哈希路由变化
this.current = window.location.hash.slice(1) //改变触发 render 渲染页面
})
}
push() {
console.log("跳转页面");
}
}
vueRouter.install = function(_vue) {
Vue = _vue
Vue.mixin({
beforeCreate() {
if (this.$options.router) {
Vue.prototype.$router = this.$options.router //将全局数据注入组件
}
}
})
Vue.component('router-link', { //注册全局 router-link 组件
props: {
to: {
type: String,
required: true
}
},
render(h) {
return h(
'a',
{
attrs: { href: '#' + this.to }
},
this.$slots.default
)
}
})
Vue.component('router-view', { //注册全局 router-view 组件
render(h) {
console.log(" this.$router", this.$router);
const route = this.$router.$options.routes.find((route) => {
return route.path == this.$router.current
})
return h(route.component) //将组件渲染返回
}
})
}
export default vueRouter
3. 使用手写vue-router:
a.vue
与 b.vue
可任意写
<template>
<div id="app">
<router-link to="/a">aaa</router-link> |
<router-link to="/b">bbb</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>