代码之家  ›  专栏  ›  技术社区  ›  Akxe

代理HTMLElement

  •  5
  • Akxe  · 技术社区  · 8 年前

    我想检查一个库对我传递给它的视频元素做了什么,所以我天真地这样做了:

    cosnt videoElement = new Proxy(document.querySelector('video'), {
        get(target, key) {
            const name = typeof key === 'symbol'? key.toString() : key;
            console.info(`Accessing video.${ name }`)
            return target[key];
        }
    });
    

    但我有个错误:

    TypeError:未能在“节点”上执行“包含”:参数1不是“节点”类型。

    有没有办法让这一切顺利进行?


    编辑:我获得了一些知识,通过它我将我的代理更新为fallow:

    cosnt videoElement = document.querySelector('video');
    cosnt proxyElement = new Proxy(videoElement , {
        get(target, key) {
            if (key == '___element___') {
                return video;
            }
    
            const name = typeof key === 'symbol'? key.toString() : key;
            console.info(`Accessing video.${ name }`);
            const value = video[key];
            if (value instanceof Function) {
                return video[key].bind(video);
            } else {
                return video[key];
            }
        },
        set(target, key, value) {
            const name = typeof key === 'symbol'? key.toString() : key;
            console.info(`Writing video.${ name } = ${ value }`);
            video[key] = value;
            return true;
        }
    });
    

    这是为了调试,所以我编辑了编译后的代码,并用 element.___element___ .

    接下来,我发现通过代理调用函数似乎有问题,所以我添加了 .bind(video) 部分

    最后,设定值是投掷。所以我不得不用直接视频引用替换目标(事实上,我用视频替换了所有的目标引用,只是为了确定),这让它工作了。。。我不知道为什么或如何,但确实如此。

    问题是:

    • 这是真的吗?(小标题) document.body.contains(myProxyElement) (部分)
    • 在代理内部设置时设置视频元素的值看起来很奇怪,这是错误吗?(第三点,也有点像第二点,我想它是相连的)

    奖励:游乐场

    const video = document.querySelector('video');
    const proxy = new Proxy(video, {
      get(target, key) {
        console.log(`Getting video.${typeof key === 'symbol'? key.toString() : key}`);
        const value = video[key];
        if (value instanceof Function) {
          return value.bind(video);
        } else {
          return value;
        }
      },
      set(target, key, value) {
        console.log(`Setting video.${typeof key === 'symbol'? key.toString() : key} =`, value);
        video[key] = value;
        return true;
      }
    });
    
    proxy.muted = true;
    proxy.play();
    proxy.controls = true;
    try {
      console.log(document.body.contains(proxy));
    } catch (e) {
      console.error('DOM operation failed', e);
    }
    video { max-width: 100%; }
    <video src="//vjs.zencdn.net/v/oceans.mp4">
    1 回复  |  直到 8 年前
        1
  •  1
  •   Daniel de Andrade Varela    5 年前

    正如评论中已经提到的那样 Proxy 对象将不会自动强制转换为 Node 打电话的时候 document.body.contains(proxy) .

    因此,您可以设置一个返回代理目标的特定密钥:

    const video = document.querySelector('video');
    const proxy = new Proxy(video, {
        get(target, key) {
            const value = video[key];
            if (value instanceof Function) {
                return value.bind(video);
            } else if (key == 'target') {
                return target;
            } else {
                return value;
            }
        },
        set(target, key, value) {
            target[key] = value;
            return true;
        }
    });
    

    然后你可以做:

    console.log(document.body.contains(proxy.target));
    

    编辑 :

    这是真的吗?(小标题) 文件身体包含(myProxyElement)部分:

    是的,我看不出其他方法可以做到这一点。

    设置代理内部时将值设置为视频元素抛出 看起来很奇怪,是虫子吗?(第三点,我想也是第二点 已连接):

    因为我无法重现这个问题,所以很难说。也许试着替换 new Proxy(video, ... 具有 new Proxy({}, ... 然后将视频设置为 proxy.video = video (您还必须更新 get 和 set )看看这是怎么回事?