hash 和 history的区别
- hash 有#,history 没有,Hash式基于锚点,History 模式 基于H5的History API
- hash 的#部分内容不会传给服务端, history 的所有内容都会给服务端,应用在部署的时候需要注意html的访问,因为无论访问什么/a,/b,/c之类的路径,其实都要访问那个html文件
- hash 通过 hashchange 监听变化,history 通过 popstate 监听变化
Hash
-
url中带有一个#,它只是浏览器/客户端的状态,不会传递给服务器,服务器拿到的都是#前面的
-
hash值的改变不会导致页面的刷新
location.hash = '#aaa'; location.hash = '#bbb';
-
hash值的更改可以在浏览器访问历史中添加一条记录,所以可以通过浏览器的返回前进来控制hash的切换
-
hash值的更改会触发hashchange事件
History
window.history.pushState();// 页面的浏览记录里添加一个历史记录
window.history.replaceState(); // 替换当前历史记录
window.history.go(-1)
pushState的参数
- state, 是一个对象,是一个与指定网址相关的对象,当 popstate 事件触发的时候,该对象会传入回调函数
- title, 新页面的标题,浏览器支持不一,可以传入null
- url, 页面的新地址
当点击浏览器的前进和后退按钮,或者调用history的back和forward方法的时候,会触发popstate
事件,可以记录改变后的地址并渲染。(要注意的是,当调用pushState,或者replaceState时,并不会触发该事件)
部署时如何配置nginx
假设访问www.lubai.com/main/
- 假设index.html 存在服务器本地(index.html文件与nginx在同一个服务器)(vue官方的写法):就可以通过try file的形式,假设访问main这个路径的话
location /main/ { // 如果是根路由可以直接 /
try_files $uri $uri/ /home/dist/index.html
}
这样无论访问 /main/a 或 /main/b 就都会访问那个 index.html
- 假设html文件 存在于远程地址,oss或cdn,地址为
www.lubai-cdn.com/file/index.html
location /main/ { // 路径的匹配规则
rewrite ^ /file/index.html // ^指的是全部,全部重写成这个路径
proxy_pass https://www.lubai-cdn.com,// 通过代理的形式
}
手写一个hash-router
<div class="container">
<a href="#gray">灰色</a>
<a href="#green">绿色</a>
<a href="#">白色</a>
<button onclick="window.history.go(-1)">返回</button>
</div>
希望能达到下面的效果,点击三个不同的a标签,页面的背景色会随之改变。使用 new BaseRouter 的形式创建并使用
const Router = new BaseRouter();
Router.route('/', function () {
changeBgColor('white');
});
Router.route('/green', function () {
changeBgColor('green');
});
Router.route('/gray', function () {
changeBgColor('gray');
});
// ---
const body = document.querySelector('body');
function changeBgColor(color) {
body.style.backgroundColor = color;
}
实现BaseRouter
class BaseRouter {
constructor() {
this.routes = {}; // 存储path以及callback的对应关系
this.refresh = this.refresh.bind(this);
window.addEventListener('load', this.refresh); // 处理页面首次加载
window.addEventListener('hashchange', this.refresh); // 处理页面hash的变化
}
route(path, callback) {
// 向this.routes存储path以及callback的对应关系
this.routes[path] = callback || function () { };
}
refresh() {
// 刷新页面
const path = `/${location.hash.slice(1) || ''}`;
console.log(location.hash);
this.routes[path]();
}
}
手写一个history-router
改路径
<div class="container">
<a href="/gray">灰色</a>
<a href="/green">绿色</a>
<a href="/">白色</a>
<button onclick="window.history.go(-1)">返回</button>
</div>
此外我们不希望a标签它执行,这个相当于执行了location.href = '/a',就出问题了,我们先阻止默认行为
const container = document.querySelector('.container');
container.addEventListener('click', e => {
if (e.target.tagName === 'A') {
e.preventDefault();
Router.go(e.target.getAttribute('href'));
}
});
实现BaseRouter
class BaseRouter {
constructor() {
this.routes = {};
// location.hash; hash的方式
this.init(location.pathname);
this._bindPopState();
}
init(path) {
window.history.replaceState({
path
}, null, path);
const cb = this.routes[path];
// cb && cb();
if (cb) {
cb();
}
}
route(path, callback) {
this.routes[path] = callback || function () { };
}
go(path) {
// 跳转并执行对应的callback
window.history.pushState({
path
}, null, path);
const cb = this.routes[path]; // 这里pushState无法被popState监听
// cb && cb();
if (cb) {
cb();
}
}
_bindPopState() {
// 演示一下popstate事件触发后,会发生什么
window.addEventListener('popstate', (e) => {
const path = e.state && e.state.path;
console.log(`in popstate listener path=${path}`);
this.routes[path] && this.routes[path]();
})
}
}