src/router/index.js
// 使用插件的流程
// 1.引入vue
import Vue from 'vue'
// 2.引入插件
import lyRouter from '../ly-router'
import Home from '../components/Home.vue'
import List from '../components/List.vue'
// 3.Vue.use使用当前插件
// 找install方法
// 如果这个插件是一个函数 就会被当做install方法 如果是对象 就必须要有install方法
Vue.use(lyRouter)
// 4.使用 export default 来导出当前路由配置项
export default new lyRouter({
routes:[
{
path:"/",
component:Home,
},
{
path:"/list",
component:List,
}
]
})
src/ly-router/index.js
let Vue
class lyRouter{
static install(_Vue){
// 将Vue.use传递的Vue构造函数赋值给全局对象
// _Vue是构造函数
Vue = _Vue
// 在这里调用init方法 原因:在这里路由会被挂载到Vue身上
// console.log(_Vue);
// console.log(this.$options);
//混入
Vue.mixin({
//在组件初始化的时候在进行路由的实例化
beforeCreate() {
if(this.$options.router){
this.$options.router.init();
}
},
})
}
constructor(options){
//接受路由的配置项参数
this.$options = options
//创建路由表对象
this.routesMap = {}
// 默认的根路径
this.app = new Vue({
data:{
//data中的数据是响应式的 因此只要curr发生改变那么组件默认也会发生改变
curr: this.getHash() || "/"
}
})
// this.init()
}
// 路由初始化
init(){
// 1.路由监听事件
this.bindEvent()
// 2.创建路由表对象
this.createRoutesMap()
// 3.创建组件
this.renderComponent()
}
bindEvent(){
//页面初次加载的时候也要监听路由的变换
window.addEventListener("load",this.handleBindEventChange.bind(this))
//hash值发生改变的时候监听路由的变换
window.addEventListener("hashchange",this.handleBindEventChange.bind(this))
}
handleBindEventChange(){
//当hash中发生改变的时候获取到hash值 赋值给this.app.curr这个响应式对象保证组件的更新
var hash = this.getHash() || "/"
this.app.curr = hash
// console.log(this.app.curr);
}
getHash(){
//获取hash值
var hash = window.location.hash.slice(1)
return hash
}
createRoutesMap(){
//创建路由表对象,根据path的路径来决定渲染的组件
this.$options.routes.forEach((item) => {
this.routesMap[item.path] = item
})
console.log(this.routesMap);
}
renderComponent(){
//注册 router-view组件
Vue.component("router-view",{
render:h=>{
// 这句话不能放在外面 render在创建虚拟dom的时候 创建的不是最新的
//注意:这句话一定要写在内部 因为组件注册只会注册一次 当this.app.curr发生改变的时候讲h函数重新执行
var component = this.routesMap[this.app.curr].component
return h(component)
}
})
//注册router-link组件
Vue.component("router-link",{
render(h){
return h("a",{
attrs:{
href:"#"+this.to
}
},this.$slots.default)
},
props:{
to:{
type:String
}
}
})
}
}
export default lyRouter
App.vue
<template>
<!-- 程序入口vue组件 -->
<div id="app">
<router-link to="/">首页</router-link>
<router-link to="/list">列表</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
// 程序入口文件
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
new Vue({
router,
render:h => h(App),
}).$mount('#app')
components/home.vue
<template>
<div>
<h2>home</h2>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
components/list.vue
<template>
<div>
<h2>list</h2>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>