首页 > 其他 > 详细

轮播插件unsilder 源码解析(一)---源码解析

时间:2016-12-31 00:24:35      阅读:446      评论:0      收藏:0      [点我收藏+]

jq扩展内容

$.fn.unslider = function(opts) {
return this.each(function(index,elem) {
var $this = $(elem);//表示的是包裹ul的元素
var unslider = $(elem).data(‘unslider‘);//给这个元素存储些数据
if(unslider instanceof $.Unslider) {//当存在这个插件时不往下执行
return;
}
// Allow usage of .unslider(‘function_name‘)
// as well as using .data(‘unslider‘) to access the
// main Unslider object
if(typeof opts === ‘string‘ && $this.data(‘unslider‘)) {//$this.data(‘unslider‘)首先执行的时候都为空,存在时为 $.Unslider 所以我觉得
opts = opts.split(‘:‘);//这段代码是不可能执行的,属于无用的
var call = $this.data(‘unslider‘)[opts[0]];//这两个配置的组成最终会指向一个函数
// Do we have arguments to pass to the string-function?
if($.isFunction(call)) {
return call.apply($this, opts[1] ? opts[1].split(‘,‘) : null);
}
}
return $this.data(‘unslider‘, new $.Unslider($this, opts));//注意这一行就是配置指向的最终函数
});
};

由上面的分析可得, $.Unslider($this, opts)

$.Unslider = function(context, options) {
var self = this;
self._ = ‘unslider‘;
self.defaults = {
//自动播放true为自动播放,false为否
autoplay: false,
//3秒后转下一页
delay: 3000,
// Animation speed in millseconds
//每毫秒的速度
speed: 750,
// An easing string to use. If you‘re using Velocity, use a
// Velocity string otherwise you can use jQuery/jQ UI options.
//速度的进入是匀速,先快后慢。。。
easing: ‘swing‘, // [.42, 0, .58, 1],
//键盘keycode
keys: {
prev: 37,
next: 39
},
// Do you want to generate clickable navigation
// to skip to each slide? Accepts boolean true/false or
// a callback function per item to generate.
nav: true,
// Should there be left/right arrows to go back/forth?
// -> This isn‘t keyboard support.
// Either set true/false, or an object with the HTML
// elements for each arrow like below:
arrows: {
prev: ‘‘,
next: ‘‘
},
// How should Unslider animate?
// It can do one of the following types:
// "fade": each slide fades in to each other
// "horizontal": each slide moves from left to right
// "vertical": each slide moves from top to bottom
animation: ‘horizontal‘,
// If you don‘t want to use a list to display your slides,
// you can change it here. Not recommended and you‘ll need
// to adjust the CSS accordingly.
selectors: {
container: ‘ul:first‘,
slides: ‘li‘
},
// Do you want to animate the heights of each slide as
// it moves
animateHeight: false,
// Active class for the nav
activeClass: self._ + ‘-active‘,
// Have swipe support?
// You can set this here with a boolean and always use
// initSwipe/destroySwipe later on.
swipe: true,
// Swipe threshold -
// lower float for enabling short swipe
swipeThreshold: 0.2
};
// Set defaults
self.$context = context;
self.options = {};
// Leave our elements blank for now
// Since they get changed by the options, we‘ll need to
// set them in the init method.
self.$parent = null;
self.$container = null;
self.$slides = null;
self.$nav = null;
self.$arrows = [];
// Set our indexes and totals
self.total = 0;
self.current = 0;
// Generate a specific random ID so we don‘t dupe events
self.prefix = self._ + ‘-‘;
self.eventSuffix = ‘.‘ + self.prefix + ~~(Math.random() * 2e3);
// In case we‘re going to use the autoplay
self.interval = null;
// Get everything set up innit
self.init = function(options) {
// Set up our options inside here so we can re-init at
// any time
self.options = $.extend({}, self.defaults, options);
// Our elements
self.$container = self.$context.find(self.options.selectors.container).addClass(self.prefix + ‘wrap‘);
self.$slides = self.$container.children(self.options.selectors.slides);
// We‘ll manually init the container
self.setup();
// We want to keep this script as small as possible
// so we‘ll optimise some checks
$.each([‘nav‘, ‘arrows‘, ‘keys‘, ‘infinite‘], function(index, module) {
self.options[module] && self[‘init‘ + $._ucfirst(module)]();
});
// Add swipe support
if(jQuery.event.special.swipe && self.options.swipe) {
self.initSwipe();
}
// If autoplay is set to true, call self.start()
// to start calling our timeouts
self.options.autoplay && self.start();
// We should be able to recalculate slides at will
self.calculateSlides();
// Listen to a ready event
self.$context.trigger(self._ + ‘.ready‘);
// Everyday I‘m chainin‘
return self.animate(self.options.index || self.current, ‘init‘);
};
self.setup = function() {
// Add a CSS hook to the main element
self.$context.addClass(self.prefix + self.options.animation).wrap(‘
‘); self.$parent = self.$context.parent(‘.‘ + self._); // We need to manually check if the container is absolutely // or relatively positioned var position = self.$context.css(‘position‘); // If we don‘t already have a position set, we‘ll // automatically set it ourselves if(position === ‘static‘) { self.$context.css(‘position‘, ‘relative‘); } self.$context.css(‘overflow‘, ‘hidden‘); }; // Set up the slide widths to animate with // so the box doesn‘t float over self.calculateSlides = function() { // update slides before recalculating the total self.$slides = self.$container.children(self.options.selectors.slides); self.total = self.$slides.length; // Set the total width if(self.options.animation !== ‘fade‘) { var prop = ‘width‘; if(self.options.animation === ‘vertical‘) { prop = ‘height‘; } self.$container.css(prop, (self.total * 100) + ‘%‘).addClass(self.prefix + ‘carousel‘); self.$slides.css(prop, (100 / self.total) + ‘%‘); } }; // Start our autoplay self.start = function() { self.interval = setTimeout(function() { // Move on to the next slide self.next(); // If we‘ve got autoplay set up // we don‘t need to keep starting // the slider from within our timeout // as .animate() calls it for us }, self.options.delay); return self; }; // And pause our timeouts // and force stop the slider if needed self.stop = function() { clearTimeout(self.interval); return self; }; // Set up our navigation self.initNav = function() { var $nav = $(‘‘); // Build our click navigation item-by-item self.$slides.each(function(key) { // If we‘ve already set a label, let‘s use that // instead of generating one var label = this.getAttribute(‘data-nav‘) || key + 1; // Listen to any callback functions if($.isFunction(self.options.nav)) { label = self.options.nav.call(self.$slides.eq(key), key, label); } // And add it to our navigation item $nav.children(‘ol‘).append(‘
  • ‘ + label + ‘
  • ‘); }); // Keep a copy of the nav everywhere so we can use it self.$nav = $nav.insertAfter(self.$context); // Now our nav is built, let‘s add it to the slider and bind // for any click events on the generated links self.$nav.find(‘li‘).on(‘click‘ + self.eventSuffix, function() { // Cache our link and set it to be active var $me = $(this).addClass(self.options.activeClass); // Set the right active class, remove any other ones $me.siblings().removeClass(self.options.activeClass); // Move the slide self.animate($me.attr(‘data-slide‘)); }); }; // Set up our left-right arrow navigation // (Not keyboard arrows, prev/next buttons) self.initArrows = function() { if(self.options.arrows === true) { self.options.arrows = self.defaults.arrows; } // Loop our options object and bind our events $.each(self.options.arrows, function(key, val) { // Add our arrow HTML and bind it self.$arrows.push( $(val).insertAfter(self.$context).on(‘click‘ + self.eventSuffix, self[key]) ); }); }; // Set up our keyboad navigation // Allow binding to multiple keycodes self.initKeys = function() { if(self.options.keys === true) { self.options.keys = self.defaults.keys; } $(document).on(‘keyup‘ + self.eventSuffix, function(e) { $.each(self.options.keys, function(key, val) { if(e.which === val) { $.isFunction(self[key]) && self[key].call(self); } }); }); }; // Requires jQuery.event.swipe // -> stephband.info/jquery.event.swipe self.initSwipe = function() { var width = self.$slides.width(); // We don‘t want to have a tactile swipe in the slider // in the fade animation, as it can cause some problems // with layout, so we‘ll just disable it. if(self.options.animation !== ‘fade‘) { self.$container.on({ movestart: function(e) { // If the movestart heads off in a upwards or downwards // direction, prevent it so that the browser scrolls normally. if((e.distX > e.distY && e.distX < -e.distY) || (e.distX < e.distY && e.distX > -e.distY)) { return !!e.preventDefault(); } self.$container.css(‘position‘, ‘relative‘); }, move: function(e) { self.$container.css(‘left‘, -(100 * self.current) + (100 * e.distX / width) + ‘%‘); }, moveend: function(e) { // Check if swiped distance is greater than threshold. // If yes slide to next/prev slide. If not animate to // starting point. if((Math.abs(e.distX) / width) > self.options.swipeThreshold) { self[e.distX < 0 ? ‘next‘ : ‘prev‘](); } else { self.$container.animate({left: -(100 * self.current) + ‘%‘ }, self.options.speed / 2 ); } } }); } }; // Infinite scrolling is a massive pain in the arse // so we need to create a whole bloody function to set // it up. Argh. self.initInfinite = function() { var pos = [‘first‘, ‘last‘]; $.each(pos, function(index, item) { self.$slides.push.apply( self.$slides, // Exclude all cloned slides and call .first() or .last() // depending on what `item` is. self.$slides.filter(‘:not(".‘ + self._ + ‘-clone")‘)[item]() // Make a copy of it and identify it as a clone .clone().addClass(self._ + ‘-clone‘) // Either insert before or after depending on whether we‘re // the first or last clone [‘insert‘ + (index === 0 ? ‘After‘ : ‘Before‘)]( // Return the other element in the position array // if item = first, return "last" self.$slides[pos[~~!index]]() ) ); }); }; // Remove any trace of arrows // Loop our array of arrows and use jQuery to remove // It‘ll unbind any event handlers for us self.destroyArrows = function() { $.each(self.$arrows, function(i, $arrow) { $arrow.remove(); }); }; // Remove any swipe events and reset the position self.destroySwipe = function() { // We bind to 4 events, so we‘ll unbind those self.$container.off(‘movestart move moveend‘); }; // Unset the keyboard navigation // Remove the handler self.destroyKeys = function() { // Remove the event handler $(document).off(‘keyup‘ + self.eventSuffix); }; self.setIndex = function(to) { if(to < 0) { to = self.total - 1; } self.current = Math.min(Math.max(0, to), self.total - 1); if(self.options.nav) { self.$nav.find(‘[data-slide="‘ + self.current + ‘"]‘)._active(self.options.activeClass); } self.$slides.eq(self.current)._active(self.options.activeClass); return self; }; // Despite the name, this doesn‘t do any animation - since there‘s // now three different types of animation, we let this method delegate // to the right type, keeping the name for backwards compat. self.animate = function(to, dir) { // Animation shortcuts // Instead of passing a number index, we can now // use .data(‘unslider‘).animate(‘last‘); // or .unslider(‘animate:last‘) // to go to the very last slide if(to === ‘first‘) to = 0; if(to === ‘last‘) to = self.total; // Don‘t animate if it‘s not a valid index if(isNaN(to)) { return self; } if(self.options.autoplay) { self.stop().start(); } self.setIndex(to); // Add a callback method to do stuff with self.$context.trigger(self._ + ‘.change‘, [to, self.$slides.eq(to)]); // Delegate the right method - everything‘s named consistently // so we can assume it‘ll be called "animate" + var fn = ‘animate‘ + $._ucfirst(self.options.animation); // Make sure it‘s a valid animation method, otherwise we‘ll get // a load of bug reports that‘ll be really hard to report if($.isFunction(self[fn])) { self[fn](self.current, dir); } return self; }; // Shortcuts for animating if we don‘t know what the current // index is (i.e back/forward) // For moving forward we need to make sure we don‘t overshoot. self.next = function() { var target = self.current + 1; // If we‘re at the end, we need to move back to the start if(target >= self.total) { target = 0; } return self.animate(target, ‘next‘); }; // Previous is a bit simpler, we can just decrease the index // by one and check if it‘s over 0. self.prev = function() { return self.animate(self.current - 1, ‘prev‘); }; // Our default animation method, the old-school left-to-right // horizontal animation self.animateHorizontal = function(to) { var prop = ‘left‘; // Add RTL support, slide the slider // the other way if the site is right-to-left if(self.$context.attr(‘dir‘) === ‘rtl‘) { prop = ‘right‘; } if(self.options.infinite) { // So then we need to hide the first slide self.$container.css(‘margin-‘ + prop, ‘-100%‘); } return self.slide(prop, to); }; // The same animation methods, but vertical support // RTL doesn‘t affect the vertical direction so we // can just call as is self.animateVertical = function(to) { self.options.animateHeight = true; // Normal infinite CSS fix doesn‘t work for // vertical animation so we need to manually set it // with pixels. Ah well. if(self.options.infinite) { self.$container.css(‘margin-top‘, -self.$slides.outerHeight()); } return self.slide(‘top‘, to); }; // Actually move the slide now // We have to pass a property to animate as there‘s // a few different directions it can now move, but it‘s // otherwise unchanged from before. self.slide = function(prop, to) { // If we want to change the height of the slider // to match the current slide, you can set // {animateHeight: true} self.animateHeight(to); // For infinite sliding we add a dummy slide at the end and start // of each slider to give the appearance of being infinite if(self.options.infinite) { var dummy; // Going backwards to last slide if(to === self.total - 1) { // We‘re setting a dummy position and an actual one // the dummy is what the index looks like // (and what we‘ll silently update to afterwards), // and the actual is what makes it not go backwards dummy = self.total - 3; to = -1; } // Going forwards to first slide if(to === self.total - 2) { dummy = 0; to = self.total - 2; } // If it‘s a number we can safely set it if(typeof dummy === ‘number‘) { self.setIndex(dummy); // Listen for when the slide‘s finished transitioning so // we can silently move it into the right place and clear // this whole mess up. self.$context.on(self._ + ‘.moved‘, function() { if(self.current === dummy) { self.$container.css(prop, -(100 * dummy) + ‘%‘).off(self._ + ‘.moved‘); } }); } } // We need to create an object to store our property in // since we don‘t know what it‘ll be. var obj = {}; // Manually create it here obj[prop] = -(100 * to) + ‘%‘; // And animate using our newly-created object return self._move(self.$container, obj); }; // Fade between slides rather than, uh, sliding it self.animateFade = function(to) { // If we want to change the height of the slider // to match the current slide, you can set // {animateHeight: true} self.animateHeight(to); var $active = self.$slides.eq(to).addClass(self.options.activeClass); // Toggle our classes self._move($active.siblings().removeClass(self.options.activeClass), {opacity: 0}); self._move($active, {opacity: 1}, false); }; // Animate height of slider self.animateHeight = function(to) { // If we want to change the height of the slider // to match the current slide, you can set // {animateHeight: true} if (self.options.animateHeight) { self._move(self.$context, {height: self.$slides.eq(to).outerHeight()}, false); } }; self._move = function($el, obj, callback, speed) { if(callback !== false) { callback = function() { self.$context.trigger(self._ + ‘.moved‘); }; } return $el._move(obj, speed || self.options.speed, self.options.easing, callback); }; // Allow daisy-chaining of methods return self.init(options); };

    轮播插件unsilder 源码解析(一)---源码解析

    原文:http://www.cnblogs.com/heyinwangchuan/p/6238538.html

    (0)
    (0)
       
    举报
    评论 一句话评论(0
    关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
    © 2014 bubuko.com 版权所有
    打开技术之扣,分享程序人生!