insertBefore代理元素:参数2的类型不是“节点”

时间:2019-07-28 12:18:29

标签: javascript dom proxy

我必须提供一个无法修改的外部脚本画布。不幸的是,我稍后必须更换画布,所以我创建了一个简单的可变代理。但是,外部脚本会尝试以我的代理对象作为第二个参数执行insertBefore,并且以某种方式失败。

重现问题(摆脱了可变性以简化一点):

var canvas = new Proxy(document.getElementById("canvas"), {
    get: function get(target, property, receiver) {
      let originalProperty = target[property]
      return typeof originalProperty === "function"
        ? originalProperty.bind(target)
        : originalProperty
    },
    set: function(target, property, value, receiver) {
      target[property] = value
    }
  })

canvas.parentElement.insertBefore(document.createElement('div'), canvas)

结果:

Uncaught TypeError: Failed to execute 'insertBefore' on 'Node': parameter 2 is not of type 'Node'.

有趣的部分:canvas instanceof Node返回truetypeof canvas返回"object",但typeof document.getElementById("canvas")也返回。

1 个答案:

答案 0 :(得分:1)

解决方案涉及重载 public class Script1 : MonoBehaviour { public List<string> testList = new List<string>(); void Start() { testList.Add ("Item 1"); testList.Add ("Item 2"); testList.Add ("Item 3"); } } public class Script2 : MonoBehaviour { Script1 s1; IEnumerator Start() { s1 = GetComponent<Script1>(); yield return new WaitForEndOfFrame(); foreach(string s in s1.testList) print (s); } } 并使用How to get the target of a JavaScript Proxy?中找到的方法

在代理处理程序中,getter为属性Node.prototype.insertBefore添加了一个条件,以返回原始目标节点。

然后在PROXY_NODE重载中,检查该属性是否为真,并更改是否为第一个参数

insertBefore
const PROXY_NODE = Symbol('PROXY_NODE');

// Overload Node.prototype.insertBefore
const oldInsertBefore = Node.prototype.insertBefore;

Node.prototype.insertBefore = function(...args) {  
  if (args[0][PROXY_NODE]) {
    args[0] = args[0][PROXY_NODE];
    console.log(args[0]);
  }
  oldInsertBefore.apply(this, args)
}

// proxy handler
const handler = {
  get: (target, property, receiver) => {
    if (property === PROXY_NODE) {
      return target
    }
    return Reflect.get(target, property, receiver)
  },
  set: function(target, property, value, receiver) {
    target[property] = value
  }
}

// Create proxy node
const proxyNode = new Proxy(document.createElement("div"), handler);
// proxy setter is working
proxyNode.textContent = 'Proxy Content';

// insert proxy node
var parentDiv = document.getElementById("parentElement");
var childDiv = document.getElementById("childElement");
parentDiv.insertBefore(proxyNode, childDiv );