Skip to content

Commit 2cc031b

Browse files
New:非本站链接跳转确认弹窗
1 parent ee53584 commit 2cc031b

1 file changed

Lines changed: 138 additions & 0 deletions

File tree

src/layouts/Layout.astro

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,40 @@ const backgroundStyle = pageBackgroundConfig.enable
207207
<ConfigCarrier></ConfigCarrier>
208208
<slot />
209209

210+
<!-- 安全跳转提示弹窗 -->
211+
<div id="safe-redirect-modal" class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm hidden">
212+
<div class="bg-[var(--card-bg)] rounded-lg shadow-lg p-6 max-w-md w-full mx-4 border border-[var(--line-divider)] relative">
213+
<!-- 关闭按钮 -->
214+
<button id="redirect-close" class="absolute top-3 right-3 text-[var(--text-75)] hover:text-[var(--text-90)] transition-colors">
215+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
216+
<line x1="18" y1="6" x2="6" y2="18"></line>
217+
<line x1="6" y1="6" x2="18" y2="18"></line>
218+
</svg>
219+
</button>
220+
<div class="flex items-center gap-2 mb-4">
221+
<div class="text-green-500">
222+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
223+
<polyline points="20 6 9 17 4 12"></polyline>
224+
</svg>
225+
</div>
226+
<h3 class="text-lg font-bold text-[var(--text-90)]">安全跳转提示</h3>
227+
</div>
228+
<p class="text-[var(--text-75)] mb-4">您即将访问外部链接:</p>
229+
<div class="bg-[var(--btn-card-bg-hover)] rounded-md p-3 mb-4 break-all">
230+
<span id="external-link-url" class="text-sm"></span>
231+
</div>
232+
<div class="bg-green-50 border border-green-200 text-green-800 rounded-md p-3 mb-4 flex items-center gap-2">
233+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
234+
<polyline points="20 6 9 17 4 12"></polyline>
235+
</svg>
236+
<span class="text-sm">外部链接使用 HTTPS 加密连接</span>
237+
</div>
238+
<button id="redirect-confirm" class="w-full bg-green-500 hover:bg-green-600 text-white font-medium py-2 px-4 rounded-md transition-colors">
239+
立即前往
240+
</button>
241+
</div>
242+
</div>
243+
210244
<!-- increase the page height during page transition to prevent the scrolling animation from jumping -->
211245
<div id="page-height-extend" class="hidden h-[300vh]"></div>
212246
</body>
@@ -598,6 +632,110 @@ window.onresize = () => {
598632
document.documentElement.style.setProperty('--banner-height-extend', `${offset}px`);
599633
}
600634

635+
// 安全跳转提示功能
636+
function initSafeRedirect() {
637+
const modal = document.getElementById('safe-redirect-modal');
638+
const urlDisplay = document.getElementById('external-link-url');
639+
const confirmBtn = document.getElementById('redirect-confirm');
640+
let redirectUrl = '';
641+
642+
// 关闭弹窗
643+
function closeModal() {
644+
if (modal) {
645+
modal.classList.add('hidden');
646+
}
647+
redirectUrl = '';
648+
}
649+
650+
// 确认跳转
651+
function confirmRedirect() {
652+
if (redirectUrl) {
653+
window.open(redirectUrl, '_blank');
654+
closeModal();
655+
}
656+
}
657+
658+
// 点击确认按钮
659+
if (confirmBtn) {
660+
confirmBtn.addEventListener('click', confirmRedirect);
661+
}
662+
663+
// 关闭按钮点击
664+
const closeBtn = document.getElementById('redirect-close');
665+
if (closeBtn) {
666+
closeBtn.addEventListener('click', closeModal);
667+
}
668+
669+
// 点击弹窗外部关闭
670+
if (modal) {
671+
modal.addEventListener('click', (e) => {
672+
if (e.target === modal) {
673+
closeModal();
674+
}
675+
});
676+
}
677+
678+
// 处理链接点击 - 使用捕获阶段确保最先执行
679+
function handleLinkClick(e: Event) {
680+
const target = e.target as HTMLElement;
681+
const anchor = target.closest('a');
682+
if (!anchor) return;
683+
684+
const href = anchor.getAttribute('href');
685+
if (!href || href.startsWith('#') || href.startsWith('javascript:')) return;
686+
687+
// 相对路径是内部链接
688+
if (href.startsWith('/')) {
689+
return;
690+
}
691+
692+
// 检查是否为外部链接
693+
try {
694+
const url = new URL(href, window.location.origin);
695+
const hostname = url.hostname;
696+
const isInternal = hostname === 'allen2030.com' || hostname.endsWith('.allen2030.com');
697+
698+
if (!isInternal && url.protocol.startsWith('http')) {
699+
// 立即阻止默认行为和传播
700+
e.preventDefault();
701+
e.stopPropagation();
702+
e.stopImmediatePropagation();
703+
704+
redirectUrl = href;
705+
706+
if (urlDisplay) {
707+
urlDisplay.textContent = href;
708+
}
709+
710+
if (modal) {
711+
modal.classList.remove('hidden');
712+
}
713+
}
714+
} catch (error) {
715+
console.error('Invalid URL:', error);
716+
}
717+
}
718+
719+
// 使用捕获阶段监听,确保在其他监听器之前执行
720+
document.addEventListener('click', handleLinkClick, true);
721+
}
722+
723+
// 确保DOM加载完成后初始化
724+
if (document.readyState === 'loading') {
725+
document.addEventListener('DOMContentLoaded', initSafeRedirect);
726+
} else {
727+
initSafeRedirect();
728+
}
729+
730+
// 页面切换时重新初始化
731+
if (window?.swup?.hooks) {
732+
window.swup.hooks.on('page:view', initSafeRedirect);
733+
} else {
734+
document.addEventListener('swup:enable', () => {
735+
window.swup.hooks.on('page:view', initSafeRedirect);
736+
});
737+
}
738+
601739
</script>
602740

603741
<script>

0 commit comments

Comments
 (0)