首先看一下vue-router得基本用法
router.js
import Router from 'vue-router'
Vue.use(Router);//应用插件做了什么????
export default new Router({//创建Router的实例
mode:'history',
base:process.env.BASE_URL,
routes:[ //配置routes
{
path:'/',
name:'home',
component:Home
}
]
})
main.js
import router from 'router'
new Vue({
router,//配置router实例(原因)???????????
}).$mount("#app")
app.vue
<div id="app">
<div>
<router-link to="/"></router-link>
</div>
<router-view></router-view>
</div>
router-link和router-view哪来的??????????
以上为vur-router的基本用法,带着一些问题,我们看一下vue-router插件是如何实现的(只实现核心代码)
router的任务分析:
1.实现vue-router插件
2.解析下routes的选项
3.监控下url的变化(实现单页面不刷新的方法html5 history api和hash)
4.实现两个全局组件(router-link和router-view)
下面自己实现一个vue-router的插件
vue-router.js
//声明插件:vue插件需要实现一个install静态方法
let Vue;//保存Vue构造函数的引用,不对他产生直接的依赖,不将vue通过import进来不将vue打包进去
class VueRouter {
constructor(options){
this.$options = options;//实例中传入的数据
this.routerMap = {};//路由的映射对象,即保存了数据,key味url,value为url对应得component {'/index':{component:Index,.....}}
//获取当前的url
//当前url需要是响应式的--值发生变化,所有用到值的组件都要刷新
//此时借鉴Vue中data的响应式
this.app = new Vue({
data:{current:'/'} //保存当前得url
})
}
//初始化
init(){
//监听事件-----当页面
this.bindEvent();
//解析routes
this.createRouteMap();
//声明组件
this.initComponent()
}
bindEvent(){
window.addEventListener('hashchange',this.onHashchange.bind(this))
}
onHashchange(){
this.app.current = window.location.hash.slice(1) || '/'
}
createRouteMap(){
//遍历用户配置路由数组
//根据地址拿到路由的配置对象
this.$options.routes.forEach(route => {
this.routeMap[route.path] = route
})
}
initComponent(){
//声明两个组件
//声明组件的方法--为什么全局的声明就可以在任何组件中使用,而不需要在componets选项里配置???????
//router-link的转换目标:<a href="/">xxx</a>
Vue.component('router-link',{
props:{
to:String
},
//这里不可以用template来写
//template:'<a></a>'
render(h){
//h(tag,data,children)
//使用createEle函数
return h('a',{
attrs:{href:'#'+this.to}
},[this.$slots.default]) //[this.$slots.default]插槽代表上面的xxx内容
//使用JSX
//return <a href={'#'+this.to}>{this.$slots.default}</a>
}
})
//获取path对应的Component将他渲染出来
Vue.component('router-view',{
render:(h) => {
//拿出要渲染的component,然后再渲染出来
//this指向组件的实例对象
const Component = this.routerMap[this.app.current].component
return h(Component)
}
})
}
/*
Vue.component("router-view",{
functional:true,
render(h,{parent}){
const router = parent.$router
const Component = router.routeMap[router.app.current].component;
return h(Component)
}
})
*/
}
//插件的use方法就是调用插件里的install方法(规定)
VueRouter.install = function(_Vue){ //参数是vue的构造函数
Vue = _Vue;
//实现一个混入---vue给我们提供了一个机制,让我们接下来写的生命周期的东西,将来会在vue组件的指定的声明周期中执行
Vue.mixin({
beforeCreate(){
//获取到VueRouter的实例并挂载到Vue.prototype上
if(this.$options.router){
//根组件beforeCreate时执行一次
Vue.prototype.$router = this.$options.router;//此处就是实现 你在组件中可以通过this.$router来进行一些操作
this.$options.router.init()
}
}
})
//为什么引入一个混入,而不是直接将赋值语句直接放在install方法里??????
//先执行的Vue.use(Router),(use执行了插件的install方法)此时实例Router还不在,所以把实例挂到根组件上,通过混入延后执行,延后到根组件beforeCreate的时候再执行
}
export default VueRouter