Skip to content

Commit ede32d0

Browse files
feat: 移除 Swup 相关功能,添加 PJAX 导航支持
Signed-off-by: wangsimiao1 <wangsimiao1@xiaomi.com>
1 parent 3a0ad52 commit ede32d0

8 files changed

Lines changed: 123 additions & 125 deletions

File tree

_javascript/commons.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { basic, initSidebar, initTopbar, initSwup } from './modules/layouts';
1+
import { basic, initSidebar, initTopbar, initPjax } from './modules/layouts';
22

33
initSidebar();
44
initTopbar();
55
basic();
6-
initSwup();
6+
initPjax();

_javascript/modules/layouts.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export { basic } from './layouts/basic';
22
export { initSidebar } from './layouts/sidebar';
33
export { initTopbar } from './layouts/topbar';
4-
export { initSwup } from './layouts/swup-setup';
4+
export { initPjax } from './layouts/pjax';
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/**
2+
* Lightweight PJAX-like navigation
3+
* Intercepts internal link clicks, fetches new page via AJAX,
4+
* replaces only the #swup container content, and updates title/URL.
5+
*/
6+
7+
const CONTAINER_ID = 'swup';
8+
const TRANSITION_DURATION = 150; // ms
9+
10+
let isNavigating = false;
11+
12+
function shouldIntercept(el) {
13+
// Only intercept internal same-origin links
14+
if (!el || el.tagName !== 'A') return false;
15+
if (el.target === '_blank' || el.hasAttribute('download')) return false;
16+
if (el.origin !== window.location.origin) return false;
17+
// Skip anchor links on same page
18+
if (el.pathname === window.location.pathname && el.hash) return false;
19+
return true;
20+
}
21+
22+
function updateActiveNav(path) {
23+
document.querySelectorAll('#sidebar .nav-item').forEach((item) => {
24+
const link = item.querySelector('a');
25+
if (!link) return;
26+
const href = link.getAttribute('href');
27+
const isActive =
28+
(href === '/' && path === '/') ||
29+
(href !== '/' && path.startsWith(href));
30+
item.classList.toggle('active', isActive);
31+
});
32+
}
33+
34+
async function navigate(url, pushState = true) {
35+
if (isNavigating) return;
36+
isNavigating = true;
37+
38+
const container = document.getElementById(CONTAINER_ID);
39+
if (!container) {
40+
// Fallback to normal navigation
41+
window.location.href = url;
42+
return;
43+
}
44+
45+
try {
46+
// Fade out
47+
container.style.opacity = '0';
48+
49+
// Fetch new page
50+
const response = await fetch(url);
51+
if (!response.ok) {
52+
window.location.href = url;
53+
return;
54+
}
55+
56+
const html = await response.text();
57+
const parser = new DOMParser();
58+
const doc = parser.parseFromString(html, 'text/html');
59+
60+
const newContainer = doc.getElementById(CONTAINER_ID);
61+
if (!newContainer) {
62+
window.location.href = url;
63+
return;
64+
}
65+
66+
// Wait for fade out to finish
67+
await new Promise((r) => setTimeout(r, TRANSITION_DURATION));
68+
69+
// Replace content
70+
container.innerHTML = newContainer.innerHTML;
71+
72+
// Update title
73+
document.title = doc.title;
74+
75+
// Update URL
76+
if (pushState) {
77+
history.pushState({}, '', url);
78+
}
79+
80+
// Update sidebar active state
81+
updateActiveNav(new URL(url, window.location.origin).pathname);
82+
83+
// Scroll to top
84+
window.scrollTo({ top: 0 });
85+
86+
// Fade in
87+
container.style.opacity = '1';
88+
} catch (e) {
89+
// On any error, fall back to normal navigation
90+
window.location.href = url;
91+
} finally {
92+
isNavigating = false;
93+
}
94+
}
95+
96+
export function initPjax() {
97+
// Intercept clicks on internal links
98+
document.addEventListener('click', (e) => {
99+
const link = e.target.closest('a');
100+
if (!shouldIntercept(link)) return;
101+
102+
e.preventDefault();
103+
104+
// Skip if same page
105+
if (link.href === window.location.href) return;
106+
107+
navigate(link.href);
108+
});
109+
110+
// Handle browser back/forward
111+
window.addEventListener('popstate', () => {
112+
navigate(window.location.href, false);
113+
});
114+
}

_javascript/modules/layouts/swup-setup.js

Lines changed: 0 additions & 42 deletions
This file was deleted.

_layouts/default.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<div class="container d-flex flex-column px-xxl-5">
2424
{% include topbar.html lang=lang %}
2525

26-
<div id="swup" class="swup-transition-main">
26+
<div id="swup">
2727
<div class="row flex-grow-1">
2828
<main aria-label="Main Content" class="col-12 col-lg-11 col-xl-9 px-md-4">
2929
{% if layout.layout == 'default' %}

_sass/components/_swup.scss

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
/* Swup page transition */
2-
.swup-transition-main {
1+
/* PJAX page transition */
2+
#swup {
33
opacity: 1;
4-
transition: opacity 0.2s ease-in-out;
5-
}
6-
7-
html.is-changing .swup-transition-main {
8-
opacity: 0;
4+
transition: opacity 0.15s ease-in-out;
95
}

package-lock.json

Lines changed: 1 addition & 69 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
"rollup": "^4.12.0"
2525
},
2626
"dependencies": {
27-
"@swup/head-plugin": "^2.3.1",
28-
"bootstrap": "^5.3.3",
29-
"swup": "^4.8.3"
27+
"bootstrap": "^5.3.3"
3028
}
3129
}

0 commit comments

Comments
 (0)