Как извлечь содержимое из полностраничной HTML-строки с помощью jQuery find

#javascript #jquery #html #ajax #typescript

#javascript #jquery #HTML #ajax #typescript

Вопрос:

У меня есть метод TypeScript, который предназначен для извлечения определенных элементов частичного представления из входящей HTML-строки, загруженной Ajax (если это полное представление).

Строка ниже возвращает длину 0, даже если строка содержит элемент с class="body-content" :

 $(html).find('.body-content')
  

Функция:

     // Extract a panel from a HTML string
    // Allow for multiple child elements
    private _extractPanel(html: string): JQuery
    {
        var $panel: JQuery;

        // Test for full vs. partial view in html
        if (/<html>/i.test(html))
        {
            // Full view: Match the content selector and extract its children
            $panel = $(html).find('.body-content').first().children();
            // *** THE LINE ABOVE GIVES ZERO MATCHES! ***
        }
        else
        {
            // Partial view: Simply return the entire partial view
            $panel = $(html);
        }
        return $panel;
    }
  

Это потому, что корень — это HTML элемент или что-то еще, что я пропустил? $(html) возвращает объект длиной 63, но find не возвращает совпадений.

Вот пример значения html параметра из отладчика:

 <!DOCTYPE html>
<html>

    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Index - My ASP.NET Application</title>
        <link href="/Content/bootstrap.css" rel="stylesheet" />
        <link href="/Content/site.css" rel="stylesheet" />
        <script src="/Scripts/modernizr-2.7.2.js"></script>
    </head>

    <body>
        <div class="navbar navbar-inverse navbar-fixed-top">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <span class="icon-bar"></span>
 <span class="icon-bar"></span>
 <span class="icon-bar"></span>

                    </button> <a class="navbar-brand" href="/">jQuery Tardis</a>

                </div>
                <div class="navbar-collapse collapse">
                    <ul class="nav navbar-nav">
                        <li><a href="/">Home</a>
                        </li>
                        <li><a href="/Home/About">About</a>
                        </li>
                        <li><a href="/Home/Contact">Contact</a>
                        </li>
                    </ul>
                    <ul class="nav navbar-nav navbar-right">
                        <li><a href="/Account/Register" id="registerLink">Register</a>
                        </li>
                        <li><a href="/Account/Login" id="loginLink">Log in</a>
                        </li>
                    </ul>
                </div>
            </div>
        </div>
        <div class="container body-content">
            <div id="testpanel" class="row">
                <div class="AddinListView"> <a href="/">Home</a>

                     <h2>Tardis transition examples</h2>

                    <ul>
                        <li><a href="/Transition/Transition/1?transition=none" target="_self">No transition (hide/show)</a>
                        </li>
                        <li><a href="/Transition/Transition/1?transition=slide" target="_self">Slide out/in</a>
                        </li>
                        <li><a href="/Transition/Transition/1?transition=fade" target="_self">Fade out/in transtions</a>
                        </li>
                    </ul>
                </div>
            </div>
            <hr />
        </div>
        <footer>
            <p>amp;copy; 2014 - My ASP.NET Application</p>
        </footer>
    </body>

</html>
  

Продолжение: http://jsfiddle.net/TrueBlueAussie/7AvmW/2 /

Основываясь на ответе from Jack , я собрал приведенный выше JSFiddle, чтобы посмотреть, что происходит.

Результат:

В основном $(html) для строки, содержащей недопустимые дочерние элементы, такие как HTML HEAD и BODY , эти элементы разворачиваются jQuery.Эффект, который я обнаружил, конечно, заключался в том, что первый уровень тела возвращался только к корневым элементам.

Решение:

Самое простое решение — всегда создавать элемент страницы с фиктивным родительским элементом для поиска.

например

 $html =$('<div>').html(html);
  

тогда будет работать любой обычный поиск:

 $html.find('.selector');
  

Комментарии:

1. Глупый вопрос, но вы пробовали $(html).filter('.body-content') ?

2. @Jack: Совсем не глупо, как выясняется. Это возвращает длину 1. Можете ли вы объяснить, почему DOM, по-видимому, сплющен (почему это сработало)? Пожалуйста, отправьте сообщение в качестве ответа 🙂

Ответ №1:

При использовании jQuery(html) он создает временное <div> , а затем присваивает его .innerHTML свойству заданное содержимое HTML. После этого выполняется итерация по .childNodes свойству для создания набора jQuery.

В документации также указано:

При передаче в сложном HTML некоторые браузеры могут не генерировать DOM, который точно копирует предоставленный источник HTML … Во время этого процесса некоторые браузеры отфильтровывают определенные элементы, такие как <html> , <title> , или <head> элементы. В результате вставленные элементы могут не соответствовать исходной переданной строке.

В Chrome (и, возможно, в других браузерах тоже), когда таким образом загружается целая страница, .firstChild свойство temporary <div> является первым дочерним элементом <body> :

 var d = document.createElement('div');
d.innerHTML = '<html><body><span>hi</span></body></html>';
console.log(d.firstChild); // <span>hi</span>
  

Решение

Для .find() надежного использования вы можете загрузить страницу во временный элемент следующим образом:

 var $root = $('<div>', {html: html});
var $items = $root.find('.body-content');
  

Если вы уже знаете структуру страницы заранее, вы также можете использовать .filter() :

 var $items = $(html).filter('.body-content');
  

Комментарии:

1. Это объясняет, почему работала эта предыдущая версия: var $panel = $('<div/>').html(html); , затем выполнение проверок.

2. Это довольно странное поведение $() documented anywhere?

3. $(html).filter('.body-content').index() возвращает 7, но это не 8-й дочерний элемент body, это примерно 8-й элемент, найденный последовательно в body. Я думаю, мой единственный вопрос сейчас: почему он сплющен?

4. Я проведу несколько экспериментов, например, для отображения иерархии, созданной на основе приведенного выше кода и HTML, и отчета. Спасибо за вашу помощь (которая действительно решила непосредственную проблему).

5. Вот результат моего эксперимента… По-видимому, это просто выравнивает тело. Стоит знать: jsfiddle.net/TrueBlueAussie/7AvmW/2 Я обновлю вопрос с помощью этой информации.