一 浏览器原生history对象
浏览器原生的 history
对象提供了对浏览器会话历史的访问,允许你在不同的页面之间进行导航。以下是 history
对象的主要特性和方法:
主要特性
-
会话历史:
- 浏览器的会话历史记录包括用户在当前窗口或标签页中访问过的所有页面。
- 每个窗口或标签页都有自己的
history
对象。
-
状态管理:
history
对象可以存储每个历史记录条目的状态信息,这些状态信息可以是任何 JavaScript 对象。
主要方法
-
back()
:- 返回上一个历史记录条目,相当于点击浏览器的后退按钮。
javascriptwindow.history.back();
-
forward()
:- 前进到下一个历史记录条目,相当于点击浏览器的前进按钮。
javascriptwindow.history.forward();
-
go(delta)
:- 导航到指定的历史记录条目。
delta
是一个整数,表示相对于当前条目的偏移量。正数表示前进,负数表示后退。
javascriptwindow.history.go(-1); // 等同于 back() window.history.go(1); // 等同于 forward()
- 导航到指定的历史记录条目。
-
pushState(state, title, url)
:- 向历史记录栈中添加一个新的条目,但不会触发页面重新加载。
state
:一个 JavaScript 对象,用于存储与新历史记录条目关联的状态信息。title
:一个字符串,用于描述新历史记录条目。现代浏览器通常忽略此参数。url
:一个字符串,表示新历史记录条目的 URL。
javascriptwindow.history.pushState({ page: 1 }, "", "/page1");
-
replaceState(state, title, url)
:- 替换当前的历史记录条目,但不会触发页面重新加载。
- 参数与
pushState
相同。
javascriptwindow.history.replaceState({ page: 2 }, "", "/page2");
事件
-
popstate
事件 :- 当历史记录条目发生变化时(例如用户点击后退或前进按钮),会触发
popstate
事件。 - 事件对象的
state
属性包含与当前历史记录条目关联的状态信息。
javascriptwindow.addEventListener('popstate', (event) => { console.log('New state:', event.state); });
- 当历史记录条目发生变化时(例如用户点击后退或前进按钮),会触发
示例代码
以下是一个简单的示例,展示了如何使用 pushState
和 popstate
事件:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>History Example</title>
</head>
<body>
<button id="back">Back</button>
<button id="forward">Forward</button>
<button id="push">Push State</button>
<button id="replace">Replace State</button>
<script>
document.getElementById('back').addEventListener('click', () => {
window.history.back();
});
document.getElementById('forward').addEventListener('click', () => {
window.history.forward();
});
document.getElementById('push').addEventListener('click', () => {
window.history.pushState({ page: 1 }, "", "/page1");
});
document.getElementById('replace').addEventListener('click', () => {
window.history.replaceState({ page: 2 }, "", "/page2");
});
window.addEventListener('popstate', (event) => {
console.log('New state:', event.state);
});
</script>
</body>
</html>
总结
浏览器原生的 history
对象提供了强大的导航功能,允许你在不重新加载页面的情况下管理会话历史。通过 pushState
和 replaceState
方法,你可以动态地更新 URL 和历史记录,而 popstate
事件则允许你监听历史记录的变化。这些功能在单页应用(SPA)中特别有用。
二 window 可以监听那些 state事件
在浏览器中,window 对象可以监听多种与状态相关的事件。这些事件通常用于响应用户的交互或页面状态的变化。以下是常见的几种状态事件及其用途:
- popstate 事件 描述:当活动的历史记录条目更改时触发,通常是因为用户点击了浏览器的后退或前进按钮,或者通过 history.back()、history.forward()、history.go() 方法导航。 用途:常用于单页应用(SPA)中,当用户导航时更新应用的状态。 示例:
javascript
// javascript:
window.addEventListener('popstate', (event) => {
console.log('New state:', event.state);
});
- hashchange 事件 描述:当当前窗口或框架的 URL 的片段标识符(即哈希值,URL 中 # 后面的部分)改变时触发。 用途:常用于基于锚点的导航,例如在单页应用中切换不同的视图。 示例:
javascript
// javascript
window.addEventListener('hashchange', (event) => {
console.log('Old URL:', event.oldURL);
console.log('New URL:', event.newURL);
});
- beforeunload 事件 描述:在窗口、文档和资源即将被卸载时触发。这是一个询问用户是否确认离开页面的机会。 用途:常用于提示用户保存未保存的数据或确认是否离开页面。 示例:
ini
// javascript
window.addEventListener('beforeunload', (event) => {
// 设置对话框的文本
const message = '确定要离开吗?';
event.returnValue = message;
return message;
});
- unload 事件 描述:在窗口、文档和资源已经被卸载时触发。注意,由于安全原因,现代浏览器限制了在这个事件中可以做的事情。 用途:常用于清理资源或发送最后的请求。 示例:
javascript
// javascript
window.addEventListener('unload', (event) => {
console.log('Page is being unloaded.');
});
- pageshow 事件 描述:当一个页面被显示时触发。这包括页面首次加载和从缓存中恢复的情况。 用途:可以用来检测页面是首次加载还是从缓存中恢复。 示例:
javascript
// javascript
window.addEventListener('pageshow', (event) => {
if (event.persisted) {
console.log('Page is restored from cache.');
} else {
console.log('Page is loaded for the first time.');
}
});
- pagehide 事件 描述:当一个页面被隐藏时触发。这包括页面卸载和浏览器标签页切换的情况。 用途:可以用来检测页面是否被隐藏或卸载。 示例:
javascript
// javascript
window.addEventListener('pagehide', (event) => {
if (event.persisted) {
console.log('Page is being hidden but not unloaded.');
} else {
console.log('Page is being unloaded.');
}
});
总结 这些事件可以帮助你更好地控制和响应浏览器中的各种状态变化,特别是在开发单页应用(SPA)时非常有用。通过监听这些事件,你可以确保用户在导航或离开页面时得到适当的反馈和处理。
三 react-router-dom useHistory history 实现原理
react-router-dom
中的 useHistory
钩子提供了对浏览器历史记录对象的访问,允许你在 React 组件中导航。下面是 useHistory
和 history
对象实现原理的简要说明:
-
history
对象 :react-router-dom
内部使用了一个名为history
的库来管理浏览器的历史记录。这个库创建了一个history
对象,该对象封装了浏览器的window.history
API,并提供了额外的方法来操作历史记录。 -
useHistory
钩子 :useHistory
是一个 React 钩子,它从react-router-dom
的路由上下文中获取history
对象。这个钩子返回一个history
对象,你可以使用它来执行导航操作,如push
、replace
和goBack
等。
实现步骤
-
创建
history
对象:- 在
react-router-dom
初始化时,会创建一个history
对象。这个对象可以是浏览器的历史记录对象,也可以是内存中的历史记录对象(用于服务器端渲染或测试)。
- 在
-
提供
history
对象:react-router-dom
使用Router
组件将history
对象传递给所有嵌套的路由组件。这通常是通过BrowserRouter
或HashRouter
组件完成的。
-
使用
useHistory
钩子:- 在 React 组件中,你可以使用
useHistory
钩子来获取history
对象。这个钩子会从当前的路由上下文中读取history
对象,并将其返回给组件。
- 在 React 组件中,你可以使用
示例代码
jsx
import { useHistory } from 'react-router-dom';
function MyComponent() {
const history = useHistory();
function handleClick() {
history.push('/new-page');
}
return (
<button onClick={handleClick}>
Go to New Page
</button>
);
}
关键方法
push(path, [state])
:向历史记录栈中添加一个新的条目,并导航到该路径。replace(path, [state])
:替换当前的历史记录条目,而不是添加新的条目。goBack()
:返回上一个历史记录条目。goForward()
:前进到下一个历史记录条目。listen(listener)
:注册一个监听器,当历史记录发生变化时调用该监听器。
总结
useHistory
钩子通过 react-router-dom
提供的路由上下文,让你可以在 React 组件中方便地访问和操作浏览器的历史记录。这个钩子依赖于 history
库来管理历史记录,提供了丰富的导航功能。
五 送一个小小的原生js实现SPA小案例
history 怎么实现 SPA 应用,react vue 框架 其实也是这个原理
在单页应用(Single Page Application, SPA)中,history
对象是实现无刷新导航的关键。通过使用 history
API,你可以在不重新加载整个页面的情况下动态地更新 URL 和页面内容。以下是实现 SPA 应用中使用 history
的基本步骤和示例代码。
基本步骤
-
初始化历史记录管理:
- 创建一个
history
对象来管理应用的历史记录。
- 创建一个
-
设置初始路由:
- 根据当前的 URL 初始化应用的状态。
-
监听
popstate
事件:- 监听
popstate
事件,以便在用户点击浏览器的后退或前进按钮时更新应用的状态。
- 监听
-
定义路由和路由处理函数:
- 定义应用的路由和相应的处理函数,用于根据 URL 更新页面内容。
-
导航函数:
- 提供导航函数,用于在应用内部导航到不同的路由。
示例代码
以下是一个简单的示例,展示了如何使用 history
API 实现一个基本的 SPA 应用。
HTML 结构
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SPA Example</title>
</head>
<body>
<nav>
<a href="#/home" onclick="navigate('/home')">Home</a>
<a href="#/about" onclick="navigate('/about')">About</a>
<a href="#/contact" onclick="navigate('/contact')">Contact</a>
</nav>
<div id="app"></div>
<script src="app.js"></script>
</body>
</html>
JavaScript 逻辑
javascript
// app.js
// 初始化历史记录
const history = window.history;
// 获取当前路径
const currentPath = window.location.pathname;
// 路由配置
const routes = {
'/home': () => renderContent('<h1>Home Page</h1>'),
'/about': () => renderContent('<h1>About Page</h1>'),
'/contact': () => renderContent('<h1>Contact Page</h1>')
};
// 渲染内容的函数
function renderContent(content) {
document.getElementById('app').innerHTML = content;
}
// 导航函数
function navigate(path) {
history.pushState({}, '', path);
handleRoute(path);
}
// 处理路由
function handleRoute(path) {
const routeHandler = routes[path] || routes['/404'];
routeHandler();
}
// 初始化应用
function initApp() {
handleRoute(currentPath);
// 监听 popstate 事件
window.addEventListener('popstate', (event) => {
handleRoute(window.location.pathname);
});
}
// 启动应用
initApp();
详细解释
-
HTML 结构:
- 包含一个简单的导航栏和一个用于显示内容的
div
元素。 - 导航链接使用
onclick
事件调用navigate
函数,而不是默认的链接行为。
- 包含一个简单的导航栏和一个用于显示内容的
-
JavaScript 逻辑:
- 初始化历史记录 :使用
window.history
对象来管理历史记录。 - 获取当前路径 :使用
window.location.pathname
获取当前的 URL 路径。 - 路由配置 :定义一个对象
routes
,其中键是路径,值是对应的处理函数。 - 渲染内容的函数 :
renderContent
函数用于将内容渲染到div
元素中。 - 导航函数 :
navigate
函数使用history.pushState
方法更新 URL 并调用handleRoute
函数来处理新的路径。 - 处理路由 :
handleRoute
函数根据路径调用相应的处理函数。 - 初始化应用 :
initApp
函数初始化应用,处理初始路径并监听popstate
事件。
- 初始化历史记录 :使用
总结
通过使用 history
API,你可以实现一个基本的 SPA 应用,实现在不重新加载页面的情况下动态更新 URL 和页面内容。这种方法在现代前端框架(如 React、Vue 和 Angular)中也非常常见,它们通常内置了更高级的路由管理功能。
PS:学会了记得,点赞,评论,收藏,分享