2016-05-23 25 views
1

我試圖創建一個動作,創建一個div並立即向上「浮動」,直到它離開屏幕。在元素創建後立即觸發轉換

爲了做到這一點,我試圖使用CSS transition,這將完全由JavaScript驅動(由於我的使用情況的限制)。

當我創建一個元素,爲其分配轉換樣式屬性,然後立即嘗試通過改變樣式來啓動轉換(top)時,會出現問題。

看起來像一個時間問題正在發生,其中top風格變化在轉換變爲可用之前觸發,因此只需立即將我的div移出屏幕,而不是實際執行轉換。

下面是一個簡化的例子:

var 
    defaultHeight = 50, 
    iCount = 0, 
    aColors = ['red', 'orange', 'yellow', 'green', 'blue', 'purple']; 

function createBlock() { 
    var testdiv = document.createElement('div'); 
    testdiv.className = 'testdiv'; 
    document.body.appendChild(testdiv); 
    testdiv.style.left = '50%'; 
    testdiv.style.backgroundColor = aColors[iCount % aColors.length]; 
    testdiv.style.width = defaultHeight + 'px'; 
    testdiv.style.height = defaultHeight + 'px'; 
    testdiv.style.fontSize = '30px'; 
    testdiv.style.textAlign = 'center'; 
    testdiv.innerHTML = iCount; 
    testdiv.style.top = '500px'; 
    testdiv.style.position = 'absolute'; 
    iCount++; 
    return testdiv; 
} 

document.getElementById('go').onclick = function() { 
    var testdiv = createBlock(); 

    testdiv.style.transition = "top 2.0s linear 0s"; 

    setTimeout(function() { 
     testdiv.style.top = (defaultHeight*-2) + 'px'; 
    }, 0); // <- change this to a higher value to see the transition always occur 
}; 

當「去」按鈕(see JSBin)被點擊迅速在div只出現零星(推測是由於上述的定時問題)。

如果你增加setTimeout的延遲值,你可以看到轉換幾乎總是有效的。

有沒有一種方法可以確定性地在創建元素後立即啓動轉換(而不必求助於延遲)?

+0

你需要在一個類中添加動畫(新)最高值,並將其賦值類代替,否則過渡不知道哪個頂部之間因爲後者動畫價值覆蓋前者。 – LGSon

+0

@LGSon新創建的div給出了'500px'的初始頂部值...爲什麼需要在CSS類中定義(除了作爲最佳實踐)? –

+0

誤讀你的問題有點...會在一秒內發佈答案。 – LGSon

回答

3

對於一個過渡你需要兩個不同的狀態。變化。

在兩個渲染週期樣式之間只會被覆蓋。它們僅在(重新)呈現節點時應用。
因此,如果您的setTimeout()在應用「舊」風格之前觸發,則只會覆蓋風格,並且您的節點將使用目標風格呈現。

Afaik。大多數(桌面)瀏覽器都會爭取60fps的幀速率,這會造成16.7ms的間隔。所以setTimeout(fn,0)很可能會在此之前觸發。你可以像上面提到的那樣增加超時時間(我推薦至少50ms),或者你可以觸發/強制執行節點的渲染;例如通過詢問它的大小。

爲了獲得節點的大小,瀏覽器首先必須將所有樣式應用到節點,以瞭解它們是如何影響它的。
此外,上下文對css很重要,所以Node必須添加到DOM的某處,以便瀏覽器能夠獲得最終計算的樣式。

龍回答簡短:

document.getElementById('go').onclick = function() { 
    var testdiv = createBlock(); 
    testdiv.style.transition = "top 2.0s linear 0s"; 

    testdiv.scrollWidth; //trigger rendering 

    //JsBin brags that you don't do anything with the value. 
    //and some minifyer may think it is irrelevant and remove it. 
    //so, increment it (`++`); the value is readonly, you can do no harm by that. 
    //but the mere expression, as shown, already triggers the rendering. 

    //now set the target-styles for the transition 
    testdiv.style.top = (defaultHeight*-2) + 'px'; 
}; 
+0

很好地工作,+1 ...現在我學到了一些新的東西:) – LGSon

+0

這是您可以有意利用的行爲就像在這種情況下一樣,或者它可以對代碼有一些重要的性能影響,只是簡單地按照您在代碼中執行的操作。因爲在性能方面,你可以做的最昂貴的事情是觸發不必要的重新渲染;通過更改某個節點上的某個className,然後詢問其中一個子節點上的樣式所影響的任何內容。比如說這個職位。 – Thomas

+0

所以你說的是,在這種情況下,使用'動畫'將獲得性能與觸發重新渲染使用'transition'? – LGSon

1

另一種方法是使用animation

如果要動態創建keyframes,用javascript,這裏是一個不錯的職位表明:https://stackoverflow.com/questions/10342494/set-webkit-keyframes-values-using-javascript-variable

var 
 
    defaultHeight = 50, 
 
    iCount = 0, 
 
    aColors = ['red', 'orange', 'yellow', 'green', 'blue', 'purple']; 
 

 
function createBlock() { 
 
    var testdiv = document.createElement('div'); 
 
    testdiv.className = 'testdiv'; 
 
    document.body.appendChild(testdiv); 
 
    testdiv.style.left = '50%'; 
 
    testdiv.style.backgroundColor = aColors[iCount % aColors.length]; 
 
    testdiv.style.width = defaultHeight + 'px'; 
 
    testdiv.style.height = defaultHeight + 'px'; 
 
    testdiv.style.fontSize = '30px'; 
 
    testdiv.style.textAlign = 'center'; 
 
    testdiv.innerHTML = iCount; 
 
    testdiv.style.top = '300px'; 
 
    testdiv.style.position = 'absolute'; 
 
    // you can preset the animation here as well 
 
    //testdiv.style.animation = 'totop 2.0s linear forwards'; 
 
    iCount++; 
 
    return testdiv; 
 
} 
 

 
document.getElementById('go').onclick = function() { 
 
    var testdiv = createBlock(); 
 
    testdiv.style.animation = 'totop 2.0s linear forwards'; 
 
};
@keyframes totop { 
 
    100% { top: -100px; } 
 
}
<button id="go">go</button>

+0

這看起來不錯,但使用動畫需要定義需要用CSS設置的關鍵幀。我正在尋找一種全JS解決方案,我不必在文檔的樣式中添加任何新的東西。我明白這是非標準的。你知道爲什麼動畫在這裏工作,但不是過渡? –

+0

@ Jonathan.Brink動畫在創建和轉換時都有一個開始和結束值,因此需要首先繪製轉換,然後再爲其分配第二個頂部值,這些轉換會踢出。在你的情況下延遲確實會發生。 – LGSon

+0

......「需要首先繪製過渡」可能是理解問題的關鍵......你的意思是「需要首先繪製」?您是否正在談論在轉型實際開始之前發生的一個步驟(通過風格轉變)? –