[Из песочницы] Пишем самый простой и быстрый input type file

Доброго времени суток, мой дорогой друг. В сети, да и на Хабре, есть множество статей на тему создания своего input type=«file», но все они отличаются большим количеством костылей и большим количеством кода, что, как мне кажется, не есть хорошо. Ибо, как бы это не было парадоксально, меньше — лучше.

46d052fc47304a3c85c5acd369067b5c.jpg

Рабочий пример того, что получится:


Сам принцип кастомизированного input file особых отличий не имеет: убираем с экрана input, и всё возлагаем на плечи label, которому мы добавим свои стили. Главное отличие — малое кол-во кода.

Начнём

Мы имеем input и label




Теперь уберём с экрана input, добавив классу my следующие стили:
.my {
  width: 0.1px;
  height: 0.1px;
  opacity: 0;
  overflow: hidden;
  position: absolute;
  z-index: -1;
}

А также стилизуем сам label, добавив ему свои стили:
.label {
    width: 180px;
    height: 50px;
    border-radius: 4px;
    text-align: center;
    cursor: pointer;
    display: block;
    font: 14px/50px Tahoma;
    transition: all 0.18s ease-in-out;
    border: 1px solid #333;
    color: #333;
}

.label:hover {
    color: white;
    background: #333;
}

И теперь самое интересное: javascript. Собственно вот он:
$('.my').change(function() {
    if ($(this).val() != '') $(this).prev().text('Выбрано файлов: ' + $(this)[0].files.length);
    else $(this).prev().text('Выберите файлы');
});

Он работает следующим образом: Когда пользователь жмёт на input с классом .my, то js начинает отслеживать его изменение. Дальше в дело вступает if (если). Так вот если у нас этот (this) input не пустой (то есть файл был какой-то выбран), то стоящий по соседству выше элемент (это у нас label) получит текст «Выбрано файлов» + кол-во файлов, которое выбрал пользователь. Ну, а если пользователь ничего не выбрал, то label просто получит текст «Выберите файлы».

Всё!

// Дополнительная информация

Может возникнуть проблема с вёрсткой, какая была и у меня. А проблема может заключаться с этим пресловутым .prev (). По факту, есть вероятность того, что невозможно расположить label и input file рядом друг с другом, и текст «Выбрано файлов» будет применяется не к label, а к левому элементу.

Эту проблему можно решить вот так:

Поместите label и input в один div, и дайте этому div’у класс, к примеру «box-form»

Текст какой-то


И замените в js
$(this).prev() 

на 
$(this).closest('.box-form').children('.label')

Вуаля! Теперь, стоявшие далеко друг от друга, label и input способны взаимодействовать друг с другом.

Лучше, конечно, избегать таких случаев, но никто не защищён от фреймворков, где input’ы пишешь не ты, а их генерирует сам фреймворк…

Спасибо за внимание

Комментарии (5)

  • 6 февраля 2017 в 13:56

    +3

    А разве зависимость в виде JQuery уже считается минималистичным решением?
    • 6 февраля 2017 в 14:16

      0

      Конечно же. В хабах же jQuery, а не Javascript. Для настоящих jQuery-программистов.

    • 6 февраля 2017 в 14:39

      0

      Любой пост, начинающийся с «Пишем самый простой\крутой\быстрый %имяФичи%…» содержит в себе jQuery. И лучше не спрашивать: «А с какой целью вы здесь используете jQuery?»
      • 6 февраля 2017 в 14:55

        +2

        Моя любимая часть — $(this)[0].
  • 6 февраля 2017 в 15:01

    0

    Если label не содержит в себе input, то он и не будет работать как лейбл. То есть, нужен id у инпута и for у этого лейбла. И если верстка не совсем кривая, то найти нужный лейбл можно через $('label[for=" + this.id + '"]').

© Habrahabr.ru