我正在尝试创建一个类型编写器效果,该效果将获取元素的节点,然后以给定的速度顺序显示这些节点的值。如果该节点是文本节点,则希望它进入并按顺序显示该文本中的每个字符。
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)[文本,span.emote,文本]
但是从那里我无法访问nodeValues。我不断出错。我不确定自己在做什么错。从那里我也不确定清空“ message” + o元素然后重新填充信息的正确方法。
希望一切都能解释!
答案 0 :(得分:0)
通过使用$.text()
,您将获得Element的textContent
,并且其所有标记内容均消失了(实际上是其所有子代)。
为了保留此内容,您需要存储DOM节点而不是仅存储它们的textContent
。
从那里,您将必须分离DOM树并在附加每个Element的同时对其进行遍历,并在每个TextNode的textContent
上缓慢地进行迭代。
但是,这样做并不容易。确实,我们将在文档内部重新添加DOM节点这一事实意味着分离的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>