这听起来有点疯狂,但我想知道是否有可能获得对comment元素的引用,以便我可以用JavaScript动态替换其他内容。
<html>
<head>
</head>
<body>
<div id="header"></div>
<div id="content"></div>
<!-- sidebar place holder: some id-->
</body>
</html>
在上面的页面中,我可以参考注释块并将其替换为本地存储中的某些内容吗?
我知道我可以有一个div占位符。只是想知道它是否适用于评论块。 感谢。
答案 0 :(得分:25)
var findComments = function(el) {
var arr = [];
for(var i = 0; i < el.childNodes.length; i++) {
var node = el.childNodes[i];
if(node.nodeType === 8) {
arr.push(node);
} else {
arr.push.apply(arr, findComments(node));
}
}
return arr;
};
var commentNodes = findComments(document);
// whatever you were going to do with the comment...
console.log(commentNodes[0].nodeValue);
答案 1 :(得分:12)
似乎存在使用注释作为占位符的合法(性能)问题 - 例如,没有可以匹配注释节点的CSS选择器,因此您将无法使用注释来查询它们。 document.querySelectorAll()
,这使得定位评论元素既复杂又缓慢。
我的问题是,是否有另一个我可以放置内联的元素,它没有任何可见的副作用?我看到有些人使用<meta>
标记,但我调查了这一点,并在<body>
中使用该标记是无效的标记。
所以我确定了<script>
标签。
使用自定义type
属性,因此它实际上不会作为脚本执行,并使用data-
属性来处理初始化占位符的脚本所需的任何初始化数据。
例如:
<script type="placeholder/foo" data-stuff="whatevs"></script>
然后只需查询这些标签 - 例如:
document.querySelectorAll('script[type="placeholder/foo"]')
然后根据需要更换它们 - here's a plain DOM example。
请注意,此示例中的placeholder
不是任何已定义的“真实”内容 - 您应将其替换为例如vendor-name
以确保您的type
不会与任何“真实”相冲突。
答案 2 :(得分:9)
基于hyperrslug的答案,你可以通过使用堆栈而不是函数递归来加快速度。如此jsPerf所示,Windows上的Chrome 36上的函数递归慢了42%,IE8兼容模式下的IE11下降了71%。在边缘模式下,IE11的运行速度似乎慢了约20%,但在所有其他测试情况下运行速度更快。
function getComments(context) {
var foundComments = [];
var elementPath = [context];
while (elementPath.length > 0) {
var el = elementPath.pop();
for (var i = 0; i < el.childNodes.length; i++) {
var node = el.childNodes[i];
if (node.nodeType === Node.COMMENT_NODE) {
foundComments.push(node);
} else {
elementPath.push(node);
}
}
}
return foundComments;
}
或者在TypeScript中完成:
public static getComments(context: any): Comment[] {
var foundComments = [];
var elementPath = [context];
while (elementPath.length > 0) {
var el = elementPath.pop();
for (var i = 0; i < el.childNodes.length; i++) {
var node = el.childNodes[i];
if (node.nodeType === Node.COMMENT_NODE) {
foundComments.push(node);
} else {
elementPath.push(node);
}
}
}
return foundComments;
}
答案 3 :(得分:4)
如果您使用jQuery,则可以执行以下操作以获取所有注释节点
comments = $('*').contents().filter(function(){ return this.nodeType===8; })
如果您只想要正文的评论节点,请使用
comments = $('body').find('*').contents().filter(function(){
return this.nodeType===8;
})
如果您希望将注释字符串作为数组,则可以使用map
:
comment_strings = comments.map(function(){return this.nodeValue;})
答案 4 :(得分:3)
有一个用于文档节点遍历的API:Document#createNodeIterator()
:
var nodeIterator = document.createNodeIterator(
document.body,
NodeFilter.SHOW_COMMENT,
{ acceptNode: function(node) { return NodeFilter.FILTER_ACCEPT; } }
);
// Replace all comment nodes with a div
while(nodeIterator.nextNode()){
var commentNode = nodeIterator.referenceNode;
var id = (commentNode.textContent.split(":")[1] || "").trim();
var div = document.createElement("div");
div.id = id;
commentNode.parentNode.replaceChild(div, commentNode);
}
&#13;
#header,
#content,
#some_id{
margin: 1em 0;
padding: 0.2em;
border: 2px grey solid;
}
#header::after,
#content::after,
#some_id::after{
content: "DIV with ID=" attr(id);
}
&#13;
<html>
<head>
</head>
<body>
<div id="header"></div>
<div id="content"></div>
<!-- sidebar place holder: some_id -->
</body>
</html>
&#13;
修改:使用NodeIterator代替TreeWalker
答案 5 :(得分:0)
这是一个老问题,但这是关于DOM“占位符”的两分钱 IMO注释元素非常适合这项工作(有效的HTML,不可见,不会以任何方式误导)。 但是,如果以相反的方式构建代码,则无需遍历dom寻找注释。
我建议使用以下方法:
使用您选择的标记标记您想要“控制”的地方(例如,具有特定类别的div元素)
<div class="placeholder"></div>
<div class="placeholder"></div>
<div class="placeholder"></div>
<div class="placeholder"></div>
<div class="placeholder"></div>
以通常的方式查找占位符(querySelector / classSelector等)
var placeholders = document.querySelectorAll('placeholder');
var refArray = [];
[...placeholders].forEach(function(placeholder){
var comment = document.createComment('this is a placeholder');
refArray.push( placeholder.parentNode.replaceChild(comment, placeholder) );
});
在此阶段,您呈现的标记应如下所示:
<!-- this is a placeholder -->
<!-- this is a placeholder -->
<!-- this is a placeholder -->
<!-- this is a placeholder -->
<!-- this is a placeholder -->
用标题替换第二条评论
let headline = document.createElement('h1');
headline.innerText = "I am a headline!";
refArray[1].parentNode.replaceChild(headline,refArray[1]);
答案 6 :(得分:0)
如果您只想从文档或文档的一部分中获取所有注释的数组,那么这是我发现在现代JavaScript中最有效的方法。
function getComments (root) {
var treeWalker = document.createTreeWalker(
root,
NodeFilter.SHOW_COMMENT,
{
"acceptNode": function acceptNode (node) {
return NodeFilter.FILTER_ACCEPT;
}
}
);
// skip the first node which is the node specified in the `root`
var currentNode = treeWalker.nextNode();
var nodeList = [];
while (currentNode) {
nodeList.push(currentNode);
currentNode = treeWalker.nextNode();
}
return nodeList;
}
我在Chrome 80中每秒获得超过50,000次操作,而堆栈和递归方法在Chrome 80中每秒都获得不到5,000次操作。我在Node.js中处理了成千上万的复杂文档,最适合我。
答案 7 :(得分:0)
使用 document.evaluate 和 xPath:
function getAllComments(node) {
const xPath = "//comment()",
result = [];
let query = document.evaluate(xPath, node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
for (let i = 0, length = query.snapshotLength; i < length; ++i) {
result.push(query.snapshotItem(i));
}
return result;
}
getAllComments(document.documentElement);
根据我的测试,使用 xPath 比 treeWalker 更快: https://jsben.ch/Feagf