fix(navigation): 改用原生DOM操作,彻底解决h函数问题

- 放弃Vue h函数,直接document.createElement创建导航栏
- mounted生命周期中渲染侧边栏和移动端底部导航
- 原生JS绑定点击事件,确保功能正常
- 避免Vue3 prod版本中render函数的参数问题
This commit is contained in:
lt
2026-05-08 14:58:28 +08:00
parent df86e01cd2
commit c13d8c29aa
+63 -55
View File
@@ -1,4 +1,4 @@
// Vue 3 导航组件 - 最终版(增强调试和样式 // 最简导航组件 - 原生DOM操作(无h函数
(function() { (function() {
console.log('[Nav] 脚本加载'); console.log('[Nav] 脚本加载');
@@ -45,52 +45,65 @@
console.log('[Nav] 样式已注入'); console.log('[Nav] 样式已注入');
} }
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) => { const installNavigation = (app) => {
console.log('[Nav] installNavigation called'); console.log('[Nav] installNavigation called');
injectStyles(); 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]));
return el;
};
console.log('[Nav] 使用 h 函数:', typeof h);
// 定义组件选项
const component = { const component = {
name: 'NavigationComponent', name: 'NavigationComponent',
props: { currentPage: { type: String, required: true }, isAdmin: { type: Boolean, default: false } }, props: { currentPage: { type: String, required: true }, isAdmin: { type: Boolean, default: false } },
mounted() { console.log('[NavigationComponent] 已挂载,isAdmin:', this.isAdmin); }, mounted() {
render(){ console.log('[NavigationComponent] 已挂载', this.currentPage, this.isAdmin);
const createElement = arguments[0] || h;
const emit = this.$emit || function() {};
const navigate = (page) => { // 在组件挂载后立即渲染导航栏到DOM
console.log('[NavigationComponent] 点击导航到:', page); setTimeout(() => {
if (typeof emit === 'function') { const container = this.$el; // 组件根元素
emit('navigate', page); container.innerHTML = '';
} else if (this.$emit) {
this.$emit('navigate', page);
}
};
const sidebarItems = [ // 渲染侧边栏
const sidebar = document.createElement('aside');
sidebar.className = 'sidebar';
const header = document.createElement('div');
header.className = 'sidebar-header';
const headerTitle = document.createElement('h3');
headerTitle.textContent = '宇之然平台';
header.appendChild(headerTitle);
const nav = document.createElement('nav');
nav.className = 'sidebar-nav';
const items = [
{ icon: '📊', label: '系统概览', page: '/' }, { icon: '📊', label: '系统概览', page: '/' },
{ icon: '📋', label: '选题管理', page: 'topics.html' }, { icon: '📋', label: '选题管理', page: 'topics.html' },
{ icon: '📄', label: '系统日志', page: 'logs.html' }, { icon: '📄', label: '系统日志', page: 'logs.html' },
...(this.isAdmin ? [{ icon: '👥', label: '用户管理', page: 'users.html' }, { icon: '⚙️', label: '系统管理', page: 'admin.html' }] : []) ...(this.isAdmin ? [{ icon: '👥', label: '用户管理', page: 'users.html' }, { icon: '⚙️', label: '系统管理', page: 'admin.html' }] : [])
]; ];
items.forEach(item => {
const btn = document.createElement('button');
btn.className = this.currentPage === (item.page === '/' ? 'dashboard' : item.page.replace('.html',''))
? 'sidebar-btn active' : 'sidebar-btn';
btn.textContent = item.icon + ' ' + item.label;
btn.addEventListener('click', () => {
console.log('[NavigationComponent] 点击导航到:', item.page);
this.$emit('navigate', item.page);
});
nav.appendChild(btn);
});
sidebar.appendChild(header);
sidebar.appendChild(nav);
container.appendChild(sidebar);
// 渲染移动端底部导航
if (window.innerWidth <= 768) {
const mobileNav = document.createElement('nav');
mobileNav.className = 'mobile-nav';
const mobileItems = [ const mobileItems = [
{ icon: '📊', label: '', page: '/' }, { icon: '📊', label: '', page: '/' },
{ icon: '📋', label: '选题', page: 'topics.html' }, { icon: '📋', label: '选题', page: 'topics.html' },
@@ -98,30 +111,25 @@
...(this.isAdmin ? [{ icon: '👥', label: '用户', page: 'users.html' }, { icon: '⚙️', label: '系统', page: 'admin.html' }] : []) ...(this.isAdmin ? [{ icon: '👥', label: '用户', page: 'users.html' }, { icon: '⚙️', label: '系统', page: 'admin.html' }] : [])
]; ];
console.log('[NavigationComponent] 渲染侧边栏项目:', sidebarItems.length, '移动端项目:', mobileItems.length); mobileItems.forEach(item => {
const btn = document.createElement('button');
btn.className = this.currentPage === (item.page === '/' ? 'dashboard' : item.page.replace('.html',''))
? 'mobile-nav-btn active' : 'mobile-nav-btn';
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 createElement('button', {
key: item.page,
class: isActive ? 'sidebar-btn active' : 'sidebar-btn',
on: { click: (e) => { e.preventDefault(); navigate(item.page); } }
}, item.icon + ' ' + item.label);
}))
]),
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; const content = item.label ? (item.icon + ' ' + item.label) : item.icon;
return createElement('button', { btn.textContent = content;
key: item.page,
class: isActive ? 'mobile-nav-btn active' : 'mobile-nav-btn', btn.addEventListener('click', () => {
on: { click: (e) => { e.preventDefault(); navigate(item.page); } } console.log('[NavigationComponent] 点击导航到:', item.page);
}, content); this.$emit('navigate', item.page);
})) });
]);
mobileNav.appendChild(btn);
});
container.appendChild(mobileNav);
}
}, 0);
} }
}; };