Files
testing-tool/sidepanel/utils/domUtils.js
T
雨霖铃 2761dbe13f feat(sidepanel): 重构路由系统并优化页面加载逻辑
- 移除冗余的开发预览页面 `index.html`
- 路由配置改为声明式结构,支持自动加载 HTML 和脚本
- 新增 `data-route` 属性用于导航按钮绑定路由路径
- 实现基于事件委托的路由跳转机制
- 重写 `Router.js` 核心逻辑,支持异步加载页面模块
- 改进 `domUtils.js` 中 `addClass` 和 `removeClass` 方法兼容性与健壮性
- 新增 `scriptLoader.js` 工具模块用于动态加载和清理页面脚本
- 时间戳页面初始化方式调整为 IIFE 并挂载至全局作用域
2025-11-30 23:34:40 +08:00

139 lines
3.4 KiB
JavaScript

/**
* DOM工具类函数
*/
/**
* 切换页面显示(带动画效果)
* @param {string} pageName - 页面名称
*/
export function switchPage(pageName) {
// 先隐藏当前活跃页面(如果有)
const currentPage = document.querySelector('.page.active');
if (currentPage) {
currentPage.classList.remove('active');
// 添加离开动画
currentPage.style.opacity = '0';
currentPage.style.transform = 'translateX(20px)';
// 等待动画完成后真正隐藏
setTimeout(() => {
if (!currentPage.classList.contains('active')) {
currentPage.style.display = 'none';
}
}, 300);
}
// 移除所有导航按钮的 active 状态
document.querySelectorAll('.nav-button').forEach((button) => {
button.classList.remove('active');
});
// 显示目标页面
const targetPage = document.getElementById(`page-${pageName}`);
if (targetPage) {
targetPage.style.display = 'block';
// 触发重排以确保display变化生效
targetPage.offsetHeight;
// 添加进入动画
targetPage.style.opacity = '0';
targetPage.style.transform = 'translateX(-20px)';
setTimeout(() => {
targetPage.classList.add('active');
targetPage.style.opacity = '1';
targetPage.style.transform = 'translateX(0)';
}, 10);
}
// 激活对应的导航按钮
const navButton =
document.getElementById(`nav-${pageName}-btn`) || document.getElementById(`nav-${pageName}`);
if (navButton) {
navButton.classList.add('active');
}
}
/**
* 根据ID获取元素的便捷方法
* @param {string} id - 元素ID
* @returns {HTMLElement} - DOM元素
*/
export function getElementById(id) {
return document.getElementById(id);
}
/**
* 为元素添加事件监听器
* @param {string} id - 元素ID
* @param {string} event - 事件类型
* @param {Function} handler - 事件处理函数
*/
export function addEventListenerById(id, event, handler) {
const element = getElementById(id);
if (element) {
element.addEventListener(event, handler);
}
}
/**
* 判断元素是否包含指定类名
* @param {*} elem
* @param {*} cls
* @returns
*/
export function hasClass(elem, cls) {
cls = cls || '';
// 检测类名是否为''
if (cls.replace(/\s/g, '').length === 0) return false;
// 检测elem类名是否包含cls指定类名
return new RegExp(' ' + cls + ' ').test(' ' + elem.className + ' ');
}
/**
* 为元素添加类名
* @param {*} elem
* @param {*} cls
*/
export function addClass(elem, cls) {
if (!elem || !cls) return;
// 统一空白字符(避免 \n \t 等导致匹配问题)
let current = elem.className.replace(/[\t\r\n]/g, ' ').trim();
// 已存在则忽略
const classes = current.split(/\s+/);
if (classes.includes(cls)) return;
// 添加并规整
classes.push(cls);
elem.className = classes.join(' ').trim();
}
/**
* 为元素删除类名
* @param {*} elem
* @param {*} cls
*/
export function removeClass(elem, cls) {
if (!elem || !cls) return;
// 使用 classList 优先(更安全)
if (elem.classList) {
elem.classList.remove(cls);
return;
}
// 传统写法的修复版本
let klass = ' ' + elem.className.replace(/[\t\r\n]/g, ' ') + ' ';
// 持续删除目标 class
while (klass.indexOf(' ' + cls + ' ') !== -1) {
klass = klass.replace(' ' + cls + ' ', ' ');
}
// 过滤多余空格
elem.className = klass.trim().replace(/\s+/g, ' ');
}