将递归函数转换为异步 CPS 实现 (javascript)
Converting a recursive function into an asynchronous CPS implementation (javascript)
这是我的函数。
function duplicate_step_through_highlighted (element_jq, target_jq, char_cb) {
console.log( element_jq);
var contents = element_jq.contents();
for (var i = 0 ; i < contents.length; ++i) {
// if text node, step
if (contents[i].nodeType === 3) {
// insert empty text node
var new_tn = document.createTextNode('');
target_jq.append(new_tn);
// iterate it
var text = contents[i].nodeValue;
for (var j = 0; j < text.length; j++) {
char_cb(text[j],new_tn);
new_tn.nodeValue += text[j];
// *** I want an async delay here ***
}
} else { // type should be 1: element
// target_jq gets a duplicate element inserted, copying attrs
var new_elem = $(contents[i].cloneNode(false)).appendTo(target_jq);
duplicate_step_through_highlighted($(contents[i]),$(new_elem),char_cb);
// then a recursive call is performed on the newly created element as target_jq
// and the existing one as element_jq. char_cb is passed in
}
}
}
我正在做的是通过一次重建一个字符来重建一个 HTML 元素。这样做有一个很好的理由,我希望它被"输入"的视觉效果。
所以现在没有延迟,所以我的元素会立即被复制。我已经检查了结果是否一致,但我越来越清楚,我可能需要完全重写功能,以便能够在插入每个字符后输入异步延迟。
我是否需要重写它并有一个堆栈来跟踪我在元素中的位置?
你可能想看看我最近的答案或这个旧的答案(演示(,关于如何实现这样的效果。
提示: 不要将元素克隆到新元素中,只需隐藏它们并使它们逐个部分显示即可。
此外,除了本机 DOM 元素之外,根本不处理 jQuery 实例可能更容易。所以是的,重写可能会做:-(而且我认为它也确实需要一个堆栈。
function animate(elements, callback) {
/* get: array with hidden elements to be displayes, callback function */
var i = 0;
(function iterate() {
if (i < elements.length) {
elements[i].style.display = "block"; // show
animateNode(elements[i], iterate);
i++;
} else if (callback)
callback();
})();
function animateNode(element, callback) {
var pieces = [];
if (element.nodeType==1) {
while (element.hasChildNodes())
pieces.push(element.removeChild(element.firstChild));
setTimeout(function childStep() {
if (pieces.length) {
animateNode(pieces[0], childStep);
element.appendChild(pieces.shift());
} else
callback();
}, 1000/60);
} else if (element.nodeType==3) {
pieces = element.data.match(/.{0,2}/g); // 2: Number of chars per frame
element.data = "";
(function addText(){
element.data += pieces.shift();
setTimeout(pieces.length
? addText
: callback,
1000/60);
})();
}
}
}
animate($("#foo").children());
jsfiddle.net 演示
工作原理:
addText
函数向当前文本节点添加一些字符,并为自己设置超时 - 动画!如果一切都完成,它会调用callback
函数。-
childStep
在子节点上运行动画,并将自身作为回调传递,直到没有子节点 - 然后调用callback
函数。 - 两者一起,
animateNode
递归地运行在节点树上,并按其顺序对文本节点进行动画处理。 iterate
函数通过自身作为回调传递自身,对所有输入元素调用animateNode
(取消阻碍后(。完成所有输入元素后,它会调用外部callback
作为animate
的第二个参数给出。
这是我的解决方案,这是一种更高效、更干净、更快捷的方法:
var start = 0; //Makes sure you start from the very beggining of the paragraph.
var text = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras viverra sem dolor, nec tempor purus luctus vitae. Nulla massa metus, iaculis et orci euismod, faucibus fringilla metus. Sed pellentesque in libero nec.'; //Your text
var speed = 14; //Of course you can choose your own speed, 0 = instant, the more you add the slower it gets.
function typeWriter() {
if (start < text.length) {
document.querySelector('.demo').innerHTML += text.charAt(start);
start++;
}
setTimeout(typeWriter, speed);
}
<body onload="typeWriter();">
<p class="demo"></p>
</body>
我制作了一个简单的脚本在我的网站上使用,它可能会帮助那些希望实现这种效果的人。
这是Github上的存储库的链接,这是解释:
class Typer {
constructor(typingSpeed, content, output) {
this.typingSpeed = typingSpeed;
// Parses a NodeList to a series of chained promises
this.parseHtml(Array.from(content), output);
};
makePromise(node, output) {
if (node.nodeType == 1) // element
{
// When a new html tag is detected, append it to the document
return new Promise((resolve) => {
var tag = $(node.outerHTML.replace(node.innerHTML, ""));
tag.appendTo(output);
resolve(tag);
});
} else if (node.nodeType == 3) // text
{
// When text is detected, create a promise that appends a character
// and sleeps for a while before adding the next one, and so on...
return this.type(node, output, 0);
} else {
console.warn("Unknown node type");
}
}
parseHtml(nodes, output) {
return nodes.reduce((previous, current) => previous
.then(() => this.makePromise(current, output)
.then((output) => this.parseHtml(Array.from(current.childNodes), output))), Promise.resolve());
}
type(node, output, textPosition) {
var textIncrement = textPosition + 1;
var substring = node.data.substring(textPosition, textIncrement);
if (substring !== "") {
return new Promise(resolve => setTimeout(resolve, this.typingSpeed))
.then(() => output.append(substring))
.then(() => this.type(node, output, textIncrement));
}
return Promise.resolve(output);
}
}
相关文章:
- 绑定函数时在IE7中未实现Javascript错误
- 可以't实现JavaScript翻转计数器
- 如何实现 Javascript 自动完成功能
- 实现JavaScript内部方法的源代码
- 当实现javascript倒计时时,其他html元素将消失
- 在aspx页面中实现javascript时出现问题
- 这是实现javascript字符串长度属性的正确方法吗
- 将递归函数转换为异步 CPS 实现 (javascript)
- 如何在Wordpress中实现javascript
- 在jQuery方法中实现Javascript变量
- 无法实现 JavaScript 代码
- 在 Rails 应用程序中实现 JavaScript 库
- 如何实现 JavaScript 对象继承
- 我将如何实现JavaScript
- 当浏览器开始实现JavaScript时,如何在支持一两个版本较旧的浏览器的同时开始使用它们
- 有没有其他方法可以在纯python中实现javascript的onClick()函数
- 如何在JavaCC中实现JavaScript自动分号插入
- 响应式网页设计 - 如何实现JavaScript部分
- 用Selfish实现Javascript中的简单继承
- 如何实现JavaScript/ECMAScript“;这里没有线路终止器”;JavaCC中的规则