先簡單說一說,咱們前端路由的實現主要是爲了SPA應用的框架,框架開發都是單頁應用,單頁應用的特色就是跳轉頁面的時候的不刷新瀏覽器,那想要實現跳轉頁面不刷新瀏覽器的方式有兩種:一種是經過hash的方式、另外一種就是經過H5的history的api實現javascript
<a href="#/home">首頁</a>
<a href="#/about">關於</a>
<div id="html"></div>
<script> window.addEventListener('load',()=>{ html.innerHTML = location.hash.slice(1); }); window.addEventListener('hashchange',()=>{ html.innerHTML = location.hash.slice(1) }) </script>
複製代碼
<a onclick="go(/home)">首頁</a>
<a onclick="go(/about)">關於</a>
<div id="html"></div>
<script > function go(pathname) { history.pushState({},null,pathname) html.innerHTML = pathname; } window.addEventListener('popstate',()=>{ go(location.pathname); }) </script>
複製代碼
class HistoryRoute{
constructor(){
this.current = null;
}
}
class vueRouter {
constructor(options){
this.mode = options.mode || "hash";
this.routes = options.routes || [];
// 傳遞的路由表是數組 須要裝換成{'/home':Home,'/about',About}格式
this.routesMap = this.createMap(this.routes);
// 路由中須要存放當前的路徑 須要狀態
this.history = new HistoryRoute;
this.init();//開始初始化操做
}
init(){
if(this.mode == 'hash'){
// 先判斷用戶打開時有沒有hash,沒有就跳轉到#/
location.hash?'':location.hash = '/';
window.addEventListener('load',()=>{
this.history.current = location.hash.slice(1);
});
window.addEventListener('hashchange',()=>{
this.history.current = location.hash.slice(1);
})
}else {
location.pathname?'':location.pathname = '/';
window.addEventListener('load',()=>{
this.history.current = location.pathname;
});
window.addEventListener('popstate',()=>{
this.history.current = location.pathname;
})
}
}
createMap(routes){
return routes.reduce((memo,current)=>{
memo[current.path] = current.component
return memo
},{})
}
}
//使用vue.use就會調用install方法
vueRouter.install = function(Vue,opts) {
//每一個組件都有 this.$router / this.$route 因此要mixin一下
Vue.mixin({
beforeCreate(){ //混合方法
if(this.$options && this.$options.router){//定位跟組件
this._root = this;//把當前實例掛載在_root上
this._router = this.$options.router // 把router實例掛載在_router上
//history中的current變化也會觸發
Vue.util.defineReactive(this,'xxx',this._router.history);
}else {
// vue組件的渲染順序 父 -> 子 -> 孫子
this._root = this.$parent._root;//獲取惟一的路由實例
}
Object.defineProperty(this,'$router',{//Router的實例
get(){
return this._root._router;
}
});
Object.defineProperty(this,'$route',{
get(){
return {
//當前路由所在的狀態
current:this._root._router.history.current
}
}
})
}
});
// 全局註冊 router的兩個組件
Vue.component('router-link',{
props:{
to:String,
tag:String
},
methods:{
handleClick(){跳轉方法
}
},
render(h){
let mode = this._self._root._router.mode;
let tag = this.tag;
return <tag on-click={this.handleClick} href={mode === 'hash'?`#${this.to}`:this.to}>{this.$slots.default}</tag>
}
})
Vue.component('router-view',{//根據當前的狀態 current 對應相應的路由
render(h){
//將current變成動態的 current變化應該會影響視圖刷新
//vue實現雙向綁定 重寫Object.defineProperty
let current = this._self._root._router.history.current;
let routeMap = this._self._root._router.routesMap
return h(routeMap[current])
}
})
}
export default VueRouter;
複製代碼