feat(frontend): 抽离页眉为公共组件;修复导航点击事件
- 新增 navbar-component.js:固定页眉,统一标题、用户信息、退出按钮 - 重构所有页面(index/topics/logs/admin/users)使用 navbar-component - 清理原有 navbar 相关样式,避免冲突 - 导航组件增加 main-content padding-top 自动调整 - 修复导航按钮点击事件(确保 触发) - 导航组件样式强应用,解决遮挡和布局问题
This commit is contained in:
@@ -1,11 +1,10 @@
|
||||
// Vue 3 导航组件 - 修复布局和事件
|
||||
// Vue 3 导航组件 - 最终版(确保事件传递)
|
||||
(function() {
|
||||
console.log('[Nav] 脚本加载');
|
||||
|
||||
function injectStyles() {
|
||||
if (document.getElementById('navigation-styles')) return;
|
||||
const styles = `
|
||||
/* 重置导航包装器,使用常规布局 */
|
||||
.navigation-wrapper { position: relative; }
|
||||
.navigation-wrapper .sidebar {
|
||||
position: fixed; top: 60px; left: 0; bottom: 0; width: 180px;
|
||||
@@ -35,20 +34,8 @@
|
||||
.navigation-wrapper .mobile-nav { display: flex !important; }
|
||||
}
|
||||
@media (min-width: 769px) { .navigation-wrapper .mobile-nav { display: none !important; } }
|
||||
/* 主内容区域避开固定侧边栏 */
|
||||
body > #app > .navigation-wrapper + .main-content,
|
||||
body > #app > .main-content {
|
||||
margin-left: 180px !important;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
body > #app > .navigation-wrapper + .main-content,
|
||||
body > #app > .main-content {
|
||||
margin-left: 0 !important;
|
||||
padding-bottom: 60px !important;
|
||||
}
|
||||
}
|
||||
/* 侧边栏固定定位时不调整主内容,让 main-content 自然位于文档流中,仅需确保 padding-top 避开 navbar */
|
||||
body > #app > .main-content { padding-top: 0; }
|
||||
body > #app > .main-content { margin-left: 180px !important; padding-top: 60px !important; }
|
||||
@media (max-width: 768px) { body > #app > .main-content { margin-left: 0 !important; padding-bottom: 60px !important; } }
|
||||
`;
|
||||
const styleEl = document.createElement('style');
|
||||
styleEl.id = 'navigation-styles';
|
||||
@@ -76,6 +63,7 @@
|
||||
else if (typeof children === 'string') el.textContent = children;
|
||||
}
|
||||
if (data && data.on) Object.keys(data.on).forEach(ev => el.addEventListener(ev, data.on[ev]));
|
||||
return el;
|
||||
};
|
||||
console.log('[Nav] 使用 h 函数:', typeof h);
|
||||
|
||||
@@ -83,11 +71,23 @@
|
||||
name: 'NavigationComponent',
|
||||
props: { currentPage: { type: String, required: true }, isAdmin: { type: Boolean, default: false } },
|
||||
mounted() { console.log('[NavigationComponent] 已挂载'); },
|
||||
render() {
|
||||
render(){
|
||||
const createElement = arguments[0] || h;
|
||||
// 获取 emit 方法:通过 this.$emit 或从闭包中捕获
|
||||
const emit = this.$emit || function() {};
|
||||
|
||||
const navigate = (page) => {
|
||||
console.log('[NavigationComponent] 导航到:', page);
|
||||
this.$emit('navigate', page);
|
||||
console.log('[NavigationComponent] 点击导航到:', page);
|
||||
// 直接调用 emit 函数
|
||||
if (typeof emit === 'function') {
|
||||
emit('navigate', page);
|
||||
} else if (this.$emit) {
|
||||
this.$emit('navigate', page);
|
||||
} else {
|
||||
console.warn('[NavigationComponent] 无法发送事件,emit unavailable');
|
||||
}
|
||||
};
|
||||
|
||||
const sidebarItems = [
|
||||
{ icon: '📊', label: '系统概览', page: '/' },
|
||||
{ icon: '📋', label: '选题管理', page: 'topics.html' },
|
||||
@@ -100,22 +100,32 @@
|
||||
{ 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 => {
|
||||
|
||||
return createElement('div', { class: 'navigation-wrapper' }, [
|
||||
createElement('aside', { class: 'sidebar' }, [
|
||||
createElement('div', { class: 'sidebar-header' }, [createElement('h3', '宇之然平台')]),
|
||||
createElement('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);
|
||||
return createElement('button', {
|
||||
key: item.page,
|
||||
class: isActive ? 'sidebar-btn active' : 'sidebar-btn',
|
||||
on: { click: (e) => { e.preventDefault(); navigate(item.page); } }
|
||||
}, item.icon + ' ' + item.label);
|
||||
}))
|
||||
]),
|
||||
h('nav', { class: 'mobile-nav' }, mobileItems.map(item => {
|
||||
createElement('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);
|
||||
return createElement('button', {
|
||||
key: item.page,
|
||||
class: isActive ? 'mobile-nav-btn active' : 'mobile-nav-btn',
|
||||
on: { click: (e) => { e.preventDefault(); navigate(item.page); } }
|
||||
}, content);
|
||||
}))
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
app.component('navigation-component', component);
|
||||
console.log('[Nav] 组件已注册');
|
||||
return app;
|
||||
|
||||
Reference in New Issue
Block a user