Открыть меню    

Оформляем обычное поле для отправки файла (input type=file) при помощи jquery, css3 и PHP

стили для input type file Мы все знаем, что поле для отправки файла весьма ограничено с точки зрения настройки-стилизации, и хотя существует с десяток плагинов для оформления данного поля, по-прежнему бывает проблематично сделать адекватное поле для отправки файла (input type="file"). В этой статье приведено руководство по созданию jquery плагина, где обычное поле для отправки файла будет заменено на поле, предусмотренное вашим дизайном; плюс мы реализуем поддержку мультиаплоада. Для старых браузеров, IE9-8, предусмотрена альтернатива.

стилизуем поле для отправки файла

Настройки проекта

Данные рекомендации можно пропустить, если вы хорошо владеете структурированием кода html/css и javascript. Создайте папку customFile и расположите в ней 3 файла, jquery.customFile.js, jquery.customFile.css и customFile.html.

Теперь, когда мы имеем все что необходимо, откройте файл html и добавьте в него блок с полем для отправки файла и элементом label.

HTML

<div class="customfile-container">
  <label>File: </label>
  <input type="file" id="file" name="myfiles[]" multiple />
</div>

Убедитесь, что полю назначен правильный идентификатор id, а атрибуту name присвоено имя массива myfiles[]. Таким образом, мы сможем извлечь все фалы.

Далее откройте файл jquery.customFile.js и создайте основу jquery плагина:

jQuery

(function( $ ) {

  $.fn.customFile = function() {

    return this.each(function() {

      var $file = $(this).addClass('customfile'); // оригинальное файловое поле

      // код здесь

    });

  };

}( jQuery ));

Наконец, плагин вызывается следующим образом:

jQuery

$('input[type=file]').customFile()

Как это рабоет

Чтобы построить нужное нам поле для отправки файла, которое мы могли бы стилизовать так, как хотим, потребуется простая по структуре разметка:

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

При клике по кнопке 'open' сработает триггер click для оригинального файлового поля. После того как будет выбран файл сработает событие change и, если в браузере реализована поддержка multiple, выбранный файл будет добавлен в соответствующую строку (смотрите код или попробуйте загрузить несколько файлов), если же поддержка множества файлов отсутствует, будет меняться значение по умолчанию файлового поля.

Строительство плагина

Сначала нам необходимо протестировать браузер на поддержку атрибута multiple. Самый простой способ это создать элемент input и проверить его на наличие свойства multiple. Нам также необходимо проверить браузер на принадлежность к IE. Следующий код можно вынести за пределы плагина, так как он не зависит от передаваемого в плагин элемента.

jQuery

    // Браузер поддерживает особенности HTML5 ?
    var multipleSupport = typeof $('<input/>')[0].multiple !== 'undefined',
    isIE = /msie/i.test( navigator.userAgent ); // просто, но не очень надежно...

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

jQuery

var $wrap = $('<div class="customfile-wrap">'),
    $input = $('<input type="text" class="customfile-filename" />'),
    $button = $('<button type="button" class="customfile-upload">Open</button>');
    $label = $('<label class="customfile-upload" for="'+ $file[0].id +'">Open</label>');

Атрибут type=«button» необходим, чтобы предотвратить отправку форму у некоторых браузеров.

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

jQuery

$file.css({
  position: 'absolute',
  left: '-9999px'
});

Наконец давайте добавим наши новые элементы в DOM.

jQuery

$wrap.insertAfter( $file ).append( $file, $input, ( isIE ? $label : $button ) );

На данный момент вы должны иметь что-то похожее на:

внешний вид элементов, которые замещают поля для отправки файла

Прикрепляем события

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

jQuery

$file.attr('tabIndex', -1);
$button.attr('tabIndex', -1);

Назначим триггер click по событию click на кнопке. В IE, как вы помните, никакой кнопки нет, и щелчок по элементу label вызывает диалоговой окно без какой-либо дополнительной работы.

jQuery

$button.click(function () {
  $file.focus().click(); // открыть диалоговое окно
});

У некоторых браузеров должно быть активировано событие focus(). Если вы кликните по кнопке 'open' в вашем браузере откроется окно загрузки файла.

Теперь мы можем использовать событие

change

, чтобы заполнить значение оригинального поля выбранными пользователем файлами.

jQuery

$file.change(function() {

    var files = [], fileArr, filename;

    //Для кода: если реализована поддержка multiple,
    // то извлекаем все имена файлов из массива
    if ( multipleSupport ) {
      fileArr = $file[0].files;    //$file[0].files содержит массив файлов
      for ( var i = 0, len = fileArr.length; i < len; i++ ) {
        files.push( fileArr[i].name );
      }
      filename = files.join(', ');

    // Если поддержки нет, тогда берем значение
    // и удаляем путь, чтобы показать только имя файла
    } else {
      filename = $file.val().split('\\').pop();
    }

    $input.val( filename ) // Устанавливаем значение
      .attr('title', filename) // Показываем имя файла через атрибут title 
      .focus(); // Восстанавливаем  focus

});

Улучшаем юзабилити

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

  • Создать триггер blur для оригинального поля, когда замена теряет фокус
  • Открыть диалоговое окно, когда пользователь нажал 'enter' в текстовом поле, в IE не работает из-за ограничений безопасности
  • Удалять файлы по 'backspace' или 'del', в противном случае пользователю придется открыть диалоговое окно и нажать на 'cancel', чтобы очистить input

jQuery

$input.on({
  blur: function() { $file.trigger('blur'); },
  keydown: function( e ) {
    if ( e.which === 13 ) { // Enter
      if ( !isIE ) { $file.trigger('click'); }
    } else if ( e.which === 8 || e.which === 46 ) { // Backspace & Del

      //в некоторых браузерах значение предназначено только для чтения
      //этим трюком мы удаляем старое поле и
      //присоединяем очищенный клон с сохранением всех оригинальных событий 

      $file.replaceWith( $file = $file.clone( true ) );
      $file.trigger('change');
      $input.val('');
    } else if ( e.which === 9 ){ // TAB
      return;
    } else { // все другие клавиши
      return false;
    }
  }
});

Альтернатива для старых браузеров

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

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

jQuery

if ( !multipleSupport ) {
  $( document ).on('change', 'input.customfile', function() {

    var $this = $(this),

        // Создаем уникальный  ID таким образом мы
        // можем присоединить метку к полю 

        uniqId = 'customfile_'+ (new Date()).getTime();
        $wrap = $this.parent(),

        // Фильтруем пустые поля

        $empty = $wrap.siblings().find('.customfile-filename')
          .filter(function(){ return !this.value }),

        $file = $('<input type="file" id="'+ uniqId +'" name="'+ $this.attr('name') +'"/>');

    // 1ms таймаут, таким образом это сработает после всех прочих событий  
    // модифицируем привязанное значение 

    setTimeout(function() {
      // Add a new input
      if ( $this.val() ) {

        // Проверяем для пустого поля, чтобы предотвратить  
        // создание нового input, когда меняем файл 

        if ( !$empty.length ) {
          $wrap.after( $file );
          $file.customFile();
        }
      // Удаляем и реорганизуем поля
      } else {
        $empty.parent().remove();

        // Перемещаем input в правильной последовательности

        $wrap.appendTo( $wrap.parent() );
        $wrap.find('input').focus();
      }
    }, 1);

  });
}

Настройка внешнего вида

CSS

/* It's easier to calculate widths
 * with border-box layout */
.customfile-container * {
  box-sizing: border-box;
  -moz-box-sizing: border-box;
  -webkit-box-sizing: border-box;
  font: normal 14px Arial, sans-serif; /* Global font to use ems with precision */
}

.customfile-container {
  width: 300px;
  background: #FFF2B8;
  padding: 1em;
}

.customfile-container label:first-child {
  width: 100px;
  display: block;
  margin-bottom: .5em;
  font: bold 18px Arial, sans-serif;
  color: #333;
}

.customfile-wrap {
  position: relative;
  padding: 0;
  margin-bottom: .5em;
}

.customfile-filename,
.customfile-upload {
  margin: 0;
  padding: 0;
}

.customfile-filename {
  width: 230px;
  padding: .4em .5em;
  border: 1px solid #A8A49D;
  border-radius: 2px 0 0 2px;
  box-shadow: inset 0 1px 2px rgba(0,0,0,.2);
}
.customfile-filename:focus {
  outline: none;
}

.customfile-upload {
  display: inline-block;
  width: 70px;
  padding: .4em 1em;
  border: 1px solid #A8A49D;
  background: #ddd;
  border-radius: 0 2px 2px 0;
  margin-left: -1px; /* align with input */
  cursor: pointer;
  background: #fcfff4;
  background: -moz-linear-gradient(top, #fcfff4 0%, #e9e9ce 100%);
  background: -webkit-linear-gradient(top, #fcfff4 0%, #e9e9ce 100%);
  background: -o-linear-gradient(top, #fcfff4 0%, #e9e9ce 100%);
  background: -ms-linear-gradient(top, #fcfff4 0%, #e9e9ce 100%);
  background: linear-gradient(to bottom, #fcfff4 0%, #e9e9ce 100%);
}

.customfile-upload:hover {
  background: #fafafa;
  box-shadow: 0 0 2px rgba(0,0,0,.2);
}
.customfile-upload::-moz-focus-inner { /* Fix firefox padding */
  padding: 0; border: 0;
}

На данный момент все должно работать, но чтобы все оживить потребуются некоторые стили.

Получаем файлы на сервере

Во-первых, обернем наше поле формой и добавим кнопку отправить.

HTML

<form action="test.php" method="post" enctype="multipart/form-data">
  <div class="customfile-container">
    <label>File: </label>
    <input type="file" id="file" name="myfiles[]" multiple />
  </div>
<button type="submit">Submit</button>
</form>

Затем мы можем получить все имена файлов и распечатать их в test.php.

Поскольку мы используем массив mifiles[], сервер будет извлекать все файлы даже, когда используется альтернативный вариант для старых браузеров.

PHP

<?php
$files = $_FILES['myfiles']; // Array containing all files
echo implode( $files, '<br/>' );

Источник

Комментарии к статье

Добавить комментарий

бдсм бондаж пояс