2017-07-05 71 views
0

我的目的很簡單:我有一個newSpan()功能,創建一個新的spanmain元素的第一個孩子之前將其插入(或追加,如果main是空的),和一個letterTyper()函數,該函數用存儲在常量CONTENT中的字符串填充插入的元素,同時生成一種向後的分類效果。這個想法是創建一個新的元素,然後用window.onload中的循環在給定的次數內觸發效果。中創建並插入DOM元素執行功能

但是,當我填的是window.onload匿名函數與

window.onload = function() { 
    newSpan(); 
    letterTyper(); 
    newSpan(); 
    letterTyper(); 
} 

我到底是什麼了在DOM是

<main> 
    <span id="#span1">lorem ipsum</span> 
    <span id="#span0"></span> 
</main> 

我還試圖用一個DOMContentLoaded事件,沒有效果。這是爲什麼?我究竟做錯了什麼?

我的代碼:

const CONTENT = 'lorem ipsum'; 
var main = document.querySelector('main'); 
var spanId = 0; 
var charCount = CONTENT.length; 


window.onload = function() { 
    newSpan(); 
    letterTyper(); 
    newSpan(); 
    letterTyper(); 
} 

function newSpan() { 
    var newSpan = document.createElement('span'); 
    var isEmpty = main.innerHTML === ''; 

    newSpan.setAttribute('id', '#span' + spanId); 

    if (isEmpty) { 
    main.appendChild(newSpan); 
    } else { 
    main.insertBefore(newSpan, document.getElementById('#span' + (spanId - 1))); 
    } 

    spanId++; 
} 

function letterTyper() { 
    var targetSpan = main.firstChild; 
    targetSpan.textContent = CONTENT.substring(charCount, charCount + 1) + targetSpan.textContent.substring(0, targetSpan.textContent.length); 
    charCount--; 

    if (charCount < 0) { 
     clearTimeout(timer); 
     charCount = CONTENT.length; 
    } else { 
     timer = setTimeout('letterTyper()', 100); 
    } 
} 
+0

的window.onload執行只有一次,也不要放置任何循環存在。 – Angels

回答

0

setTimeout是異步的。當您第一次致電letterTyper時,它將返回到您的window.onload並觸發下一個newSpan()letterTyper()

這意味着第一個量程的letterTyper環路干擾第二個環路,因爲當第二個環路啓動時第一個環路尚未完成。換句話說,第二個循環永遠不會創建,但所有letterTyper的調用都將看到#span1元素(第二個span元素)作爲main的第一個子元素。

您必須等到第一個循環完成後再開始第二個循環。我建議你看看Promises

我在你的代碼改變了一些東西,所以是現在使用的承諾:

const CONTENT = 'lorem ipsum'; 
 
var main = document.querySelector('main'); 
 
var spanId = 0; 
 
var charCount = CONTENT.length; 
 

 
window.onload = function() { 
 
    // start the first loop 
 
    letterTyper(newSpan()).then(function() { 
 
    // the first loop has finished, start the second loop 
 
    return letterTyper(newSpan()); 
 
    }).then(function() { 
 
    // the second loop has finished, start the third loop 
 
    return letterTyper(newSpan()); 
 
    }); 
 
} 
 

 
function newSpan() { 
 
    var newSpan = document.createElement('span'); 
 
    var isEmpty = main.children.length === 0; 
 

 
    newSpan.setAttribute('id', '#span' + spanId); 
 

 
    if (isEmpty) { 
 
    main.appendChild(newSpan); 
 
    } else { 
 
    main.insertBefore(newSpan, document.getElementById('#span' + (spanId - 1))); 
 
    } 
 

 
    spanId++; 
 
    charCount = CONTENT.length; // reset the character count 
 
    
 
    return newSpan; 
 
} 
 

 
function letterTyper(span) { 
 
    return new Promise(function (resolve, reject) { 
 
    // executes one tick (adds one character and calls itself after 100ms) 
 
    var tick = function() { 
 
     // prepend a new character 
 
     span.textContent = CONTENT[charCount -= 1] + span.textContent; 
 
     if (charCount > 0) { 
 
     // call tick again in 100ms 
 
     setTimeout(tick, 100); 
 
     } else { 
 
     // loop is finished, the "then" part will be called 
 
     resolve(); 
 
     } 
 
    }; 
 
    // start the loop 
 
    setTimeout(tick, 100); 
 
    }); 
 
}
<main></main>