我必须为无法修改的外部脚本提供画布。不幸的是,我稍后必须更换画布,因此我创建了一个简单的可变代理。但是,外部脚本尝试以我的代理对象作为第二个参数执行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
返回true
。 typeof canvas
返回"object"
,但typeof document.getElementById("canvas")
也返回。 最佳答案
解决方案涉及重载Node.prototype.insertBefore
并使用How to get the target of a JavaScript Proxy?中的方法
在代理处理程序中,getter为属性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 );
<div id="parentElement">
<div id="childElement">Child</div>
</div>
关于javascript - insertBefore代理元素:参数2的类型不是“节点”,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57240828/