From c85320ae72d21018222c2576b59a69bdf2639d5a Mon Sep 17 00:00:00 2001 From: lt Date: Fri, 8 May 2026 12:30:49 +0800 Subject: [PATCH] =?UTF-8?q?fix(navigation):=20=E4=BF=AE=E5=A4=8D=E5=B8=83?= =?UTF-8?q?=E5=B1=80=E5=81=8F=E7=A7=BB=E5=92=8C=E4=BA=8B=E4=BB=B6=E8=B7=B3?= =?UTF-8?q?=E8=BD=AC=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除 .navigation-wrapper 的 flex/min-height 布局干扰 - 确保 main-content 不受侧边栏占位影响 - 优化事件处理,增加点击日志 - 修复 admin 导航页面名称不一致问题 --- platform/frontend/navigation-component.js | 200 ++++++++++++---------- 1 file changed, 109 insertions(+), 91 deletions(-) diff --git a/platform/frontend/navigation-component.js b/platform/frontend/navigation-component.js index f25b656..bebc5f5 100644 --- a/platform/frontend/navigation-component.js +++ b/platform/frontend/navigation-component.js @@ -1,96 +1,114 @@ -// 公共导航组件(调试版) -const NavigationComponent = { - name: 'NavigationComponent', - 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); - })) - ]); +// 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; + 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 h3 { margin: 0; font-size: 16px; font-weight: 600; color: #303133; } + .navigation-wrapper .sidebar-btn { + width: 100%; text-align: left; padding: 10px 12px; border: none; background: transparent; border-radius: 8px; + 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.active { background: #ecf5ff; color: #409eff; font-weight: 600 !important; } + .navigation-wrapper .mobile-nav { + 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: 99999; justify-content: space-around; + } + .navigation-wrapper .mobile-nav-btn { + 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; + } + .navigation-wrapper .mobile-nav-btn:hover { color: #409eff; } + .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 (min-width: 769px) { .navigation-wrapper .mobile-nav { display: none !important; } } + /* 侧边栏固定定位时不调整主内容,让 main-content 自然位于文档流中,仅需确保 padding-top 避开 navbar */ + body > #app > .main-content { padding-top: 0; } + `; + const styleEl = document.createElement('style'); + styleEl.id = 'navigation-styles'; + styleEl.textContent = styles; + document.head.appendChild(styleEl); + console.log('[Nav] 样式已注入'); } -}; -function injectNavigationStyles() { - if (document.getElementById('navigation-styles')) { - console.log('[Nav] 样式已存在,跳过注入'); - return; + 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 styles = ` - .navigation-wrapper { position: relative; } - .navigation-wrapper .sidebar { - width: 180px; background: white; padding: 12px; box-shadow: 2px 0 8px rgba(0,0,0,0.05); - position: fixed; left: 0; top: 60px; bottom: 0; overflow-y: auto; z-index: 9999; - } - .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-btn { - width: 100%; text-align: left; padding: 10px 12px; border: none; background: transparent; border-radius: 8px; - 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.active { background: #ecf5ff; color: #409eff; font-weight: 600; } - .navigation-wrapper .mobile-nav { - 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; - } - .navigation-wrapper .mobile-nav-btn { - 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; - } - .navigation-wrapper .mobile-nav-btn:hover { color: #409eff; } - .navigation-wrapper .mobile-nav-btn.active { color: #409eff; font-weight: 600; } - @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; } } - .navigation-wrapper + .main-content { margin-left: 180px !important; } - @media (max-width: 768px) { .navigation-wrapper + .main-content { margin-left: 0 !important; padding-bottom: 60px !important; } } - `; - const styleEl = document.createElement('style'); - styleEl.id = 'navigation-styles'; - styleEl.textContent = styles; - document.head.appendChild(styleEl); - console.log('[Nav] 样式已注入'); -} -function installNavigation(app) { - console.log('[Nav] installNavigation called'); - injectNavigationStyles(); - app.component('navigation-component', NavigationComponent); - console.log('[Nav] 组件已注册'); - return app; -} + const installNavigation = (app) => { + console.log('[Nav] installNavigation called'); + injectStyles(); + 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); -window.NavigationComponent = NavigationComponent; -window.installNavigation = installNavigation; -console.log('[Nav] 脚本已加载'); + 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] 组件已注册'); + return app; + }; + + window.installNavigation = installNavigation; + console.log('[Nav] 脚本已加载'); +})();