咱們都知道vue單頁應用須要藉助vue-router插件來實現頁面的跳轉,但實現原理如何呢?下面簡單的分析下。單頁的跳轉通常有兩種方式:hash變化和history控制。下面以hash變化爲例說明:vue
// rvue-router.js let Vue; class Router { constructor(options){ this.$options = options; // this.current保存當前頁面的hash值 this.current = window.location.hash.slice(1) || '/'; // matched數組保存路由與組件的映射表,只保留當前路由和當前路由的嵌套路由 Vue.util.defineReactive(this, 'matched', []); // match方法遞歸遍歷路由表,得到匹配關係的數組,也就是建立新的路由映射表 this.match(); // 3. 監控url的變化:監聽hashchange或popstate事件 window.addEventListener('hashchange', this.onHashChange.bind(this)); // 頁面刷新時獲取hash值 window.addEventListener('load', this.onHashChange.bind(this)); } onHashChange(){ this.current = window.location.hash.slice(1); // hash變化時,路由映射表從新匹配 this.matched = []; this.match(); } match(routes){ routes = routes || this.$options.routes; for(const route of routes){ // 根路由 if(route.path === '/' && this.current == '/'){ this.matched.push(route); return; } // 嵌套路由 /main/about if(route.path !== '/' && this.current.indexOf(route.path) > -1){ this.matched.push(route); if(route.children){ this.match(route.children); } return; } } } } // 1. 做爲一個插件:實現VueRouter的install方法 Router.install = function(_Vue){ // 保存_Vue構造函數,在Router內部使用 // 避免import Vue時致使打包文件過大,因此經過變量Vue來保存_Vue引用 Vue = _Vue; // 掛載$router // (入口文件實例化Vue時的根組件)在組件根實例中掛載$router Vue.prototype.$router = router // 經過混入的方式,在每一個組件生命週期中實現掛載$router Vue.mixin({ beforeCreate() { // 確保是根實例的時候才執行,只有根實例組件纔有router選項 if(this.$options.router){ Vue.prototype.$router = this.$options.router; } }, }); // 2. 實現兩個全局組件:router-view用於匹配組件內容,router-link用於跳轉 Vue.component('router-link', { props:{ to: { type: String, required: true } }, render(h) { // <a href="#/form">連接</a> // <router-link to="/slot" /> 調用方式 // h(tag, data, children) return h('a', {attrs: {href: `#${this.to}`}}, this.$slots.default); } }); Vue.component('router-view', { render(h){ // 標記當前router-view的深度,標記本身是router-view組件 this.$vnode.data.routeView = true; let depth = 0; let parent = this.$parent; while(parent){ const vnodeData = parent.$vnode && parent.$vnode.data; // 若是是router-view組件,則記錄routeView的深度 if(vnodeData && vnodeData.routeView){ depth ++; } parent = parent.$parent; } // 4. 響應最新的url:建立一個響應式的屬性matched,當它改變時獲取對應組件的顯示內容 // mathed保存的是組件路由的映射關係,只涉及當前路由和當前路由的子路由 // this.$router指當前VueRouter的實例 const { matched } = this.$router; const component = matched[depth] && matched[depth].component; return h(component); } }); } export default Router 複製代碼
引入rvue-router插件後,先使用Vue.use(Router)註冊插件,調用rvue-router的install方法,而後建立router實例,將路由配置項做爲參數傳入。node
//router.js import Vue from 'vue' import Router from 'rvue-router' // 引入上面的rvue-router.js import Form from 'components_path/form' const routes = [{ path: '/form', name: 'form', component: Form }] // 第一步 應用註冊插件 Vue.use(Router); // 第二步 建立實例 const router = new Router({ mode: 'history', routes //將路由配置項傳入 }) export default router 複製代碼
在入口文件main.js中引入路由配置router.jsvue-router
// main.js import Vue from 'vue' import App from './app' import router from './router' new Vue({ render: h => h(App), router // Vue.prototype.$router = router }).$mount('#app') 複製代碼
npm地址:www.npmjs.com/package/rvu…npm
以上內容爲網上學習課程的複習總結。數組