简体   繁体   English

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

[英]Javascript Typewriter Effect from element childNodes

I am trying to create a type writer effect that will get the nodes of an element and then display the values of those nodes sequentially at a given speed. 我正在尝试创建一个类型编写器效果,它将获取元素的节点,然后以给定的速度顺序显示这些节点的值。 If the node is a text node I want it to go in and sequentially display each character in that text. 如果节点是文本节点,我希望它进入并顺序显示该文本中的每个字符。

HTML: 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: 使用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);

    }                    

Here is an example of an element with the id "message2". 以下是id为“message2”的元素示例。 As you can see it contains some text, then a span containing an image and then some more text. 如您所见,它包含一些文本,然后是包含图像的跨度,然后是一些文本。

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

In my code posted above I am able to create the typewriter effect of the text. 在我上面发布的代码中,我能够创建文本的打字机效果。 However, using the above example, I can't figure out a way to type "Hello" then the span with the image and then "There". 但是,使用上面的例子,我无法找到一种方法来键入“Hello”然后键入带有图像的跨度然后“There”。

I have tried to get the nodes like this: 我试图得到这样的节点:

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

When I log that to the console I get: NodeList(3) [text, span.emote, text] 当我将其记录到控制台时,我得到:NodeList(3)[text,span.emote,text]

From there however I am having trouble accessing the nodeValues. 但是从那里我无法访问nodeValues。 I keep getting errors thrown. 我一直在犯错误。 I am not sure exactly what I am doing wrong. 我不确定我做错了什么。 From there I am also not sure the proper way to empty the "message"+o element and then refill it with the information. 从那里我也不确定正确的方法来清空“消息”+ o元素,然后用信息重新填充它。

Hopefully that explains everything! 希望这能解释一切!

By using $.text() , you are getting your Element's textContent , and all its markup content is gone (actually all its children). 通过使用$.text() ,您将获得Element的textContent ,并且其所有标记内容都已消失(实际上是其所有子项)。

In order to retain this content, you need to store the DOM nodes instead of just their textContent . 为了保留此内容,您需要存储DOM节点而不仅仅是textContent
From there, you will have to detach the DOM tree and walk it while appending every Element, iterating slowly over each TextNode's textContent . 从那里开始,你将不得不分离DOM树并在附加每个Element时移动它,在每个TextNode的textContent缓慢迭代。

However, doing so is not that easy. 但是,这样做并不容易。 Indeed, the fact that we will re-append the DOM nodes inside the document means that the detached DOM tree we were walking will get broken. 实际上,我们将在文档中重新附加DOM节点的事实意味着我们正在行走的分离的DOM树将被破坏。

To circumvent that, we thus need to create a copy of the detached DOM tree, that we will keep intact, so we can continue walking it just like if it were the original one. 为了避免这种情况,我们因此需要创建一个分离的DOM树的副本,我们将保持完整,所以我们可以继续走它,就像它是原始的一样。
And in order to know where to place our elements, we need to store each original node as a property of the cloned one. 并且为了知道在哪里放置元素,我们需要将每个原始节点存储为克隆的属性。

To do so, we'll create two TreeWalkers , one for the original nodes, and one for the cloned version. 为此,我们将创建两个TreeWalkers ,一个用于原始节点,另一个用于克隆版本。 By walking both at the same time, we can set our clones' .original property easily. 通过同时行走,我们可以轻松地设置克隆的.original属性。
We then just have to go back to the root of our clones TreeWalker and start again walking it, this time being able to append the correct node to its original parentNode. 然后,我们必须回到我们的克隆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