Пятничные сниппеты. JavaScript, продолжение стилизации файл-инпута

Пятничные сниппеты. JavaScript, продолжение стилизации файл-инпута

Сегодняшние сниппеты — продолжение урока о стилизации файл-инпутов. Мы упростим разметку и добавим возможность динамически создавать дополнительные файл-инпуты.

А в качестве сниппетов будут функции, которые помогут это сделать.

В прошлой реализации стильного файл-инпута нам неободимо было создать оболочку (wrapper) для нашего инпута. Давайте сделаем так, чтобы в разметке не было ничего, кроме самого инпута. А чтобы как-то его идентифицировать, пропишем у него класс «customFileInput».
То есть в разметке останется только
<input type="file" id="File1" class="customFileInput" />

Что мы должны сделать — это найти инпут по классу и завернуть его в обертку, и уже туда добавлять необходимые элементы.
Для того, чтобы найти инпут используем функцию getElementsByClassName(<название класса>):

 function getElementsByClassName(searchClass) {
var classElements = new Array();
var els = document.getElementsByTagName('*');
var elsLen = els.length;
var pattern = new RegExp("(^|s)"+searchClass+"(s|$)");
for (i = 0, j = 0; i < elsLen; i++) {
if ( pattern.test(els[i].className) ) {
classElements[j] = els[i];
j++;
}
}
return classElements;
};


Завернем все инпуты во враппер:

 function WrapEverything()
{
inputs = getElementsByClassName('customFileInput');
for (var i = 0 ; i < inputs.length; i++)
wrap(inputs[i]);

};


Сама функция wrap:

 function wrap(element)
{
wraper = document.createElement('div');
wraper.className = 'wrapper';
fileInput = document.createElement('input');
fileInput.value = '';
fileInput.setAttribute('type','file');
var id = element.getAttribute('id');
wraper.setAttribute('id','wrapper'+id);
fileInput.setAttribute('id',id);
fileInput.className = 'customFile';
fileInput.onchange = function(){ HandleChanges(id) };
fileInput.onmouseover = function() { MakeActive(id) };
fileInput.onmouseout = function() { UnMakeActive(id) };
fileName = document.createElement('div');
fileName.style.display = 'none';
fileName.style.background = 'url(images/icons.png)';
fileName.setAttribute('id','name'+id);
fileName.className = "FileName";
bb = document.createElement('div');
bb.setAttribute('id','bb' + id);
bb.className = 'fakeButton';
bl = document.createElement('div');
bl.setAttribute('id','bl' + id);
bl.className = 'blocker';
wraper.appendChild(bb);
wraper.appendChild(bl);
wraper.appendChild(fileInput);
wraper.appendChild(fileName);
x = element.parentNode;
x.replaceChild(wraper,element);
};


Функция replaceChild заменяет element на wraper, который содержит необходимые нам элементы.

Хочу обратить внимание на то, как привязываются события к элементу fileInput:

fileInput.onmouseout = function() { UnMakeActive(id) };


Если бы мы делали как раньше

fileInput.onmouseout = UnMakeActive(id);

то браузер сообщил бы нам об ошибке.

Это все, что нам надо сделать для того чтобы упростить разметку.

Теперь добавим возможность динамически создавать новые инпуты. Чтобы сделать эту возможность легко адаптируемой под индивидуальные нужды, мы создадим простую кнопку, которая будет вызывать функцию addCustomFileInput(container). container — это блок, в котором будут распологаться все создаваемые инпуты.

Разметка выглядит следующим образом:

 <div id="MyInputs">
<input type="file" class="customFileInput" id="File1" />
</div>
<a href="javascript:addCustomFileInput('MyInputs')">добавить еще</a>


Для того чтобы можно было удалять добавленные инпуты, мы добавляем минусик рядом с самим инпутом. В остальном содержимое функции аналогично функции wrap.

 function addCustomFileInput(container) {
w = document.getElementById(container);
AddInput(w);
};

function AddInput(container) {
wraper = document.createElement('div');
wraper.className = 'wrapper';
fileInput = document.createElement('input');
fileInput.value = '';
fileInput.setAttribute('type', 'file');
var id = 'customFileInput' + inputNumber;
wraper.setAttribute('id', 'wrapper' + id);
fileInput.setAttribute('id', id);
fileInput.className = 'customFile';
fileInput.onchange = function() { HandleChanges(id) };
fileInput.onmouseover = function() { MakeActive(id) };
fileInput.onmouseout = function() { UnMakeActive(id) };
fileName = document.createElement('div');
fileName.style.display = 'none';
fileName.style.background = 'url(images/icons.png)';
fileName.setAttribute('id', 'name' + id);
fileName.className = "FileName";
bb = document.createElement('div');
bb.setAttribute('id', 'bb' + id);
bb.className = 'fakeButton';
bl = document.createElement('div');
bl.setAttribute('id', 'bl' + id);
bl.className = 'blocker';
deleteButton = document.createElement('div');
deleteButton.className = 'minus';
deleteButton.onclick = function() { DeleteCustomInput(id) };
wraper.appendChild(bb);
wraper.appendChild(bl);
wraper.appendChild(fileInput);
wraper.appendChild(fileName);
wraper.appendChild(deleteButton);
container.appendChild(wraper);
inputNumber++;

};


Если вы хотите, чтобы у вас был не минусик, а свой текст, изменить надо всего лишь эту часть:

deleteButton = document.createElement('div');
deleteButton.className = 'minus';


Теперь, чтобы интегрировать такой файл-инпут, вам достаточно добавить скрипт и стили, а у самого инпута прописать класс customFileInput.

Собственно, все это не так важно, как живой пример.

Архив со примером
ZIP архив, 23КБ
 

Расскажите друзьям

Оцените статью:
  • 1
  • 2
  • 3
  • 4
  • 5

Комментарии — 27

sergy
занятно, спасибо
#
sergy
switch
Круто, ещё бы плагин для jQuery такой.
#
switch
чя
В сафари под маком не работает кнопка добавить
#
чя
drw
отлично!
#
drw
DeadLy
как href=[http://vremenno.net/samples/updated-file-input-styling/index.htmlk>живой пример. поправить бы
#
DeadLy
Жека
Спасибо, поправил.
PR
хорошая статья можно было бы еще скрывать кнопку после выбора файла, а вместо нее вставлять пиктограмму удаления (либо менять сменить надпись на кнопке на "удалить"). Так наверное было бы более понятно для пользователя. А то выходит, что он файл добавил, а кнопка остается активной
#
PR
Denis
Скрипт создает кучу глобальных переменных: bb, bl, fileInput, fileName, и даже i и j. Вроде все здорово, но такая невнимательность к коду к сильно портит впечатление.
#
Denis
Denis
fileName.innerHTML = fileTitle;                 // а если добавить файл "{.html" ?
И несколько регэкпов когда можно обойтись одним. Функу HandleChanges переписал бы так:
        function HandleChanges(id)
        {
            var fileName = document.getElementById(id).value,
                elFileName = document.getElementById('name' + id),
                m = fileName.match(/^.*[\/](.*(?:.(.*)))$/),
                ext = m[2];

            if(!elFileName) return;

            elFileName.innerHTML = '';
            elFileName.firstChild.nodeValue = m[1] || '';
            elFileName.title = fileName;

            if (ext){

                var pos = ({
                    doc: 1,
                    bmp: 17, jpg: 33, jpeg: 33, png: 49, gif: 65,
                    psd: 81,
                    mp3: 97, wav: 97, ogg: 97,
                    avi: 113, wmv: 113, flv: 113,
                    pdf: 129,
                    exe: 145,
                    txt: 161
                }[ext.toLowerCase()] || 177) -1;

                elFileName.style.display = 'block';
                elFileName.style.background = 'url(images/icons.png) no-repeat 0 -' pos 'px';
            };
        };
#
Denis
Denis
имелось ввиду:
fileName.innerHTML = fileTitle;                 // а если добавить файл "&#123;.html" ?
#
Denis
Nesnosne
в Сафари 3.1.2 на Маке все работает.
#
Nesnosne
Вячеслав
Самому не когда делать ) но такую идею бы предложил, путь же до файла становится известен, так как расширение функционала - навесить просмотр этого файла с локали при наведении (как на стандартных в jQuery), то есть имя файла видеть это хорошо, но когда десяток подготовлен - не плохо иметь возможность пробежаться по ним и поглядеть, те ли это фотки.
castertroy
Здравствуйте, Евгений, тема полугодичной давности, но, со стилизацией никаких проблем - везде все работает -) за исключением собственно самого процесса передачи файла на сервер. Я интегрировал ваши скрипты в свой продукт, создал простую форму для отправки файла на сервер методом ПОСТ, но данные не обрабатываются, т.е. присвоив файл инпуту какой-то name=item, после нажатия кнопки submit и отправки формы на обработку в массиве $_FILES (в котором собственно и должны находиться сведения о передаваемых файлах) нашего item'a нет.
(п.с. работаю на PHP)

Что делать ?
#
castertroy
castertroy
Сам задал вопрос - сам и ответил.

в функции AddInput() и wrap() добавить строку:
fileInput.setAttribute('name','имя инпута');
#
castertroy
vit
господа, а вы в форму отправки это пробовали встроить?
Если да, то расскажите , плииз, где искать на сервере отправленные файлы. В папке временных файлов на сервере их нет, и в PHP Variables они не отсвечивают никак...
#
vit
Evgenij
Без проблем встраивал в страницу ASP.NET. Но там все иначе.
vit
Ага, разобрался, это работает только под эксплорером. Под оперой и гугл-хромом файлы на сервер не передаются :(
#
vit
Гость
Как поставить ограничитель добавляемых импутов ?
И как каждому импуту поставить своё уникальное имя ? (file1, file2, file3,...)
#
Гость
php-Чайник
ну добавил fileInput.setAttribute('name','имя инпута'); в нужные функции и нифига. По человечески-то обьяснить никак?!
#
php-Чайник
Костик
В ИЕ7 - не работает!
#
Костик
Zhendalf
Костик, должно работать. Я проверял. И перепроверил сейчас.
Alex
В IE 9 поверяли? А то у меня не работет.
#
Alex
Alex
ХОтя нет...с сайта работает в IE9 а из архива не работает...
#
Alex
Alex
Автор, обновили бы информацию про $_FILES, написанную castertroy...актуально...
#
Alex
LS
Для работы в PHP на данный момент проку от этого инпута никакого - красиво выглядит, но НЕ передает информацию - т.к. $_FILES при получении сабмита пуста как никогда.
Фразы про добавлении в инпут fileInput.setAttribute('name','имя_файла'); тем более бессмысленны, если это мультизагрузочная страница и необходима передача атрибута file для КАЖДОГО работающего элемента.

Есть где нибудь нормально доработанный скрипт для передачи через php-POST?
#
LS
Dargonaks
Добрый день а как можно дописать код что бы к каждому элементу id="File1" и id="File2" можно было присваивать свои атрибуты name?
#
Dargonaks

Новый комментарий

как выглядит какой тег
жирный текст <b>жирный текст</b>
курсивный тект <i>курсивный тект</i>
зачеркнутый текст <s>зачеркнутый текст</s>
подчеркнутый текст <u>подчеркнутый текст</u>
ссылка <a href="адрес">ссылка</a>
function foo() { ... }
<pre><code>function foo() { ... } </code></pre>
разрешенные теги или посмотреть как будет выглядеть
как выглядит какой тег
жирный текст <b>жирный текст</b>
курсивный тект <i>курсивный тект</i>
зачеркнутый текст <s>зачеркнутый текст</s>
подчеркнутый текст <u>подчеркнутый текст</u>
ссылка <a href="адрес">ссылка</a>
function foo() { ... }
<pre><code>function foo() { ... } </code></pre>
разрешенные теги или посмотреть как будет выглядеть

metin2 pvp metin2 pvp serverler pvp serverler