後端有後端路由,根據路由返回特定的網頁,表明者是傳統的mvc模式,模板引擎+node。前端也有前端的路由,咱們用三大框架作spa的時候,老是和路由離不開關係。主要有兩種方法:基於哈希路由、基於historyjavascript
#後面的內容是網頁位置標識符,通常是錨點<a name='xx'>
或id屬性<div id='xx'>
。經過location.hash能夠取到該值,常見的返回頂部也能夠利用href=‘#’
。改變#後面的內容不會引發頁面從新刷新,可是會有歷史記錄,因此能夠後退。這對於ajax應用程序特別有用,能夠用不一樣的#值,表示不一樣的訪問狀態,而後向用戶給出能夠訪問某個狀態的連接。可是IE 6和IE 7不會有歷史記錄。#後面的內容不會提交到服務器。html
對於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的位置。vue
對於前端路由,咱們有一個事件能夠利用的,onhashchange,監聽哈希的變化而後執行相應的回調函數。因而咱們能夠寫下路由類的代碼: html:java
<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:node
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上面的#後面 內容改變,並且控制檯打印了相應的數字ajax
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()
複製代碼
若是不瞭解的,點擊這裏瞭解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直接定位到某個視圖。