feat(frontend): 公共导航组件完整实现

- 组件改为render函数,避免模板编译器依赖
- 自动注入样式,无需页面额外CSS
- 自适应布局:PC固定侧边栏,H5底部导航
- 所有页面统一使用,admin权限动态控制
- 自动调整main-content边距,防止遮挡
This commit is contained in:
lt
2026-05-08 11:03:33 +08:00
parent 5587fa0bce
commit ef168e3d90
6 changed files with 63 additions and 6 deletions
+2
View File
@@ -396,6 +396,8 @@ const app = createApp({
}); });
app.use(ElementPlus); app.use(ElementPlus);
// 安装导航组件
if (window.installNavigation) { window.installNavigation(app); }
app.mount('#app'); app.mount('#app');
</script> </script>
</body> </body>
+3 -1
View File
@@ -531,7 +531,9 @@
const app = Vue.createApp(App); const app = Vue.createApp(App);
app.use(ElementPlus); app.use(ElementPlus);
app.mount('#app'); // 安装导航组件
if (window.installNavigation) { window.installNavigation(app); }
app.mount('#app');
</script> </script>
</body> </body>
</html> </html>
+3 -1
View File
@@ -147,7 +147,9 @@
}; };
const app = Vue.createApp(LogsApp); const app = Vue.createApp(LogsApp);
app.use(ElementPlus); app.use(ElementPlus);
app.mount('#app'); // 安装导航组件
if (window.installNavigation) { window.installNavigation(app); }
app.mount('#app');
</script> </script>
</body> </body>
</html> </html>
+50 -3
View File
@@ -69,7 +69,7 @@ function injectNavigationStyles() {
.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); 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; 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 { 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; }
@@ -93,8 +93,8 @@ function injectNavigationStyles() {
.navigation-wrapper .sidebar { display: none !important; } .navigation-wrapper .sidebar { display: none !important; }
.navigation-wrapper .mobile-nav { display: flex !important; } .navigation-wrapper .mobile-nav { display: flex !important; }
} }
@media (min-width: 769px) { .navigation-wrapper .mobile-nav { display: none !important; } } undefined
body > #app > .navigation-wrapper + .main-content { margin-left: 180px; } body > #app > .navigation-wrapper + .main-content { margin-left: 180px !important; }
@media (max-width: 768px) { @media (max-width: 768px) {
body > #app > .navigation-wrapper + .main-content { margin-left: 0 !important; padding-bottom: 60px !important; } body > #app > .navigation-wrapper + .main-content { margin-left: 0 !important; padding-bottom: 60px !important; }
} }
@@ -119,3 +119,50 @@ if (typeof window !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) { if (typeof module !== 'undefined' && module.exports) {
module.exports = { NavigationComponent, installNavigation }; module.exports = { NavigationComponent, installNavigation };
} }
// 自动调整 main-content 边距
(function adjustLayout() {
// 等待DOM加载
const check = () => {
const main = document.querySelector('.main-content');
if (main) {
// 检测是否有导航组件
const hasSidebar = document.querySelector('.navigation-wrapper .sidebar') !== null;
if (hasSidebar) {
main.style.marginLeft = '180px';
} else {
main.style.marginLeft = '0';
}
}
// 移动端调整
const mobileNav = document.querySelector('.navigation-wrapper .mobile-nav');
if (mobileNav) {
main.style.paddingBottom = '60px';
}
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', check);
} else {
check();
}
// Vue 挂载后再次调整(通过全局API)
if (window.Vue) {
window.Vue.mixin({
mounted() {
setTimeout(check, 0);
}
});
}
})();
// 运行时检查(仅开发环境)
if (typeof window !== 'undefined') {
window.addEventListener('load', () => {
setTimeout(() => {
const nav = document.querySelector('.navigation-wrapper');
if (!nav) {
console.warn('[NavigationComponent] 未找到 .navigation-wrapper 元素,可能未正确渲染');
} else {
console.log('[NavigationComponent] 已渲染');
}
}, 100);
});
}
+2
View File
@@ -668,6 +668,8 @@ const TopicsApp = {
}; };
const app = Vue.createApp(TopicsApp); const app = Vue.createApp(TopicsApp);
app.use(ElementPlus); app.use(ElementPlus);
// 安装导航组件
if (window.installNavigation) { window.installNavigation(app); }
app.mount('#app'); app.mount('#app');
</script> </script>
+3 -1
View File
@@ -225,7 +225,9 @@
}; };
const app = Vue.createApp(UsersApp); const app = Vue.createApp(UsersApp);
app.use(ElementPlus); app.use(ElementPlus);
app.mount('#app'); // 安装导航组件
if (window.installNavigation) { window.installNavigation(app); }
app.mount('#app');
</script> </script>
</body> </body>
</html> </html>