如果说 DOM 操作是构建了网页的骨架,那么动画和UI 组件就是为这个骨架注入了灵魂和活力。流畅的动画可以引导用户注意力,提供愉悦的反馈;而强大的 UI 组件则能极大地提升用户交互的效率和便捷性。MooTools 为此提供了非常完善且易于使用的解决方案。

1. 动画系统
MooTools 的动画系统核心是 Fx 类,它提供了强大的基础来创建平滑的过渡效果。
1.1 Fx.Tween
Fx.Tween 是最基础也是最常用的动画类,它用于对一个元素的单个 CSS 属性进行平滑的数值过渡。
示例: 一个简单的宽度变化动画。
// 确保 DOM 加载完成
window.addEvent('domready', function() {
var box = $('animatedBox'); // 假设页面上有一个 id 为 'animatedBox' 的 div
// 创建一个 Fx.Tween 实例
var tweenAnimation = new Fx.Tween(box, {
duration: 500, // 动画持续时间,单位毫秒
transition: Fx.Transitions.Quad.easeInOut // 过渡效果,先慢后快再慢
});
// 为按钮添加点击事件来触发动画
$('toggleButton').addEvent('click', function() {
// 检查当前宽度,然后决定是扩大还是缩小
var currentWidth = box.getStyle('width').toInt();
if (currentWidth < 300) {
tweenAnimation.start('width', 300); // 从当前宽度动画到 300px
} else {
tweenAnimation.start('width', 100); // 从当前宽度动画到 100px
}
});
});
HTML:
Fx.Tween 的 start 方法可以接受两个参数:要动画的 CSS 属性名,以及目标值。如果省略初始值,它会自动使用元素当前的属性值。
1.2 Fx.Morph
当你需要同时动画多个 CSS 属性时,Fx.Morph 是最佳选择。它可以让多个属性在同一个动画时间线上同步变化。
示例: 一个元素同时移动、变色和改变大小。
window.addEvent('domready', function() {
var box = $('morphBox');
// 创建 Fx.Morph 实例
var morphAnimation = new Fx.Morph(box, {
duration: 700,
transition: Fx.Transitions.Back.easeOut // 带有回弹效果的过渡
});
$('morphButton').addEvent('click', function() {
// 使用一个对象来定义所有要变化的属性和目标值
morphAnimation.start({
'width': [100, 250], // 从 100px 到 250px
'height': [100, 150],
'left': [0, 100], // 需要元素有 position: absolute 或 relative
'background-color': ['#4CAF50', '#FF9800'] // 颜色也可以动画
});
});
});
HTML:
Fx.Morph 的 start 方法接受一个对象,键是 CSS 属性,值可以是一个包含起始值和目标值的数组,也可以直接是目标值(此时起始值为当前值)。
1.3 Fx.Transitions
过渡效果(Transitions)定义了动画在时间轴上的速度变化模式,是决定动画 “感觉” 的关键。MooTools 内置了多种过渡效果,位于 Fx.Transitions 对象中。
常用的过渡效果:
- 线性 (Linear):
Fx.Transitions.Linear- 速度恒定,适用于机械、精确的动画。 - 缓动 (Ease):
Fx.Transitions.Quad.easeIn- 开始慢,结束快。Fx.Transitions.Quad.easeOut- 开始快,结束慢。Fx.Transitions.Quad.easeInOut- 开始和结束都慢,中间快(最常用)。
- 回弹 (Back):
Fx.Transitions.Back.easeOut- 动画结束时会稍微超出目标值再弹回,非常生动。 - 弹跳 (Bounce):
Fx.Transitions.Bounce.easeOut- 像球落地一样弹跳几次后停止。
你可以在创建 Fx.Tween 或 Fx.Morph 实例时,通过 transition 选项来指定。
2. UI 组件
MooTools 的 UI 组件是基于其核心功能(动画、DOM、事件)构建的高级模块,能够快速实现复杂的交互功能。
2.1 拖放 (Drag.Move)
Drag.Move 是一个简单而强大的拖放组件,允许用户用鼠标拖动一个元素。
示例: 一个可在页面上自由拖动的盒子。
window.addEvent('domready', function() {
var draggableBox = $('draggableBox');
// 初始化 Drag.Move
new Drag.Move(draggableBox, {
// 可以指定一个手柄元素,如果不指定,则整个元素都可以拖动
// handle: $('handle'),
// 拖动开始时的回调
onStart: function() {
draggableBox.setStyle('opacity', 0.8); // 拖动时半透明
},
// 拖动结束时的回调
onComplete: function() {
draggableBox.setStyle('opacity', 1); // 结束后恢复不透明
}
});
});
HTML:
2.2 可排序列表 (Sortables)
Sortables 组件允许用户通过拖放来重新排列列表项(<li>)的顺序,是构建交互性强的列表(如任务列表、相册)的理想选择。
示例: 一个可排序的任务列表。
window.addEvent('domready', function() {
var taskList = $('taskList');
// 初始化 Sortables
var sortableList = new Sortables(taskList, {
// 列表项的选择器
handle: '.task-handle', // 只有点击带 .task-handle 类的元素才能拖动
// 排序时的不透明度
opacity: 0.7,
// 当排序结束后触发
onComplete: function(item) {
// item 是被移动的列表项
console.log('任务重新排序:', item.get('text'));
// 在这里可以将新的顺序保存到服务器
}
});
// 添加一个新任务的按钮
$('addTaskButton').addEvent('click', function() {
var newTaskText = prompt('请输入新任务:');
if (newTaskText) {
var newLi = new Element('li', {
'html': '☰ ' + newTaskText
}).inject(taskList);
// 通知 Sortables 有新元素加入
sortableList.addItems(newLi);
}
});
});
HTML:
- ☰ 学习 MooTools
- ☰ 构建一个组件
- ☰ 喝杯咖啡
2.3 折叠面板 (Accordion)
虽然 MooTools 核心库中没有一个名为 Accordion 的官方组件,但利用我们学过的 Fx.Tween 和事件处理,我们可以轻松地自己实现一个。这是一个非常好的综合练习。
思路:
- 为每个面板标题绑定点击事件。
- 点击时,获取对应的内容面板。
- 使用
Fx.Tween动画内容面板的height或opacity属性,实现展开和折叠。 - (可选)实现 “互斥” 效果,即展开一个面板时,自动折叠其他面板。
3. 实战练习:开发带平滑动画与拖放功能的轻量级交互组件
现在,让我们将所学的知识结合起来,创建一个实用的组件:带拖放排序和动画效果的可折叠任务卡片。
需求分析:
- 每个任务是一个卡片。
- 点击卡片标题可以展开 / 折叠卡片内容(带平滑动画)。
- 可以通过拖放卡片来改变它们的顺序(带拖放效果)。
- 点击 “完成” 按钮可以将卡片标记为已完成(带状态变化动画)。
HTML 结构 (index.html):
MooTools Task Cards
我的任务
<script src="https://cdnjs.cloudflare.com/ajax/libs/mootools/1.6.0/mootools-core.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mootools-more/1.6.0/mootools-more.min.js"></script>
<script src="task-cards.js"></script>
注意:我们引入了 mootools-more.min.js,因为 Sortables 组件在 more 扩展库中。
JavaScript 实现 (task-cards.js):
window.addEvent('domready', function() {
var taskList = $('task-list');
var sortable = null; // Will hold the Sortables instance
// Function to create a new task card element
function createTaskCard(title, description) {
var contentHeight = 100; // Approximate height of content
var card = new Element('li', {
'class': 'task-card',
'html': `
☰
${title}
${description}
`
});
// Store a reference to the content element
var content = card.getElement('.task-content');
// Initially, we set the height to 0 for the animation to work
content.setStyle('height', 0);
// Toggle content visibility on header click
card.getElement('.task-header').addEvent('click', function(e) {
// Prevent event from bubbling to Sortables if clicking the handle
if (!e.target.hasClass('handle')) {
var isVisible = content.getStyle('height').toInt() > 0;
new Fx.Tween(content, {
property: 'height',
duration: 300,
transition: Fx.Transitions.Quad.easeInOut
}).start(isVisible ? 0 : contentHeight);
}
});
// Complete button functionality
card.getElement('.complete-btn').addEvent('click', function() {
card.toggleClass('completed');
// Add a subtle animation effect
new Fx.Morph(card, {
duration: 300,
transition: Fx.Transitions.Linear
}).start({
'opacity': [1, 0.7, 1]
});
});
return card;
}
// Function to refresh the sortable list
function refreshSortables() {
if (sortable) sortable.destroy(); // Clean up old instance
sortable = new Sortables(taskList, {
handle: '.handle',
opacity: 0.8,
clone: true, // Show a clone while dragging
onComplete: function() {
console.log('Task order changed.');
// Here you would typically save the new order to a server
}
});
}
// Add initial tasks
var initialTasks = [
{ title: '学习 MooTools 动画', description: '深入理解 Fx.Tween 和 Fx.Morph 的用法。' },
{ title: '构建拖放组件', description: '使用 Sortables 实现一个可排序的列表。' },
{ title: '完成实战练习', description: '将动画和拖放结合起来,创建任务卡片。' }
];
initialTasks.each(function(taskData) {
createTaskCard(taskData.title, taskData.description).inject(taskList);
});
// Initialize sortables
refreshSortables();
// Add new task button
$('add-task-btn').addEvent('click', function() {
var title = prompt('请输入任务标题:');
if (title) {
var description = prompt('请输入任务描述:') || '无描述';
var newCard = createTaskCard(title, description);
newCard.inject(taskList);
refreshSortables(); // Refresh sortables to include the new card
// Animate the new card's appearance
new Fx.Morph(newCard, {
duration: 500,
transition: Fx.Transitions.Back.easeOut
}).start({
'opacity': [0, 1],
'scale': [0.8, 1] // Scale from 80% to 100%
});
}
});
});
练习解析:
- HTML & CSS: 我们定义了任务卡片的基本样式。特别注意
.task-content的max-height和overflow: hidden,以及初始的display: none和height: 0,这些是实现平滑高度动画的关键。 createTaskCard(title, description): 这个函数负责生成一个完整的任务卡片 DOM 结构,并为其绑定所有交互逻辑。- 折叠动画: 点击标题时,我们使用
Fx.Tween来动画height属性。通过判断当前高度是否大于 0,来决定是展开(start(0, contentHeight))还是折叠(start(currentHeight, 0))。 - 完成功能: 点击 “完成” 按钮时,我们为卡片添加一个
.completed类,CSS 会自动处理样式变化。同时,我们用Fx.Morph添加了一个简单的闪烁动画,提供即时反馈。
- 折叠动画: 点击标题时,我们使用
refreshSortables(): 每次添加新卡片后,我们需要销毁旧的Sortables实例并创建一个新的,以确保新卡片也能被拖动。- 拖放排序:
new Sortables(...)初始化了可排序功能。handle: '.handle'指定了只有点击那个 “☰” 图标才能拖动卡片,这可以防止与折叠功能冲突。clone: true会在拖动时显示一个半透明的克隆体,提升了用户体验。 - 添加新任务: 点击按钮会弹出提示框收集信息,然后创建新卡片并注入到列表中。我们还为新卡片的出现添加了一个
scale和opacity的组合动画,使其看起来更生动。
这个实战练习完美地结合了 MooTools 的动画系统(Fx.Tween, Fx.Morph, Fx.Transitions)和 UI 组件(Sortables),并综合运用了 DOM 操作、事件处理等核心知识。你可以基于这个例子,进一步扩展功能,比如添加删除按钮、数据持久化到 localStorage 或服务器等,打造一个更完整的应用。
最后小结:
在这一课时中,我们深入探索了 MooTools 的高级特性:
- 动画系统:
Fx.Tween用于单属性动画,Fx.Morph用于多属性同步动画,而Fx.Transitions则为动画赋予了丰富的节奏和风格。 - UI 组件:我们学习了如何使用
Drag.Move实现元素拖放,以及如何用Sortables快速构建可排序列表。我们还亲手实现了一个带动画效果的折叠面板。 - 实战整合:通过开发 “任务卡片” 组件,我们将所学知识融会贯通,展示了如何构建一个功能丰富、交互流畅的轻量级前端组件。
MooTools 以其优雅的 API 和强大的功能,在没有构建工具和复杂框架的年代,为开发者提供了极大的便利。虽然现代前端开发的主流已经转向 React、Vue 等框架,但 MooTools 这种 “手写” 交互和动画的思想,对于理解前端开发的本质仍然非常有价值。希望这两课时的学习能让你对 MooTools 有一个全面的了解,并从中汲取灵感。
浙公网安备 33010602011771号