<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>混合浏览器方案</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Segoe UI', sans-serif;
background: #f0f2f5;
height: 100vh;
display: flex;
flex-direction: column;
}
.toolbar {
background: white;
padding: 12px 20px;
border-bottom: 1px solid #ddd;
display: flex;
gap: 10px;
align-items: center;
flex-wrap: wrap;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
z-index: 10;
}
.toolbar input {
flex: 1;
padding: 10px 16px;
border: 2px solid #ddd;
border-radius: 24px;
font-size: 14px;
outline: none;
min-width: 200px;
}
.toolbar input:focus {
border-color: #4a90d9;
}
.toolbar button {
padding: 10px 20px;
background: #4a90d9;
color: white;
border: none;
border-radius: 24px;
cursor: pointer;
font-weight: 600;
transition: 0.2s;
white-space: nowrap;
}
.toolbar button:hover {
background: #357abd;
transform: scale(0.98);
}
.toolbar .btn-secondary {
background: #6c757d;
}
.toolbar .btn-secondary:hover {
background: #5a6268;
}
.toolbar .mode-switch {
display: flex;
gap: 6px;
background: #e9ecef;
padding: 4px;
border-radius: 24px;
}
.toolbar .mode-switch button {
background: transparent;
color: #495057;
padding: 6px 14px;
border-radius: 20px;
font-size: 12px;
}
.toolbar .mode-switch button.active {
background: white;
color: #4a90d9;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.viewport {
flex: 1;
position: relative;
background: white;
}
.viewport iframe {
width: 100%;
height: 100%;
border: none;
}
.status-bar {
background: #f8f9fa;
padding: 6px 20px;
border-top: 1px solid #ddd;
font-size: 12px;
color: #6c757d;
display: flex;
justify-content: space-between;
}
.badge {
display: inline-block;
padding: 2px 10px;
border-radius: 12px;
font-size: 11px;
font-weight: 600;
}
.badge-same { background: #d4edda; color: #155724; }
.badge-cross { background: #fff3cd; color: #856404; }
.badge-external { background: #cce5ff; color: #004085; }
@media (max-width: 768px) {
.toolbar { padding: 10px 12px; }
.toolbar input { font-size: 13px; padding: 8px 12px; }
.toolbar button { padding: 8px 14px; font-size: 13px; }
.mode-switch button { font-size: 11px; padding: 4px 10px; }
}
</style>
</head>
<body>
<div class="toolbar">
<div class="mode-switch">
<button class="active" data-mode="iframe" id="modeIframe">📦 内嵌</button>
<button data-mode="newtab" id="modeNewtab">🔄 新窗口</button>
</div>
<input type="text" id="urlInput" placeholder="输入网址,如 https://google.com" value="https://example.com">
<button id="loadBtn">🚀 加载</button>
<button class="btn-secondary" id="reloadBtn">🔄 刷新</button>
<button class="btn-secondary" id="externalBtn">🌐 外部打开</button>
</div>
<div class="viewport" id="viewport">
<iframe id="webFrame"
sandbox="allow-same-origin allow-scripts allow-popups allow-forms allow-modals allow-top-navigation allow-top-navigation-by-user-activation"
loading="lazy"></iframe>
</div>
<div class="status-bar">
<span id="statusText">✅ 就绪</span>
<span>
<span class="badge badge-same" id="modeBadge">📦 内嵌模式</span>
<span id="urlDisplay" style="margin-left: 12px;">https://example.com</span>
</span>
</div>
<script>
(function() {
const DOM = {
input: document.getElementById('urlInput'),
frame: document.getElementById('webFrame'),
viewport: document.getElementById('viewport'),
loadBtn: document.getElementById('loadBtn'),
reloadBtn: document.getElementById('reloadBtn'),
externalBtn: document.getElementById('externalBtn'),
statusText: document.getElementById('statusText'),
urlDisplay: document.getElementById('urlDisplay'),
modeBadge: document.getElementById('modeBadge'),
modeIframe: document.getElementById('modeIframe'),
modeNewtab: document.getElementById('modeNewtab')
};
let currentMode = 'iframe'; // 'iframe' | 'newtab'
let currentUrl = 'https://example.com';
function sanitizeUrl(raw) {
if (!raw || raw.trim() === '') return null;
let url = raw.trim();
if (!/^https?:\/\//i.test(url)) {
if (/^[a-z0-9-]+\.[a-z]{2,}/i.test(url)) {
url = 'https://' + url;
} else {
url = 'https://' + url;
}
}
return url;
}
function loadUrl(url) {
const sanitized = sanitizeUrl(url);
if (!sanitized) {
DOM.statusText.textContent = '⚠️ 无效网址';
return;
}
currentUrl = sanitized;
DOM.input.value = sanitized;
DOM.urlDisplay.textContent = sanitized;
if (currentMode === 'iframe') {
// 内嵌模式
DOM.frame.src = sanitized;
DOM.statusText.textContent = '⏳ 加载中...';
DOM.viewport.style.display = 'block';
} else {
// 新窗口模式 - 直接跳转
window.open(sanitized, '_blank');
DOM.statusText.textContent = '🔗 已在新窗口打开';
}
}
function reloadCurrent() {
if (currentMode === 'iframe') {
DOM.frame.src = currentUrl;
DOM.statusText.textContent = '🔄 刷新中...';
} else {
window.open(currentUrl, '_blank');
DOM.statusText.textContent = '🔗 已在新窗口重新打开';
}
}
function openExternal() {
if (currentUrl) {
window.open(currentUrl, '_blank');
DOM.statusText.textContent = '🌐 已在新窗口打开';
}
}
// 监听iframe加载
DOM.frame.addEventListener('load', function() {
DOM.statusText.textContent = '✅ 加载完成';
// 尝试获取URL(同源)
try {
const frameUrl = this.contentWindow?.location?.href;
if (frameUrl && frameUrl.startsWith('http')) {
currentUrl = frameUrl;
DOM.input.value = frameUrl;
DOM.urlDisplay.textContent = frameUrl;
DOM.statusText.textContent = '✅ 同源 · 地址已同步';
DOM.modeBadge.textContent = '🔗 同源';
DOM.modeBadge.className = 'badge badge-same';
}
} catch (_) {
// 跨域
DOM.statusText.textContent = '🌐 跨域 · 地址可能未同步';
DOM.modeBadge.textContent = '🌐 跨域';
DOM.modeBadge.className = 'badge badge-cross';
}
});
// 模式切换
DOM.modeIframe.addEventListener('click', function() {
currentMode = 'iframe';
DOM.modeIframe.classList.add('active');
DOM.modeNewtab.classList.remove('active');
DOM.modeBadge.textContent = '📦 内嵌模式';
DOM.modeBadge.className = 'badge badge-same';
DOM.viewport.style.display = 'block';
loadUrl(currentUrl);
});
DOM.modeNewtab.addEventListener('click', function() {
currentMode = 'newtab';
DOM.modeNewtab.classList.add('active');
DOM.modeIframe.classList.remove('active');
DOM.modeBadge.textContent = '🔄 新窗口模式';
DOM.modeBadge.className = 'badge badge-external';
DOM.viewport.style.display = 'none';
DOM.statusText.textContent = '📌 点击加载将在新窗口打开';
// 不清除iframe,但隐藏
});
// 事件绑定
DOM.loadBtn.addEventListener('click', function() {
loadUrl(DOM.input.value);
});
DOM.input.addEventListener('keydown', function(e) {
if (e.key === 'Enter') {
loadUrl(this.value);
}
});
DOM.reloadBtn.addEventListener('click', reloadCurrent);
DOM.externalBtn.addEventListener('click', openExternal);
// 初始化
loadUrl('https://example.com');
// 提示
console.log('💡 提示:\n- "内嵌模式":在iframe中显示,同源可同步地址\n- "新窗口模式":直接在浏览器新标签页打开,完全跳转\n- 跨域网站建议使用"新窗口模式"');
})();
</script>
</body>
</html>
推荐编译环境:菜鸟教程在线编辑器
或者保存个文本文档再把后缀名改成.html也行
不建议套娃,因为越往里越卡,一般三层就动不了了
