2013-03-10 87 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