Статьи

Создание заменителей пузыря проверки формы HTML5

Автор TJ VanToll для Telerik Blog.

Я писал и говорил о проверке формы HTML5 в течение последних нескольких лет, и один из самых распространенных вопросов, которые я получаю, касается пузырей. Под пузырями я подразумеваю, что браузеры контролируют пользовательский интерфейс и отображают ошибки проверки. Ниже вы можете увидеть реализации Chrome, Firefox и IE:

пузырьки

По какой-то причине мы, разработчики (или, скорее, наши коллеги-дизайнеры), имеем глубокое желание стилизовать эти вещи. Но, к сожалению, мы не можем, так как нулевые браузеры предоставляют хуки для стиля, предназначенные для этих пузырей. Chrome использовался для предоставления ряда псевдоэлементов с префиксом производителя ( ::-webkit-validation-bubble-*), но они были удалены в Chrome 28 .

Так что же делать разработчику? Ну, хотя браузеры не позволяют вам настраивать их пузыри, спецификация проверки ограничений позволяет вам отключить пузырьковый интерфейс браузера и создать свой собственный. В остальной части статьи показано, как это сделать.

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

Подавление пузырьков по умолчанию

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

<form>
    <input required>
    <button>Submit</button>
</form>
<script>
    document.querySelector( "input" ).addEventListener( "invalid",
        function( event ) {
            event.preventDefault();
        });
</script>

invalidСобытие не пузырь (не каламбур), поэтому если вы хотите , чтобы предотвратить пузыри проверки на нескольких элементов , которые вы должны приложить захват фазы слушателя.

Если вы не понимаете различий между фазами всплытия и захвата событий DOM, ознакомьтесь с этой статьей MDN для довольно хорошего объяснения.

Следующий код предотвращает появление пузырьков на обоих входах с помощью одного invalidпрослушивателя событий для родительского <form>элемента:

<form>
    <input required>
    <input required>
    <button>Submit</button>
</form>
<script>
    document.querySelector( "form" )
        .addEventListener( "invalid", function( event ) {
            event.preventDefault();
        }, true );
</script>

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

Создание альтернативных интерфейсов

Существует множество способов отображения ошибок проверки формы, и ни один из них не является правильным или неправильным. (Хорошо, есть некоторые неправильные способы сделать это.) Давайте рассмотрим несколько распространенных подходов, которые вы можете использовать. Для каждого мы будем использовать очень простое имя и адрес электронной почты ниже. Мы также будем использовать простой CSS, чтобы эта форма выглядела прилично.

<form>
    <div>
        <label for="name">Name:</label>
        <input id="name" name="name" required>
    </div>
    <div>
        <label for="email">Email:</label>
        <input id="email" name="email" type="email" required>
    </div>
    <div>
        <button>Submit</button>
    </div>
</form>

Одно важное замечание, прежде чем мы начнем: все эти пользовательские интерфейсы работают только в Internet Explorer версии 10 и выше, так как API проверки ограничений недоступен в более старых версиях. Если вам нужно поддерживать старый IE и по-прежнему использовать проверку формы HTML5, ознакомьтесь с этой слайд-колодой, в которой я наметил некоторые варианты для этого.

Альтернативный интерфейс № 1: список сообщений

Распространенный способ отображения ошибок валидации находится в рамке в верхней части экрана, и это поведение относительно легко построить с помощью API валидации форм HTML5. Прежде чем мы перейдем к коду, вот как он выглядит в действии:

Вот код, который вам нужен для создания этого интерфейса:

function replaceValidationUI( form ) {
    // Suppress the default bubbles
    form.addEventListener( "invalid", function( event ) {
        event.preventDefault();
    }, true );

    // Support Safari, iOS Safari, and the Android browser—each of which do not prevent
    // form submissions by default
    form.addEventListener( "submit", function( event ) {
        if ( !this.checkValidity() ) {
            event.preventDefault();
        }
    });

    // Add a container to hold error messages
    form.insertAdjacentHTML( "afterbegin", "<ul class='error-messages'></ul>" );

    var submitButton = form.querySelector( "button:not([type=button]), input[type=submit]" );
    submitButton.addEventListener( "click", function( event ) {
        var invalidFields = form.querySelectorAll( ":invalid" ),
            listHtml = "",
            errorMessages = form.querySelector( ".error-messages" ),
            label;

        for ( var i = 0; i < invalidFields.length; i++ ) {
            label = form.querySelector( "label[for=" + invalidFields[ i ].id + "]" );
            listHtml += "<li>" + 
                label.innerHTML +
                " " +
                invalidFields[ i ].validationMessage +
                "</li>";
        }

        // Update the list with the new error messages
        errorMessages.innerHTML = listHtml;

        // If there are errors, give focus to the first invalid field and show
        // the error messages container
        if ( invalidFields.length > 0 ) {
            invalidFields[ 0 ].focus();
            errorMessages.style.display = "block";
        }
    });
}

// Replace the validation UI for all forms
var forms = document.querySelectorAll( "form" );
for ( var i = 0; i < forms.length; i++ ) {
    replaceValidationUI( forms[ i ] );
}

В этом примере предполагается, что каждое поле формы имеет соответствующий <label>, где idатрибут поля формы соответствует forатрибуту <label>. Возможно, вы захотите настроить код, который создает сами сообщения, чтобы он соответствовал вашим приложениям, но кроме этого это может быть что-то, что можно просто вставить.

Альтернативный интерфейс № 2: сообщения под полями

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

Для создания этого пользовательского интерфейса большая часть кода остается такой же, как и в первом подходе, с небольшими различиями в clickобработчике событий кнопки отправки .

function replaceValidationUI( form ) {
    // Suppress the default bubbles
    form.addEventListener( "invalid", function( event ) {
        event.preventDefault();
    }, true );

    // Support Safari, iOS Safari, and the Android browser—each of which do not prevent
    // form submissions by default
    form.addEventListener( "submit", function( event ) {
        if ( !this.checkValidity() ) {
            event.preventDefault();
        }
    });

    var submitButton = form.querySelector( "button:not([type=button]), input[type=submit]" );
    submitButton.addEventListener( "click", function( event ) {
        var invalidFields = form.querySelectorAll( ":invalid" ),
            errorMessages = form.querySelectorAll( ".error-message" ),
            parent;

        // Remove any existing messages
        for ( var i = 0; i < errorMessages.length; i++ ) {
            errorMessages[ i ].parentNode.removeChild( errorMessages[ i ] );
        }

        for ( var i = 0; i < invalidFields.length; i++ ) {
            parent = invalidFields[ i ].parentNode;
            parent.insertAdjacentHTML( "beforeend", "<div class='error-message'>" + 
                invalidFields[ i ].validationMessage +
                "</div>" );
        }

        // If there are errors, give focus to the first invalid field
        if ( invalidFields.length > 0 ) {
            invalidFields[ 0 ].focus();
        }
    });
}

// Replace the validation UI for all forms
var forms = document.querySelectorAll( "form" );
for ( var i = 0; i < forms.length; i++ ) {
    replaceValidationUI( forms[ i ] );
}

Альтернативный интерфейс № 3: замена пузырьков

Последний пользовательский интерфейс, который я представлю, представляет собой способ имитации пузыря проверки браузера с помощью полностью настраиваемого (и настраиваемого) пузыря, созданного с помощью JavaScript. Вот реализация в действии:

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

$( "form" ).each(function() {
    var form = this;

    // Suppress the default bubbles
    form.addEventListener( "invalid", function( event ) {
        event.preventDefault();
    }, true );

    // Support Safari, iOS Safari, and the Android browser—each of which do not prevent
    // form submissions by default
    $( form ).on( "submit", function( event ) {
        if ( !this.checkValidity() ) {
            event.preventDefault();
        }
    });

    $( "input, select, textarea", form )
        // Destroy the tooltip on blur if the field contains valid data
        .on( "blur", function() {
            var field = $( this );
            if ( field.data( "kendoTooltip" ) ) {
                if ( this.validity.valid ) {
                    field.kendoTooltip( "destroy" );
                } else {
                    field.kendoTooltip( "hide" );
                }
            }
        })
        // Show the tooltip on focus
        .on( "focus", function() {
            var field = $( this );
            if ( field.data( "kendoTooltip" ) ) {
                field.kendoTooltip( "show" );
            }
        });

    $( "button:not([type=button]), input[type=submit]", form ).on( "click", function( event ) {
        // Destroy any tooltips from previous runs
        $( "input, select, textarea", form ).each( function() {
            var field = $( this );
            if ( field.data( "kendoTooltip" ) ) {
                field.kendoTooltip( "destroy" );
            }
        });

        // Add a tooltip to each invalid field
        var invalidFields = $( ":invalid", form ).each(function() {
            var field = $( this ).kendoTooltip({
                content: function() {
                    return field[ 0 ].validationMessage;
                }
            });
        });

        // If there are errors, give focus to the first invalid field
        invalidFields.first().trigger( "focus" ).eq( 0 ).focus();
    });
});

Хотя замена пузырей проверки требует к сожалению большого количества кода, это довольно близко подходит к репликации реализации браузера. Разница в том, что реализация JavaScript гораздо более настраиваема, так как вы можете изменить ее по своему желанию. Например, если вам нужно добавить некоторую розовую, зеленую и Comic Sans ваших пузырьков, вы полностью можете:

Виджет всплывающей подсказки Kendo UI — это один из 25+ виджетов, доступных в Kendo UI Core , бесплатном дистрибутиве Kendo UI с открытым исходным кодом. Таким образом, вы можете использовать этот код сегодня, не беспокоясь об лицензионных ограничениях или платя деньги. Вы можете загрузить исходный код ядра Kendo UI напрямую , использовать наш CDN или взять библиотеку из Bower ( bower install kendo-ui-core).

Завершение

Хотя вы не можете стилизовать пузырьки проверки браузера, вы можете подавить их и создать любой пользовательский интерфейс, какой захотите. Не стесняйтесь попробовать и изменить подходы, показанные в этой статье, чтобы удовлетворить ваши потребности. Если у вас есть другие подходы, которые вы использовали в прошлом, не стесняйтесь делиться ими в комментариях.