【问题标题】:Intercept calls to DOM API functions拦截对 DOM API 函数的调用
【发布时间】:2016-10-14 09:23:38
【问题描述】:

我需要拦截对某些 DOM API 函数的调用并将它们的参数存储为副作用。例如,假设我对函数getElementsByTagNamegetElementById 感兴趣。请参见下面的示例:

"use strict";
const jsdom = require("jsdom");
let document = jsdom.jsdom("<html><head></head><body><div id='foo'><div></div></div></body></html>");
let cpool = {ids: [], tags: []};
let obj = document.getElementById("foo");
// --> cpool = {ids: ["foo"], tags: []}
obj.getElementsByTagName("div"); 
// --> cpool = {ids: ["foo"], tags: ["div"]}

一个重要提示是我使用的是 node.js 并且document 对象是由 jsdom 库实现的。到目前为止,我尝试利用 ES6 代理来修改上述 DOM 函数的行为。

这就是我尝试代理 document 对象以捕获所有方法调用的方式。我想知道是否以及如何使用这种技术或其他技术来解决我的问题。

let documentProxy = new Proxy(document, {
    get(target, propKey, receiver) {
        return function (...args) {
            Reflect.apply(target, propKey, args);
            console.log(propKey + JSON.stringify(args));
            return result;
        };
    }
});    
documentProxy.getElementById("foo");
// --> getElementById["foo"]

【问题讨论】:

  • 我不知道为什么,但听起来你在做坏事......
  • @evolutionxbox bad thing 是什么意思?
  • 你试图通过拦截这些调用来解决的actual problem 是什么?

标签: javascript node.js ecmascript-6 jsdom es6-proxy


【解决方案1】:

如果你只想拦截对这两个函数的调用,你不需要使用代理。您可以只存储原始函数的副本,然后使用保存参数的函数覆盖要拦截调用的函数,然后调用原始函数。

const cpool = {ids: [], tags: []}

;(getElementsByTagNameCopy => {
  document.getElementsByTagName = tag => {
    cpool.tags.push(tag)
    return Reflect.apply(getElementsByTagNameCopy, document, [tag])
  }
})(document.getElementsByTagName)

;(getElementsByTagNameCopy => {
  Element.prototype.getElementsByTagName = function(tag) {
    cpool.tags.push(tag)
    return Reflect.apply(getElementsByTagNameCopy, this, [tag])
  }
})(Element.prototype.getElementsByTagName)

;(getElementByIdCopy => {
  document.getElementById = id => {
    cpool.ids.push(id)
    return Reflect.apply(getElementByIdCopy, document, [id])
  }
})(document.getElementById)

console.log(document.getElementsByTagName('body'))
console.log(document.getElementById('whatever'))
console.log(document.body.getElementsByTagName('div'))
console.log(cpool)

【讨论】:

  • 它只跟踪对文档对象的调用,而不是对元素的调用。例如这里console.log(document.getElementById('test').getElementsByTagName('span')); span 不存储在标签之间。
  • 覆盖每个单独的方法似乎不切实际;只是说。
  • @Gothdo 您的解决方案给出了正确的答案。谢谢你的主意!剩下的唯一问题是使用 node.jsjsdom 来实现相同的效果。
  • @AlexElyasov 它应该可以在带有 jsdom 的 Node.js 中正常工作,您只需要将 Element 替换为 document.defaultView.Element
  • 虽然它仍然觉得 Proxies 可以使解决方案减少样板。
猜你喜欢
  • 2018-08-25
  • 2011-03-23
  • 1970-01-01
  • 1970-01-01
  • 2014-01-07
  • 1970-01-01
  • 1970-01-01
  • 2019-07-07
相关资源
最近更新 更多