2013-03-10 287 views
1

下面的JavaScript代码会生成CSS以使用随机值设置动画。代码复杂且重复。这段代码如何写得更优雅?如何让这个JavaScript/CSS随机动画代码更简单?

axis=["X","Y","Z"]; 
document.write("@keyframes tumble { "+ 
"12% {transform:rotate"+axis[Math.floor(Math.random()*3)]+"(-"+Math.floor(Math.random()*180)+"deg) rotate"+axis[Math.floor(Math.random()*3)]+ 
"("+Math.floor(Math.random()*180)+"deg) rotate"+axis[Math.floor(Math.random()*3)]+"("+Math.floor(Math.random()*180)+"deg)}"+ 
"32% {transform:rotate"+axis[Math.floor(Math.random()*3)]+"(-"+Math.floor(Math.random()*180)+"deg) rotate"+axis[Math.floor(Math.random()*3)]+ 
"("+Math.floor(Math.random()*180)+"deg) rotate"+axis[Math.floor(Math.random()*3)]+"("+Math.floor(Math.random()*180)+"deg)}"+ 
"50% {transform:rotate"+axis[Math.floor(Math.random()*3)]+"("+Math.floor(Math.random()*180)+"deg) rotate"+axis[Math.floor(Math.random()*3)]+ 
"("+Math.floor(Math.random()*180)+"deg) rotate"+axis[Math.floor(Math.random()*3)]+"("+Math.floor(Math.random()*180)+"deg)}"+ 
"66% {transform:rotate"+axis[Math.floor(Math.random()*3)]+"("+Math.floor(Math.random()*180)+"deg) rotate"+axis[Math.floor(Math.random()*3)]+ 
"("+Math.floor(Math.random()*180)+"deg) rotate"+axis[Math.floor(Math.random()*3)]+"("+Math.floor(Math.random()*180)+"deg)}"+ 
"84% {transform:rotate"+axis[Math.floor(Math.random()*3)]+"("+Math.floor(Math.random()*180)+"deg) rotate"+axis[Math.floor(Math.random()*3)]+ 
"("+Math.floor(Math.random()*180)+"deg) rotate"+axis[Math.floor(Math.random()*3)]+"("+Math.floor(Math.random()*180)+"deg)}"+"}</style>"); 
+2

对于这样的问题,也许你最好关闭,以更好地http://codereview.stackexchange.com/ – Nobita 2013-03-11 00:47:11

回答

3

我要对答案的工作在一个时间步和大家分享一下,我去。

第一个简单的步骤是一些非常小的重新格式化,只是为了缩短行长度并使其更容易看到代码。在实践中,我可能就不会担心该导线长度在这一点上,但更短的行会显示更好地在这里:

axis = [ "X","Y","Z" ]; 

document.write(
    "@keyframes tumble { "+ 

    "12% {transform:rotate" + 
    axis[Math.floor(Math.random()*3)] + 
    "(-" + Math.floor(Math.random()*180) + "deg) rotate" + 
    axis[Math.floor(Math.random()*3)] + 
    "(" + Math.floor(Math.random()*180) + "deg) rotate" + 
    axis[Math.floor(Math.random()*3)] + 
    "(" + Math.floor(Math.random()*180) + "deg)}" + 

    "32% {transform:rotate" + 
    axis[Math.floor(Math.random()*3)] + 
    "(-" + Math.floor(Math.random()*180) + "deg) rotate" + 
    axis[Math.floor(Math.random()*3)] + 
    "(" + Math.floor(Math.random()*180) + "deg) rotate" + 
    axis[Math.floor(Math.random()*3)] + 
    "(" + Math.floor(Math.random()*180) + "deg)}" + 

    "50% {transform:rotate" + 
    axis[Math.floor(Math.random()*3)] + 
    "(" + Math.floor(Math.random()*180) + "deg) rotate" + 
    axis[Math.floor(Math.random()*3)] + 
    "(" + Math.floor(Math.random()*180) + "deg) rotate" + 
    axis[Math.floor(Math.random()*3)] + 
    "(" + Math.floor(Math.random()*180) + "deg)}" + 

    "66% {transform:rotate" + 
    axis[Math.floor(Math.random()*3)] + 
    "(" + Math.floor(Math.random()*180) + "deg) rotate" + 
    axis[Math.floor(Math.random()*3)] + 
    "(" + Math.floor(Math.random()*180) + "deg) rotate" + 
    axis[Math.floor(Math.random()*3)] + 
    "(" + Math.floor(Math.random()*180) + "deg)}" + 

    "84% {transform:rotate" + 
    axis[Math.floor(Math.random()*3)] + 
    "(" + Math.floor(Math.random()*180) + "deg) rotate" + 
    axis[Math.floor(Math.random()*3)] + 
    "(" + Math.floor(Math.random()*180) + "deg) rotate" + 
    axis[Math.floor(Math.random()*3)] + 
    "(" + Math.floor(Math.random()*180) + "deg)}" + 

    "}</style>" 
); 

两个项目跳出马上:它看起来像有一个遗漏<style>标签在生成的代码开始(最后有一个</style>)。axis = ...声明中缺少var

这是显而易见的,接下来的事情就是发生了一遍又一遍在代码中这两种模式:

Math.floor(Math.random()*3) 

Math.floor(Math.random()*180) 

让我们写一些功能,使那些简单,做一个简单的搜索和替换,以改变现有的代码使用这些功能:

// Return a random integer n in the range 0 <= n < limit 
function randInt(limit) { 
    return Math.floor(Math.random() * limit); 
} 

// Return a random integer n in the range 0 <= n < 3 
function rand3() { 
    return randInt(3); 
} 

// Return a random integer n in the range 0 <= n < 180 
function rand180() { 
    return randInt(180); 
} 

var axis = [ "X","Y","Z" ]; 

// Write a <style> tag to the document with a random animation 
document.write(
    "<style>@keyframes tumble { "+ 

    "12% {transform:rotate" + 
    axis[rand3()] + 
    "(-" + rand180() + "deg) rotate" + 
    axis[rand3()] + 
    "(" + rand180() + "deg) rotate" + 
    axis[rand3()] + 
    "(" + rand180() + "deg)}" + 

    "32% {transform:rotate" + 
    axis[rand3()] + 
    "(-" + rand180() + "deg) rotate" + 
    axis[rand3()] + 
    "(" + rand180() + "deg) rotate" + 
    axis[rand3()] + 
    "(" + rand180() + "deg)}" + 

    "50% {transform:rotate" + 
    axis[rand3()] + 
    "(" + rand180() + "deg) rotate" + 
    axis[rand3()] + 
    "(" + rand180() + "deg) rotate" + 
    axis[rand3()] + 
    "(" + rand180() + "deg)}" + 

    "66% {transform:rotate" + 
    axis[rand3()] + 
    "(" + rand180() + "deg) rotate" + 
    axis[rand3()] + 
    "(" + rand180() + "deg) rotate" + 
    axis[rand3()] + 
    "(" + rand180() + "deg)}" + 

    "84% {transform:rotate" + 
    axis[rand3()] + 
    "(" + rand180() + "deg) rotate" + 
    axis[rand3()] + 
    "(" + rand180() + "deg) rotate" + 
    axis[rand3()] + 
    "(" + rand180() + "deg)}" + 

    "}</style>" 
); 

正如你看到的,代码已经简单。

现在让我们来看看这五个相似的代码块之间有什么相同以及不同之处。将这些块加载到可逐字符(intraline)差异的程序中很有用。我为此使用Araxis MergeBeyond Compare是另一个不错的选择。这些都是商业产品;毫无疑问,这也是很好的免费选择。

这里是Araxis合并显示,当我们第一块与上次比较:

Araxis Merge diff of two similar code blocks

(如果你不喜欢的字体,不怪Araxis,这只是我的个人设置。并与自动换行宽度较窄只是为了使其适合在列这里)

我们可以看到,只有两个区别:第一行的百分比数,以及"(-""("第三线。的确,这些是所有区块中唯一的两个区别。

所以,我们现在可以做的是编写一个函数,返回这段代码,让我们插入这两个值。

// Return a transform:rotate string with the specified 
// percent and flag 
function makeTransform(percent, flag) { 
    return (
     percent + "% {transform:rotate" + 
     axis[rand3()] + 
     "(" + flag + rand180() + "deg) rotate" + 
     axis[rand3()] + 
     "(" + rand180() + "deg) rotate" + 
     axis[rand3()] + 
     "(" + rand180() + "deg)}" 
     ); 
} 

现在看看这个函数,还有中的重复那几个东西。但是这一点非常简单,重复是相当小的。由于我们在这,但是,让我们看看我们如何重构代码多一点:

// Return a random axis and degree string 
function randAxisDegree(flag) { 
    return axis[rand3()] + "(" + flag + rand180() + "deg)"; 
} 

// Return a transform:rotate string with the specified 
// percent and flag 
function makeTransform(percent, flag) { 
    return (
     percent + "% {transform:rotate" + 
      randAxisDegree(flag) + " rotate" + 
      randAxisDegree("") + " rotate" + 
      randAxisDegree("") + 
     "}" 
    ); 
} 

当然,现在我们可能会注意到,rand3()rand180()功能我早些时候是不是真的有必要,因为他们现在每个人只使用一个地方,根本就不需要单独的功能。

其实,回看代码,这两个功能都没有,即使他们称为多处真正有用的:rand3()几乎比randInt(3)更好,或保持相同的简洁,甚至重命名功能rand()所以我们可以说rand(3)而不是rand3()

我很想试着编辑这个答案,从一开始就采取这种方法,但让我们单独留下来,以显示重构可能带来的有点歪曲的路径。现在,我们将虽然删除它们,并直接从randAxisDegree()调用randInt()

// Return a random axis and degree string 
function randAxisDegree(flag) { 
    return axis[randInt(3)] + "(" + flag + randInt(180) + "deg)"; 
} 

现在我们可以看到这一切是如何结合在一起的:

// Return a random integer n in the range 0 <= n < limit 
function randInt(limit) { 
    return Math.floor(Math.random() * limit); 
} 

var axis = [ "X", "Y", "Z" ]; 

// Return a random axis and degree string 
function randAxisDegree(flag) { 
    return axis[randInt(3)] + "(" + flag + randInt(180) + "deg)"; 
} 

// Return a transform:rotate string with the specified 
// percent and flag 
function makeTransform(percent, flag) { 
    return (
     percent + "% {transform:rotate" + 
      randAxisDegree(flag) + " rotate" + 
      randAxisDegree("") + " rotate" + 
      randAxisDegree("") + 
     "}" 
    ); 
} 

// Write a <style> tag to the document with a random animation 
document.write(
    "<style>@keyframes tumble { " + 
     makeTransform(12, "-") + 
     makeTransform(32, "-") + 
     makeTransform(50, " ") + 
     makeTransform(66, " ") + 
     makeTransform(84, " ") + 
    "}</style>" 
); 
+1

谢谢Michael,非常优雅!我一直在努力想出这样的事情。 – gaba 2013-03-11 00:42:47

+0

不客气,gaba,我很高兴知道这很有帮助。请务必在我继续进行简化过程的过程中查看最新版本的答案。新代码很好,很干净 - 如果我自己这样说的话。 :-) 唉,由于某种原因,您的问题已关闭。这对我没有意义:我认为这是一个非常好的问题。我很高兴我有机会在结束之前回答它。 – 2013-03-11 18:28:45

+0

伟大的思想过程。在初始的“rand3”和“rand180”中留下一个很好的方式来说明初始化简化过程如何在以后被颠倒或消除,但这是该过程的关键部分。有时你只需要让事情更清洁一点,这样即使这些更改后来被分解出来,你也可以开始围绕它进行思考。 – brichins 2016-09-09 17:17:47