【问题标题】:How to console.log entire HTML DOM tree in order with attribute names如何使用属性名称按顺序控制台记录整个 HTML DOM 树
【发布时间】:2018-05-12 10:30:29
【问题描述】:

所以我正在尝试创建一个函数,它将 console.log 整个 HTML 页面的 DOM 树。它应该按照它们出现的顺序输出每个 HTML 元素的标签名称 - 兄弟姐妹之前的孩子 + 属性名称。

我有这段工作代码:

"use strict";

document.addEventListener("DOMContentLoaded", traverse);

function traverse() {
    let elm = document.documentElement;
    displayInfo(elm);
};

function displayInfo(elm){
    //console.log(elm) 
    /* if (elm.childElementCount>0) {
        let children = Array.from(elm.children);
        console.log(children);
        children.forEach( displayInfo );
    }; */
    if (elm.hasAttributes) {
        //console.log(elm.attributes[0]);
    }; 
    var c = elm.childNodes;
    let i;
    for (i = 0; i < c.length; i++) {
        console.log(c[i].nodeName);
        if (c[i].childElementCount>0) {
            //console.log(c[i].childElementCount);
            if (c[i].hasAttributes) {
                //console.log(c[i].attributes[0]);
            };
            let cc = c[i].children;
            let ii;
            for (ii=0; ii < cc.length; ii++) {
                console.log(cc[ii].nodeName);
                if (cc[ii].hasAttributes) {
                    //console.log(cc[ii].attributes[0]);
                };
                if (cc[ii].childElementCount>0) {
                    //console.log(cc[ii].childElementCount);
                    let ccc = cc[ii].children;
                    let iii;
                    for (iii=0; iii < ccc.length; iii++) {
                        console.log(ccc[iii].nodeName);
                        if (ccc[iii].hasAttributes) {
                            //console.log(ccc[iii].attributes[0]);
                        };
                        if (ccc[iii].childElementCount>0) {
                            //console.log(ccc[iii].childElementCount);
                            let cccc = ccc[iii].children;
                            let iiii;
                            for (iiii=0; iiii < cccc.length; iiii++) {
                                console.log(cccc[iiii].nodeName);
                                if (cccc[iiii].hasAttributes) {
                                    //console.log(cccc[iiii].attributes[0]);
                                };
                                if (cccc[iiii].childElementCount>0) {
                                    console.log(cccc[iiii].childElementCount)
                                }
                            }
                        }
                    }
                }
            }
        }
    }
 };

问题是,我在可怕地重复自己,而且我正在手动设置它将穿越的“深度”。有没有办法只声明一个遍历的函数?

PS:我知道这看起来很糟糕,我只是确保该功能能够一直“工作”。

【问题讨论】:

  • 而不是if (condition) { big block },你可以if (!condition) continue;来减少缩进地狱。
  • 在示例中会是什么样子?很抱歉,我仍然不完全熟悉 if 语句

标签: javascript function for-loop


【解决方案1】:

有一个专门用于此的 API,它比您可以尝试自己构建的任何东西都强大得多:TreeWalker。

var walker = document.createTreeWalker(
  document.documentElement,
  NodeFilter.SHOW_ELEMENT // only elements
);
while (walker.nextNode()) {
  let current = walker.currentNode;
  console.log(
    current.tagName,
    [...current.attributes].map(({value,name}) => `${name}=${value}`).join()
  );
}
<article>
  <div id="container">container content
    <span>one span</span>
    <span class="nest1">nest1 span<span class="nest2">nest2 span</span></span>
  </div>
</article>

【讨论】:

  • 这个!这个的一百倍。谢谢!
【解决方案2】:

只是想在一个文档对象元素名称 id 和包含的类中添加这个简单的所有节点日志放在一个整洁的数组中。

console.log(document.getElementsByTagName('*'));

【讨论】:

  • 下班后我将编辑我的答案以包含完整的用例
【解决方案3】:

注意hasAttributes 是一个函数,而不是一个属性。 element.hasAttributes 将永远是 true。

使用递归,像这样:

function displayInfo(node) {
  console.log(node.nodeName);
  if (node.nodeType === 3) {
    console.log('Text node: ' + node.textContent);
    return;
  }
  if (node.hasAttributes()) {
    [...node.attributes].forEach(({ name, value }) => console.log(`${name}=${value}`));
  }
  node.childNodes.forEach(displayInfo);
}
displayInfo(document.documentElement);
<article>
<div id="container">container content
<span>one span</span>
<span class="nest1">nest1 span<span class="nest2">nest2 span</span></span>
</div>
</article>

我提到的continue 快捷方式如下所示:

for (i = 0; i < c.length; i++) {
  console.log(c[i].nodeName);
  if (c[i].childElementCount === 0) continue;
  //console.log(c[i].childElementCount);
  if (c[i].hasAttributes) {
    //console.log(c[i].attributes[0]);
  };
  let cc = c[i].children;

尽可能避免缩进 - 你会让你的代码更具可读性。

【讨论】:

  • 好吧,这有点工作,但现在它忽略了类型 3 以外的其他节点,直接进入 textContent。我正在寻找的是一些东西,它将一直从文档节点开始,检查属性(如果有的话 - console.log 它们)然后检查子节点和 console.log 它们,然后越来越深入和更深。这实际上非常好,因为您的代码适用于文本,这是我以前无法做到的,但现在它不会记录父节点的名称,如 HTML、HEAD(元、标题)和 BODY(部分。 .) 等等。
  • 只需在documentElement 上调用它。
  • 你所说的快捷方式是指那三个点...?
  • 完全没有,就像我说的那样——一种减少缩进地狱的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-02-22
  • 2015-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多