【问题标题】:How can I get all the HTML in a document or node containing shadowRoot elements如何获取包含 shadowRoot 元素的文档或节点中的所有 HTML
【发布时间】:2021-12-20 08:46:14
【问题描述】:

我还没有看到这个问题的满意答案。这基本上是this question 的副本,但它被错误地关闭并且给出的答案不够充分。

我想出了我自己的解决方案,我将在下面发布。

这对于网页抓取很有用,或者在我的情况下,在处理自定义元素的 javascript 库上运行测试。我确保它产生了我想要的输出,然后我使用这个函数为给定的测试输出抓取 HTML,并使用复制的 HTML 作为 expected 输出来比较未来的测试.

【问题讨论】:

    标签: javascript web-scraping shadow-dom custom-element native-web-component


    【解决方案1】:

    这是一个可以执行请求的函数。请注意,它忽略了 html cmets 和其他边缘事物。但它使用 shadowRoots 检索常规元素、文本节点和自定义元素。它还处理开槽的模板内容。它尚未经过详尽的测试,但似乎可以很好地满足我的需求。

    extractHTML(document.body)extractHTML(document.getElementByID('app')) 一样使用它。

    function extractHTML(node) {
                
        // return a blank string if not a valid node
        if (!node) return ''
    
        // if it is a text node just return the trimmed textContent
        if (node.nodeType===3) return node.textContent.trim()
    
        //beyond here, only deal with element nodes
        if (node.nodeType!==1) return ''
    
        let html = ''
    
        // clone the node for its outer html sans inner html
        let outer = node.cloneNode()
    
        // if the node has a shadowroot, jump into it
        node = node.shadowRoot || node
        
        if (node.children.length) {
            
            // we checked for children but now iterate over childNodes
            // which includes #text nodes (and even other things)
            for (let n of node.childNodes) {
                
                // if the node is a slot
                if (n.assignedNodes) {
                    
                    // an assigned slot
                    if (n.assignedNodes()[0]){
                        // Can there be more than 1 assigned node??
                        html += extractHTML(n.assignedNodes()[0])
    
                    // an unassigned slot
                    } else { html += n.innerHTML }                    
    
                // node is not a slot, recurse
                } else { html += extractHTML(n) }
            }
    
        // node has no children
        } else { html = node.innerHTML }
    
        // insert all the (children's) innerHTML 
        // into the (cloned) parent element
        // and return the whole package
        outer.innerHTML = html
        return outer.outerHTML
        
    }
    

    【讨论】:

      【解决方案2】:

      只有使用mode:"open" 设置创建shadowRoots 才能从外部访问shadowRoots。

      然后,您可以使用 something 进入 元素和 shadowRoots,例如:

       const shadowDive = (
                el, 
                selector, 
                match = (m, r) => console.warn('match', m, r)
        ) => {
          let root = el.shadowRoot || el;
          root.querySelector(selector) && match(root.querySelector(selector), root);
          [...root.children].map(el => shadowDive(el, selector, match));
        }
      

      注意:如果 Web 组件样式基于 shadowDOM 行为,则提取原始 HTML 是没有意义的;您将失去所有正确的样式。

      【讨论】:

      • 你能解释一下这个函数应该如何使用吗?你应该将什么传递给“匹配”?
      • 它需要一个与 inside 每个 shadowRoot 的内容匹配的 selector
      • 是的,我得到了 el 和 selector,但你还没有解释应该是什么匹配,所以我不能使用它。
      • 您可以指定自己的函数来“操作”内部 shadowroots
      • 好的,你的代码不是问题的答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-28
      • 1970-01-01
      • 2015-02-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多