fix(navigation): 修复布局偏移和事件跳转问题

- 移除 .navigation-wrapper 的 flex/min-height 布局干扰
- 确保 main-content 不受侧边栏占位影响
- 优化事件处理,增加点击日志
- 修复 admin 导航页面名称不一致问题
This commit is contained in:
lt
2026-05-08 12:30:49 +08:00
parent beb2cf2473
commit c85320ae72
+82 -64
View File
@@ -1,57 +1,16 @@
// 公共导航组件(调试版) // Vue 3 导航组件 - 修复布局和事件
const NavigationComponent = { (function() {
name: 'NavigationComponent', console.log('[Nav] 脚本加载');
props: {
currentPage: { type: String, required: true },
isAdmin: { type: Boolean, default: false }
},
mounted() {
console.log('[NavigationComponent] 已挂载');
console.log('[NavigationComponent] currentPage:', this.currentPage, 'isAdmin:', this.isAdmin);
},
render() {
console.log('[NavigationComponent] render called');
const h = this.$createElement;
const navigate = (page) => this.$emit('navigate', page === 'dashboard' ? '/' : page + '.html');
const sidebarItems = [
{ icon: '📊', label: '系统概览', page: 'dashboard' },
{ icon: '📋', label: '选题管理', page: 'topics' },
{ icon: '📄', label: '系统日志', page: 'logs' },
...(this.isAdmin ? [{ icon: '👥', label: '用户管理', page: 'users' }, { icon: '⚙️', label: '系统管理', page: 'admin' }] : [])
];
const mobileItems = [
{ icon: '📊', label: '', page: 'dashboard' },
{ icon: '📋', label: '选题', page: 'topics' },
{ icon: '📄', label: '日志', page: 'logs' },
...(this.isAdmin ? [{ icon: '👥', label: '用户', page: 'users' }, { icon: '⚙️', label: '系统', page: 'admin' }] : [])
];
return h('div', { class: 'navigation-wrapper' }, [
h('aside', { class: 'sidebar' }, [
h('div', { class: 'sidebar-header' }, [h('h3', '宇之然平台')]),
h('nav', { class: 'sidebar-nav' }, sidebarItems.map(item => {
const isActive = this.currentPage === item.page;
return h('button', { class: isActive ? 'sidebar-btn active' : 'sidebar-btn', on: { click: () => navigate(item.page) } }, [item.icon, ' ', item.label].join(''));
}))
]),
h('nav', { class: 'mobile-nav' }, mobileItems.map(item => {
const isActive = this.currentPage === item.page;
const content = item.label ? [item.icon, item.label].join('') : item.icon;
return h('button', { class: isActive ? 'mobile-nav-btn active' : 'mobile-nav-btn', on: { click: () => navigate(item.page) } }, content);
}))
]);
}
};
function injectNavigationStyles() { function injectStyles() {
if (document.getElementById('navigation-styles')) { if (document.getElementById('navigation-styles')) return;
console.log('[Nav] 样式已存在,跳过注入');
return;
}
const styles = ` const styles = `
/* 重置导航包装器,使用常规布局 */
.navigation-wrapper { position: relative; } .navigation-wrapper { position: relative; }
.navigation-wrapper .sidebar { .navigation-wrapper .sidebar {
width: 180px; background: white; padding: 12px; box-shadow: 2px 0 8px rgba(0,0,0,0.05); position: fixed; top: 60px; left: 0; bottom: 0; width: 180px;
position: fixed; left: 0; top: 60px; bottom: 0; overflow-y: auto; z-index: 9999; background: #ffffff; padding: 12px; box-shadow: 2px 0 8px rgba(0,0,0,0.1);
overflow-y: auto; z-index: 99999; border-right: 1px solid #ebeef5;
} }
.navigation-wrapper .sidebar-header { padding: 12px 8px 16px; border-bottom: 1px solid #ebeef5; margin-bottom: 12px; } .navigation-wrapper .sidebar-header { padding: 12px 8px 16px; border-bottom: 1px solid #ebeef5; margin-bottom: 12px; }
.navigation-wrapper .sidebar-header h3 { margin: 0; font-size: 16px; font-weight: 600; color: #303133; } .navigation-wrapper .sidebar-header h3 { margin: 0; font-size: 16px; font-weight: 600; color: #303133; }
@@ -60,37 +19,96 @@ function injectNavigationStyles() {
margin-bottom: 6px; cursor: pointer; transition: all 0.3s; color: #606266; font-size: 14px; display: flex; align-items: center; gap: 6px; margin-bottom: 6px; cursor: pointer; transition: all 0.3s; color: #606266; font-size: 14px; display: flex; align-items: center; gap: 6px;
} }
.navigation-wrapper .sidebar-btn:hover { background: #f5f7fa; color: #409eff; } .navigation-wrapper .sidebar-btn:hover { background: #f5f7fa; color: #409eff; }
.navigation-wrapper .sidebar-btn.active { background: #ecf5ff; color: #409eff; font-weight: 600; } .navigation-wrapper .sidebar-btn.active { background: #ecf5ff; color: #409eff; font-weight: 600 !important; }
.navigation-wrapper .mobile-nav { .navigation-wrapper .mobile-nav {
display: none; position: fixed; bottom: 0; left: 0; right: 0; background: white; display: none; position: fixed; bottom: 0; left: 0; right: 0; background: white;
box-shadow: 0 -2px 8px rgba(0,0,0,0.1); padding: 8px 0; z-index: 1000; justify-content: space-around; box-shadow: 0 -2px 8px rgba(0,0,0,0.1); padding: 8px 0; z-index: 99999; justify-content: space-around;
} }
.navigation-wrapper .mobile-nav-btn { .navigation-wrapper .mobile-nav-btn {
flex: 1; border: none; background: transparent; padding: 10px 4px; text-align: center; flex: 1; border: none; background: transparent; padding: 10px 4px; text-align: center;
font-size: 11px; color: #606266; cursor: pointer; display: flex; flex-direction: column; align-items: center; gap: 2px; font-size: 11px; color: #606266; cursor: pointer; display: flex; flex-direction: column; align-items: center; gap: 2px;
} }
.navigation-wrapper .mobile-nav-btn:hover { color: #409eff; } .navigation-wrapper .mobile-nav-btn:hover { color: #409eff; }
.navigation-wrapper .mobile-nav-btn.active { color: #409eff; font-weight: 600; } .navigation-wrapper .mobile-nav-btn.active { color: #409eff; font-weight: 600 !important; }
@media (max-width: 768px) { .navigation-wrapper .sidebar { display: none !important; } .navigation-wrapper .mobile-nav { display: flex !important; } } @media (max-width: 768px) {
.navigation-wrapper .sidebar { display: none !important; }
.navigation-wrapper .mobile-nav { display: flex !important; }
}
@media (min-width: 769px) { .navigation-wrapper .mobile-nav { display: none !important; } } @media (min-width: 769px) { .navigation-wrapper .mobile-nav { display: none !important; } }
.navigation-wrapper + .main-content { margin-left: 180px !important; } /* 侧边栏固定定位时不调整主内容,让 main-content 自然位于文档流中,仅需确保 padding-top 避开 navbar */
@media (max-width: 768px) { .navigation-wrapper + .main-content { margin-left: 0 !important; padding-bottom: 60px !important; } } body > #app > .main-content { padding-top: 0; }
`; `;
const styleEl = document.createElement('style'); const styleEl = document.createElement('style');
styleEl.id = 'navigation-styles'; styleEl.id = 'navigation-styles';
styleEl.textContent = styles; styleEl.textContent = styles;
document.head.appendChild(styleEl); document.head.appendChild(styleEl);
console.log('[Nav] 样式已注入'); console.log('[Nav] 样式已注入');
} }
function installNavigation(app) { function getHFromApp(app) {
try {
if (app._context && app._context.h) return app._context.h;
if (app._instance && app._instance.proxy && app._instance.proxy._cf) return app._instance.proxy._cf;
} catch (e) { console.warn('[Nav] 获取 h 失败', e); }
return null;
}
const installNavigation = (app) => {
console.log('[Nav] installNavigation called'); console.log('[Nav] installNavigation called');
injectNavigationStyles(); injectStyles();
app.component('navigation-component', NavigationComponent); const h = getHFromApp(app) || (window.Vue && Vue.h) || function(tag, data, children) {
const el = document.createElement(tag);
if (data && data.class) el.className = data.class;
if (children) {
if (Array.isArray(children)) children.forEach(c => { if (typeof c === 'string') el.appendChild(document.createTextNode(c)); else if (c && c.nodeType) el.appendChild(c); });
else if (typeof children === 'string') el.textContent = children;
}
if (data && data.on) Object.keys(data.on).forEach(ev => el.addEventListener(ev, data.on[ev]));
};
console.log('[Nav] 使用 h 函数:', typeof h);
const component = {
name: 'NavigationComponent',
props: { currentPage: { type: String, required: true }, isAdmin: { type: Boolean, default: false } },
mounted() { console.log('[NavigationComponent] 已挂载'); },
render() {
const navigate = (page) => {
console.log('[NavigationComponent] 导航到:', page);
this.$emit('navigate', page);
};
const sidebarItems = [
{ icon: '📊', label: '系统概览', page: '/' },
{ icon: '📋', label: '选题管理', page: 'topics.html' },
{ icon: '📄', label: '系统日志', page: 'logs.html' },
...(this.isAdmin ? [{ icon: '👥', label: '用户管理', page: 'users.html' }, { icon: '⚙️', label: '系统管理', page: 'admin.html' }] : [])
];
const mobileItems = [
{ icon: '📊', label: '', page: '/' },
{ icon: '📋', label: '选题', page: 'topics.html' },
{ icon: '📄', label: '日志', page: 'logs.html' },
...(this.isAdmin ? [{ icon: '👥', label: '用户', page: 'users.html' }, { icon: '⚙️', label: '系统', page: 'admin.html' }] : [])
];
return h('div', { class: 'navigation-wrapper' }, [
h('aside', { class: 'sidebar' }, [
h('div', { class: 'sidebar-header' }, [h('h3', '宇之然平台')]),
h('nav', { class: 'sidebar-nav' }, sidebarItems.map(item => {
const isActive = this.currentPage === (item.page === '/' ? 'dashboard' : item.page.replace('.html',''));
return h('button', { key: item.page, class: isActive ? 'sidebar-btn active' : 'sidebar-btn', on: { click: () => navigate(item.page) } }, item.icon + ' ' + item.label);
}))
]),
h('nav', { class: 'mobile-nav' }, mobileItems.map(item => {
const isActive = this.currentPage === (item.page === '/' ? 'dashboard' : item.page.replace('.html',''));
const content = item.label ? (item.icon + ' ' + item.label) : item.icon;
return h('button', { key: item.page, class: isActive ? 'mobile-nav-btn active' : 'mobile-nav-btn', on: { click: () => navigate(item.page) } }, content);
}))
]);
}
};
app.component('navigation-component', component);
console.log('[Nav] 组件已注册'); console.log('[Nav] 组件已注册');
return app; return app;
} };
window.NavigationComponent = NavigationComponent; window.installNavigation = installNavigation;
window.installNavigation = installNavigation; console.log('[Nav] 脚本已加载');
console.log('[Nav] 脚本已加载'); })();