单页面应用hash、history原理以及JSONP的分析
单页面应用核心:不通过后端完成路由切换
(Vue、React路由切换原理类似)
history
模式基于window.history/history(this===window,不写window直接可以访问)
,原本只有back()、go()、forward()
API,在HTML5中新增pushState
、replaceState({new State},titlexxx,url)
(这里的state可以在history中拿到,类似传参)
优点:
- 即使相同的url也会被推进浏览历史栈中
- state可以传obj类型数据作为参数,而hash只能传#短字符串
- 还有个title可以等待使用
缺点
- 需要后端配置支持,每一种路由需要后端有相应的接收处理,不能仅仅是最外层的url
- 一般是通配符+返回主页面文件(此做法原因:每一次都返回打包好的index.html文件,由前端去根据state参数具体展示)
没次go、bach、replace会触发popState
方法`
- 一般是通配符+返回主页面文件(此做法原因:每一次都返回打包好的index.html文件,由前端去根据state参数具体展示)
hash
模式基于location.href+location.hash
完成,由#
开头的字符串组成区分不同的hash字符串
优点
- #及以后的值不会传给后端,而history会
- 由上可知,hash模式不需要左后端配置
缺点
- 不美观
home.html文件
<body>
<div>
<button id='btn1'>按钮1</button>
<button id="btn2">按钮2</button>
</div>
</body>
<script>
const bindEventListener = function (type) {
const historyEvent = history[type];
return function () {
const newEvent = historyEvent.apply(this, arguments);
const e = new Event(type);
e.arguments = arguments;
window.dispatchEvent(e);
return newEvent;
};
};
history.pushState = bindEventListener('pushState');
history.replaceState = bindEventListener('replaceState');
window.addEventListener('replaceState', function (e) {
console.log('THEY DID IT AGAIN! replaceState');
});
window.addEventListener('pushState', function (e) {
console.log('THEY DID IT AGAIN! pushState');
});
document.addEventListener('popstate', (e) => {
console.log(e, 'popstate');
})
document.addEventListener('hashchange', (e) => {
console.log(e, 'hashchange');
})
let btn1 = document.getElementById('btn1')
let btn2 = document.getElementById('btn2')
btn1.addEventListener('click', (e) => {
})
</script>
index.html文件
<body>
<div id='root'>
测试
</div>
</body>
<script>
function callBack(data){
var box = document.createElement('div')
box.innerText = '回来了'
root.appendChild(box)
}
function genScript(url){
var newS = document.createElement('script');
newS.src = url
window.onload = function(){
root.appendChild(newS)
}
}
</script>
<script>
var root = document.getElementById('root')
genScript('http://localhost:8080/test?cb=callback')
</script>
app.js文件
const http = require('http')
const fs = require('fs')
const httpPort = 8080
http.createServer((req, res) => {
fs.readFile('home.html', 'utf-8', (err, content) => {
console.log(req.url);
if (err) {
console.log('We cannot open "index.html" file.')
}
console.log('接收到');
res.writeHead(200, {
'Content-Type': 'text/html; charset=utf-8'
})
res.end()
})
}).listen(httpPort, () => {
console.log('Server listening on: http://localhost:%s', httpPort)
})