Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

子应用使用innerHTML生成子节点时候会出现instanceof异常 #256

Closed
jardenliu opened this issue Nov 14, 2022 · 6 comments
Closed

Comments

@jardenliu
Copy link
Contributor

写了一个简单的demo

可以使用wujie在线预览的功能查看效果(https://wujie-micro.github.io/doc/wujie/)

demo1的链接:https://www.jarden.vip/wujie-demo/demo1.html
demo2的链接:https://www.jarden.vip/wujie-demo/demo2.html

场景描述:

  1. 父div 使用 innerHTML 构建子div
  2. 将父节点插入body (在 wujie中是插入 shadowroot 的 body)
  3. 使用document.querySelector 获取子节点

问题描述:

  1. 直接使用 document.querySelector 获取的子节点, child instanceof HTMLElement 为 false
  2. 奇怪的是在document.querySelector之前执行 parentDiv.querySelector 获取子节点, child instanceof HTMLElement 为 true

期望值:
child instanceof HTMLElement 均为 true

@jardenliu
Copy link
Contributor Author

附上demo1 demo2的代码:
demo1 代码

<!DOCTYPE html>
<html lang="en">
<body>
    <div id="result"></div>

    <script>
        const parent = document.createElement('div')
        parent.innerHTML = '<div id="child"></div>'
        document.body.appendChild(parent)

        const child  = document.querySelector('#child')

        console.log(child instanceof HTMLElement) //  false 
        
        document.getElementById('result').innerHTML = `child instanceof HTMLElement: ${child instanceof HTMLElement}`
        
    </script>
</body>
</html>

demo2代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Demo2</title>
</head>
<body>
    <div id="result"></div>

    <script>
        const parent = document.createElement('div')
        parent.innerHTML = '<div id="child"></div>'
        document.body.appendChild(parent)

        parent.querySelector('#child') // 先使用parent querySelector
        const child  = document.querySelector('#child')

        console.log(child instanceof HTMLElement) // true  
        
        document.getElementById('result').innerHTML = `child instanceof HTMLElement: ${child instanceof HTMLElement}`
        
    </script>
</body>
</html>

@yiludege
Copy link
Collaborator

这个地方确实比较奇怪,不过 docuemnt.createElement 统一用的是父应用的 document.createElement

如果要判断元素是否是 htmlElement 可以用 (child instanceof HTMLElement || child instanceof window.top.HTMLElement) ?

@jardenliu
Copy link
Contributor Author

其实这个是我这边用了quill这个编辑器发现的,像这种第三方库,多处出现这种 instanceof HTMLElement 、 instanceof Text ,还有就是代码混淆过,使用jsloader去替换,要考虑的情景很多,正则写起来也很吃力

@jardenliu
Copy link
Contributor Author

@yiludege 这个是我这边目前workaround的做法

const raw = window.HTMLElement;
window.HTMLElement = new Proxy(raw, {
    get(target, p ,receiver) {

        if (p === Symbol.hasInstance) {
            return function (obj) {
                const res = Object.[Symbol.hasInstance].apply(this, arguments) // 默认行为
                if (res) return res
                if (obj instanceof window.parent.HTMLElement) return true // 父容器HTMLElemnt对比
                return false
            }
        }

        return Reflect.get(target, p ,receiver);
    }
})

@jardenliu
Copy link
Contributor Author

有小伙伴遇到类似问题,临时解决方法可以参考楼上👆

@yiludege
Copy link
Collaborator

在这个 #275 中已经将createElement等替换成iframe的原生的,但是还是存在这个问题,目前我这边也没有更好的方法,先这样处理吧

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants