繁体   English   中英

来自元素childNodes的Javascript打字机效果

[英]Javascript Typewriter Effect from element childNodes

我正在尝试创建一个类型编写器效果,它将获取元素的节点,然后以给定的速度顺序显示这些节点的值。 如果节点是文本节点,我希望它进入并顺序显示该文本中的每个字符。

HTML:

<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

<!-- item will be appened to this layout -->
<div id="log" class="sl__chat__layout">
</div>


<!-- chat item -->
<script type="text/template" id="chatlist_item">

  <div data-from="{from}" data-id="{messageId}" id="messageID">
    <div id="messageBox">

    <span id="message">
      {message}
    </span>

    </div>
  </div>
</script>

使用Javascript:

// Please use event listeners to run functions.
document.addEventListener('onLoad', function(obj) {
    // obj will be empty for chat widget
    // this will fire only once when the widget loads
});

document.addEventListener('onEventReceived', function(obj) {
    // obj will contain information about the event
e++  
typeEffect(e);  
});

var speed = 50;
var e = 1;

function typeEffect(inp) {
    var o = inp;
    document.getElementById("messageID").id= "messageID"+o;
    document.getElementById("message").id= "message"+o;
    var text = $("#message"+o).text();
    $("#message"+o).text('');

    var i = 0;
    var timer = setInterval(function() {
        if(i < text.length) {
            $("#message"+o).append(text.charAt(i));
            i++;
        }

        else{
            clearInterval(timer);
        };   
  }, speed);

    }                    

以下是id为“message2”的元素示例。 如您所见,它包含一些文本,然后是包含图像的跨度,然后是一些文本。

   <span id="message2">
      Hello 
      <span class="emote">
         <img src="https://static-cdn.jtvnw.net/emoticons/v1/1251411/1.0"> 
      </span> 
      There
    </span>

在我上面发布的代码中,我能够创建文本的打字机效果。 但是,使用上面的例子,我无法找到一种方法来键入“Hello”然后键入带有图像的跨度然后“There”。

我试图得到这样的节点:

   var contents = document.getElementById("message"+o).childNodes;

当我将其记录到控制台时,我得到:NodeList(3)[text,span.emote,text]

但是从那里我无法访问nodeValues。 我一直在犯错误。 我不确定我做错了什么。 从那里我也不确定正确的方法来清空“消息”+ o元素,然后用信息重新填充它。

希望这能解释一切!

通过使用$.text() ,您将获得Element的textContent ,并且其所有标记内容都已消失(实际上是其所有子项)。

为了保留此内容,您需要存储DOM节点而不仅仅是textContent
从那里开始,你将不得不分离DOM树并在附加每个Element时移动它,在每个TextNode的textContent缓慢迭代。

但是,这样做并不容易。 实际上,我们将在文档中重新附加DOM节点的事实意味着我们正在行走的分离的DOM树将被破坏。

为了避免这种情况,我们因此需要创建一个分离的DOM树的副本,我们将保持完整,所以我们可以继续走它,就像它是原始的一样。
并且为了知道在哪里放置元素,我们需要将每个原始节点存储为克隆的属性。

为此,我们将创建两个TreeWalkers ,一个用于原始节点,另一个用于克隆版本。 通过同时行走,我们可以轻松地设置克隆的.original属性。
然后,我们必须回到我们的克隆TreeWalker的根,然后再次开始它,这次能够将正确的节点附加到其原始的parentNode。

 async function typeWrite(root, freq) { // grab our element's content const content = [...root.childNodes]; // move it to a documentFragment const originals = document.createDocumentFragment(); originals.append.apply(originals, content); // clone this documentFragment so can keep a clean version of the DOM tree const clones = originals.cloneNode(true); // every clone will have an `original` node // clones documentFragment's one is the root Element, still in doc clones.original = root; // make two TreeWalkers const originals_walker = document.createTreeWalker(originals, NodeFilter.SHOW_ALL, null); const clones_walker = document.createTreeWalker(clones, NodeFilter.SHOW_ALL, null); while(originals_walker.nextNode() && clones_walker.nextNode()) { // link each original node to its clone clones_walker.currentNode.original = originals_walker.currentNode } while(clones_walker.parentNode()) { // go back to root } // walk down only our clones (will stay untouched now) while(clones_walker.nextNode()) { const clone = clones_walker.currentNode; const original = clone.original; // retrieve the original parentNode (which is already in doc) clone.parentNode.original .append(original); // and append the original version of our currentNode if(clone.nodeType === 3) { // TextNode const originalText = original.textContent; // we use a trimmed version to avoid all non visible characters const txt = originalText.trim().replace(/\\n/g, ''); original.textContent = ''; // in doc => empty for now let i = 0; while(i < txt.length) { await wait(freq); // TypeWriting effect... original.textContent += txt[i++]; } // restore original textContent (invisible to user) original.textContent = originalText; } } } typeWrite(message2, 200) .catch(console.error); function wait(time) { return new Promise(res => setTimeout(res, time)); } 
 <span id="message2"> Hello <span class="emote"> <img src="https://static-cdn.jtvnw.net/emoticons/v1/1251411/1.0"> </span> There </span> 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM