После прочтения урока о создании плагинов для jQuery, я решил попробовать написать эту статью, решающую мою проблему, смотрим что вышло.
Для начала давайте создадим jQuery плагин
(function( $ ) {
$.fn.mozaika= function() {
};
})(jQuery);
Как и в большинстве плагинов, в нашем будут настройки. Давайте определимся с ними:
- Количество столбиков
- Отступы между блоками
- Поле (padding) сверху и снизу поля с «пазлами»
- Класс для блоков
- Класс для блоков с двойной шириной
- Класс для блоков с тройной шириной
- нижний Padding ячейки
Имеем
(function( $ ) {
$.fn.mozaika= function() {
var set = $.extend( {
'n': 4,
'margin': 4,
'padding' : 30,
'item' : 'item',
'citem2' : 'item-w2',
'citem3' : 'item-w3',
'itembot' : 0
}, options);
};
})(jQuery);
Создадим массив для высоты каждой колонки:
var cols = new Array() // Массив для высоты колонки
for(i = 0; i < set.n; i++)
cols[i] = 0;
Найдём ширину элемента с мозаикой:
var width = this.width(); // ширина элемента с мозаикой
Следующим шагом нужно вычислить ширину одной ячейки (с обычной шириной):
var one = (width - set.margin * (set.n - 1))/set.n;
// ширина одного элемента
var left = 0; // позиция по Х
Следующим шагом стоит найти все ячейки и построить наш «пазл». Для этого нужно проверить, не являются ли наши ячейки — ячейками с двойной или тройной шириной. Если вдруг элемент с двойной шириной будет строиться на четвёртой колонке из четырёх, нужно перенести его в первую. Так-же для случаев с не одинарной шириной, нужно будет строить ячейку в самом низу большей из колонок. Так-что найдём максимальную высоту, из колонок которые затрагиваются.
Дальше зададим координаты нашей ячейке.
Следующим шагом запишем новую высоту нашего столбика(столбиков), и новые координаты по оси x. Если строка закончилась, переходим на новую. В конце — задаём высоту блока для наших ячеек.
(function( $ ) {
$.fn.mozaika= function(options) {
var set = $.extend( {
'n': 4,
'margin': 4,
'padding' : 30,
'item' : 'item',
'citem2' : 'item-w2',
'citem3' : 'item-w3',
'itembot' : 0
}, options);
var cols = new Array() // Массив для высоты колонки
for(i = 0; i < set.n; i++)
cols[i] = 0;
var width = this.width(); // ширина элемента с мозайкой
var one = (width - set.margin * (set.n - 1))/set.n;
// ширина одного элемента
var left = 0; // позиция по Х
var moz = this.children('.'+set.item); // ячейки
i = 0;
$(moz).each(function( k, v ) {
if($(v).hasClass(set.citem2)){
w = one*2+set.margin;
q=2;
}else if($(v).hasClass(set.citem3)){
w = one*3+set.margin*2;
q=3;
}else{
w = one;
q = 1;
}
if(i+q>set.n){
i = 0;
}
var mx = cols[i];
var mn = i;
for(e = i; e <i+q; e++)
if(cols[e] > mx){
mx = cols[e];
mn = e;
}
$(v).css({'position':'absolute', 'width' : w+'px'});
$(v).css({'left' : left+'px', 'top':mx, 'padding-bottom':set.itembot});
$(v).animate({opacity:1},1000);
hg = cols[i];
for(e = i; e < i+q; e++){
cols[e] = hg + $(v).height() + set.margin + set.itembot;
//console.log('n ' + i + ' q ' + q + ' cols[' + e + '] ' + cols[e]);
}
left = left + set.margin + w;
i = i+q;
if(i>=set.n){
i=0;
left = 0;
}
});
mx = cols[0];
for(e = 0; e <set.n; e++)
if(cols[e] > mx){
mx = cols[e];
}
if(this.height()<(mx+set.padding*2))
this.height(mx+set.padding*2);
};
})(jQuery);
Вызываем:
$(document).ready(function(e) {
$(".catalog").moZaika({
'n': 4,
'margin': 2,
'item' : 'cat-item',
'citem2' : 'cat-w2',
'citem3' : 'cat-w3',
'itembot' : 20,
'padding' : 0
});
});
Готово, всё работает!
Единственное с чем осталось побороться, это с перестроением при изменении ширины поля для мозаики. Для этого я пока-что ещё раз вызываю плагин в $(window).resize().
Комментарии (17)
hell0w0rd
08.01.2016 14:25+2Шел 2016, люди все еще пишут jquery плагины. Судя по коду — совершенно спокойно можно сделать с помощью современного JS.
neyrowebster
08.01.2016 14:33для практики пойдёт.
Честно, понимаю что нужно уходить от jQuery.
Стараюсь.)
Писал чтобы получить приглашение на хабр.
Rastishka
08.01.2016 15:10Мне кажется что такое уже давно должно делаться на чистом CSS, флексбоксами какими нибудь…
Или пока еще невозможно?Akuma
08.01.2016 15:26+1Можно вот так делать: http://w3bits.com/css-masonry/
Но это немного не то, т.к. нет разнородных элементов. А в точности повторить масонри на чистом CSS пока, думаю, не получится.
k12th
08.01.2016 15:46var cols = new Array() // Массив для высоты колонки
Есть только один повод писатьnew Array
в JS — это если нужен массив undefined заданной длины. В принципе, вреда в этом нет, если человек понимает, что делает, но во многих code style порицается.
for(i = 0; i < set.n; i++) cols[i] = 0;
А вот за это в приличных проектах канделябром-с:)
Вообще этот кусок можно переписать (субъективно) красивее:
var cols = (new Array(set.n)).map(_ => 0)
Как минимум, короче.
Плагины к jQuery не нужны — раньше они позволяли несколько уменьшить риск коллизий имен, сейчас этим занимается модульная система. Переделайте на обычную функцию, которая принимает элемент, и положите в пакет с зависимостью от jQuery.neyrowebster
08.01.2016 16:31не знаю точно что, но что-то тут не так. Попробовал, не работает(
var cols = (new Array(set.n)).map(_ => 0);
покручу ещё.k12th
08.01.2016 16:36Это ES6, если что. Оно может где-то не работать без компиляции. В ES5 это будет так:
var cols = new Array(set.n).map(function (_) { return 0; });
POPSuL
09.01.2016 18:21Решал однажды подобную задачу. Сопротивлялся недели две, не желал это делать, ибо считал это убожеством, но за пол часа накидал прототип, который после пары мелких правок ушел в продакшен, и не менялся уже года 4 :)
Это не рекламаhttp://rinamika.ru/
раньше работал в этой компании, и пилил эту мозайку
Решил задачу таким вот говнокодом http://rinamika.ru/resources/javascript/mosaic.js.
И не просите это прокомментировать!
Isis
masonry.desandro.com
neyrowebster
Да, я его видел. Не знаю причин, но строило через раз.
novoxudonoser
Вы просто не смогли его приготовить. Работает он через раз из за асинхронной загрузки изображений. Надо использовать imagesLoaded пример — http://codepen.io/desandro/pen/RPKgEN
neyrowebster
благодарю