5

Question

How to create a proxy for browser native DOM object?


Background

I want to intercept the settings for the element style. So I create a proxy for the DOM object. However, it causes error when I use some function like getComputedStyle().

  const setHandler = (target: any, prop: PropertyKey, value: any, _receiver?: any) => {
    if (/*some condition*/) {
      target[prop] = value
    }
    return true
  }

  const getHandler = (target: any, prop: PropertyKey, _receiver?: any) => {
    return target[prop]
  }

  const style = new Proxy(el.style, {
    get: getHandler,
    set: setHandler
  })
  const classList = new Proxy(el.classList,{
    get: getHandler,
    set: setHandler
  })

  const proxy = new Proxy(el/*HTMLElement*/, {
    get: (target, prop, _receiver) => {
      if (prop === 'target') {
        return target
      }
      if (prop === 'style') {
        return style
      }
      if (prop === 'classList') {
        return classList
      }
      return getHandler(target, prop, target)
    },
    set: setHandler
  })

  const style = getComputedStyle(el)

el is the native browser DOM object. In my code, there are many methods whose parameters are el, and these methods may modify el.

I want to prevent some of these methods from modifying el, so I am trying to proxy the el object.

But after the proxy, some methods for DOM objects can't be used on proxy objects (like getComputedStyle()).


Demo

I create a demo below.

(function() {
  const node = document.querySelector('#demo')
  const proxy = new Proxy(node, {
    getPrototypeOf(target){
      return Object.getPrototypeOf(target)
    },
    get(target, prop, receiver){
      let value = target[prop]
      if (typeof value === 'function') {
        value = Function.prototype.bind.call(value, target)
      }
      return value
    },
    set(target, prop,value, receiver){
      target[prop] = value
    },
    apply(target, args, newTarget) {
      return Object.apply(target,args)
    },
  })
  console.log(proxy)
  console.log(Object.getPrototypeOf(proxy))         
 
  console.log(proxy.style)

  // error: Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
  const style = getComputedStyle(proxy)
  console.log(style)
})()
<div id='demo'>demo</div>
Zearin
  • 1,474
  • 2
  • 17
  • 36
Ryths Xia
  • 61
  • 3
  • 1
    Please describe what you mean by "proxy element". What are you trying to accomplish? Where is `el` declared? – Scott Marcus May 06 '19 at 15:42
  • 2
    1) You call `getComputedStyle` onto `el`, not on `proxy`. 2) You should really use `Reflect.get` and others. 3) "but get error" which error? [mcve] please. – Jonas Wilms May 06 '19 at 15:45
  • @JonasWilms A minimal example would be: `div = document.createElement('div'); proxy=new Proxy(div, {}); getComputedStyle(proxy)` . The last command throws the error, claiming that `proxy` does not implement the interface `Element`. This seems in contrast to `proxy instanceof HTMLElement == true`. Extending the handler with `Reflect.get` etc doesn't seem to work to get around this issue. The function `document.body.appendChild(proxy)` throws a similar error. Both function don't regard the Proxy as an HTMLElement, which leads to a major limitation of what one can do with a Proxy. – Sebastian Nov 28 '22 at 14:18
  • just as a remark, this question is closely related to another [SO question, trying to make a proxy undetectable](https://stackoverflow.com/questions/45688944/javascript-make-proxy-undetectable) . It's not a duplicate, but the answer to the former question would probably also lead to an answer for this question. – Sebastian Nov 28 '22 at 15:14

0 Answers0