自己動手寫一個前端路由插件


      在單頁應用上,前端路由並不陌生。單頁應用是指在瀏覽器中運行的應用,在使用期間頁面不會重新加載。 
      基本原理:以 hash 形式(也可以使用 History API 來處理)為例,當 url 的 hash 發生改變時,觸發 hashchange 注冊的回調,回調中去進行不同的操作,進行不同的內容的展示。 
      基於hash的前端路由優點是:能兼容低版本的瀏覽器。 
history 是 HTML5 才有的新 API,可以用來操作瀏覽器的 session history (會話歷史)。 
      從性能和用戶體驗的層面來比較的話,后端路由每次訪問一個新頁面的時候都要向服務器發送請求,然后服務器再響應請求,這個過程肯定會有延遲。而前端路由在訪問一個新頁面的時候僅僅是變換了一下路徑而已,沒有了網絡延遲,對於用戶體驗來說會有相當大的提升。 

      SPA的核心即是前端路由。何為路由呢?說的通俗點就是網址,比如https://www.talkingcoder.com/article/6333760306895988699;專業點就是每次GET或者POST等請求,在服務端有一個專門的正則配置列表,然后匹配到具體的一條路徑后,分發到不同的Controller,然后進行各種操作后,最終將html或數據返回給前端,這就完成了一次IO。當然,目前絕大多數的網站都是這種后端路由,也就是多頁面的,這樣的好處有很多,比如頁面可以在服務端渲染好直接返回給瀏覽器,不用等待前端加載任何js和css就可以直接顯示網頁內容,再比如對SEO的友好等。那SPA的缺點也是很明顯的,就是模板是由后端來維護或改寫。前端開發者需要安裝整套的后端服務,必要還得學習像PHP或Java這些非前端語言來改寫html結構,所以html和數據、邏輯混為一談,維護起來即臃腫也麻煩。然后就有了前后端分離的開發模式,后端只提供API來返回數據,前端通過Ajax獲取到數據后,再用一定的方式渲染到頁面里,這么做的優點就是前后端做的事情分的很清楚,后端專注在數據上,前端專注在交互和可視化上,從此前后搭配,干活不累,如果今后再開發移動App,那就正好能使用一套API了,當然缺點也很明顯,就是首屏渲染需要時間來加載css和js。這種開發模式被很多公司認同,也出現了很多前端技術棧,比如以jQuery+artTemplate+Seajs(requirejs)+gulp為主的開發模式所謂是萬金油了。在Node.js出現后,這種現象有了改善,就是所謂的大前端,得益於Node.js和JavaScript的語言特性,html模板可以完全由前端來控制,同步或異步渲染完全由前端自由決定,並且由前端維護一套模板,這就是為什么在服務端使用artTemplate、React以及即將推出的Vue2.0原因了。那說了這么多,到底怎樣算是SPA呢,其實就是在前后端分離的基礎上,加一層前端路由。

     前端路由,即由前端來維護一個路由規則。實現有兩種,一種是利用url的hash,就是常說的錨點(#),JS通過hashChange事件來監聽url的改變,IE7及以下需要用輪詢;另一種就是HTML5的History模式,它使url看起來像普通網站那樣,以"/"分割,沒有#,但頁面並沒有跳轉,不過使用這種模式需要服務端支持,服務端在接收到所有的請求后,都指向同一個html文件,不然會出現404。所以,SPA只有一個html,整個網站所有的內容都在這一個html里,通過js來處理。

     前端路由的優點有很多,比如頁面持久性,像大部分音樂網站,你都可以在播放歌曲的同時,跳轉到別的頁面而音樂沒有中斷,再比如前后端徹底分離。前端路由的框架,通用的有Director,更多還是結合具體框架來用,比如Angular的ngRouter,React的ReactRouter,以及我們后面用到的Vue的vue-router。這也帶來了新的開發模式:MVC和MVVM。如今前端也可以MVC了,這也是為什么那么多搞Java的鍾愛於Angular。

     開發一個前端路由,主要考慮到頁面的可插拔、頁面的生命周期、內存管理等。

(function() {
	window.Router = function() {
		var self = this;

		self.hashList = {}; /* 路由表 */
		self.index = null;
		self.key = '!';

		window.onhashchange = function() {
			self.reload();
		};
	};

	/**
	 * 添加路由,如果路由已經存在則會覆蓋
	 * @param addr: 地址
	 * @param callback: 回調函數,調用回調函數的時候同時也會傳入相應參數
	 */
	Router.prototype.add = function(addr, callback) {
		var self = this;

		self.hashList[addr] = callback;
	};

	/**
	 * 刪除路由
	 * @param addr: 地址
	 */
	Router.prototype.remove = function(addr) {
		var self = this;

		delete self.hashList[addr];
	};

	/**
	 * 設置主頁地址
	 * @param index: 主頁地址
	 */
	Router.prototype.setIndex = function(index) {
		var self = this;

		self.index = index;
	};

	/**
	 * 跳轉到指定地址
	 * @param addr: 地址值
	 */
	Router.prototype.go = function(addr) {
		var self = this;

		window.location.hash = '#' + self.key + addr;
	};

	/**
	 * 重載頁面
	 */
	Router.prototype.reload = function() {
		var self = this;

		var hash = window.location.hash.replace('#' + self.key, '');
		var addr = hash.split('/')[0];
		var cb = getCb(addr, self.hashList);
		if(cb != false) {
			var arr = hash.split('/');
			arr.shift();
			cb.apply(self, arr);
		} else {
			self.index && self.go(self.index);
		}
	};

	/**
	 * 開始路由,實際上只是為了當直接訪問路由路由地址的時候能夠及時調用回調
	 */
	Router.prototype.start = function() {
		var self = this;

		self.reload();
	}

	/**
	 * 獲取callback
	 * @return false or callback
	 */
	function getCb(addr, hashList) {
		for(var key in hashList) {
			if(key == addr) {
				return hashList[key]
			}
		}
		return false;
	}
})();

  每次hash的變化我們還可以通過onhashchange事件【核心+精髓】來監聽,然后做出相應的處理。。

<!DOCTYPE html>
<html>

	<head>
		<meta charset="utf8" />
		<script type="text/javascript" src="./router.js"></script>
		<style type="text/css">
		</style>
	</head>

	<body>
		<a href="#!index">go to index</a><br />
		<a href="#!search/SB/shi/ni">go to search</a>
	</body>

	<script type="text/javascript">
		window.onload = function() {
			var router = new Router();
			router.add('index', function() {
				alert('current page: index');
			});

			router.add('search', function(wd, sortType, sortBy) {
				alert('current page: search' + '\nwd: ' + wd + '\nsortType: ' + sortType + '\nsortBy: ' + sortBy);
			});
			router.setIndex('index');
			router.start();
		};
	</script>

</html>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM