Обтекание веб-формы ASP.NET с div вызывает двойную асинхронную обратную передачу, но только с jQuery, а не с обычным DOM. Зачем?
Почему это происходит?
- Возьмите простую веб-форму ASP.NET с одной UpdatePanel и кнопкой.
- В удобной функции события pageLoad на стороне клиента ASP.NET (если хотите, используйте готовый JQuery DOM), оберните элемент формы во вновь созданный элемент div с помощью jQuery.
- Нажмите на кнопку и обратите внимание, что отправляются два асинхронных (xhr) постбека (для их просмотра используйте вкладку "Сеть" в инструментах разработчика браузера F12).
Вот пример кода, чтобы воспроизвести проблему:
<%@ Language="C#" %>
<!DOCTYPE html>
<html>
<head><title>Double async postback when form element wrapped in new div after page load</title></head>
<body>
<form id="frmTest" runat="server">
<asp:ScriptManager ID="smTest" runat="server" ScriptMode="Release" />
<asp:UpdatePanel ID="upTest" runat="server">
<ContentTemplate>
<asp:Button ID="btnTest" runat="server" Text="Test Postback"/>
</ContentTemplate>
</asp:UpdatePanel>
</form>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js" type="text/javascript"></script>
<script type="text/javascript">
function pageLoad() {
// jQuery:
$("<div></div>").insertBefore("form").append($("form"));
// DOM-only:
//document.body.insertBefore(document.createElement("div"), document.forms[0]).appendChild(document.forms[0]);
}
</script>
</body>
</html>
(Я использую простой файл web.config для.NET Framework 4.5.2 и jQuery 1.7.1. Мне удалось воспроизвести это в Firefox 40.0.3, Chrome 45.0.2454.85 и IE 11.)
Теперь обратите внимание, что если вы закомментируете строку jQuery и раскомментируете строку только для DOM, отправляется только один постбэк.
Кроме того, если вы оборачиваете тег формы в div перед загрузкой страницы (то есть в статическом HTML), он работает нормально (без двойной обратной передачи.)
Почему это важно / почему меня это волнует? Многие плагины jQuery (например, jPanelMenu) обертывают все содержимое тега body (или большинство из них) в div, чтобы обеспечить относительно расположенного предка.
1 ответ
Так что, как это часто бывает, в процессе составления правильного вопроса с максимально полным и лаконичным демонстрационным кодом, я полагаю, я нашел ответ.
Я обнаружил, что если я обновлю jQuery до 1.9.0, проблема исчезнет. Но согласно их документации, в версии 1.9.0 произошло много изменений, которые потенциально могли сломать старые плагины (которых в моем проекте несколько.) У меня есть ощущение, что эта проблема связана с этим изменением в 1.9.0:
Загрузка и запуск скриптов внутри содержимого HTML
До версии 1.9 любой принимающий HTML-метод (например, $(), .append() или.wrap()) выполнял любые сценарии в HTML и удалял их из документа, чтобы предотвратить их повторное выполнение. Это все еще ломалось в ситуациях, когда скрипт мог быть удален и вставлен в документ с помощью таких методов, как.wrap(). Начиная с версии 1.9, сценарии, вставленные в документ, выполняются, но остаются в документе и помечаются как уже выполненные, поэтому они не будут выполняться снова, даже если они будут удалены и вставлены заново.
Каждая веб-форма ASP.NET с элементами управления ScriptManager/UpdatePanel имеет эти WebResource.axd и ScriptResource.axd. <script>
теги вставляются в нижней части содержимого элемента формы. Они предоставляют клиентскую среду AJAX. Я считаю, что jQuery перезагружал эти сценарии, когда он добавлял узел формы к новому узлу div, и, следовательно, дублировал обработчики событий обратной передачи. Теперь мой единственный вопрос: почему мне было так трудно это обнаружить? Я не видел каких-либо дополнительных обработчиков событий или дополнительных поисков сценариев (даже кэшированных). Но это отдельный вопрос...:)