От автора: Учебник о том, как создать адаптивное растяжение поле поиска с хорошей поддержкой сенсорного ввода.
Возможно, вы заметили те маленькие усовершенствования, которые в последнее время появились здесь, на Codrops. Одной из тех вещей, которые мы решили изменить, стало поле ввода для поиска. Оно было перенесено из боковой колонки в верхний колонтитул и применен простой эффект, при котором нужно щелкнуть, чтобы поле ввода увеличилось. Мы получили множество просьб объяснить, как это сделано, и сегодня хотели бы показать вам, как «с нуля» создать подобный input для поиска. Нашей целью стало максимальное увеличение совместимости мобильных устройств и старых браузеров (вплоть до IE8). Хотя это может показаться очень легкой задачей, нам придется применить несколько хитростей, чтобы все заработало должным образом.
Вкратце, вот что должен делать наш поисковый компонент:
С самого начала нам нужно, чтобы показывалась только кнопка с иконкой поиска.
При щелчке по иконке нужно, чтобы выскальзывало поле поиска.
Компонент должен быть гибким, чтобы его можно было использовать в адаптивном контексте.
После написания чего-либо нужна возможность отправки формы путем нажатия enter или щелчка по иконке поиска.
Если поле ввода растянуто и пусто, оно должно снова закрываться при щелчке по иконке поиска.
Нам также требуется, чтобы поле ввода закрывалось при щелчке вне его независимо от того, пустое оно или нет.
При отключенном JavaScript’е нужно, чтобы поле поиска отображалось растянутым.
Для применения в сенсорных устройствах требуется добавить поддержку событий касания.
Теперь, когда понятно, что нам нужно, давайте начнем с разметки.
РАЗМЕТКА
Для разметки нам нужен основной контейнер, форма, текст и input-ы отправки, а для иконки – span:
1 2 3 4 5 6 7 |
<div id="sb-search" class="sb-search"> <form> <input class="sb-search-input" placeholder="Enter your search term..." type="search" value="" name="search" id="search"> <input class="sb-search-submit" type="submit" value=""> <span class="sb-icon-search"></span> </form> </div> |
Как правило, для иконки можно было бы применить псевдоэлемент, но так как не планируется его использования с замещаемыми элементами, такими как элементы формы, то мы просто в данном случае воспользуемся span. Когда все элементы размещены, давайте назначим им стили.
CSS
Следуя собственным требованиям, нам сначала нужно убедиться, что кнопка с иконкой поиска видна. Все остальное должно быть скрыто. Но давайте продумаем еще один шаг вперед и представим себе, что случится, когда мы увеличим поле поиска (основной упаковщик). Как нам это сделать? Давайте воспользуемся overflow: hidden и при увеличении ширины упаковщика sb-search input должен проявиться.
Поэтому первым мы назначаем стили упаковщику sb-search. Свободно размещаем его справа и устанавливаем overflow на hidden. Изначально ширина должна быть 60px, но так как нам нужно анимировать ее до 100%, на мобильных браузерах (iOS) будет проблема. Им не нравится переход с ширины на основе пикселей до процентной. Они просто пропустят переход. Поэтому вместо того мы определяем значение min-width в 60px и ширину в 0%. Это блестящее решение, придуманное @julienknebel, и он пишет о нем здесь: Переход CSS от фиксированной ширины в пикселях к автоматической (CSS transition from a fixed px width to an auto width).
Также добавим переход ширины и -webkit-backface-visibility: hidden во избежание некоторых отпечатков ввода для мобильных браузеров (iOS):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
.sb-search { position: relative; margin-top: 10px; width: 0%; min-width: 60px; height: 60px; float: right; overflow: hidden; -webkit-transition: width 0.3s; -moz-transition: width 0.3s; transition: width 0.3s; -webkit-backface-visibility: hidden; } |
Все, что переполняет этот небольшой блок, видно не будет. Теперь разместим input поиска. Установим ширину на основе процентов с тем, чтобы при расширении родительского элемента input увеличивался вместе с ним. Установка правильной высоты, размера шрифта и отступа гарантирует, что текст будет находиться по центру (использование высоты строки в IE8 не сработает должным образом, поэтому давайте установим вместо него отступы).
Установка input на position absolute может показаться ненужной затеей, но она решает мелкую досадную неприятность, которая иногда случается при закрытии поиска: на какое-то короткое время input кажется видимым справа.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
.sb-search-input { position: absolute; top: 0; right: 0; border: none; outline: none; background: #fff; width: 100%; height: 60px; margin: 0; z-index: 10; padding: 20px 65px 20px 20px; font-family: inherit; font-size: 20px; color: #2c3e50; } input[type="search"].sb-search-input { -webkit-appearance: none; -webkit-border-radius: 0px; } |
К тому же мы удаляем стили input по умолчанию для браузеров WebKit. Давайте определим цвет текста-заполнителя с помощью вендорных правил:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
.sb-search-input::-webkit-input-placeholder { color: #efb480; } .sb-search-input:-moz-placeholder { color: #efb480; } .sb-search-input::-moz-placeholder { color: #efb480; } .sb-search-input:-ms-input-placeholder { color: #efb480; } |
Теперь позаботимся о кнопке с иконкой поиска и input -ом отправки. Известно, что они нужны нам в одном месте, поэтому разместим их в правом углу и установим одинаковые размеры. Так как они будут находиться один над другим, мы установим им абсолютное позиционирование:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
.sb-icon-search, .sb-search-submit { width: 60px; height: 60px; display: block; position: absolute; right: 0; top: 0; padding: 0; margin: 0; line-height: 60px; text-align: center; cursor: pointer; } |
В исходном положении нам требуется, чтобы на кнопку с иконкой можно было щелкнуть. Затем, при открытии input -а, нужна возможность щелкнуть input отправки. Поэтому мы сначала установим z-index для input -а отправки на -1 и сделаем его прозрачным, чтобы все время видеть иконку поиска:
1 2 3 4 5 6 7 8 9 10 |
.sb-search-submit { background: #fff; /* нужно для IE */ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; /* IE 8 */ filter: alpha(opacity=0); /* IE 5-7 */ opacity: 0; color: transparent; border: none; outline: none; z-index: -1; } |
Почему бы просто не установить прозрачный фон? Похоже, что в IE это нормально не сработает, так как элемент не поддается щелчку. Следовательно, мы вместо этого применяем плотный фоновый цвет и устанавливаем непрозрачность на 0.
У диапазона иконки поиска будет изначально высокий z-index, потому что нам нужно, чтобы она находилась поверх всего остального. Для добавления иконки поиска мы применим псевдоэлемент :before:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
.sb-icon-search { color: #fff; background: #e67e22; z-index: 90; font-size: 22px; font-family: 'icomoon'; speak: none; font-style: normal; font-weight: normal; font-variant: normal; text-transform: none; -webkit-font-smoothing: antialiased; } .sb-icon-search:before { content: "\e000"; } |
Не забудьте подключить шрифт в начале вашего CSS:
1 2 3 4 5 6 7 8 9 10 11 |
/* Иконка поиска от IcoMoon, созданная с помощью приложения //icomoon.io/app/ */ @font-face { font-family: 'icomoon'; src:url('../fonts/icomoon/icomoon.eot'); src:url('../fonts/icomoon/icomoon.eot?#iefix') format('embedded-opentype'), url('../fonts/icomoon/icomoon.woff') format('woff'), url('../fonts/icomoon/icomoon.ttf') format('truetype'), url('../fonts/icomoon/icomoon.svg#icomoon') format('svg'); font-weight: normal; font-style: normal; } |
Когда стили назначены таким образом, уже можно просто установить ширину упаковщика sb-search, чтобы та становилась 100% при добавлении класса sb-search-open. При неактивном JavaScript’е нам нужно, чтобы input поиска был по умолчанию открыт:
1 2 3 4 |
.sb-search.sb-search-open, .no-js .sb-search { width: 100%; } |
Давайте изменим цвет диапазона иконки поиска и поместим ее под input -ом отправки, установив z-index на более низкое значение:
1 2 3 4 5 6 |
.sb-search.sb-search-open .sb-icon-search, .no-js .sb-search .sb-icon-search { background: #da6d0d; color: #fff; z-index: 11; } |
И наконец, установим z-index input отправки на более высокое значение, чтобы на него можно было щелкать:
1 2 3 4 |
.sb-search.sb-search-open .sb-search-submit, .no-js .sb-search .sb-search-submit { z-index: 90; } |
Когда все необходимые стили определены, можно перейти к JavaScript’у.
JAVASCRIPT
Начнем с переключения класса sb-search-open. Добавляем его при щелчке по основному упаковщику (sb-search) и удаляем при щелчке по input -у отправки, только если input пуст. В противном случае мы отправляем форму. Чтобы не запускать удаление класса при щелчке по input -у (так как наш спусковой механизм – это весь упаковщик), на этом элементе нужно предотвратить появление события щелчка. Это значит, что щелчок по input -у не вызовет запуск щелчка на его родительских элементах.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
;( function( window ) { function UISearch( el, options ) { this.el = el; this.inputEl = el.querySelector( 'form > input.sb-search-input' ); this._initEvents(); } UISearch.prototype = { _initEvents : function() { var self = this, initSearchFn = function( ev ) { if( !classie.has( self.el, 'sb-search-open' ) ) { // откройте его ev.preventDefault(); self.open(); } else if( classie.has( self.el, 'sb-search-open' ) && /^\s*$/.test( self.inputEl.value ) ) { // закройте его self.close(); } } this.el.addEventListener( 'click', initSearchFn ); this.inputEl.addEventListener( 'click', function( ev ) { ev.stopPropagation(); }); }, open : function() { classie.add( this.el, 'sb-search-open' ); }, close : function() { classie.remove( this.el, 'sb-search-open' ); } } // добавьте в глобальное пространство имен window.UISearch = UISearch; } )( window ); |
Далее нам следует добавить события для удаления класса sb-search-open при щелчке в любом месте вне поля поиска. Чтобы это заработало, также нужно позаботиться о появлении события при щелчке по основному упаковщику.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
;( function( window ) { function UISearch( el, options ) { this.el = el; this.inputEl = el.querySelector( 'form > input.sb-search-input' ); this._initEvents(); } UISearch.prototype = { _initEvents : function() { var self = this, initSearchFn = function( ev ) { ev.stopPropagation(); if( !classie.has( self.el, 'sb-search-open' ) ) { // откройте его ev.preventDefault(); self.open(); } else if( classie.has( self.el, 'sb-search-open' ) && /^\s*$/.test( self.inputEl.value ) ) { // закройте его self.close(); } } this.el.addEventListener( 'click', initSearchFn ); this.inputEl.addEventListener( 'click', function( ev ) { ev.stopPropagation(); }); }, open : function() { var self = this; classie.add( this.el, 'sb-search-open' ); // в случае щелчка по телу закройте input поиска var bodyFn = function( ev ) { self.close(); this.removeEventListener( 'click', bodyFn ); }; document.addEventListener( 'click', bodyFn ); }, close : function() { classie.remove( this.el, 'sb-search-open' ); } } // добавьте в глобальное пространство имен window.UISearch = UISearch; } )( window ); |
Еще одна вещь, о которой следует позаботиться – это обрезка поисковой фразы. Кроме того, при щелчке по иконке поиска нам нужно, чтобы input попадал в фокус. Так как в мобильных браузерах (iOS) это вызывает несколько дерганый переход (с одновременным открытием клавиатуры), в данном случае хотелось бы этого избежать. При закрытии поля поиска мы сделаем размытие input-а поиска. Это решит проблемы на некоторых устройствах, где даже после закрытия input -а курсор показывается мерцающим.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
;( function( window ) { // //stackoverflow.com/a/11381730/989439 function mobilecheck() { var check = false; (function(a){if(/(android|ipad|playbook|silk|bb\d+|meego).+mobile| avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile |ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo |up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda |xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s |a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw) |aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq) |bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u) |c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng) |dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul) |er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene |gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t) |hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp) |hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom |im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji |kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg ( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo) |mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo (01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5) |n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i) |nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg |pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po (ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-) |qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va) |sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar |sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel (i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up (\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v) |vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera); return check; } // //www.jonathantneal.com/blog/polyfills-and-prototypes/ !String.prototype.trim && (String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); }); function UISearch( el, options ) { this.el = el; this.inputEl = el.querySelector( 'form > input.sb-search-input' ); this._initEvents(); } UISearch.prototype = { _initEvents : function() { var self = this, initSearchFn = function( ev ) { ev.stopPropagation(); // обрежьте его значение self.inputEl.value = self.inputEl.value.trim(); if( !classie.has( self.el, 'sb-search-open' ) ) { // откройте его ev.preventDefault(); self.open(); } else if( classie.has( self.el, 'sb-search-open' ) && /^\s*$/.test( self.inputEl.value ) ) { // закройте его self.close(); } } this.el.addEventListener( 'click', initSearchFn ); this.inputEl.addEventListener( 'click', function( ev ) { ev.stopPropagation(); }); }, open : function() { var self = this; classie.add( this.el, 'sb-search-open' ); // сфокусируйте на вводе if( !mobilecheck() ) { this.inputEl.focus(); } // закройте ввод поиска при щелчке по телу var bodyFn = function( ev ) { self.close(); this.removeEventListener( 'click', bodyFn ); }; document.addEventListener( 'click', bodyFn ); }, close : function() { this.inputEl.blur(); classie.remove( this.el, 'sb-search-open' ); } } // добавьте в глобальное пространство имен window.UISearch = UISearch; } )( window ); |
Чтобы в мобильных устройствах все работало гладко, нам понадобится добавить соответствующие события касания. Добавив preventDefault в функцию initSearchFn, мы предотвратим события касания и щелчка от одновременного запуска на сенсорных устройствах.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
;( function( window ) { // //stackoverflow.com/a/11381730/989439 function mobilecheck() { var check = false; (function(a){if(/(android|ipad|playbook|silk|bb\d+|meego).+mobile|avantgo |bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od) |iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo |up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda |xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i |770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw) |aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq) |bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb |bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd) |craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d) |el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc |fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un) |haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c |ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230 |iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris |ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w]) |libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo) |mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef |mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2] |n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10) |ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv) |oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire |pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60 |\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va) |sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar |sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m) |tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst |v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc |vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera); return check; } // //www.jonathantneal.com/blog/polyfills-and-prototypes/ !String.prototype.trim && (String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); }); function UISearch( el, options ) { this.el = el; this.inputEl = el.querySelector( 'form > input.sb-search-input' ); this._initEvents(); } UISearch.prototype = { _initEvents : function() { var self = this, initSearchFn = function( ev ) { ev.stopPropagation(); // обрежьте его значение self.inputEl.value = self.inputEl.value.trim(); if( !classie.has( self.el, 'sb-search-open' ) ) { // откройте его ev.preventDefault(); self.open(); } else if( classie.has( self.el, 'sb-search-open' ) && /^\s*$/.test( self.inputEl.value ) ) { // закройте его ev.preventDefault(); self.close(); } } this.el.addEventListener( 'click', initSearchFn ); this.el.addEventListener( 'touchstart', initSearchFn ); this.inputEl.addEventListener( 'click', function( ev ) { ev.stopPropagation(); }); this.inputEl.addEventListener( 'touchstart', function( ev ) { ev.stopPropagation(); } ); }, open : function() { var self = this; classie.add( this.el, 'sb-search-open' ); // сфокусируйте на вводе if( !mobilecheck() ) { this.inputEl.focus(); } //закройте ввод поиска, если щелчок производится по телу var bodyFn = function( ev ) { self.close(); this.removeEventListener( 'click', bodyFn ); this.removeEventListener( 'touchstart', bodyFn ); }; document.addEventListener( 'click', bodyFn ); document.addEventListener( 'touchstart', bodyFn ); }, close : function() { this.inputEl.blur(); classie.remove( this.el, 'sb-search-open' ); } } // добавьте в глобальное пространство имен window.UISearch = UISearch; } )( window ); |
Наконец, для браузеров, не имеющих поддержки addEventListener и removeEventListener, мы применяем полифил EventListener Джонатана Нила (Jonathan Neal).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
// EventListener | @jon_neal | //github.com/jonathantneal/EventListener !window.addEventListener && window.Element && (function () { function addToPrototype(name, method) { Window.prototype[name] = HTMLDocument.prototype[name] = Element.prototype[name] = method; } var registry = []; addToPrototype("addEventListener", function (type, listener) { var target = this; registry.unshift({ __listener: function (event) { event.currentTarget = target; event.pageX = event.clientX + document.documentElement.scrollLeft; event.pageY = event.clientY + document.documentElement.scrollTop; event.preventDefault = function () { event.returnValue = false }; event.relatedTarget = event.fromElement || null; event.stopPropagation = function () { event.cancelBubble = true }; event.relatedTarget = event.fromElement || null; event.target = event.srcElement || target; event.timeStamp = +new Date; listener.call(target, event); }, listener: listener, target: target, type: type }); this.attachEvent("on" + type, registry[0].__listener); }); addToPrototype("removeEventListener", function (type, listener) { for (var index = 0, length = registry.length; index < length; ++index) { if (registry[index].target == this && registry[index].type == type && registry[index].listener == listener) { return this.detachEvent("on" + type, registry.splice(index, 1)[0].__listener); } } }); addToPrototype("dispatchEvent", function (eventObject) { try { return this.fireEvent("on" + eventObject.type, eventObject); } catch (error) { for (var index = 0, length = registry.length; index < length; ++index) { if (registry[index].target == this && registry[index].type == eventObject.type) { registry[index].call(this, eventObject); } } } }); })(); |
Вот и все! Надеюсь, вам понравился этот учебник и вы сочли его полезным!
Автор: Mary Lou
Источник: //tympanus.net/
Редакция: Команда webformyself.