0.前言
後端有後端路由,根據路由返回特定的網頁,代表者是傳統的mvc模式,模板引擎+node。前端也有前端的路由,我們用三大框架做spa的時候,總是和路由離不開關係。主要有兩種方法:基於哈希路由、基於history
1.哈希路由
#後面的內容是網頁位置標識符,一般是錨點<a name='xx'>
或id屬性<div id='xx'>
。通過location.hash可以取到該值,常見的返回頂部也可以利用href=‘#’
。改變#後面的內容不會引起頁面重新刷新,但是會有歷史記錄,所以可以後退。這對於ajax應用程序特別有用,可以用不同的#值,表示不同的訪問狀態,然後向用戶給出可以訪問某個狀態的鏈接。但是IE 6和IE 7不會有歷史記錄。#後面的內容不會提交到服務器。
對於a標籤,平時有一個常規的操作: 想要在某個點擊按鈕變成a標籤的那個cursor:pointer
(手指),一般就用a標籤包住文字, <a href="#">按鈕</a>
但是這樣子是會有歷史記錄,所以我們應該改成 <a href="javascript:void 0">按鈕</a>
我們在用vue路由的時候,其實可以發現,router-link
到最後就是一個a標籤。而我們也知道a標籤有一個href屬性,如果是哈希路由就不會引發頁面的刷新。所以平時也有一種常規操作,返回頂部,就是a標籤的href=“#”
,就是直接跳轉到頁面頂部。如果我們給dom一個id,#<id>
就跳轉到那個dom的位置。
對於前端路由,我們有一個事件可以利用的,onhashchange,監聽哈希的變化然後執行相應的回調函數。於是我們可以寫下路由類的代碼: html:
<a href="#1">1</a> <a href="#2">2</a> <a href="#3">3</a> <button onclick="r.back()">後退</button> <button onclick="r.forward()">前進</button> 複製代碼
js:
const addEvent = (function () {//事件 if (window.addEventListener) { return function (ele, event, handle, isBunble) { isBunble = isBunble || false ele.addEventListener(event, handle, isBunble) } } else if (window.attachEvent) { return function (ele, event, handle) { ele.attachEvent('on' + event, handle) } } else { return function (ele, event, handle) { ele['on' + event] = handle } } })() class Router { constructor () { this.routes = {} this.currentUrl = '/' this.pre = this.pre || null this.next = this.next || null addEvent(window, 'load', () => { this.updateUrl() }) addEvent(window, 'hashchange', () => { this.pre = this.currentUrl this.updateUrl() }) } route (path, cb) { this.routes[path] = cb || function () {} } updateUrl () {//路由更新的回調 this.currentUrl = window.location.hash.slice(1) || '/' console.log(this.currentUrl) } back () {//後退 if( !this.currentUrl ) return; this.next = this.currentUrl window.location.hash = '#' + this.pre } forward () {//前進 if( !this.next ) return ; window.location.hash = '#' + this.next } } const r = new Router() 複製代碼
我們嘗試點擊一下a標籤,發現url上面的#後面 內容改變,而且控制檯打印了相應的數字
在VUE中使用路由
html:
<div id="app"> <a href="#1">1</a> <a href="#2">2</a> <a href="#3">3</a> <component :is="page"></component> </div> <template id="page1"> <div> <h1>這是第一頁</h1> </div> </template> <template id="page2"> <div> <h1>這是第二頁</h1> <p>通過監聽路由改變來改變視圖</p> </div> </template> <template id="page3"> <div> <h1>這是第三頁</h1> <p>動態改變組件,模擬類似於前端路由的效果</p> </div> </template> 複製代碼
js:
const vm = new Vue({ el: "#app", data () { return { page: "page1" } }, components:{ "page1":{ template:'#page1' }, "page2":{ template:'#page2' }, "page3":{ template:'#page3' } } }); const addEvent = (function () { if (window.addEventListener) { return function (ele, event, handle, isBunble) { isBunble = isBunble || false ele.addEventListener(event, handle, isBunble) } } else if (window.attachEvent) { return function (ele, event, handle) { ele.attachEvent('on' + event, handle) } } else { return function (ele, event, handle) { ele['on' + event] = handle } } })() class Router { constructor () { this.routes = {} this.currentUrl = '/' this.pre = this.pre || null this.next = this.next || null addEvent(window, 'hashchange', () => { this.pre = this.currentUrl this.updateUrl() }) } route (path, cb) { this.routes[path] = cb || function () {} } updateUrl () { this.currentUrl = window.location.hash.slice(1) || '/' console.log(this.currentUrl) vm.$data.page = "page" + this.currentUrl } back () { if( !this.currentUrl ) return; this.next = this.currentUrl window.location.hash = '#' + this.pre } forward () { if( !this.next ) return ; window.location.hash = '#' + this.next } } const r = new Router() 複製代碼
2.history路由
如果不瞭解的,點擊這裏瞭解history路由
html:
<div id="app"> <component :is="page"></component> <button @click="to1">page1</button> <button @click="to2">page2</button> <button @click="to3">page3</button> </div> <template id="page1"> <div> <h1>這是第一頁</h1> </div> </template> <template id="page2"> <div> <h1>這是第二頁</h1> <p>通過監聽路由改變來改變視圖</p> </div> </template> <template id="page3"> <div> <h1>這是第三頁</h1> <p>動態改變組件,模擬類似於前端路由的效果</p> </div> </template> 複製代碼
js:
const vm = new Vue({ el: "#app", data () { return { page: "page1" } }, components:{ "page1":{ template:'#page1' }, "page2":{ template:'#page2' }, "page3":{ template:'#page3' } }, methods: { to1(){ r.go('1') }, to2(){ r.go('2') }, to3(){ r.go('3') } } }); const addEvent = (function () { if (window.addEventListener) { return function (ele, event, handle, isBunble) { isBunble = isBunble || false ele.addEventListener(event, handle, isBunble) } } else if (window.attachEvent) { return function (ele, event, handle) { ele.attachEvent('on' + event, handle) } } else { return function (ele, event, handle) { ele['on' + event] = handle } } })() class Router { constructor (from, history) { this.from = from//保存起點 this.history = history this.list = {} //緩存k-v對 } go (pagename) { if(!this.list[pagename]){ this.list[pagename] = ++this.from window.history.pushState({page:pagename},pagename,pagename) }else{ window.history.go(this.list[pagename]) } vm.$data.page = "page" + pagename } } const r = new Router(window.history.length, window.history) 複製代碼
引用vue官網一句話:如果你嫌哈希路由難看可以用history路由。不過history路由有一個問題,我們知道pushState和replaceState只是對url欄進行改變,不會觸發頁面刷新,只是導致history對象發生變化,另外也不能跨域。所以這個例子你不能直接雙擊打開了,因爲file沒有域名好講,你只能通過後臺打開這個頁面。既然不會觸發頁面更新,那麼也不會發送http請求,就有了一個問題:如果直接輸入url,後端又沒有對應的url處理的話,那肯定是404,而哈希路由則可以直接輸入 url直接定位到某個視圖。