后端有后端路由,根据路由返回特定的网页,表明者是传统的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直接定位到某个视图。