(function ($) { jQuery.fn.reverse = Array.prototype.reverse; var // auxiliar functions aux = { setup: function ($wrapper, $items, opts) { // set the wrappers position to relative $wrapper.css('position', 'relative'); // save the items position aux.saveInitialPosition($items); // set the items to absolute and assign top & left $items.each(function (i) { var $item = $(this); $item.css({ position: 'absolute', left: $item.data('left'), top: $item.data('top') }); }); // check how many items we have per row var rowCount = Math.floor($wrapper.width() / $items.width()), // number of items to show is rowCount * n rows shown = rowCount * opts.rows, // total number of rows totalRows = Math.ceil($items.length / rowCount); // save this values for later var config = {}; config.currentRow = 1; config.totalRows = totalRows; config.rowCount = rowCount; config.shownItems = shown; $wrapper.data('config', config); // show n rowns $wrapper.children(':gt(' + (shown - 1) + ')').hide(); // assign row classes to the items $items.each(function (i) { var $item = $(this), row = Math.ceil((i + 1) / rowCount); $item.addClass('tj_row_' + row); }); nav.setup($wrapper, $items, opts); }, saveInitialPosition: function ($items) { $items.each(function (i) { var $item = $(this); $item.data({ left: $item.position().left + 'px', top: $item.position().top+ 'px' }); }); } }, // navigation types nav = { setup: function ($wrapper, $items, opts) { nav[opts.type.mode].setup($wrapper, $items, opts); }, def: { setup: function ($wrapper, $items, opts) { var config = $wrapper.data('config'); $items.each(function (i) { var $item = $(this), row = Math.ceil((i + 1) / config.rowCount), t, f = row % opts.rows; if (f === 1) { t = '0px'; } else if (f === 0) { t = (opts.rows - 1) * $items.height() + 'px'; } else { t = (f - 1) * $items.height() + 'px'; } $item.css({ top: t }); }); }, pagination: function ($wrapper, dir, opts) { var config = $wrapper.data('config'); if ((dir === 1 && config.currentRow + opts.rows > config.totalRows) || (dir === -1 && config.currentRow - opts.rows <= 0) ) { $wrapper.data('anim', false); return false; } // var currentRows = '', nextRows = ''; // for (var i = 0; i < opts.rows; ++i) { // currentRows += '.tj_row_' + (config.currentRow + i) + ','; // (dir === 1) // ? nextRows += '.tj_row_' + (config.currentRow + opts.rows + i) + ',' // : nextRows += '.tj_row_' + (config.currentRow - 1 - i) + ','; // } // 使用数组来存储选择器 var currentRows = []; var nextRows = []; // 获取当前行的起始位置 var currentRowStart = config.currentRow; for (var i = 0; i < opts.rows; ++i) { // 生成当前行选择器并存储到数组中 currentRows.push('.tj_row_' + (currentRowStart + i)); // 根据方向计算下一行的选择器并存储到数组中 if (dir === 1) { nextRows.push('.tj_row_' + (currentRowStart + opts.rows + i)); } else { nextRows.push('.tj_row_' + (currentRowStart - 1 - i)); } } // 通过 join(',') 将数组中的选择器连接成字符串 currentRows = currentRows.join(','); nextRows = nextRows.join(','); $wrapper.children(currentRows).hide(); $wrapper.children(nextRows).show(); (dir === 1) ? config.currentRow += opts.rows : config.currentRow -= opts.rows; $wrapper.data('anim', false); $wrapper.data('config', config); } }, fade: { setup: function ($wrapper, $items, opts) { // same like def mode nav['def'].setup($wrapper, $items, opts); }, pagination: function ($wrapper, dir, opts) { var config = $wrapper.data('config'); if ((dir === 1 && config.currentRow + opts.rows > config.totalRows) || (dir === -1 && config.currentRow - opts.rows <= 0) ) { $wrapper.data('anim', false); return false; } // var currentRows = '', nextRows = ''; // for (var i = 0; i < opts.rows; ++i) { // currentRows += '.tj_row_' + (config.currentRow + i) + ','; // (dir === 1) // ? nextRows += '.tj_row_' + (config.currentRow + opts.rows + i) + ',' // : nextRows += '.tj_row_' + (config.currentRow - 1 - i) + ','; // } var currentRows = []; var nextRows = []; for (var i = 0; i < opts.rows; ++i) { currentRows.push('.tj_row_' + (config.currentRow + i)); if (dir === 1) { nextRows.push('.tj_row_' + (config.currentRow + opts.rows + i)); } else { nextRows.push('.tj_row_' + (config.currentRow - 1 - i)); } } // 生成最终的选择器字符串 currentRows = currentRows.join(','); nextRows = nextRows.join(','); $wrapper.children(currentRows).fadeOut(opts.type.speed, opts.type.easing); var $nextRowElements = $wrapper.children(nextRows), totalNextRows = $nextRowElements.length, cnt = 0; $nextRowElements.fadeIn(opts.type.speed, opts.type.easing, function () { ++cnt; if (cnt === totalNextRows) { $wrapper.data('anim', false); } }); (dir === 1) ? config.currentRow += opts.rows : config.currentRow -= opts.rows; $wrapper.data('config', config); } }, seqfade: { setup: function ($wrapper, $items, opts) { // same like def mode nav['def'].setup($wrapper, $items, opts); }, pagination: function ($wrapper, dir, opts) { var config = $wrapper.data('config'); if ((dir === 1 && config.currentRow + opts.rows > config.totalRows) || (dir === -1 && config.currentRow - opts.rows <= 0) ) { $wrapper.data('anim', false); return false; } // var currentRows = '', nextRows = ''; // for (var i = 0; i < opts.rows; ++i) { // currentRows += '.tj_row_' + (config.currentRow + i) + ','; // (dir === 1) // ? nextRows += '.tj_row_' + (config.currentRow + opts.rows + i) + ',' // : nextRows += '.tj_row_' + (config.currentRow - 1 - i) + ','; // } // 使用数组来收集结果 var currentRows = []; var nextRows = []; // 获取当前行和下一行的起始位置 var currentStart = config.currentRow; var nextStartOffset = opts.rows; for (var i = 0; i < opts.rows; ++i) { // 将当前行的选择器加入数组 currentRows.push('.tj_row_' + (currentStart + i)); // 根据方向计算下一行的选择器并加入数组 if (dir === 1) { nextRows.push('.tj_row_' + (currentStart + nextStartOffset + i)); } else { nextRows.push('.tj_row_' + (currentStart - 1 - i)); } } // 通过 join(',') 将数组中的选择器连接成字符串 currentRows = currentRows.join(','); nextRows = nextRows.join(','); var seq_t = opts.type.factor; var $currentRowElements; (dir === 1) ? $currentRowElements = $wrapper.children(currentRows) : $currentRowElements = $wrapper.children(currentRows).reverse(); $currentRowElements.each(function (i) { var $el = $(this); setTimeout(function () { $el.fadeOut(opts.type.speed, opts.type.easing) }, seq_t + i * seq_t); }); var $nextRowElements; (dir === 1) ? $nextRowElements = $wrapper.children(nextRows) : $nextRowElements = $wrapper.children(nextRows).reverse(); var total_elems = $nextRowElements.length, cnt = 0; $nextRowElements.each(function (i) { var $el = $(this); setTimeout(function () { $el.fadeIn(opts.type.speed, opts.type.easing, function () { ++cnt; if (cnt === total_elems) { $wrapper.data('anim', false); } }) }, (seq_t * 2) + i * seq_t); }); (dir === 1) ? config.currentRow += opts.rows : config.currentRow -= opts.rows; $wrapper.data('config', config); } }, updown: { setup: function ($wrapper, $items, opts) { var config = $wrapper.data('config'); $wrapper.children(':gt(' + (config.shownItems - 1) + ')').css('opacity', 0); $items.each(function (i) { var $item = $(this), row = Math.ceil((i + 1) / config.rowCount), t = $item.position().top, f = row % opts.rows; if (row > opts.rows) { t = (opts.rows * $items.height()); } $item.css({ top: t + 'px' }); }); }, pagination: function ($wrapper, dir, opts) { var config = $wrapper.data('config'); if ((dir === 1 && config.currentRow + opts.rows > config.totalRows) || (dir === -1 && config.currentRow - 1 <= 0) ) { $wrapper.data('anim', false); return false; } var movingRows = ''; for (var i = 0; i <= opts.rows; ++i) { if (i > 0) movingRows += ','; // 添加逗号作为分隔符 movingRows += '.tj_row_' + (dir === 1 ? (config.currentRow + i) : (config.currentRow + (i - 1))); } var $elements; (dir === 1) ? $elements = $wrapper.children(movingRows) : $elements = $wrapper.children(movingRows).reverse(); var total_elems = $elements.length, cnt = 0; $elements.each(function (i) { var $el = $(this), row = $el.attr('class'), animParam = {}, currentRow = config.currentRow; // if first row fade out // if last row fade in // for all the rows move them up / down if (dir === 1) { if (row === 'tj_row_' + (currentRow)) { animParam.opacity = 0; } else if (row === 'tj_row_' + (currentRow + opts.rows)) { animParam.opacity = 1; } } else { if (row === 'tj_row_' + (currentRow - 1)) { animParam.opacity = 1; } else if (row === 'tj_row_' + (currentRow + opts.rows - 1)) { animParam.opacity = 0; } } $el.show(); (dir === 1) ? animParam.top = $el.position().top - $el.height() + 'px' : animParam.top = $el.position().top + $el.height() + 'px' $el.stop().animate(animParam, opts.type.speed, opts.type.easing, function () { if (parseInt(animParam.top) < 0 || parseInt(animParam.top) > $el.height() * (opts.rows - 1)) $el.hide(); ++cnt; if (cnt === total_elems) { $wrapper.data('anim', false); } }); }); (dir === 1) ? config.currentRow += 1 : config.currentRow -= 1; $wrapper.data('config', config); } }, sequpdown: { setup: function ($wrapper, $items, opts) { // same like updown mode nav['updown'].setup($wrapper, $items, opts); }, pagination: function ($wrapper, dir, opts) { var config = $wrapper.data('config'); if ((dir === 1 && config.currentRow + opts.rows > config.totalRows) || (dir === -1 && config.currentRow - 1 <= 0) ) { $wrapper.data('anim', false); return false; } var movingRows = ''; for (var i = 0; i <= opts.rows; ++i) { if (i > 0) movingRows += ','; // 添加逗号作为分隔符 movingRows += '.tj_row_' + (dir === 1 ? (config.currentRow + i) : (config.currentRow + (i - 1))); } var seq_t = opts.type.factor, $elements; var dircond = 1; if (opts.type.reverse) dircond = -1; (dir === dircond) ? $elements = $wrapper.children(movingRows) : $elements = $wrapper.children(movingRows).reverse(); var total_elems = $elements.length, cnt = 0; $elements.each(function (i) { var $el = $(this), row = $el.attr('class'), animParam = {}, currentRow = config.currentRow; setTimeout(function () { // if first row fade out // if last row fade in // for all the rows move them up / down if (dir === 1) { if (row === 'tj_row_' + (currentRow)) { animParam.opacity = 0; } else if (row === 'tj_row_' + (currentRow + opts.rows)) { animParam.opacity = 1; } } else { if (row === 'tj_row_' + (currentRow - 1)) { animParam.opacity = 1; } else if (row === 'tj_row_' + (currentRow + opts.rows - 1)) { animParam.opacity = 0; } } $el.show(); (dir === 1) ? animParam.top = $el.position().top - $el.height() + 'px' : animParam.top = $el.position().top + $el.height() + 'px' $el.stop().animate(animParam, opts.type.speed, opts.type.easing, function () { if (parseInt(animParam.top) < 0 || parseInt(animParam.top) > $el.height() * (opts.rows - 1)) $el.hide(); ++cnt; if (cnt === total_elems) { $wrapper.data('anim', false); } }); }, seq_t + i * seq_t); }); (dir === 1) ? config.currentRow += 1 : config.currentRow -= 1; $wrapper.data('config', config); } }, showhide: { setup: function ($wrapper, $items, opts) { var config = $wrapper.data('config'); $items.each(function (i) { var $item = $(this), row = Math.ceil((i + 1) / config.rowCount), t, f = row % opts.rows; if (f === 1) { t = '0px'; } else if (f === 0) { t = (opts.rows - 1) * $items.height() + 'px'; } else { t = (f - 1) * $items.height() + 'px'; } $item.css({ top: t }); }); }, pagination: function ($wrapper, dir, opts) { var config = $wrapper.data('config'); if ((dir === 1 && config.currentRow + opts.rows > config.totalRows) || (dir === -1 && config.currentRow - opts.rows <= 0) ) { $wrapper.data('anim', false); return false; } // var currentRows = '', nextRows = ''; // for (var i = 0; i < opts.rows; ++i) { // currentRows += '.tj_row_' + (config.currentRow + i) + ','; // (dir === 1) // ? nextRows += '.tj_row_' + (config.currentRow + opts.rows + i) + ',' // : nextRows += '.tj_row_' + (config.currentRow - 1 - i) + ','; // } // 使用数组来存储选择器 var currentRows = []; var nextRows = []; // 获取当前行的起始位置 var currentRowStart = config.currentRow; for (var i = 0; i < opts.rows; ++i) { // 生成当前行选择器并存储到数组中 currentRows.push('.tj_row_' + (currentRowStart + i)); // 根据方向计算下一行的选择器并存储到数组中 if (dir === 1) { nextRows.push('.tj_row_' + (currentRowStart + opts.rows + i)); } else { nextRows.push('.tj_row_' + (currentRowStart - 1 - i)); } } // 通过 join(',') 将数组中的选择器连接成字符串 currentRows = currentRows.join(','); nextRows = nextRows.join(','); $wrapper.children(currentRows).hide(opts.type.speed, opts.type.easing); var $nextRowElements = $wrapper.children(nextRows), totalNextRows = $nextRowElements.length, cnt = 0; $nextRowElements.show(opts.type.speed, opts.type.easing, function () { ++cnt; if (cnt === totalNextRows) { $wrapper.data('anim', false); } }); (dir === 1) ? config.currentRow += opts.rows : config.currentRow -= opts.rows; $wrapper.data('config', config); } }, disperse: { setup: function ($wrapper, $items, opts) { var config = $wrapper.data('config'); $items.each(function (i) { var $item = $(this), row = Math.ceil((i + 1) / config.rowCount), t, f = row % opts.rows; if (f === 1) { t = '0px'; } else if (f === 0) { t = (opts.rows - 1) * $items.height() + 'px'; } else { t = (f - 1) * $items.height() + 'px'; } $item.css({ top: t }).data('top', t); }); }, pagination: function ($wrapper, dir, opts) { var config = $wrapper.data('config'); if ((dir === 1 && config.currentRow + opts.rows > config.totalRows) || (dir === -1 && config.currentRow - opts.rows <= 0) ) { $wrapper.data('anim', false); return false; } // var currentRows = '', nextRows = ''; // for (var i = 0; i < opts.rows; ++i) { // currentRows += '.tj_row_' + (config.currentRow + i) + ','; // (dir === 1) // ? nextRows += '.tj_row_' + (config.currentRow + opts.rows + i) + ',' // : nextRows += '.tj_row_' + (config.currentRow - 1 - i) + ','; // } // 使用数组来存储选择器 var currentRows = []; var nextRows = []; // 获取当前行的起始位置 var currentRowStart = config.currentRow; for (var i = 0; i < opts.rows; ++i) { // 生成当前行选择器并存储到数组中 currentRows.push('.tj_row_' + (currentRowStart + i)); // 根据方向计算下一行的选择器并存储到数组中 if (dir === 1) { nextRows.push('.tj_row_' + (currentRowStart + opts.rows + i)); } else { nextRows.push('.tj_row_' + (currentRowStart - 1 - i)); } } // 通过 join(',') 将数组中的选择器连接成字符串 currentRows = currentRows.join(','); nextRows = nextRows.join(','); $wrapper.children(currentRows).each(function (i) { var $el = $(this); $el.stop().animate({ left: $el.position().left + Math.floor(Math.random() * 101) - 50 + 'px', top: $el.position().top + Math.floor(Math.random() * 101) - 50 + 'px', opacity: 0 }, opts.type.speed, opts.type.easing, function () { $el.css({ left: $el.data('left'), top: $el.data('top') }).hide(); }); }); var $nextRowElements = $wrapper.children(nextRows); total_elems = $nextRowElements.length, cnt = 0; $nextRowElements.each(function (i) { var $el = $(this); $el.css({ left: parseInt($el.data('left')) + Math.floor(Math.random() * 301) - 150 + 'px', top: parseInt($el.data('top')) + Math.floor(Math.random() * 301) - 150 + 'px', opacity: 0 }) .show() .animate({ left: $el.data('left'), top: $el.data('top'), opacity: 1 }, opts.type.speed, opts.type.easing, function () { ++cnt; if (cnt === total_elems) { $wrapper.data('anim', false); } }); }); (dir === 1) ? config.currentRow += opts.rows : config.currentRow -= opts.rows; $wrapper.data('config', config); } }, rows: { setup: function ($wrapper, $items, opts) { // same like def mode nav['def'].setup($wrapper, $items, opts); }, pagination: function ($wrapper, dir, opts) { var config = $wrapper.data('config'); if ((dir === 1 && config.currentRow + opts.rows > config.totalRows) || (dir === -1 && config.currentRow - opts.rows <= 0) ) { $wrapper.data('anim', false); return false; } // var currentRows = '', nextRows = ''; // for (var i = 0; i < opts.rows; ++i) { // currentRows += '.tj_row_' + (config.currentRow + i) + ','; // (dir === 1) // ? nextRows += '.tj_row_' + (config.currentRow + opts.rows + i) + ',' // : nextRows += '.tj_row_' + (config.currentRow - 1 - i) + ','; // } // 使用数组来存储选择器 var currentRows = []; var nextRows = []; // 获取当前行的起始位置 var currentRowStart = config.currentRow; for (var i = 0; i < opts.rows; ++i) { // 生成当前行选择器并存储到数组中 currentRows.push('.tj_row_' + (currentRowStart + i)); // 根据方向计算下一行的选择器并存储到数组中 if (dir === 1) { nextRows.push('.tj_row_' + (currentRowStart + opts.rows + i)); } else { nextRows.push('.tj_row_' + (currentRowStart - 1 - i)); } } // 通过 join(',') 将数组中的选择器连接成字符串 currentRows = currentRows.join(','); nextRows = nextRows.join(','); $wrapper.children(currentRows).each(function (i) { var $el = $(this), rownmb = $el.attr('class').match(/tj_row_(\d+)/)[1], diff; if (rownmb % 2 === 0) { diff = opts.type.factor; } else { diff = -opts.type.factor; } $el.stop().animate({ left: $el.position().left + diff + 'px', opacity: 0 }, opts.type.speed, opts.type.easing, function () { $el.css({ left: $el.data('left') }).hide(); }); }); var $nextRowElements = $wrapper.children(nextRows); total_elems = $nextRowElements.length, cnt = 0; $nextRowElements.each(function (i) { var $el = $(this), rownmb = $el.attr('class').match(/tj_row_(\d+)/)[1], diff; if (rownmb % 2 === 0) { diff = opts.type.factor; } else { diff = -opts.type.factor; } $el.css({ left: parseInt($el.data('left')) + diff + 'px', opacity: 0 }) .show() .animate({ left: $el.data('left'), opacity: 1 }, opts.type.speed, opts.type.easing, function () { ++cnt; if (cnt === total_elems) { $wrapper.data('anim', false); } }); }); (dir === 1) ? config.currentRow += opts.rows : config.currentRow -= opts.rows; $wrapper.data('config', config); } } }, methods = { init: function (options) { if (this.length) { var settings = { rows: 2, navL: '#tj_prev', navR: '#tj_next', type: { mode: 'def', // use def | fade | seqfade | updown | sequpdown | showhide | disperse | rows speed: 500, // for fade, seqfade, updown, sequpdown, showhide, disperse, rows easing: 'jswing', // for fade, seqfade, updown, sequpdown, showhide, disperse, rows factor: 50, // for seqfade, sequpdown, rows reverse: false // for sequpdown } }; return this.each(function () { // if options exist, lets merge them with our default settings if (options) { $.extend(settings, options); } var $el = $(this).css('visibility', 'hidden'), // the ul $wrapper = $el.find('ul.tj_gallery'), // the items $thumbs = $wrapper.children('li'), total = $thumbs.length, // the navigation elements $p_nav = $(settings.navL), $n_nav = $(settings.navR); // save current row for later (first visible row) //config.currentRow = 1; // flag to control animation progress $wrapper.data('anim', false); // preload thumbs var loaded = 0; $thumbs.find('img').each(function (i) { var $img = $(this); $('').on('load', function () { ++loaded; if (loaded === total) { // setup aux.setup($wrapper, $thumbs, settings); $el.css('visibility', 'visible'); // navigation events if ($p_nav.length) { $p_nav.on('click.gridnav', function (e) { if ($wrapper.data('anim')) return false; $wrapper.data('anim', true); nav[settings.type.mode].pagination($wrapper, -1, settings); return false; }); } if ($n_nav.length) { $n_nav.on('click.gridnav', function (e) { if ($wrapper.data('anim')) return false; $wrapper.data('anim', true); nav[settings.type.mode].pagination($wrapper, 1, settings); return false; }); } /* adds events to the mouse */ // $el.on('mousewheel.gridnav', function (e, delta) { // if (delta > 0) { // if ($wrapper.data('anim')) return false; // $wrapper.data('anim', true); // nav[settings.type.mode].pagination($wrapper, -1, settings); // } // else { // if ($wrapper.data('anim')) return false; // $wrapper.data('anim', true); // nav[settings.type.mode].pagination($wrapper, 1, settings); // } // return false; // }); $el.on('wheel.gridnav', function(e) { var delta = e.originalEvent.deltaY; // 使用 deltaY 来检测滚轮方向 var direction = delta > 0 ? 1 : -1; if ($wrapper.data('anim')) { return false; } $wrapper.data('anim', true); nav[settings.type.mode].pagination($wrapper, direction, settings); return false; }); } }).attr('src', $img.attr('src')); }); }); } } }; $.fn.gridnav = function (method) { if (methods[method]) { return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); } else if (typeof method === 'object' || !method) { return methods.init.apply(this, arguments); } else { $.error('Method ' + method + ' does not exist on jQuery.gridnav'); } }; })(jQuery);