我正在尝试使用函数式编程和DOM操作。我的目标是在两个值之间切换DOM元素的某些样式。我有所有必需的部件,他们孤立地工作。以下是所用函数的第一个版本:
const toggleBetween = (...args) => {
let index=0;
const ln = args.length;
return () => {
const val = args[index];
index = (index +1)% ln;
return val;
}
}
export const toggleStyle = (domNode, name: string, value: any) => {
const toggleValue = toggleBetween(domNode.style[name], value);
return () => {
domNode.style[name] = toggleValue();
}
}
这两个功能都非常简单。第一个将返回一个函数,该函数将在每次调用时返回列表中的下一个值,第二个函数将返回一个函数,该函数将在当前值和提供的值之间切换给定的样式属性。到现在为止还挺好。
我还有一些函数可以获取所需的DOM元素:
const pickDomA = () => {/* Code that picks and caches DomNode A*/}
const pickDomB = () => {/* Code that picks and caches DomNode B*/}
然后就可以像这样使用
const toggleThing = toggleStyle(pickDomA(), 'display', '');
当我想初始化包含这些函数的模块时出现问题:文档没有准备好,尝试获取DOM节点将返回null并且一切都将失败。
问题在于启动,执行会很好,因为这些功能是由UI元素触发的,只有在文档准备就绪后才可用。
在文档准备好之前,是否有一种优雅但功能性的方法来推迟DOM节点选择?
到目前为止,我得到的最好的是将一个参数访问封装在一个函数中,该函数检查参数是否为函数,如果是,则执行它并返回值。然后,我所要做的就是传递封装为函数的值。
虽然有效,但我发现它有点脆弱,也有点扭曲。如果它不是因为文档初始化一切都会更简单。
看起来像这样:
const getValue = (val) => {
if (typeof val === 'function') {
return val();
}
return val;
}
const toggleBetween = (...args) => {
let index=0;
const ln = args.length;
return () => {
const val = args[index];
index = (index +1)% ln;
return getValue(val);
}
}
export const toggleStyle = (domNode, name: string, value: any) => {
const originalValue = memoize(()=> getValue(domNode).style[name]);
const toggleValue = toggleBetween(originalValue , value);
return () => {
getValue(domNode).style[name] = toggleValue();
}
}
正如您所看到的,现在每个函数都可以使用函数而不是值并执行它来获取值,因此DOM选择将延迟到第一次执行。 memoize
的原因是因为我只想要第一个提取的值,这意味着原始的DOM节点值。
然后,我所要做的就是删除DOM选取功能的()
,一切都会好的:
const toggleThing = toggleStyle(pickDomA, 'display', '');
但同样,我对这个解决方案不满意。还有什么更简单的吗?
答案 0 :(得分:0)
天真地,你只是推迟执行需要文档准备好的代码,即pickDomA()
和pickDomB()
之前不应执行。
这通常是这样做的:
document.addEventListener('DOMContentLoaded', _ => {
const toggleThing = toggleStyle(pickDomA(), 'display', '');
// rest of code that depends on toggleThing ...
});
或者,您确保将pickDomA()
的脚本放在body
标记的末尾:然后DOM就绪了。