html
<!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;
font-family: Arial, sans-serif;
}
body {
display: flex;
height: 100vh;
overflow: hidden;
flex-direction: column;
}
/* 侧边栏样式 */
.sidebar {
width: 220px;
background-color: #2c3e50;
color: white;
transition: transform 0.3s ease;
z-index: 10;
overflow-y: auto;
height: 100%;
}
.sidebar-header {
padding: 20px;
font-size: 18px;
font-weight: bold;
border-bottom: 1px solid #34495e;
}
/* 导航分组样式 */
.nav-group {
margin: 10px 0;
}
.group-title {
padding: 15px 20px;
font-weight: bold;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
background-color: #34495e;
}
.group-title .arrow {
transition: transform 0.3s ease;
}
.group-title.expanded .arrow {
transform: rotate(90deg);
}
/* 子菜单样式 */
.submenu {
list-style: none;
display: none; /* 默认隐藏子菜单 */
background-color: #2c3e50;
}
.submenu.show {
display: block; /* 显示子菜单 */
}
.submenu li a {
display: block;
padding: 12px 35px; /* 缩进显示层级 */
color: #bdc3c7;
text-decoration: none;
transition: all 0.3s;
}
.submenu li a:hover,
.submenu li a.active {
background-color: #1abc9c;
color: white;
}
/* 主内容区 */
.main-container {
display: flex;
flex: 1;
overflow: hidden;
}
.main-content {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* 顶部导航 */
.top-nav {
height: 60px;
background-color: #3498db;
color: white;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.menu-toggle {
cursor: pointer;
font-size: 20px;
}
.user-info {
display: flex;
align-items: center;
gap: 10px;
}
/* 标签页样式 */
.tabs-container {
height: 40px;
background-color: #f8f9fa;
border-bottom: 1px solid #ddd;
display: flex;
align-items: center;
overflow-x: auto;
white-space: nowrap;
}
.tab {
display: inline-flex;
align-items: center;
padding: 0 15px;
height: 100%;
background-color: #fff;
border-right: 1px solid #ddd;
cursor: pointer;
transition: background-color 0.2s;
}
.tab.active {
background-color: #e9ecef;
border-bottom: 2px solid #3498db;
}
.tab-title {
margin-right: 8px;
}
.tab-close {
width: 16px;
height: 16px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
transition: background-color 0.2s;
}
.tab-close:hover {
background-color: #eee;
}
/* iframe 内容区域 */
.iframe-container {
flex: 1;
overflow: hidden;
position: relative;
}
.iframe-page {
width: 100%;
height: 100%;
border: none;
position: absolute;
top: 0;
left: 0;
display: none;
}
.iframe-page.active {
display: block;
}
/* 移动端适配 */
.media (max-width: 768px) {
.sidebar
{
position: absolute;
height: 100%;
transform: translateX(-100%);
}
.sidebar.show {
transform: translateX(0);
}
.tabs-container {
height: 36px;
}
}
</style>
</head>
<body>
<div class="main-container">
<!-- 侧边栏导航(两层结构) -->
<div class="sidebar" id="sidebar">
<div class="sidebar-header">管理系统</div>
<!-- 第一个分组 -->
<div class="nav-group">
<div class="group-title expanded" data-group="dashboard-group">
<span>控制台</span>
<span class="arrow">▶</span>
</div>
<ul class="submenu show" id="dashboard-group">
<li><a class="active" href="javascript:;" data-src="dashboard.html" data-title="仪表盘" data-id="dashboard">仪表盘</a></li>
<li><a href="javascript:;" data-src="statistics.html" data-title="数据统计" data-id="statistics">数据统计</a></li>
</ul>
</div>
<!-- 第二个分组 -->
<div class="nav-group">
<div class="group-title" data-group="user-group">
<span>用户管理</span>
<span class="arrow">▶</span>
</div>
<ul class="submenu" id="user-group">
<li><a href="javascript:;" data-src="users/list.html" data-title="用户列表" data-id="user-list">用户列表</a></li>
<li><a href="javascript:;" data-src="users/add.html" data-title="添加用户" data-id="user-add">添加用户</a></li>
<li><a href="javascript:;" data-src="users/roles.html" data-title="角色权限" data-id="user-roles">角色权限</a></li>
</ul>
</div>
<!-- 第三个分组 -->
<div class="nav-group">
<div class="group-title" data-group="product-group">
<span>产品管理</span>
<span class="arrow">▶</span>
</div>
<ul class="submenu" id="product-group">
<li><a href="javascript:;" data-src="products/list.html" data-title="产品列表" data-id="product-list">产品列表</a></li>
<li><a href="javascript:;" data-src="products/categories.html" data-title="产品分类" data-id="product-cate">产品分类</a></li>
</ul>
</div>
<!-- 第四个分组 -->
<div class="nav-group">
<div class="group-title" data-group="system-group">
<span>系统设置</span>
<span class="arrow">▶</span>
</div>
<ul class="submenu" id="system-group">
<li><a href="javascript:;" data-src="settings/basic.html" data-title="基本设置" data-id="setting-basic">基本设置</a></li>
<li><a href="javascript:;" data-src="settings/logs.html" data-title="操作日志" data-id="setting-log">操作日志</a></li>
<li><a href="javascript:;" data-src="https://www.baidu.com" data-title="外部链接" data-id="external-link">百度搜索</a></li>
</ul>
</div>
</div>
<!-- 主内容区域 -->
<div class="main-content">
<!-- 顶部导航栏 -->
<div class="top-nav">
<div class="menu-toggle" id="menuToggle">☰</div>
<div class="user-info">
<span>管理员</span>
</div>
</div>
<!-- 标签页容器 -->
<div class="tabs-container" id="tabsContainer">
<!-- 标签页会动态生成在这里 -->
</div>
<!-- iframe 容器 -->
<div class="iframe-container" id="iframeContainer">
<!-- iframe 页面会动态生成在这里 -->
</div>
</div>
</div>
<script>
// 获取DOM元素
const sidebar = document.getElementById('sidebar');
const menuToggle = document.getElementById('menuToggle');
const groupTitles = document.querySelectorAll('.group-title');
const submenuLinks = document.querySelectorAll('.submenu a');
const tabsContainer = document.getElementById('tabsContainer');
const iframeContainer = document.getElementById('iframeContainer');
// 存储打开的页面信息
let openedPages = [];
let activePageId = '';
// 初始化 - 打开默认页面
function init() {
const defaultLink = document.querySelector('.submenu a.active');
if (defaultLink) {
openPage(defaultLink);
}
}
// 侧边栏切换
menuToggle.addEventListener('click', () => {
sidebar.classList.toggle('show');
});
// 分组标题点击事件(展开/折叠子菜单)
groupTitles.forEach(title => {
title.addEventListener('click', () => {
const groupId = title.getAttribute('data-group');
const submenu = document.getElementById(groupId);
// 切换当前分组的展开状态
title.classList.toggle('expanded');
submenu.classList.toggle('show');
});
});
// 打开页面
function openPage(link) {
const pageId = link.getAttribute('data-id');
const pageTitle = link.getAttribute('data-title');
const pageSrc = link.getAttribute('data-src');
// 检查页面是否已打开
const existingPage = openedPages.find(page => page.id === pageId);
if (existingPage) {
// 如果已打开,切换到该页面
switchToPage(pageId);
return;
}
// 添加到打开的页面列表
openedPages.push({
id: pageId,
title: pageTitle,
src: pageSrc
});
// 创建标签页
createTab(pageId, pageTitle);
// 创建iframe
createIframe(pageId, pageSrc);
// 切换到新页面
switchToPage(pageId);
// 更新激活状态
updateActiveLink(pageId);
// 移动端自动关闭侧边栏
if (window.innerWidth <= 768) {
sidebar.classList.remove('show');
}
}
// 创建标签页
function createTab(pageId, title) {
const tab = document.createElement('div');
tab.className = 'tab';
tab.dataset.id = pageId;
tab.innerHTML = `
<span class="tab-title">${title}</span>
<span class="tab-close">×</span>
`;
// 标签点击事件
tab.addEventListener('click', (e) => {
if (!e.target.classList.contains('tab-close')) {
switchToPage(pageId);
}
});
// 关闭按钮点击事件
tab.querySelector('.tab-close').addEventListener('click', (e) => {
e.stopPropagation();
closePage(pageId);
});
tabsContainer.appendChild(tab);
}
// 创建iframe
function createIframe(pageId, src) {
const iframe = document.createElement('iframe');
iframe.className = 'iframe-page';
iframe.dataset.id = pageId;
iframe.src = src;
iframeContainer.appendChild(iframe);
}
// 切换到指定页面
function switchToPage(pageId) {
// 移除所有标签和iframe的激活状态
document.querySelectorAll('.tab').forEach(tab => {
tab.classList.remove('active');
});
document.querySelectorAll('.iframe-page').forEach(iframe => {
iframe.classList.remove('active');
});
// 设置当前页面为激活状态
document.querySelector(`.tab[data-id="${pageId}"]`).classList.add('active');
document.querySelector(`.iframe-page[data-id="${pageId}"]`).classList.add('active');
// 更新当前激活页面ID
activePageId = pageId;
// 更新侧边栏链接激活状态
updateActiveLink(pageId);
}
// 关闭页面
function closePage(pageId) {
// 如果关闭的是当前激活页面,需要切换到其他页面
if (pageId === activePageId) {
const currentIndex = openedPages.findIndex(page => page.id === pageId);
// 尝试切换到前一个页面,如果没有则切换到后一个
let newIndex = currentIndex > 0 ? currentIndex - 1 : currentIndex + 1;
if (openedPages[newIndex]) {
switchToPage(openedPages[newIndex].id);
}
}
// 从列表中移除
openedPages = openedPages.filter(page => page.id !== pageId);
// 移除标签和iframe
const tab = document.querySelector(`.tab[data-id="${pageId}"]`);
const iframe = document.querySelector(`.iframe-page[data-id="${pageId}"]`);
if (tab) tab.remove();
if (iframe) iframe.remove();
}
// 更新侧边栏链接激活状态
function updateActiveLink(pageId) {
submenuLinks.forEach(link => {
link.classList.remove('active');
if (link.getAttribute('data-id') === pageId) {
link.classList.add('active');
}
});
}
// 子菜单链接点击事件(打开或切换页面)
submenuLinks.forEach(link => {
link.addEventListener('click', () => {
openPage(link);
});
});
// 初始化页面
init();
</script>
</body>
</html>
这是基于: 极简后台模板 HTML+CSS+JS 纯手写 无第三方UI框架 复制粘贴即用 做了修改....
主要修改内容说明:
-
新增了标签页容器 (
.tabs-container),用于显示顶部标签页 -
修改了内容区域结构,使用多个 iframe 实现多页面同时加载
-
添加了页面管理逻辑,包括:
- 打开新页面(已打开则切换)
- 切换标签页
- 关闭标签页
- 标签页与侧边栏联动
-
核心功能特点:
- 点击侧边栏菜单会在顶部创建对应标签页
- 已打开的页面再次点击会直接切换
- 可通过标签页右上角关闭按钮关闭页面
- 关闭当前页面会自动切换到其他页面
- 侧边栏链接会与当前激活页面保持同步
-
保留了原有的响应式设计,在移动设备上仍可正常使用
您可以根据实际需求进一步调整样式和交互细节,比如添加标签页右键菜单、标签页拖拽排序等高级功能。
