mip2
mip2 copied to clipboard
MIP.sandbox.document.querySelector('body').ownerDocument.defaultView 指向 window
要解决什么问题 MIP.sandbox.document.querySelector('body').ownerDocument.defaultView 指向 window
描述一下你理想中的解决方案 MIP.sandbox.document.querySelector('body').ownerDocument.defaultView 指向 MIP.sandbox
描述你的备选方案 无
补充信息 无
问题的原因在于 Node.prototype.ownerDocument ,实例化后的对象调用ownerDocument 会返回当前 document 对象,而 document 的原型链上的属性 defaultView 指向 document 所关联的 window,因此需要对这个属性进行屏蔽操作:
Object.defineProperty(Node.prototype, 'ownerDocument', {
get: function () {
return MIP.sandbox.document
}
})
这样,这些操作结果均返回 undefined
MIP.sandbox.document.defaultView // undefined
document.querySelector('.markdown-body').ownerDocument.defaultView // undefined
document.body.ownerDocument.defaultView // undefined
如果存在需要 document.defaultView 的情况,可申请 document.defaultView 的白名单,这样,MIP.sandbox.document.defaultView 将返回 MIP.sandbox:
Object.defineProperty(MIP.sandbox.document, 'defaultView', {
get: function () {
return MIP.sandbox
}
})
已知兼容性问题有: 华为荣耀6出错
但这个做法存在一个问题,就是修改 Node.prototype 的影响面是全局性的,并不能将其仅作用在组件代码中,这样是否会导致某些第三方库出错呢? 或者是否有一些别的方法去处理这个 ownerDocument?
想到一个解决方案,就是对需要进行沙盒诸如的代码中,所有的 MemberExpression 做处理。 举例如下:
// a.b
wrapper(a, 'b')
// a['a' + 1]
wrapper(a, 'b' + c)
// a[1].b.c
wrapper(wrapper(wrapper(a, 1), 'b'), 'c')
// def wrapper
function wrapper (obj, prop) {
let val = obj[prop]
if (val === window) {
return MIP.sandbox
}
if (val === document) {
return MIP.sandbox.document
}
return val
}
这样一来就能够解决 document.querySelector('body').ownerDocument.defaultView 指向 window 的问题,以及类似的通过别的属性访问操作,访问到 window 或者 document 的情况。而且这种做法也不会导致之前讨论中提到的会影响到全局。
当然,这样子处理存在的问题就是,会降低属性访问的执行效率,就看值不值得了。
性能问题是否可以考虑只在开发环境下校验