Доброго времени суток, мой дорогой друг. В сети, да и на Хабре, есть множество статей на тему создания своего input type=«file», но все они отличаются большим количеством костылей и большим количеством кода, что, как мне кажется, не есть хорошо. Ибо, как бы это не было парадоксально, меньше — лучше.
Рабочий пример того, что получится:
Сам принцип кастомизированного input file особых отличий не имеет: убираем с экрана input, и всё возлагаем на плечи label, которому мы добавим свои стили. Главное отличие — малое кол-во кода.
Начнём
Мы имеем input и label
<label for="myfile" class="label">Выберите файлы</label>
<input type="file" class="my" id="myfile" name="myfile" multiple>
Теперь уберём с экрана 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»
<div class="box-form">
<p>Текст какой-то</p>
<div>
<label for="myfile" class="label">Выберите файлы</label>
</div>
<div>
<div></div>
<input type="file" class="my" id="myfile" name="myfile" multiple>
</div>
</div>
И замените в js
$(this).prev()
на
$(this).closest('.box-form').children('.label')
Вуаля! Теперь, стоявшие далеко друг от друга, label и input способны взаимодействовать друг с другом.
Лучше, конечно, избегать таких случаев, но никто не защищён от фреймворков, где input'ы пишешь не ты, а их генерирует сам фреймворк…
Спасибо за внимание
Автор: kirigosh