Как определяется кнопка отправки по умолчанию в форме HTML?


210

Если форма отправлена, но не с помощью какой-либо конкретной кнопки, например,

  • нажав Enter
  • используя HTMLFormElement.submit()в JS

Как браузер должен определить, какую из нескольких кнопок отправки, если они есть, использовать как нажатую?

Это важно на двух уровнях:

  • вызов onclickобработчика события, прикрепленного к кнопке отправки
  • данные отправляются обратно на веб-сервер

Мои эксперименты до сих пор показали, что:

  • при нажатии EnterFirefox, Opera и Safari используют первую кнопку отправки в форме
  • при нажатии EnterIE использует либо первую кнопку отправки, либо ни одной вообще, в зависимости от условий, которые я не смог выяснить
  • все эти браузеры вообще не используют ни один для отправки JS

Что говорит стандарт?

Если это поможет, вот мой тестовый код (PHP относится только к моему методу тестирования, а не к самому моему вопросу)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Test</title>
</head>

<body>

<h1>Get</h1>
<dl>
<?php foreach ($_GET as $k => $v) echo "<dt>$k</dt><dd>$v</dd>"; ?>
</dl>

<h1>Post</h1>
<dl>
<?php foreach ($_POST as $k => $v) echo "<dt>$k</dt><dd>$v</dd>"; ?>
</dl>

<form name="theForm" method="<?php echo isset($_GET['method']) ? $_GET['method'] : 'get'; ?>" action="<?php echo $_SERVER['SCRIPT_NAME']; ?>">
    <input type="text" name="method" />
    <input type="submit" name="action" value="Button 1" onclick="alert('Button 1'); return true" />
    <input type="text" name="stuff" />
    <input type="submit" name="action" value="Button 2" onclick="alert('Button 2'); return true" />
    <input type="button" value="submit" onclick="document.theForm.submit();" />
</form>

</body></html>

Ответы:


115

Если вы отправляете форму через Javascript (то есть formElement.submit()или что-либо эквивалентное), то ни одна из кнопок отправки не считается успешной, и ни одно из их значений не включается в отправленные данные. (Обратите внимание, что если вы отправляете форму с помощью, submitElement.click()то отправка, на которую вы ссылались, считается активной; это не относится к сфере компетенции вашего вопроса, поскольку здесь кнопка отправки является однозначной, но я решил включить ее для людей, которые читают первую часть и задаются вопросом, как сделать кнопку отправки успешной с помощью отправки формы JS. Конечно, обработчики отправки формы все равно будут срабатывать таким образом, тогда как они не будут проходить, form.submit()так что это еще один чайник рыбы ...)

Если форма отправляется нажатием клавиши Enter, находящейся в нетекстовом поле, то пользовательский агент сам решает, что ему здесь нужно. В спецификации ничего не говорится об отправке формы с помощью клавиши ввода в поле ввода текста (если вы нажимаете на кнопку и активируете ее с помощью пробела или чего-то еще, проблем нет, поскольку эта конкретная кнопка отправки однозначно используется). Все, что он говорит, - то, что форма должна быть отправлена, когда кнопка отправки активирована, даже не требование, чтобы нажать ввод, например, текстовый ввод отправит форму.

Я считаю, что Internet Explorer выбирает кнопку отправки, которая появляется первой в источнике; У меня такое ощущение, что Firefox и Opera выбирают кнопку с самым низким tabindex, возвращаясь к первому определенному, если ничего не определено. Существуют также некоторые сложности, связанные с тем, имеют ли отправляемые атрибуты значения не по умолчанию IIRC.

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


1
По поводу пункта 2: Мой основной вопрос заключался в том, есть ли в какой-либо спецификации что-либо с эффектом «Если браузер предоставляет какие-либо средства для отправки формы без указания элемента управления для отправки ...». Но я понял из ответа Дэвида, что нет. Моя точка зрения на IE заключалась в том, что иногда нажатие клавиши Enter отправляет форму и не устанавливает никакой кнопки отправки. Как следствие, если у вас есть несколько форм, отправляющих один и тот же скрипт, вы не можете полагаться на кнопки отправки, чтобы различать их. Это появилось в проекте, над которым я работаю.
Стюарт

1
Очень полезный первый раздел абзаца в скобках - спасибо
rbassett

63

HTML 4 не делает его явным. Текущий рабочий проект HTML5 указывает, что первая кнопка отправки должна быть по умолчанию :

А formкнопка элемента по умолчанию является первой кнопки отправки в порядке дерева , чья форма владелец является то , что formэлемент.

Если пользовательский агент поддерживает разрешение пользователю неявно отправлять форму (например, на некоторых платформах нажатие клавиши «ввод», когда текстовое поле неявно фокусируется, отправляет форму), то это делается для формы, кнопка по умолчанию которой имеет определенную активацию из-за этого поведения пользовательский агент должен выполнить шаги активации искусственного щелчка для этой кнопки по умолчанию .


Хорошо, вот что он должен делать. Могу ли я использовать?
Pacerier

Я рад видеть "подразумеваемое представление" в HTML5.
Клинт Пахл

61

У Andrezj все получилось ... но вот простое кросс-браузерное решение.

Примите форму, подобную этой:

<form>
    <input/>
    <button type="submit" value="some non-default action"/>
    <button type="submit" value="another non-default action"/>
    <button type="submit" value="yet another non-default action"/>

    <button type="submit" value="default action"/>
</form>

и рефакторинг к этому:

<form>
    <input/>

    <button style="overflow: visible !important; height: 0 !important; width: 0 !important; margin: 0 !important; border: 0 !important; padding: 0 !important; display: block !important;" type="submit" value="default action"/>

    <button type="submit" value="some non-default action"/>
    <button type="submit" value="another non-default action"/>
    <button type="submit" value="yet another non-default action"/>
    <button type="submit" value="still another non-default action"/>

    <button type="submit" value="default action"/>
</form>

Поскольку спецификация W3C указывает, что несколько кнопок отправки действительны, но не содержит указаний относительно того, как пользовательский агент должен их обрабатывать, производители браузеров остаются для реализации по своему усмотрению. Я обнаружил, что они либо отправят первую кнопку отправки в форме, либо отправят следующую кнопку отправки после поля формы, которое в данный момент имеет фокус.

К сожалению, просто добавив стиль отображения: нет; не будет работать, потому что спецификация W3C указывает, что любой скрытый элемент должен быть исключен из взаимодействия с пользователем. Так что скрывайте это на виду!

Выше приведен пример решения, которое я в итоге поставил в производство. Нажатие клавиши ввода запускает отправку формы по умолчанию, как и ожидалось, даже когда присутствуют другие значения, отличные от значений по умолчанию, и предшествуют кнопке отправки по умолчанию в DOM. Бонус за взаимодействие мыши и клавиатуры с явным пользовательским вводом, избегая обработчиков JavaScript.

Примечание. Вкладка в форму не будет отображать фокус для какого-либо визуального элемента, но все равно будет вызывать выбор невидимой кнопки. Чтобы избежать этой проблемы, просто установите соответствующие атрибуты tabindex и пропустите атрибут tabindex на невидимой кнопке отправки. Несмотря на то, что продвижение этих стилей может показаться неуместным, они не должны мешать каркасу или существующим стилям кнопок вмешиваться в это исправление. Кроме того, эти встроенные стили определенно плохи, но мы здесь проверяем концепции ... не пишем производственный код.


5
Спасибо. Наткнулся на дисплей: никаких проблем. Вместо того, чтобы свернуть кнопку, вы также можете переместить ее со страницы, окружив ее символом <div style="position: fixed; left: -1000px; top: -1000px />. Еще одна вещь для беспокойства: просто сворачивание или удаление кнопки из потока страниц с помощью CSS может вызвать проблемы с WAI, потому что программы чтения с экрана все равно увидят кнопку по умолчанию.
Стефан Хаберл

2
СПАСИБО @James за этот подробный ответ.
Натан

1
это сработало для меня, спасибо. Мне пришлось добавить это для границы кнопки: нет; чтобы сделать его полностью
исчезнуть

4
Вы можете просто установить атрибут tabindex скрытой кнопки на -1
tvanc

2
Для чего это <input/>там?
СЗ

16

Я думаю, что этот пост поможет, если кто-то захочет сделать это с помощью jQuery:

http://greatwebguy.com/programming/dom/default-html-button-submit-on-enter-with-jquery/

Основное решение:

$(function() {
    $("form input").keypress(function (e) {
    if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
        $('input[type=submit].default').click();
        return false;
    } else {
        return true;
    }
    });
});

и еще один мне понравился был:

jQuery(document).ready(function() {
$("form input, form select").live('keypress', function (e) {
if ($(this).parents('form').find('button[type=submit].default, input[type=submit].default').length <= 0)
return true;

if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
$(this).parents('form').find('button[type=submit].default, input[type=submit].default').click();
return false;
} else {
return true;
}
});
}); 

jQuery.Event всегда имеет свой .wichатрибут. Также нет необходимости прибегать к DOM .keyCode(или .charCodeв этом отношении).
Арьян

Другая проблема, связанная с jQuery, - это ненужный двойной запрос. Поскольку нет необходимости возвращать true, кроме того, версия jQuery становится действительно ясной и не хватает интегрированных сокращений, рекомендованных Арджаном ранее.
Soletan

Я использовал keydown вместо нажатия клавиш (избегайте ожидания нажатия клавиш) и добавил e.preventDefault();в начало этой функции, чтобы избежать выполнения «настоящей» кнопки по умолчанию. Работает действительно хорошо.
Мэтт Рой

6

У меня была форма с 11 кнопками отправки, и она всегда использовала первую кнопку отправки, когда пользователь нажимал ввод. В другом месте я читал, что не стоит (и не рекомендуется) иметь в форме более одной кнопки отправки, и лучший способ сделать это - использовать кнопку, которую вы хотите использовать по умолчанию, как единственную кнопку отправки в форме. Другие кнопки должны быть превращены в «TYPE = BUTTON» и добавлено событие onClick, которое вызывает вашу собственную процедуру отправки в Javascript. Что-то вроде этого :-

<SCRIPT Language="JavaScript">
function validform()
{
  // do whatever you need to validate the form, and return true or false accordingly
}

function mjsubmit()
{
  if (validform()) { document.form1.submit(); return true;}
  return false;
}
</SCRIPT>
<INPUT TYPE=BUTTON NAME="button1" VALUE="button1" onClick="document.form1.submitvalue='button1'; return mjsubmit();">
<INPUT TYPE=BUTTON NAME="button2" VALUE="button2" onClick="document.form1.submitvalue='button2'; return mjsubmit();">
<INPUT TYPE=SUBMIT NAME="button3" VALUE="button3" onClick="document.form1.submitvalue='button3'; return validform();">
<INPUT TYPE=BUTTON NAME="button4" VALUE="button4" onClick="document.form1.submitvalue='button4'; return mjsubmit();">

Здесь button3 является значением по умолчанию, и хотя вы программно отправляете форму с другими кнопками, процедура mjsubmit проверяет их. НТН.


19
Плохая идея. Ваша форма не будет работать с отключенным JS. JS следует использовать ненавязчиво.
BalusC

7
Очень немногие браузеры по умолчанию отключают JS, даже те, что на iPod! На форме, которую я цитировал, JS off сделает ее бесполезной! Так много зависит от работы JS.
графика

7
По умолчанию выключено или нет, тем, у кого отключен JS, не нужно включать его, чтобы обойти такую ​​глупую загадку, как эта.
Стюарт

2
какая форма имеет 11 кнопок отправки ?? ( любопытство )
Бен

2
Самая большая причина, по которой я проверяю ненавязчивый Javascript, заключается в том, что навязчивый Javascript имеет тенденцию быть нервным. Я не уверен, как оценить то, что я думаю, но когда я вижу, что страницы полностью зависят от JS, я также держу пари, что я могу сделать некоторые сложные вещи с моей DOM и сделать что-то непреднамеренное на сервере.
Саманта Бранхам

6

Теперь это можно решить с помощью flexbox:

HTML

<form>
    <h1>My Form</h1>
    <label for="text">Input:</label>
    <input type="text" name="text" id="text"/>

    <!-- Put the elements in reverse order -->
    <div class="form-actions">
        <button>Ok</button> <!-- our default action is first -->
        <button>Cancel</button>
    </div>
</form>

CSS

.form-actions {
    display: flex;
    flex-direction: row-reverse; /* reverse the elements inside */
}

Explaination
Использование гибкого окна, мы можем изменить порядок элементов в контейнере , который использует display: flexтакже при помощи правила CSS: flex-direction: row-reverse. Это не требует CSS или скрытых элементов. Для старых браузеров, которые не поддерживают flexbox, они все еще получают работоспособное решение, но элементы не будут обращены вспять.

Демо-
версия http://codepen.io/Godwin/pen/rLVKjm


2

Я боролся с тем же вопросом, так как у меня была кнопка «Отправить», посередине которой перенаправлено отправить на другую страницу, вот так:

<button type="submit" onclick="this.form.action = '#another_page'">More</button>

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

Итак, я сделал несколько примитивных тестов, создав из с несколькими кнопками отправки и различными параметрами видимости и оповещения о событиях onclick, какая кнопка была нажата: https://jsfiddle.net/aqfy51om/1/

Браузеры и ОС, которые я использовал для тестирования:

WINDOWS

  • Google Chrome 43 (давай, Google: D)
  • Mozilla Firefox 38
  • Internet Explorer 11
  • Опера 30.0

OSX

  • Google Chrome 43
  • Safari 7.1.6

Большинство из этих браузеров нажимали самую первую кнопку, несмотря на примененные параметры видимости, кроме IE и Safari, которые нажимали третью кнопку, которая «видна» внутри «скрытого» контейнера:

<div style="width: 0; height: 0; overflow: hidden;">
    <button type="submit" class="btn btn-default" onclick="alert('Hidden submit button #3 was clicked');">Hidden submit button #3</button>
</div>

Итак, мое предложение, которое я собираюсь использовать сам:

Если в вашей форме есть несколько кнопок отправки с различным значением, включите кнопку «Отправить» с действием по умолчанию в начале формы:

  1. Полностью видимый
  2. Завернут в контейнер с style="width: 0; height: 0; overflow: hidden;"

РЕДАКТИРОВАТЬ Другим вариантом может быть смещение кнопки (все еще в начале от) style="position: absolute; left: -9999px; top: -9999px;", только что попробовал в IE - сработало, но я понятия не имею, что еще он может испортить, например, печать ..


1

Из ваших комментариев:

Как следствие, если у вас есть несколько форм, отправляющих один и тот же скрипт, вы не можете полагаться на кнопки отправки, чтобы различать их.

Я бросаю <input type="hidden" value="form_name" />в каждой форме.

При отправке с использованием JavaScript: добавляйте события отправки в формы, а не щелкайте события на их кнопках. Пользователи Saavy не очень часто касаются мыши.


Действительно, но этот вопрос напрашивается: stackoverflow.com/questions/541869/…
Стюарт

1

Если в одной форме имеется несколько кнопок отправки, и пользователь нажимает клавишу ВВОД, чтобы отправить форму из текстового поля, этот код переопределяет функциональность по умолчанию, вызывая событие отправки в форме из события нажатия клавиши. Вот этот код:

$('form input').keypress(function(e){

    if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)){ $(e.target).closest('form').submit(); return false; }
    else return true;

});

Просто и исправляет проблему
toddmo

1

Странно, что первая кнопка Enter всегда идет к первой кнопке, независимо от того, видна она или нет, например, с помощью jquery show/hide(). Добавление атрибута .attr('disabled', 'disabled')предотвращает получение кнопки Enter submit полностью. Это проблема, например, при настройке видимости кнопки « Вставить / Редактировать + Удалить» в диалоговых окнах записи. Я нашел менее хакерское и простое размещение Edit перед Insert

<button type="submit" name="action" value="update">Update</button>
<button type="submit" name="action" value="insert">Insert</button>
<button type="submit" name="action" value="delete">Delete</button>

и используйте код JavaScript:

$("#formId button[type='submit'][name='action'][value!='insert']").hide().attr('disabled', 'disabled');
$("#formId button[type='submit'][name='action'][value='insert']").show().removeAttr('disabled');

0

мой рецепт:

<form>
<input type=hidden name=action value=login><!-- the magic! -->

<input type=text name=email>
<input type=text name=password>

<input type=submit name=action value=login>
<input type=submit name=action value="forgot password">
</form>

Он отправит скрытое поле по умолчанию, если ни одна из кнопок не нажата.

если они нажаты, у них есть предпочтение, и его значение передается.


2
Но определяется ли это поведение стандартом? И можно ли доверять браузерам для правильной реализации?
Стюарт

хороший вопрос. я протестировал его для работы во всех браузерах A (из матрицы браузера yui), и это самый удобный инструмент, который я мог получить в реальной жизни (независимо от того, что указано в стандартах)
gcb

@yellowandred что происходит? посмотрим позже
gcb

1
моя ошибка, я изменил {type = "hidden"} и не заметил тех же значений 'name'.
Желто-красный

Это не работает для меня в IE11 или Fx30. Значение всегда установлено на скрытое значение.
Джейми Китсон

0

Другое решение, которое я использовал, это просто иметь одну кнопку в форме и подделывать другие кнопки.

Вот пример:

<form>
  <label for="amount">Amount of items</label>
  <input id="amount" type="text" name="amount" />
  <span id="checkStock" class="buttonish">Check stock</span>
  <button type="submit" name="action" value="order">Place order</button>
</form>

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

Не обязательно подходит для всех ситуаций, но по крайней мере это довольно легко сделать.


1
Каков запасной вариант для пользователей, у которых отключен JS?
Стюарт

Пользователи с отключенным JS не смогут пользоваться Интернетом, это так просто, как сейчас.
Кристоффер Бубах

0

Из спецификации HTML 4 :

Если форма содержит более одной кнопки отправки, успешной будет только активированная кнопка отправки.

Это означает, что при наличии более 1 кнопки отправки и ни одной не активированной (нажатой) ни одна не должна быть успешной.

И я бы сказал, что это имеет смысл: представьте себе огромную форму с несколькими кнопками отправки. Вверху есть кнопка «удалить эту запись», затем следует множество входов, а внизу кнопка «обновить эту запись». Пользователь, нажимающий клавишу ввода, находясь в поле внизу формы, никогда не будет подозревать, что он неявно нажимает кнопку «удалить эту запись» сверху.

Поэтому я думаю, что не стоит использовать первую или любую другую кнопку, если пользователь не определил (не нажал) одну. Тем не менее, браузеры делают это, конечно.


-2

РЕДАКТИРОВАТЬ: Извините, когда писал этот ответ, я думал о кнопках отправки в общем смысле. Ответ ниже не о нескольких type="submit"кнопках, так как он оставляет только одну type="submit"и меняет другую на type="button". Я оставляю ответ здесь в качестве справки на тот случай, если поможет кто-то, кто может изменить typeсвою форму:

Чтобы определить, какая кнопка нажимается при нажатии клавиши ввода, вы можете пометить ее type="submit", а другие кнопки пометить их type="button". Например:

<input type="button" value="Cancel" />
<input type="submit" value="Submit" />

Тип "кнопка" не вызывает форму для отправки. Он используется только для запуска клиентских сценариев.
Стюарт

именно поэтому браузер пропускает его, когда вы нажимаете Enter, и запускается тот, который имеет тип «submit». Вы можете использовать тот, который имеет тип «кнопка», чтобы сделать что-нибудь еще, например, по клику. Пожалуйста, удалите отрицательный голос.
Хесус Каррера

Вопрос был о нескольких кнопках отправки .
Стюарт

Мой пример полностью подходит для нескольких кнопок отправки. Тот, который имеет тип «отправить», определяется браузером, чтобы он действовал как нажатый (о чем и был вопрос). Затем с помощью другой кнопки вы можете использовать ее в качестве кнопки отправки, а также использовать события JavaScript, такие как событие onClick, которое есть в вашем примере. Так что мой ответ актуален и не заслуживает отрицательного ответа. Пожалуйста, удалите это.
Хесус Каррера

1
Если вы предлагали устранить неоднозначность, сделав только один из них, типа «отправить» и используя JavaScript для реализации других кнопок, то это дубликат ответа графики, и поэтому он уже был отклонен как плохая идея.
Стюарт
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.