Можно ли получить ссылку на элемент / блок комментария с помощью JavaScript? - PullRequest
20 голосов
/ 17 мая 2011

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

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

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

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

Ответы [ 6 ]

25 голосов
/ 17 мая 2011
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);
12 голосов
/ 23 марта 2016

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

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

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

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

Например:

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

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

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

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

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

9 голосов
/ 19 августа 2014

Основываясь на ответе гиперслуга, вы можете ускорить его, используя стек вместо рекурсии функции.Как показано в этом 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 голосов
/ 31 октября 2014

Если вы используете 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;})
3 голосов
/ 07 марта 2017

Существует 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>

Редактировать: использовать NodeIterator вместо TreeWalker

0 голосов
/ 30 мая 2018

Это старый вопрос, но вот мои два цента на 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');

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...