0.前端路由原理
1.history模式原理:
利用history.pushState這個api,將路徑推動棧中,頁面不會刷新,網址會發生改變。而後window監聽load和popstate事件,根據location.pathname的值,來替換router-view的內容。javascript
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title></title> </head> <body> <a href="/home">主頁</a> <a href="/about">關於</a> <div class="router-view"></div> <script src="./history.js"></script> </body> </html>
const router_view = document.querySelector('.router-view'); const a_list = document.querySelectorAll('a'); for (let i = 0; i < a_list.length; i++) { a_list[i].onclick = (e) => { e.preventDefault(); const href = e.target.getAttribute('href') || '/'; history.pushState({ }, null, path); routerChange(href); }; } window.addEventListener('load', () => { routerChange(location.pathname); }); window.addEventListener('popstate', () => { routerChange(location.pathname); }); function routerChange(path) { switch (path) { case '/home': router_view.innerHTML = 'Home'; break; case '/about': router_view.innerHTML = 'About'; break; default: router_view.innerHTML = ''; break; } }
2.hash路由原理:
瀏覽器改變網址後面的#/xxx部分是不會刷新頁面的,咱們就能夠經過監聽hashchange事件,從而變動router-view裏面的內容。html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title></title> </head> <body> <a href="#/home">主頁</a> <a href="#/about">關於</a> <div class="router-view"></div> <script src="./hash.js"></script> </body> </html>
const router_view = document.querySelector('.router-view'); window.addEventListener('load', () => { routerChange(location.hash.slice(1)); }); window.addEventListener('hashchange', () => { routerChange(location.hash.slice(1)); }); function routerChange(path) { switch (path) { case '/home': router_view.innerHTML = 'Home'; break; case '/about': router_view.innerHTML = 'About'; break; default: router_view.innerHTML = ''; break; } }
1.解析vue-router
vue-router的基本使用:前端
import Vue from 'vue'; import VueRouter from '../extends/my-router'; import Home from '../views/Home.vue'; Vue.use(VueRouter); const routes = [ { path: '/', name: 'Home', component: Home, }, { path: '/about', name: 'About', // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'), }, ]; const router = new VueRouter({ mode: 'hash', routes, }); export default router;
- Vue.use(VueRouter):表示VueRouter是一個插件,它是一個方法或者VueRouter.install是一個方法
- new VueRouter(): 表示VueRouter是一個構造函數,因此它具備VueRouter.install這個一個方法。
2.重寫vue-router
class HistoryRoute { constructor() { this.current = null; } } class VueRouter { constructor(options) { this.mode = options.mode || 'hash'; this.routes = options.routes || []; this.routeMap = this.createMap(this.routes); this.history = new HistoryRoute(); this.init(); } init() { if (this.mode === 'history') { window.addEventListener('popstate', () => { this.history.current = location.pathname ? location.pathname : '/'; }); window.addEventListener('load', () => { this.history.current = location.pathname ? location.pathname : '/'; }); } else { window.addEventListener('hashchange', () => { this.history.current = location.hash ? location.hash.slice(1) : '/'; }); window.addEventListener('load', () => { this.history.current = location.hash ? location.hash.slice(1) : '/'; }); } } createMap(routes) { const routeMap = { }; routes.forEach((route) => { routeMap[route.path] = route.component; }); return routeMap; } } VueRouter.install = function(Vue) { Vue.mixin({ beforeCreate() { if (this.$options && this.$options.router) { // 跟組件組件 this._root = this; this._router = this.$options.router; // 咱們須要將this._router.history變成響應式的,這樣才能動態改變組件 Vue.util.defineReactive(this, 'xxx', this._router.history); } else { // 子組件 this._root = this.$parent && this.$parent._root; } // 在每個組件實例上添加$router Object.defineProperty(this, '$router', { get: () => { return this._root._router; }, }); // 在每一個組件實例上添加$route Object.defineProperty(this, '$route', { get: () => { return this._root_router.history.current; }, }); // 註冊router-link組件 Vue.component('router-link', { props: { to: String, }, render(h) { return h('a', { attrs: { href: this.to } }, this.$slots.default); }, }); // 註冊router-view組件 Vue.component('router-view', { render(h) { console.log(this.$router); console.log(this.$router.history.current); return h(this.$router.routeMap[this.$router.history.current]); }, }); }, }); }; export default VueRouter;
本文同步分享在 博客「冬天愛吃冰淇淋」(CSDN)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。vue