单页应用(SPA)的核心特性之一就是无刷新页面切换,这主要通过以下几种技术实现:
// 路由切换函数
function navigate(path) {
// 1. 更新页面内容
loadPageContent(path);
// 2. 修改浏览器历史记录
window.history.pushState({ path }, null, path);
}
// 加载页面内容
function loadPageContent(path) {
// 这里可以是AJAX请求或直接显示预加载的内容
fetch(`/api/content?path=${path}`)
.then(response => response.text())
.then(html => {
document.getElementById('app').innerHTML = html;
});
}
// 监听popstate事件处理前进/后退
window.addEventListener('popstate', (e) => {
if (e.state) {
loadPageContent(e.state.path);
}
});
// 拦截所有链接点击
document.addEventListener('click', (e) => {
if (e.target.tagName === 'A' && e.target.href.startsWith(window.location.origin)) {
e.preventDefault();
navigate(e.target.pathname);
}
});
推荐使用成熟的路由库简化开发:
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
function App() {
return (
<Router>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
</Router>
);
}
const router = new VueRouter({
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About }
]
});
const app = new Vue({
router
}).$mount('#app');
// CSS
.page {
transition: opacity 0.3s ease;
}
.page-enter {
opacity: 0;
}
.page-enter-active {
opacity: 1;
}
.page-exit {
opacity: 1;
}
.page-exit-active {
opacity: 0;
}
// JavaScript
function transitionPages(newPage) {
const currentPage = document.querySelector('.page.active');
currentPage.classList.remove('active');
currentPage.classList.add('page-exit');
newPage.classList.add('page-enter', 'active');
setTimeout(() => {
currentPage.classList.remove('page-exit');
newPage.classList.remove('page-enter');
}, 300);
}
// 主应用结构
class SPA {
constructor(routes) {
this.routes = routes;
this.initRouter();
this.initEventListeners();
}
initRouter() {
// 初始加载
this.navigate(window.location.pathname);
// 监听前进后退
window.addEventListener('popstate', () => {
this.navigate(window.location.pathname, false);
});
}
initEventListeners() {
document.addEventListener('click', (e) => {
if (e.target.tagName === 'A' && e.target.href.startsWith(window.location.origin)) {
e.preventDefault();
this.navigate(e.target.pathname);
}
});
}
navigate(path, pushState = true) {
const route = this.routes.find(r => r.path === path) || this.routes.find(r => r.path === '/*');
// 更新DOM
document.getElementById('app').innerHTML = route.component();
// 更新浏览器历史
if (pushState) {
window.history.pushState({}, '', path);
}
}
}
// 使用示例
new SPA([
{ path: '/', component: () => '<h1>Home Page</h1>' },
{ path: '/about', component: () => '<h1>About Us</h1>' },
{ path: '/*', component: () => '<h1>404 Not Found</h1>' }
]);
以上方案可以根据项目需求进行组合和调整,现代前端框架通常已经内置了路由解决方案,建议优先使用框架提供的路由功能。