Полностью своя кнопка «Выбрать файл»

Изучая веб-программирование, я не нашел внятного решения проблемы оформления загрузки файла на сервер при помощи одной кастомной кнопки.

Предлагаю на суд сообщества свой велосипед. На написание данного текста вдохновил Способ №5 из материала Делаем красивый input[type=file] для адаптивного сайта… И да — все работает в IE, начиная с 9 версии.

Демо на dropbox:

Цель: создать свою кнопку/элемент управления по нажатию которой происходит загрузка файла на сервер (либо иные, предусмотренные разработчиком, файловые операции).
Инструменты: CSS, PHP, JavaScript.
Используемые технологии: Ajax, через скрытый iframe.

Преамбула


Из кода для упрощения сознательно выкинуты все процедуры проверки принятого файла и try-catch вызовов функций, так как эти моменты не являются темой данной статьи. Также не охватывается момент по предотвращению звукового сигнала в IE. В работе используем технологию Ajax, подразумевающую, что у нас есть основная страница, осуществляющая взаимодействие с пользователем(front-end) и скрипт на сервере, обрабатывающая наши запросы(back-end)

Технология работы


1. На главной странице создаем «form action» Делаем ей target на скрытый фрейм, который создаем статически (или динамически). Создаем два «input» с типом «file» и «submit», даем им «id», помещаем их в «div», который спрячем со страницы стилем. Все эти элементы не видимы для пользователя и не воспринимают каких-либо его действий.
2. Начинаем «магию». Для «input» с типом «file» на событие по изменению вешаем вызов функции onchange=«LoadFile();».
3. На главной странице создаем кнопку. Навешиваем ей на событие нажатия кнопки мыши вызов функции onclick=«FindFile();».
4. В функции FindFile() имитируем клик на «input» с типом «file». То есть при нажатии на нашу кнопку вызывается стандартный диалог выбора файла. Как только пользователь выбрал файл, срабатывает событие onchange и вызывается функция LoadFile(). В функции LoadFile() имитируем клик на «input» с типом «submit».
5. Форма формирует POST запрос с именем файла к нашему back-end скрипту, который осуществляет все проверки по безопасности и загрузку файла. После этого скрипт вызывает callback функцию главной страницы, которой сообщает о результате выполнения.

Собственно все. Для примера приведены четыре основных файла, код которых приведён ниже:

css/style.css – стили главной страницы
view/upload.php – back-end скрипт загрузки файла
index.php – главная страницы
js/upload.js – front-end скрипты главной страницы

Кроме того, необходим любой файл с картинкой для кнопки buttons/openfile.png

Загружаемые файлы помещаем в директорию ../temp/

Таблица стилей (css/style.css)
Создаем стиль кнопки и скрытого «input».
.navButtons{  
      border:1px gray solid;
      position:absolute;
      overflow: hidden;
      display:block;  
      height:50px;  
      width:50px;  
      margin:10px;
      -moz-box-shadow:5px 5px 7px rgba(3,33,33,.7);  
      -webkit-box-shadow: 5px 5px 7px rgba(3,33,33,.7);  
      box-shadow: 5px 5px 7px rgba(3,33,33,.7);  
      -moz-border-radius:4px;
      -webkit-border-radius:4px;
      border-radius:4px;
  }

.navButtons:hover
{
  border:2px solid black;
  background-color:#fff;
}

.hiddenInput{  
      position:absolute;
      overflow: hidden;
      display:block;  
      height:0px;  
      width:0px;  
  }
Input мы просто делаем нулевой ширины и высоты


Скрипт обрабатывающий запрос на загрузку файла (view/upload.php)
Здесь все согласно примерам в интернете, валидация файлов изъята:
<?php  
// определяем callback функцию основного окна которой вернем ответ по окончанию загрузки 
 function jsOnResponse($obj)  
 {  
 echo '<script type="text/javascript"> window.parent.onResponse("'.$obj.'"); </script> ';  
 }  
// определяем куда скопируем файл пользователя
 $dir = '../temp/';  
 $name = basename($_FILES['loadfile']['name']);  
 $file = $dir . $name;  
//копируем файл и получаем результат
 $success = move_uploaded_file($_FILES['loadfile']['tmp_name'], $file);  
//вызываем callback функцию и передаем ей результат
 jsOnResponse("{'filename':'" . $name . "', 'success':'" . $success . "'}");  
?> 


Главная страница (index.php)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="content-type" content="text/html; charset=windows-1251" />
    <title>OpenFile test</title>
    <link rel="stylesheet" href="css/style.css" type="text/css" media="screen, projection" />
</head>
<body>

<!-- Рисуем нашу кнопку, определяем ей реакцию на нажатие кнопки мыши  -->
<div class="navButtons" onclick="FindFile();" title="Загрузка файла"><img src="buttons/openfile.png"   width=100% height=100%/></a></div>

<!-- Делаем форму   -->
<form action="view/upload.php" target="rFrame" method="POST" enctype="multipart/form-data">  
<!-- Формируем спрятанные элементы -->
<div class="hiddenInput">
 <input type="file"   id="my_hidden_file" accept="image/jpeg,image/png,image/gif" name="loadfile" onchange="LoadFile();">  
 <input type="submit" id="my_hidden_load" style="display: none" value='Загрузить'>  
</div></form>
<!-- И скрытый iframe таргет  -->
<iframe id="rFrame" name="rFrame" style="display: none"> </iframe>  

<!-- Подключаем скрипты -->
<script src="js/upload.js"> </script>


JavaScript в главной форме (js/upload.js)
function FindFile() { document.getElementById('my_hidden_file').click(); }  
function LoadFile() { document.getElementById('my_hidden_load').click(); }  

function onResponse(d) // Функция обработки ответа от сервера 
{  
 eval('var obj = ' + d + ';');  
 if(obj.success!=1)
   {
    alert('Ошибка!\nФайл ' + obj.filename + " не загружен - "+obj.myres); 
    return; 
   }; 
 alert('Файл загружен'); 
}  

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 35

    +3
    Скриншот бы хоть, в качестве КДПВ :)
      +1
      Да и демка бы не помешала ;)
      для тестирования в разных браузерах
        0
        Демку добавил в начале топика перед Целью качайте смотрите )
      +2
      Как-то маловато для статьи. И да, способ давно известный, в свой древней статье я его приводил)
        0
        Хм… использую Plupload, поддерживает клик, Drag'n'Drop.
        Есть различные варианты в зависимости от того, что умеет браузер: HTML5, HTML4, Flash, Silverlight.
        Я обычно беру только HTML5 вариант для минимизации объема, и даже iframe не нужен.
          0
          Привет! А с телефонов и планшетов загружает картинки/видео?
            0
            Конечно, почему нет?
              0
              Например, год назад большие видео-файлы с айфонов почему то не загружались. Вот и спрашиваю как сейчас))
                0
                Вот большие файлы с iphone не загружал, не знаю.
          +1
          Где можно «пощупать»?
            +4
            Не проще input=file с прозрачностью в ноль расположить поверх дива, который и стилизовать?
              0
              Проще конечно.
              Но мы же не ищем лёгких путей, тем более в статье ссылка есть на статью с этим примером (Способ №3), но автор сказал, что лучше рассмотреть N5
              На написание данного текста вдохновил Способ №5 из материала «Делаем красивый input[type=file] для адаптивного сайта…»


              Единственное — в статье нет этого способа (вроде):
              input[type=file] {
                -webkit-appearance: none;
                -moz-appearance: none;
                appearance: none;
                /** А дальше пишем что хотим **/
              }
              
                0
                Да. Сходил прочитал, есть там такое. Тут только не выделено, почему именно 5-ый способ используется.
              0
              Можете бросить в меня камнем, но кажется только вчера прочел, что нормальные браузеры запрещают из js вызывать клик на input[type=file]. Пруф
                0
                Пример нормального браузера?
                  0
                  FF, Chome, НЕ IE.
                  Кстати, в каком из… вы тестировали?
                    0
                    Да? А почему у меня работало и работает?
                      0
                      отлично, тогда можно демку в студию?
                      0
                      Кстати только что проверил в консоли хрома. Не работает. Увы…
                      Взял кусочек вашего кода…
                      Может я что-то не так сделал?
                        0
                        Моего кода?
                          0
                          да, вот так
                          document.getElementById('my_hidden_file').click();
                            0
                            Я не автор статьи
                              0
                              Еще раз все протестировал, тьфу тьфу работает…
                              можно глянуть в мою dyukha.rurs.net/MySlider
                              песочницу на бесплатном(плохом) хостинге
                              снизу вторая справа кнопка
                          +1
                          а я замечал обратное, когда пытался инпут стилизовать (давно это было):
                          ие8 не давал делать клик js, а нормальные браузеры давали.
                          в итоге прозрачность — самое нормальное решение
                          если кнопка большая, можно сделать, чтобы input ездил за курсором, т.к. размеры его тоже нельзя поправить в некоторых браузерах :)
                            0
                            Хах, интересное решение) Спасибо, мб где-то пригодится.
                    0
                    > запрещают из js вызывать клик на input[type=file]

                    кроме случаев, когда вызов делается внутри обработчика события клика нам чем-либо еще. Может быть не только клика (keydown, например), точно не знаю.
                      0
                      Спасибо за решение. Проверил. GOOD! :)
                      0
                      У нас на проекте angular.element('#file-upload').trigger('click') запросто работает.Ну т.е. есть некоторый кастомный блок (кнопка), по клику на который вызываем клик на инпут #file-upload.
                        0
                        Спасибо, постараюсь запомнить.
                      0
                        0
                        Думаю, пост был бы в несколько раз полезнее, если бы имел демку.
                          0
                          Извиняюсь если что сделал не так, человек я тут новый, за что заминусовали не понимаю (.
                          Демку добавил — в тексте перед Целью ссылка на дропбокс, там весь проект — проверял на IE9+, Opera 12.17, FF 34.05, Yandex 14.10, Chrome 39.0, Chrome Android (какой то 4+ — не успел посмотреть какая там версия была)
                            0
                            Вот хорошая подборка на эту тему.
                            obninsksite.ru/blog/html-and-css/input-file-style

                            Only users with full accounts can post comments. Log in, please.