以下是 Julian Shapiro 的客座文章。Julian 最近发布了 Velocity.js,这是一个比 .animate()
性能更高的 jQuery 替代方案。他最近在 David Walsh 的博客上 撰写了关于 JavaScript 动画如何如此快速的 文章,我们也曾 在这里 讨论过这个话题。在这篇文章中,Julian 介绍了 Velocity.js 本身。
Velocity.js 是一个 jQuery 插件,它重新实现了 jQuery 的 $.animate()
函数,以产生更高的性能(在许多情况下,Velocity 也比 CSS 过渡更快),同时还包含一些新功能来改进动画工作流。
Velocity 压缩后只有 7Kb,包含了 $.animate()
的所有功能,同时还打包了变形动画、循环、类动画和滚动。简而言之,Velocity 旨在成为 jQuery、jQuery UI 和 CSS 过渡的最佳结合。
Velocity 在所有地方都能工作——回溯到 IE8 和 Android 2.3。此外,由于 Velocity 的语法与 $.animate()
的语法相同,因此您页面上的任何代码都不需要更改。
Velocity 的目标是在 DOM 动画性能和便利性方面成为领导者。本文重点关注后者。要了解有关前者的更多信息,请参阅 Velocity 在 VelocityJS.org 上的性能比较。特别是,本文演示了如何使用 Velocity 来改进您的 UI 动画工作流。在一个简洁的对比中,将 Velocity 的八个功能与其 jQuery 对应功能进行了比较。
如果您觉得当前的 UI 工作流混乱、分割不佳或过分依赖 jQuery 的各种样式函数,那么本演练适合您。
简要概述
在深入了解 Velocity 之前,让我们快速了解一下基础知识:需要指出的是,$.animate()
和 $.velocity()
都支持灵活的选项语法。您可以将选项作为逗号分隔的值传递,也可以将选项作为独立的选项对象传递。
以下是用逗号分隔语法的一个示例,其中整数被视为动画的持续时间,字符串被视为缓动类型,函数被视为回调函数(在动画完成后触发)
$div.animate(
{
opacity: 1
},
1000,
"linear",
function() {
alert("Done animating.");
}
);
接下来,这是一个对象语法的示例
$div.animate(
{
opacity: 1
},
{
duration: 1000,
easing: "linear",
complete: function() {
alert("Done animating!")
},
queue: "myQueue"
}
);
除了生成更清晰的代码外,使用选项对象还可以访问其他动画参数,而这些参数无法通过逗号分隔语法指定。
jQuery 提供的一个此类选项示例是“queue”。Velocity 也提供了 queue 选项,并且链到单个元素上的多个动画调用会自动排队。
这里,div 的不透明度将以 1000 毫秒动画到 1,然后在接下来的 1000 毫秒内动画回 0
$div
.animate({ opacity: 1 }, 1000)
.animate({ opacity: 0 }, 1000);
现在,在了解了基础知识后,让我们开始比较 Velocity 和 jQuery。
反转
Velocity 除了接受属性映射之外,还接受 "reverse"
作为其第一个参数。Reverse 将目标元素动画到其上一个 Velocity 调用之前的值。
在 jQuery 中,这就像
$div
/* Fade an element in while sliding it into view. */
.animate({ opacity: 1, top: "50%" })
/* The values below are what we originally set the element to in our stylesheet. Animate back to them. */
.animate({ opacity: 0, top: "-25%" });
在 Velocity 中,它更容易,因为它不仅代码更少,而且您不必重复样式表中的值
$div
.velocity({ opacity: 1, top: "50%" })
.velocity("reverse");
默认情况下,Velocity 的 reverse 命令使用传递到上一个 Velocity 调用的相同选项。可以通过将新选项传递到“reverse”调用中来扩展这些选项。例如
$div
.velocity({ opacity: 1, top: "50%" }, 1000)
/* Animate back to the prior visual state at half the duration of the previous animation. */
.velocity("reverse", 500);
滚动
一种流行的 UI 技术是滚动浏览器,使其与页面下方某个元素对齐,然后使用引人注目的修饰来动画化该元素。使用 jQuery 实现此操作会涉及混乱且性能不佳的代码
在 jQuery 中,动画化 scrollTop
属性需要同时定位 html
元素和 body
元素,才能使动画在旧版 Internet Explorer 中正常工作。
$("html, body").animate(
{
scrollTop: $div.offset().top
},
1000,
function() {
/* We use a callback to fade in the div once the browser has completed scrolling. */
$div.animate({ opacity: 1 });
}
);
在 Velocity 中,您可以定位要滚动到的元素
$div
.velocity("scroll", 1000)
.velocity({ opacity: 1 });
就像 Velocity 的“reverse”命令一样,“scroll”可以作为 Velocity 的第一个参数传递,以代替属性映射。与 reverse 命令一样,scroll 命令接受动画选项,并且可以链到其他调用中。
scroll 命令的行为很简单:将浏览器滚动到 Velocity 调用目标元素的顶部。
循环
通常,元素的动画需要循环。例如,摇动对话框以指示用户输入无效,或弹跳通知图标以吸引用户的注意力。
在 jQuery 中,循环动画需要通过将其一部分分解为 for 语句来弄乱动画逻辑
for (var i = 0; i < 5; i++) {
$div
/* Slide the element up by 100px. */
.animate({ top: -100 })
/* Then animate back to the original value. */
.animate({ top: 0 });
}
在 Velocity 中,只需将 loop 选项设置为等于所需循环次数的整数即可。一个循环周期包括向属性映射中的值动画化,然后反向动画回原始值。
$div.velocity(
{ top: -100 },
{ loop: 5 }
);
淡入淡出元素
您经常会发现自己淡入一个最初将 display 属性设置为 none
的元素,以便该元素在页面加载时不会立即可见。随后淡入这些元素需要几行 jQuery 代码
$div
/* Use jQuery's $.show() function to make the element visible by switching its display property to "block"/"inline" as appropriate. */
.show()
/* Set the element's starting opacity to 0 so that it can be gradually faded in by the subsequent animation call. */
.css("opacity", 0)
/* Fade in and slide into view. */
.animate({
opacity: 1,
top: "50%"
});
在 Velocity 中,您只需将 display 作为选项传递即可。display 选项接受与其 CSS 属性对应部分相同的取值集(例如,“block”、“inline”和“none”)。
$div.velocity(
{
opacity: 1,
top: "50%"
},
{
display: "block"
}
);
当 display
选项设置为除 none
之外的值时,元素的 display
属性会在动画的 开始 设置为提供的值。相反,当 display 传递的值为 none
时,display 属性会在动画 完成 时设置。
$div
/* Fade out and slide out of view. */
.animate({ opacity: 0, top: "-50%" })
/* Then set the display property to "none" via a queued $.fadeOut() call. */
.fadeOut(1);
$div.velocity(
{
opacity: 0,
top: "-50%"
},
{
display: "none"
}
);
此外,如果元素的 opacity
正在动画化为非零值,而其 display
选项正在设置为除 none
之外的值,则 Velocity 会方便地将 opacity
的起始值默认为 0。
延迟
Velocity 接受 delay 选项,它取代了在动画代码中散布 $.delay()
调用的做法
$div
.delay(1000)
.animate({
opacity: 1
});
$div.velocity(
{
opacity: 1
},
{
delay: 1000
}
);
除了将动画逻辑合并到单个调用中之外,使用 Velocity 的内置 delay 选项还允许 Velocity 通过缓存它们之间的值来优化链式动画。
序列
Velocity 独有的功能是 序列,它是动画的宏:动画序列创建一次,然后可以在需要时跨所有页面上的元素触发。
序列的好处包括:
- 命名动画以实现更好的代码组织。
- 将 UI 动画逻辑与 UI 交互逻辑分开。
- 打包动画以在您的项目之间以及与其他开发人员共享。
序列是通过扩展 $.Velocity.Sequences 对象创建的。此后,通过将序列的名称作为 Velocity 的第一个参数传递来触发它们。
下面是一个简单的“hover”序列
$.Velocity.Sequences.hover = function (element, options) {
var duration = options.duration || 750;
$.Velocity.animate(element,
{
translateY: "-=10px",
}, {
/* Delay is relative to user-adjustable duration. */
delay: duration * 0.033,
duration: duration,
loop: 3,
easing: "easeInOutSine"
});
};
现在,您可以将其应用于元素
$div.velocity("hover");
在上述序列中,元素向上然后向下平移 10px 三次(loop: 3),并带有短暂的延迟。
要了解有关序列细微差别的更多信息,请 阅读其文档。
Velocity 使用其自己的序列功能预先打包了 fadeIn
、fadeOut
、slideUp
和 slideDown
函数(与它们的 jQuery 等效项相同)。
例如,将容器 div 向下滑动到视图中
$div.velocity("slideDown", function() {
/* Then fade in its children over a duration of 1000ms. */
$children.velocity("fadeIn", 1000);
});
强制硬件加速
在元素上强制启用硬件加速 (HA) 是一种简单易行的方法,可以显著提升移动设备上的动画性能。传统上,启用 HA 是通过将元素的 transform 属性设置为 `translateZ(0)` 来实现的。
$div
.css("transform", "translateZ(0)")
.animate({ opacity: 1 })
.css("transform", "none");
在 Velocity 中,HA 会自动应用于移动设备(桌面设备上不会带来性能提升)。Velocity 对 HA 的控制进行了高度优化。
$div.velocity({ opacity: 1 });
总结
本教程的目的是演示 Velocity 如何将动画逻辑整合到你的代码中。简而言之,Velocity 是一款功能强大且高效的 UI 动画制作工具。
虽然 jQuery 功能非常强大,但它从未将自身定位为一个优化的动画引擎,因此在性能和工作流程方面存在一些不足。Velocity 压缩后仅 7Kb,却包含了足够多的功能和速度提升,足以让你考虑将其作为首选动画引擎。
要探索 Velocity 的其他功能,包括颜色和变换动画,请查看 Velocity 的文档 VelocityJS.org。
在结束之前,让我们看看一些通过 Velocity 的功能和速度实现的极端 Web 动画示例。
很棒的东西。这意味着我们不应该再使用 `transition` CSS 属性了吗?
嗨,Mike!这是一个很好的问题。这是我之前在其他地方评论中的一段摘录:
“我建议在仅针对移动设备开发并且动画仅包含简单的状态更改时使用原始 CSS 过渡。在这种情况下,过渡是一种高性能的原生解决方案,允许你在样式表中保留所有动画逻辑,并避免使用 JavaScript 库来使页面膨胀。但是,如果你正在设计复杂的 UI 装饰或开发具有状态化 UI 的应用程序,请始终使用动画库,以便你的动画保持高性能并且工作流程保持可管理。Transit 就是一个能够出色管理 CSS 过渡的库。”
这是一个很棒的、立即可用的总结。谢谢。
比 GSAP 好吗?
我不确定。
这不是重点。GSAP 更适合游戏等场景,而 Velocity 更适合 UI。Velocity 使用简单且完全开源(GSAP 需要许可证费用)。更多信息请访问 http://davidwalsh.name/css-js-animation
+1
我同意 Michal 的观点,GSAP 是一套用于脚本化、高性能 HTML5 动画、游戏等的工具,我真正喜欢 GSAP 的一点是它与所有主要浏览器兼容,因为我并不深入或使用 GSAP,我更习惯普通的语法。
好的,Julian,你引起了我的兴趣。我特别喜欢 Velocity 如何使用 CSS 动画作为实际 JS 变换的蓝图。非常棒。
非常感谢,Ryan。如果你尝试使用 Velocity 并有任何问题,我随时可以通过 Twitter @Shapiro 联系。
VelocityJS 并非为像 GSAP 那样复杂的排序而构建。但它看起来非常适合简单的动画 :)
GSAP 是一款功能强大的完整动画套件。
Velocity 的重点是成为一个非常快速的工具,以提升 UI 动画性能和工作流程。
我不明白为什么它在这种特定情况下依赖于 jQuery,似乎 `$.queue` 是原因所在。
Julian,实现 *Promise*(原生或通过像 **RSVP** 这样的库)对你来说是否过于复杂或不可行?
或者 `$.animate` 确保为你节省了大量工作,从而使插件独立于 jQuery。
嗨,Kevin,
关于 jQuery:我们目前正在努力消除对 jQuery 的依赖——https://github.com/julianshapiro/velocity/issues/5。这并不难。我设计 Velocity 时使其对 jQuery 的依赖降到最低。
关于 Promise:这是一个完全合理的特性添加。你是否有兴趣为此提交一个 GitHub 问题?
谢谢,伙计 :)
Promise 会让 Velocity 变得如此强大。
嗨,Julian
我刚刚看到这个;如果还没有创建,我将在今天结束前提交一个问题。
你可以技术上使用 JavaScript 的原生 Promise(ES6)将 jQuery 的实现更改为更合适的实现,使用 `Promise.resolve()`。
Jake ‘The Great’ Archibald 之前在 HTMl5Rocks 上发表过一篇 关于此的优秀文章。
嗨,Kevin!非常感谢你的跟进。是的,请提交一个问题。
我今天下午会看看 HTML5Rocks 上的文章 :)
关于循环,这是 jQuery 的方法 :)
**演示:** http://jsfiddle.net/tovic/KzRcF/1/embedded/js,result,html,css
这实际上只是迭代链式队列——而不是循环 :)
但它是一个非常棒的技术。非常干净。
我认为,velocity.js 更适合简单的动画,而不是像 gsap 那样高级的动画。
不错的教程,谢谢兄弟 :)
看看这个库:http://motorcortexjs.com/
它基于 velocity.js 构建。使用 MotorCortex.js,你可以通过外部类似 CSS 的语法文件定义所有动画,并仅通过 JavaScript 触发事件以启动它们。
完整的逻辑 - 动画/设计解耦。
我真的很沮丧 Velocity。无法与 CSS 缩放一起使用反向,complete 回调以某种方式混淆了所有内容并保持对象的弹跳。当我尝试使用 UI 包时,它一直向我发送“第一个参数不是属性映射、已知操作或已注册的序列。中止。”,没有关于我需要使用什么的指示,因为到处他都使用 `$elements`。所以我猜它应该是类似 `$(‘div’)` 的东西,但它一直向我发送错误。通过描述和简单的操作,我推荐了 Velocity,但现在,我不确定现在是否能找到任何支持。
我浪费了很多时间试图弄清楚发生了什么,但没有注释也没有涵盖此内容的文档。
请忽略上面的评论,这是 JavaScript 顺序的问题。如果你遇到了相同的错误“第一个参数不是属性映射、已知操作或已注册的序列。中止。”,请检查你的脚本顺序以及 UI 包是否位于 Velocity 之下。
很棒的插件,唯一存在的问题是缩放问题。
嗨,Lucas!
感谢你表达你的担忧 :)
坦率地说:如果你不熟悉 jQuery/JavaScript/编程/Web 动画并且对基本实现细节有疑问,**你应该查看 StackOverflow.com**。
如果你已经走过这条路并且认为你在 Velocity 中遇到了实际的错误,那么有一个非常活跃的 GitHub 问题通道,我非常欢迎所有错误报告:https://github.com/julianshapiro/velocity/issues?state=open。我修复错误的速度非常快 :-p
你只需要使用 JSFiddle 或 CodePen 演示你的错误,然后打开一个新问题来描述你期望看到的行为与 Velocity 实际执行的行为之间的差异。这适用于 GitHub 上的任何项目。加入讨论吧 :)
解决了这个问题后,**您在上面评论中报告的任何问题都没有其他人报告过**。(并且数千名开发者正在使用 Velocity。)
此外,您描述问题的措辞比较模糊,因此很难给出具体的帮助。尽管如此,我还是尽力尝试解决您的问题。
1) 在我的所有测试中,使用反向缩放都运行良好。如果您能创建一个 JS Fiddle 示例,我将很乐意进一步调查您的问题!
2) 尝试使用 jQuery 的 $.animate() 而不是 $.velocity() 来运行您的完整回调代码。如果错误仍然存在,则问题出在您自己的代码中。
3) 对于 UI Pack,您要么在 Velocity 后没有加载文件,要么输入了错误的效果名称。
4) 不确定您在最后关于 $(“div”) 的说法是什么意思。
5) 关于文档:VelocityJS.org 上有很多文档。
再次,请原谅我的直率,我假设您是 JavaScript 初学者。但是,当有人将自己代码中的错误广泛地误认为是 Velocity 中的错误时,我需要肯定地回应,以便读者不会误解 Velocity 的质量和可靠性 :)
糟糕,我刚刚看到了您的后续评论:) 谢谢您的好话。关于缩放问题:让我们一起解决它。如果您想一起编写代码示例,我随时准备着。
嗨,Julian,我真的很满意你回答我的速度(ba dum tiss)。我想我刚刚找到了我的问题。我的按钮有悬停时的过渡效果。当我移除这些过渡效果时,缩放效果可以正常工作:http://jsfiddle.net/hspNd/
它在我的网站上也正常工作。所以,我的问题是:在这种情况下,我应该使用 jQuery 悬停而不是 CSS 动画吗?
哈哈:-D
1) 正确,您通过 CSS 定义的过渡声明会与 Velocity 动画冲突。
2) 好消息。有一个简单的解决方法:只需将所有 *-transition CSS 样式放在 hover 类本身中即可:)
谢谢 Julian!现在一切正常了。对于没有通过正确的渠道联系您,我表示歉意,我这样做是因为我真的很兴奋 Velocity 并感到沮丧,但现在我确信这将是我在未来项目中 Bootstrap 的必备工具。
太棒了。很高兴听到,Lucas。不用道歉——没问题。当您需要任何帮助时,只需查看 SO/GitHub 即可:)
嗨,Julian,
这看起来很棒。在你看来,这与 Transit 有什么区别?我有点困惑。
高度/滚动更改在移动设备上仍然有点粗糙(正在测试旧的 GS3 - 现在归咎于硬件),但比 css3 过渡或原始 jQuery 好(尽管这并不是什么挑战 (;)。我真的很喜欢这个插件的功能 - 它非常适合 UI - 并且文件大小极小(说真的,是怎么做到的..)
嗨,Julian,
我想在动画执行一次后停止它。我该怎么做?我正在使用您的示例代码。
谢谢!感谢您出色的工作!:)