功能DOM和闭包,推迟到文档就绪

时间:2017-08-04 10:37:57

标签: javascript dom

背景

我正在尝试使用函数式编程和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', '');

但同样,我对这个解决方案不满意。还有什么更简单的吗?

1 个答案:

答案 0 :(得分:0)

天真地,你只是推迟执行需要文档准备好的代码,即pickDomA()pickDomB()之前不应执行。

这通常是这样做的:

document.addEventListener('DOMContentLoaded', _ => {
    const toggleThing = toggleStyle(pickDomA(), 'display', '');
    // rest of code that depends on toggleThing ...
});

或者,您确保将pickDomA()的脚本放在body标记的末尾:然后DOM就绪了。