Подтвердить что ты не робот

Можно ли получить ссылку на элемент/блок комментария JavaScript?

Звучит немного сумасшедшим, но мне интересно, можно ли получить ссылку на элемент комментария, чтобы я мог динамически заменить его другим контентом на JavaScript.

<html>
<head>
</head>
<body>
<div id="header"></div>
<div id="content"></div>
<!-- sidebar place holder: some id-->
</body>
</html>

На вышеприведенной странице я могу получить ссылку на блок комментариев и заменить его некоторым содержимым в локальном хранилище?

Я знаю, что у меня может быть владелец места. Просто интересно, относится ли это к блоку комментариев. Спасибо.

4b9b3361

Ответ 1

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);

Ответ 2

Кажется, есть законные (производительность) проблемы с использованием комментариев в качестве заполнителей - например, нет селектора CSS, который может соответствовать узлам комментариев, поэтому вы не сможете запросить их, например. document.querySelectorAll(), что делает его сложным и медленным для нахождения элементов комментариев.

Мой вопрос тогда был, есть ли еще один элемент, который я могу разместить в строке, который не имеет видимых побочных эффектов? Я видел некоторых людей, использующих тег <meta>, но я изучил это, и использование этого в <body> не является допустимой разметкой.

Итак, я остановился на теге <script>.

Использовать собственный атрибут type, поэтому он фактически не будет выполняться как script и использовать атрибуты data- для любых данных инициализации, требуемых script, которые собираются инициализировать ваши заполнители.

Например:

<script type="placeholder/foo" data-stuff="whatevs"></script>

Затем просто запросите те теги - например:

document.querySelectorAll('script[type="placeholder/foo"]')

Затем замените их по мере необходимости - здесь простой пример DOM.

Обратите внимание, что placeholder в этом примере не является какой-либо определенной "реальной" вещью - вы должны заменить ее, например. vendor-name, чтобы убедиться, что ваш type не сталкивается ни с чем "реальным".

Ответ 3

Построив ответ на гиперслог, вы можете ускорить его, используя стек вместо рекурсии функции. Как показано в этом jsPerf, рекурсия функций на моем Chrome 36 на Windows медленнее на 42% и на 71% с IE11 в режиме совместимости с IE8. Похоже, что он работает примерно на 20% медленнее в IE11 в граничном режиме, но быстрее во всех других протестированных случаях.

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;
}

Ответ 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;})

Ответ 5

Существует 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);
}
#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);
}
<html>
<head>
</head>
<body>
<div id="header"></div>
<div id="content"></div>
<!-- sidebar place holder: some_id -->
</body>
</html>

Ответ 6

Это старый вопрос, но здесь мои два цента на DOM "заполнители" IMO, элемент комментария идеально подходит для работы (действительный html, не виден и не вводит в заблуждение в любом случае). Однако обходить дом в поисках комментариев не обязательно, если вы строите свой код наоборот.

Я бы предложил использовать следующий метод:

  1. Пометьте места, которые вы хотите "контролировать", с помощью разметки по вашему выбору (например, элемент div с определенным классом)

    <div class="placeholder"></div>
    <div class="placeholder"></div>
    <div class="placeholder"></div>
    <div class="placeholder"></div>
    <div class="placeholder"></div>
    
  2. Найдите заполнители обычным способом (querySelector/classSelector и т.д.)

var placeholders = document.querySelectorAll('placeholder');

  1. Замените их комментариями и сохраните ссылки на эти комментарии:

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 -->
  1. Теперь вы можете получить доступ к каждому из этих комментариев непосредственно с помощью встроенного refArray и делать то, что хотите, например...

заменить второй комментарий заголовком

let headline = document.createElement('h1'); headline.innerText = "I am a headline!"; refArray[1].parentNode.replaceChild(headline,refArray[1]);

Ответ 7

Вот как я это делаю:

function getCommentNodes(element)
{
    let treeWalker = document.createTreeWalker(element, NodeFilter.SHOW_COMMENT);
    let commentNodes = [];
    while(treeWalker.nextNode()) {commentNodes.push(treeWalker.currentNode);}
    return commentNodes;
};