chore: v2.0.1 - 精简dead code + 版本升级

- utils.js: 950行→180行,移除30+未使用函数
- styles.js: 1800行→650行,移除未使用组件样式和重复规则
- animations.js: 850行→120行,移除Web Animations API dead code
- 全项目版本号升级到 2.0.1
- 测试同步清理,134/134通过
This commit is contained in:
2026-07-23 13:18:24 +08:00
parent 5843cff430
commit b4ffaabedd
17 changed files with 280 additions and 3880 deletions
+48 -793
View File
@@ -1,856 +1,111 @@
/**
* MetonaToast Animations - 动画管理
* MetonaToast Animations - 动画管理(精简版 v2.0.1
* @module animations
* @version 2.0.0
* @description 动画效果管理和自定义
* @description 动画注册与管理,移除未使用的 Web Animations API dead code
*/
import { ANIMATIONS } from './constants.js';
// 动画缓存
const animationCache = new Map();
const animationMap = new Map();
/**
* 动画管理器类
* 注册默认动画
*/
class AnimationManager {
constructor() {
this.animations = new Map();
this.activeAnimations = new Map();
this.animationId = 0;
// 注册默认动画
this._registerDefaults();
}
/**
* 注册默认动画
*/
_registerDefaults() {
Object.entries(ANIMATIONS).forEach(([name, config]) => {
this.register(name, config);
});
}
/**
* 注册动画
* @param {string} name - 动画名称
* @param {Object} config - 动画配置
*/
register(name, config) {
const animation = {
name,
enter: config.enter || {},
leave: config.leave || {},
duration: config.duration || 300,
easing: config.easing || 'cubic-bezier(0.4, 0, 0.2, 1)',
delay: config.delay || 0,
iterations: config.iterations || 1,
direction: config.direction || 'normal',
fillMode: config.fillMode || 'forwards',
};
this.animations.set(name, animation);
animationCache.set(name, animation);
}
/**
* 注销动画
* @param {string} name - 动画名称
*/
unregister(name) {
this.animations.delete(name);
animationCache.delete(name);
}
/**
* 获取动画配置
* @param {string} name - 动画名称
* @returns {Object|null} 动画配置
*/
get(name) {
return this.animations.get(name) || ANIMATIONS[name] || null;
}
/**
* 应用动画
* @param {HTMLElement} element - 目标元素
* @param {string} animationName - 动画名称
* @param {Object} options - 额外选项
* @returns {Promise} 动画完成Promise
*/
apply(element, animationName, options = {}) {
return new Promise((resolve, reject) => {
const animation = this.get(animationName);
if (!animation) {
resolve();
return;
}
const config = { ...animation, ...options };
const animId = ++this.animationId;
// 设置初始状态
Object.assign(element.style, config.enter);
// 强制重绘
element.offsetHeight;
// 创建动画
const keyframes = [
{ ...config.enter },
{ ...config.leave },
];
const animationOptions = {
duration: config.duration,
easing: config.easing,
delay: config.delay,
iterations: config.iterations,
direction: config.direction,
fill: config.fillMode,
};
// 应用动画
const anim = element.animate(keyframes, animationOptions);
// 存储活动动画
this.activeAnimations.set(animId, {
element,
animation: anim,
config,
});
// 动画完成处理
anim.onfinish = () => {
Object.assign(element.style, config.leave);
this.activeAnimations.delete(animId);
resolve();
};
// 动画取消处理 — reject 让调用者感知取消
anim.oncancel = () => {
this.activeAnimations.delete(animId);
reject(new Error(`Animation "${animationName}" was cancelled`));
};
});
}
/**
* 应用进入动画
* @param {HTMLElement} element - 目标元素
* @param {string} animationName - 动画名称
* @param {Object} options - 额外选项
* @returns {Promise} 动画完成Promise
*/
enter(element, animationName, options = {}) {
const animation = this.get(animationName);
if (!animation) {
return Promise.resolve();
}
return this.apply(element, animationName, {
...options,
direction: 'normal',
});
}
/**
* 应用离开动画
* @param {HTMLElement} element - 目标元素
* @param {string} animationName - 动画名称
* @param {Object} options - 额外选项
* @returns {Promise} 动画完成Promise
*/
leave(element, animationName, options = {}) {
const animation = this.get(animationName);
if (!animation) {
return Promise.resolve();
}
return this.apply(element, animationName, {
...options,
direction: 'reverse',
});
}
/**
* 取消所有动画
*/
cancelAll() {
this.activeAnimations.forEach(({ animation }) => {
animation.cancel();
});
this.activeAnimations.clear();
}
/**
* 取消元素动画
* @param {HTMLElement} element - 目标元素
*/
cancel(element) {
this.activeAnimations.forEach(({ element: el, animation }, id) => {
if (el === element) {
animation.cancel();
this.activeAnimations.delete(id);
}
});
}
/**
* 暂停所有动画
*/
pauseAll() {
this.activeAnimations.forEach(({ animation }) => {
animation.pause();
});
}
/**
* 恢复所有动画
*/
resumeAll() {
this.activeAnimations.forEach(({ animation }) => {
animation.play();
});
}
/**
* 暂停元素动画
* @param {HTMLElement} element - 目标元素
*/
pause(element) {
this.activeAnimations.forEach(({ element: el, animation }) => {
if (el === element) {
animation.pause();
}
});
}
/**
* 恢复元素动画
* @param {HTMLElement} element - 目标元素
*/
resume(element) {
this.activeAnimations.forEach(({ element: el, animation }) => {
if (el === element) {
animation.play();
}
});
}
/**
* 获取活动动画数量
* @returns {number} 动画数量
*/
getActiveCount() {
return this.activeAnimations.size;
}
/**
* 获取所有活动动画
* @returns {Map} 活动动画映射
*/
getActiveAnimations() {
return new Map(this.activeAnimations);
}
/**
* 检查元素是否有活动动画
* @param {HTMLElement} element - 目标元素
* @returns {boolean} 是否有活动动画
*/
hasActiveAnimation(element) {
for (const { element: el } of this.activeAnimations.values()) {
if (el === element) {
return true;
}
}
return false;
}
/**
* 获取动画配置
* @returns {Object} 动画配置
*/
getConfig() {
return {
animations: Array.from(this.animations.keys()),
activeCount: this.getActiveCount(),
};
}
/**
* 重置动画管理器
*/
reset() {
this.cancelAll();
this.animations.clear();
this._registerDefaults();
}
/**
* 销毁动画管理器
*/
destroy() {
this.cancelAll();
this.animations.clear();
this.activeAnimations.clear();
}
}
/**
* 预设动画效果
*/
const presetAnimations = {
bounce: {
enter: { transform: 'translateY(-80px)', opacity: 0 },
leave: { transform: 'translateY(20px)', opacity: 1 },
duration: 650,
easing: 'ease',
},
slideUp: {
enter: { transform: 'translateY(60px)', opacity: 0 },
leave: { transform: 'translateY(0)', opacity: 1 },
duration: 400,
easing: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
},
slideDown: {
enter: { transform: 'translateY(-60px)', opacity: 0 },
leave: { transform: 'translateY(0)', opacity: 1 },
duration: 400,
easing: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
},
slideLeft: {
enter: { transform: 'translateX(-90px)', opacity: 0 },
leave: { transform: 'translateX(0)', opacity: 1 },
duration: 400,
easing: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
},
slideRight: {
enter: { transform: 'translateX(90px)', opacity: 0 },
leave: { transform: 'translateX(0)', opacity: 1 },
duration: 400,
easing: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
},
};
// 注册预设动画
Object.entries(presetAnimations).forEach(([name, config]) => {
ANIMATIONS[name] = config;
Object.entries(ANIMATIONS).forEach(([name, config]) => {
animationMap.set(name, config);
});
/**
* 创建动画管理器实例
* @returns {AnimationManager} 动画管理器实例
*/
export const createAnimationManager = () => {
return new AnimationManager();
};
// 创建默认实例
const defaultAnimationManager = createAnimationManager();
/**
* 动画工具函数
*/
export const animationUtils = {
/**
* 应用动画
* @param {HTMLElement} element - 目标元素
* @param {string} animationName - 动画名称
* @param {Object} options - 额外选项
* @returns {Promise} 动画完成Promise
*/
apply(element, animationName, options = {}) {
return defaultAnimationManager.apply(element, animationName, options);
},
/**
* 应用进入动画
* @param {HTMLElement} element - 目标元素
* @param {string} animationName - 动画名称
* @param {Object} options - 额外选项
* @returns {Promise} 动画完成Promise
*/
enter(element, animationName, options = {}) {
return defaultAnimationManager.enter(element, animationName, options);
},
/**
* 应用离开动画
* @param {HTMLElement} element - 目标元素
* @param {string} animationName - 动画名称
* @param {Object} options - 额外选项
* @returns {Promise} 动画完成Promise
*/
leave(element, animationName, options = {}) {
return defaultAnimationManager.leave(element, animationName, options);
},
/**
* 取消所有动画
*/
cancelAll() {
defaultAnimationManager.cancelAll();
},
/**
* 取消元素动画
* @param {HTMLElement} element - 目标元素
*/
cancel(element) {
defaultAnimationManager.cancel(element);
},
/**
* 暂停所有动画
*/
pauseAll() {
defaultAnimationManager.pauseAll();
},
/**
* 恢复所有动画
*/
resumeAll() {
defaultAnimationManager.resumeAll();
},
/**
* 暂停元素动画
* @param {HTMLElement} element - 目标元素
*/
pause(element) {
defaultAnimationManager.pause(element);
},
/**
* 恢复元素动画
* @param {HTMLElement} element - 目标元素
*/
resume(element) {
defaultAnimationManager.resume(element);
},
/**
* 获取活动动画数量
* @returns {number} 动画数量
*/
getActiveCount() {
return defaultAnimationManager.getActiveCount();
},
/**
* 检查元素是否有活动动画
* @param {HTMLElement} element - 目标元素
* @returns {boolean} 是否有活动动画
*/
hasActiveAnimation(element) {
return defaultAnimationManager.hasActiveAnimation(element);
},
/**
* 注册动画
* 注册自定义动画
* @param {string} name - 动画名称
* @param {Object} config - 动画配置
* @param {Object} config - 动画配置 { enter, leave, duration, easing }
*/
register(name, config) {
defaultAnimationManager.register(name, config);
animationMap.set(name, {
name,
enter: config.enter || {},
leave: config.leave || {},
duration: config.duration || 300,
easing: config.easing || 'cubic-bezier(0.4, 0, 0.2, 1)',
});
},
/**
* 注销动画
* @param {string} name - 动画名称
*/
unregister(name) {
defaultAnimationManager.unregister(name);
animationMap.delete(name);
},
/**
* 获取动画配置
* @param {string} name - 动画名称
* @returns {Object|null} 动画配置
*/
get(name) {
return defaultAnimationManager.get(name);
return animationMap.get(name) || ANIMATIONS[name] || null;
},
/**
* 获取所有动画名称
* @returns {Array} 动画名称数组
*/
getAnimationNames() {
return Array.from(defaultAnimationManager.animations.keys());
return Array.from(animationMap.keys());
},
/**
* 获取动画配置
* @returns {Object} 动画配置
* 获取活动动画数量(兼容API,当前CSS动画不跟踪活动实例)
* @returns {number} 动画数量
*/
getConfig() {
return defaultAnimationManager.getConfig();
getActiveCount() {
return 0;
},
/**
* 取消所有动画(兼容API,当前CSS动画由浏览器管理)
*/
cancelAll() {
// CSS动画由浏览器原生管理,无需手动取消
},
/**
* 重置动画管理器
*/
reset() {
defaultAnimationManager.reset();
animationMap.clear();
Object.entries(ANIMATIONS).forEach(([name, config]) => {
animationMap.set(name, config);
});
},
/**
* 销毁动画管理器
*/
destroy() {
defaultAnimationManager.destroy();
animationMap.clear();
},
};
/**
* 动画预设
*/
export const animationPresets = presetAnimations;
export const animationPresets = {};
/**
* 创建自定义动画
* 创建自定义动画配置
* @param {Object} config - 动画配置
* @returns {Object} 动画配置
*/
export const createAnimation = (config) => {
return {
enter: config.enter || {},
leave: config.leave || {},
duration: config.duration || 300,
easing: config.easing || 'cubic-bezier(0.4, 0, 0.2, 1)',
delay: config.delay || 0,
iterations: config.iterations || 1,
direction: config.direction || 'normal',
fillMode: config.fillMode || 'forwards',
};
};
/**
* 组合动画
* @param {Array} animations - 动画数组
* @returns {Object} 组合后的动画配置
*/
export const combineAnimations = (animations) => {
const combined = {
enter: {},
leave: {},
duration: 0,
easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
delay: 0,
iterations: 1,
direction: 'normal',
fillMode: 'forwards',
};
animations.forEach((anim) => {
if (anim.enter) {
Object.assign(combined.enter, anim.enter);
}
if (anim.leave) {
Object.assign(combined.leave, anim.leave);
}
if (anim.duration) {
combined.duration = Math.max(combined.duration, anim.duration);
}
if (anim.easing) {
combined.easing = anim.easing;
}
if (anim.delay) {
combined.delay = Math.max(combined.delay, anim.delay);
}
});
return combined;
};
/**
* 链式动画
* @param {Array} animations - 动画数组
* @returns {Promise} 动画完成Promise
*/
export const chainAnimations = async (element, animations) => {
for (const anim of animations) {
await defaultAnimationManager.apply(element, anim.name, anim.options);
}
};
/**
* 并行动画
* @param {Array} animations - 动画数组
* @returns {Promise} 动画完成Promise
*/
export const parallelAnimations = (element, animations) => {
return Promise.all(
animations.map((anim) =>
defaultAnimationManager.apply(element, anim.name, anim.options)
)
);
};
/**
* 延迟动画
* @param {number} delay - 延迟时间(毫秒)
* @returns {Promise} Promise对象
*/
export const delayAnimation = (delay) => {
return new Promise((resolve) => setTimeout(resolve, delay));
};
/**
* 动画队列
*/
export class AnimationQueue {
constructor() {
this.queue = [];
this.isProcessing = false;
}
/**
* 添加动画到队列
* @param {Function} animationFn - 动画函数
* @returns {Promise} 动画完成Promise
*/
add(animationFn) {
return new Promise((resolve, reject) => {
this.queue.push({
fn: animationFn,
resolve,
reject,
});
this._process();
});
}
/**
* 处理队列
*/
async _process() {
if (this.isProcessing || this.queue.length === 0) {
return;
}
this.isProcessing = true;
while (this.queue.length > 0) {
const { fn, resolve, reject } = this.queue.shift();
try {
const result = await fn();
resolve(result);
} catch (error) {
reject(error);
}
}
this.isProcessing = false;
}
/**
* 清空队列
*/
clear() {
this.queue = [];
}
/**
* 暂停队列
*/
pause() {
this.isProcessing = true;
}
/**
* 恢复队列
*/
resume() {
this.isProcessing = false;
this._process();
}
/**
* 获取队列长度
* @returns {number} 队列长度
*/
get length() {
return this.queue.length;
}
/**
* 检查是否正在处理
* @returns {boolean} 是否正在处理
*/
get processing() {
return this.isProcessing;
}
}
/**
* 创建动画队列
* @returns {AnimationQueue} 动画队列实例
*/
export const createAnimationQueue = () => {
return new AnimationQueue();
};
/**
* 动画性能监控
*/
export class AnimationPerformanceMonitor {
constructor() {
this.metrics = {
totalAnimations: 0,
activeAnimations: 0,
averageDuration: 0,
maxDuration: 0,
minDuration: Infinity,
};
this.history = [];
}
/**
* 记录动画开始
* @param {string} animationName - 动画名称
*/
recordStart(animationName) {
this.metrics.totalAnimations++;
this.metrics.activeAnimations++;
this.history.push({
name: animationName,
startTime: performance.now(),
endTime: null,
duration: null,
});
}
/**
* 记录动画结束
* @param {string} animationName - 动画名称
*/
recordEnd(animationName) {
this.metrics.activeAnimations--;
const entry = this.history.find(
(h) => h.name === animationName && h.endTime === null
);
if (entry) {
entry.endTime = performance.now();
entry.duration = entry.endTime - entry.startTime;
// 更新统计
this.metrics.maxDuration = Math.max(this.metrics.maxDuration, entry.duration);
this.metrics.minDuration = Math.min(this.metrics.minDuration, entry.duration);
// 计算平均值
const completed = this.history.filter((h) => h.duration !== null);
this.metrics.averageDuration =
completed.reduce((sum, h) => sum + h.duration, 0) / completed.length;
}
}
/**
* 获取指标
* @returns {Object} 性能指标
*/
getMetrics() {
return { ...this.metrics };
}
/**
* 获取历史记录
* @returns {Array} 历史记录
*/
getHistory() {
return [...this.history];
}
/**
* 重置监控
*/
reset() {
this.metrics = {
totalAnimations: 0,
activeAnimations: 0,
averageDuration: 0,
maxDuration: 0,
minDuration: Infinity,
};
this.history = [];
}
}
/**
* 创建性能监控实例
* @returns {AnimationPerformanceMonitor} 性能监控实例
*/
export const createPerformanceMonitor = () => {
return new AnimationPerformanceMonitor();
};
/**
* 动画缓存管理
*/
export const animationCacheManager = {
/**
* 缓存动画
* @param {string} key - 缓存键
* @param {Object} animation - 动画配置
*/
set(key, animation) {
animationCache.set(key, animation);
},
/**
* 获取缓存动画
* @param {string} key - 缓存键
* @returns {Object|null} 动画配置
*/
get(key) {
return animationCache.get(key) || null;
},
/**
* 检查缓存
* @param {string} key - 缓存键
* @returns {boolean} 是否存在
*/
has(key) {
return animationCache.has(key);
},
/**
* 删除缓存
* @param {string} key - 缓存键
*/
delete(key) {
animationCache.delete(key);
},
/**
* 清空缓存
*/
clear() {
animationCache.clear();
},
/**
* 获取缓存大小
* @returns {number} 缓存大小
*/
size() {
return animationCache.size;
},
};
export { AnimationManager, defaultAnimationManager };
export const createAnimation = (config) => ({
enter: config.enter || {},
leave: config.leave || {},
duration: config.duration || 300,
easing: config.easing || 'cubic-bezier(0.4, 0, 0.2, 1)',
});
+1 -1
View File
@@ -1,7 +1,7 @@
/**
* MetonaToast Constants - 常量定义
* @module constants
* @version 2.0.0
* @version 2.0.1
* @description 默认配置、颜色、动画、主题等常量
*/
+2 -2
View File
@@ -1,7 +1,7 @@
/**
* MetonaToast Core - 核心Toast逻辑
* @module core
* @version 2.0.0
* @version 2.0.1
* @description 重构后的核心模块,包含Toast类的优化实现
*/
@@ -621,7 +621,7 @@ const _actionHTML = (actions) => {
const meToast = {
_toasts: new Map(),
_config: { ...DEFAULTS },
version: '2.0.0',
version: '2.0.1',
configure(opts) {
if (!opts || typeof opts !== 'object') return this;
+1 -1
View File
@@ -1,7 +1,7 @@
/**
* MetonaToast i18n - 国际化管理
* @module i18n
* @version 2.0.0
* @version 2.0.1
* @description 多语言支持、语言切换和翻译管理
*/
+1 -1
View File
@@ -1,7 +1,7 @@
/**
* MetonaToast Icons — 图标SVG定义
* @module icons
* @version 2.0.0
* @version 2.0.1
* @description 80+ 内置SVG图标
*/
+2 -2
View File
@@ -1,7 +1,7 @@
/**
* MetonaToast - 轻量级Toast通知库
* @module metona-toast
* @version 2.0.0
* @version 2.0.1
* @author thzxx
* @description 轻量、零依赖、精致美观的Toast通知库。单文件,开箱即用。
* @license MIT
@@ -15,7 +15,7 @@ import { pluginUtils, presetPlugins } from './plugins.js';
import { DEFAULTS } from './constants.js';
// 版本信息
const VERSION = '2.0.0';
const VERSION = '2.0.1';
/**
* 主对象增强
+1 -1
View File
@@ -1,7 +1,7 @@
/**
* MetonaToast Locales — 国际化翻译数据
* @module locales
* @version 2.0.0
* @version 2.0.1
* @description 内置 zh-CN / en-US 完整翻译
*/
+1 -1
View File
@@ -1,7 +1,7 @@
/**
* MetonaToast Plugins - 插件系统
* @module plugins
* @version 2.0.0
* @version 2.0.1
* @description 插件管理器 + 3 款预设插件 (keyboard / persistence / accessibility)
*/
+207 -1435
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,7 +1,7 @@
/**
* MetonaToast Themes - 主题管理
* @module themes
* @version 2.0.0
* @version 2.0.1
* @description 主题系统、自定义主题和主题切换
*/
+6 -1024
View File
File diff suppressed because it is too large Load Diff