Files
yu-zhi-ran/platform/frontend/navigation-component.js
T
lt 5587fa0bce fix(navigation): 使用render函数替代template,兼容prod版Vue
- 重写组件为render函数实现,避免编译器依赖
- 优化按钮生成逻辑,使用JS数组map
- 修复样式注入时机和CSS冲突问题
- 确保app实例化后调用installNavigation进行注册
2026-05-08 10:57:23 +08:00

122 lines
5.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 公共导航组件定义(使用 render 函数,兼容 prod 版 Vue
const NavigationComponent = {
name: 'NavigationComponent',
props: {
currentPage: {
type: String,
required: true,
validator: (value) => ['dashboard', 'topics', 'logs', 'users', 'admin'].includes(value)
},
isAdmin: {
type: Boolean,
default: false
}
},
render() {
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' }
] : [])
];
const createSidebarBtn = (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(''));
};
const createMobileBtn = (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);
};
return h('div', { class: 'navigation-wrapper' }, [
h('aside', { class: 'sidebar' }, [
h('div', { class: 'sidebar-header' }, [h('h3', '宇之然平台')]),
h('nav', { class: 'sidebar-nav' }, sidebarItems.map(createSidebarBtn))
]),
h('nav', { class: 'mobile-nav' }, mobileItems.map(createMobileBtn))
]);
}
};
function injectNavigationStyles() {
if (document.getElementById('navigation-styles')) return;
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: 100;
}
.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; } }
body > #app > .navigation-wrapper + .main-content { margin-left: 180px; }
@media (max-width: 768px) {
body > #app > .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);
}
function installNavigation(app) {
injectNavigationStyles();
app.component('navigation-component', NavigationComponent);
app.config.globalProperties.$redirectToPage = (path) => { window.location.href = path; };
return app;
}
if (typeof window !== 'undefined') {
window.NavigationComponent = NavigationComponent;
window.installNavigation = installNavigation;
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = { NavigationComponent, installNavigation };
}