#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 Я обновлю вопрос с помощью этой информации.