/** * bxslider v4.1.2 - fully loaded, responsive content slider * http://bxslider.com * * copyright 2014, steven wanderski - http://stevenwanderski.com - http://bxcreative.com * written while drinking belgian ales and listening to jazz * mode: 'horizontal', // 'horizontal', 'vertical', 'fade' 定义slider滚动的方向,有三个值可供选择 infiniteloop: true, // true, false - display first slide after last 无限循环 hidecontrolonend: false, // true, false - if true, will hide 'next' control on last slide and 'prev' control on first 如果设置true,将会在最后一个幻灯片隐藏“next”,在最前面的幻灯片因此“prev” controls: true, // true, false - previous and next controls 是否显示“previous”和“next”按钮 speed: 500, // integer - in ms, duration of time slide transitions will occupy 速度,单位为毫秒 easing: 'swing', // used with jquery.easing.1.3.js - see http://gsgd.co.uk/sandbox/jquery/easing/ for available options pager: true, // true / false - display a pager pagerselector: null, // jquery selector - element to contain the pager. ex: '#pager' pagertype: 'full', // 'full', 'short' - if 'full' pager displays 1,2,3... if 'short' pager displays 1 / 4 如果设置full,将显示1,2,3……,如果设置short,将显示1/4 . pagerlocation: 'bottom', // 'bottom', 'top' - location of pager 页码的位置 pagershortseparator: '/', // string - ex: 'of' pager would display 1 of 4 页面分隔符 pageractiveclass: 'pager-active', // string - classname attached to the active pager link 当前页码的classname nexttext: 'next', // string - text displayed for 'next' control 下一页的文字 nextimage: '', // string - filepath of image used for 'next' control. ex: 'images/next.jpg' 可以设置下一页为图片 nextselector: null, // jquery selector - element to contain the next control. ex: '#next' prevtext: 'prev', // string - text displayed for 'previous' control 上一页的文字 previmage: '', // string - filepath of image used for 'previous' control. ex: 'images/prev.jpg' 上一页的图片 prevselector: null, // jquery selector - element to contain the previous control. ex: '#next' captions: false, // true, false - display image captions (reads the image 'title' tag) 是否显示图片的标题,读取图片的title属性的内容。 captionsselector: null, // jquery selector - element to contain the captions. ex: '#captions' auto: false, // true, false - make slideshow change automatically 幻灯片自动滚动 autodirection: 'next', // 'next', 'prev' - direction in which auto show will traverse 自动滚动的顺序 autocontrols: false, // true, false - show 'start' and 'stop' controls for auto show 自动滚动的控制键 autocontrolsselector: null, // jquery selector - element to contain the auto controls. ex: '#auto-controls' autostart: true, // true, false - if false show will wait for 'start' control to activate autohover: false, // true, false - if true show will pause on mouseover 设置鼠标mouseover将会使自动滚动暂停 autodelay: 0, // integer - in ms, the amount of time before starting the auto show pause: 3000, // integer - in ms, the duration between each slide transition 过渡时间 starttext: 'start', // string - text displayed for 'start' control 开始按钮的文字 startimage: '', // string - filepath of image used for 'start' control. ex: 'images/start.jpg' 开始按钮的图片 stoptext: 'stop', // string - text displayed for 'stop' control 停止按钮的文本 stopimage: '', // string - filepath of image used for 'stop' control. ex: 'images/stop.jpg' 停止按钮的图片 ticker: false, // true, false - continuous motion ticker mode (think news ticker) // note: autocontrols and autocontrolsselector apply to ticker! tickerspeed: 5000, // integer - has an inverse effect on speed. therefore, a value of 10000 will // scroll very slowly while a value of 50 will scroll very quickly. tickerdirection: 'next', // 'next', 'prev' - direction in which ticker show will traverse tickerhover: false, // true, false - if true ticker will pause on mouseover wrapperclass: 'bx-wrapper', // string - classname attached to the slider wraper startingslide: 0, // integer - show will start on specified slide. note: slides are zero based! displayslideqty: 1, // integer - number of slides to display at once moveslideqty: 1, // integer - number of slides to move at once randomstart: false, // true, false - if true show will start on a random slide * released under the mit license - http://opensource.org/licenses/mit */ ;(function($){ var plugin = {}; var defaults = { // general mode: 'horizontal', slideselector: '', infiniteloop: true, hidecontrolonend: false, speed: 500, easing: null, slidemargin: 0, startslide: 0, randomstart: false, captions: false, ticker: false, tickerhover: false, adaptiveheight: false, adaptiveheightspeed: 500, video: false, usecss: true, preloadimages: 'visible', responsive: true, slidezindex: 50, wrapperclass: 'bx-wrapper', // touch touchenabled: true, swipethreshold: 50, onetoonetouch: true, preventdefaultswipex: true, preventdefaultswipey: false, // pager pager: true, pagertype: 'full', pagershortseparator: ' / ', pagerselector: null, buildpager: null, pagercustom: null, // controls controls: true, nexttext: 'next', prevtext: 'prev', nextselector: null, prevselector: null, autocontrols: false, starttext: 'start', stoptext: 'stop', autocontrolscombine: false, autocontrolsselector: null, // auto auto: false, pause: 4000, autostart: true, autodirection: 'next', autohover: false, autodelay: 0, autoslideforonepage: false, // carousel minslides: 1, maxslides: 1, moveslides: 0, slidewidth: 0, // callbacks onsliderload: function() {}, onslidebefore: function() {}, onslideafter: function() {}, onslidenext: function() {}, onslideprev: function() {}, onsliderresize: function() {} } $.fn.bxslider = function(options){ if(this.length == 0) return this; // support mutltiple elements if(this.length > 1){ this.each(function(){$(this).bxslider(options)}); return this; } // create a namespace to be used throughout the plugin var slider = {}; // set a reference to our slider element var el = this; plugin.el = this; /** * makes slideshow responsive */ // first get the original window dimens (thanks alot ie) var windowwidth = $(window).width(); var windowheight = $(window).height(); /** * =================================================================================== * = private functions * =================================================================================== */ /** * initializes namespace settings to be used throughout plugin */ var init = function(){ // merge user-supplied options with the defaults slider.settings = $.extend({}, defaults, options); // parse slidewidth setting slider.settings.slidewidth = parseint(slider.settings.slidewidth); // store the original children slider.children = el.children(slider.settings.slideselector); // check if actual number of slides is less than minslides / maxslides if(slider.children.length < slider.settings.minslides) slider.settings.minslides = slider.children.length; if(slider.children.length < slider.settings.maxslides) slider.settings.maxslides = slider.children.length; // if random start, set the startslide setting to random number if(slider.settings.randomstart) slider.settings.startslide = math.floor(math.random() * slider.children.length); // store active slide information slider.active = { index: slider.settings.startslide } // store if the slider is in carousel mode (displaying / moving multiple slides) slider.carousel = slider.settings.minslides > 1 || slider.settings.maxslides > 1; // if carousel, force preloadimages = 'all' if(slider.carousel) slider.settings.preloadimages = 'all'; // calculate the min / max width thresholds based on min / max number of slides // used to setup and update carousel slides dimensions slider.minthreshold = (slider.settings.minslides * slider.settings.slidewidth) + ((slider.settings.minslides - 1) * slider.settings.slidemargin); slider.maxthreshold = (slider.settings.maxslides * slider.settings.slidewidth) + ((slider.settings.maxslides - 1) * slider.settings.slidemargin); // store the current state of the slider (if currently animating, working is true) slider.working = false; // initialize the controls object slider.controls = {}; // initialize an auto interval slider.interval = null; // determine which property to use for transitions slider.animprop = slider.settings.mode == 'vertical' ? 'top' : 'left'; // determine if hardware acceleration can be used slider.usingcss = slider.settings.usecss && slider.settings.mode != 'fade' && (function(){ // create our test div element var div = document.createelement('div'); // css transition properties var props = ['webkitperspective', 'mozperspective', 'operspective', 'msperspective']; // test for each property for(var i in props){ if(div.style[props[i]] !== undefined){ slider.cssprefix = props[i].replace('perspective', '').tolowercase(); slider.animprop = '-' + slider.cssprefix + '-transform'; return true; } } return false; }()); // if vertical mode always make maxslides and minslides equal if(slider.settings.mode == 'vertical') slider.settings.maxslides = slider.settings.minslides; // save original style data el.data("origstyle", el.attr("style")); el.children(slider.settings.slideselector).each(function() { $(this).data("origstyle", $(this).attr("style")); }); // perform all dom / css modifications setup(); } /** * performs all dom and css modifications */ var setup = function(){ // wrap el in a wrapper el.wrap('
'); // store a namspace reference to .bx-viewport slider.viewport = el.parent(); // add a loading div to display while images are loading slider.loader = $(''); slider.viewport.prepend(slider.loader); // set el to a massive width, to hold any needed slides // also strip any margin and padding from el el.css({ width: slider.settings.mode == 'horizontal' ? (slider.children.length * 100 + 215) + '%' : 'auto', position: 'relative' }); // if using css, add the easing property if(slider.usingcss && slider.settings.easing){ el.css('-' + slider.cssprefix + '-transition-timing-function', slider.settings.easing); // if not using css and no easing value was supplied, use the default js animation easing (swing) }else if(!slider.settings.easing){ slider.settings.easing = 'swing'; } var slidesshowing = getnumberslidesshowing(); // make modifications to the viewport (.bx-viewport) slider.viewport.css({ width: '100%', overflow: 'hidden', position: 'relative' }); slider.viewport.parent().css({ maxwidth: getviewportmaxwidth() }); // make modification to the wrapper (.bx-wrapper) if(!slider.settings.pager) { slider.viewport.parent().css({ margin: '0 auto 0px' }); } // apply css to all slider children slider.children.css({ 'float': slider.settings.mode == 'horizontal' ? 'left' : 'none', liststyle: 'none', position: 'relative' }); // apply the calculated width after the float is applied to prevent scrollbar interference slider.children.css('width', getslidewidth()); // if slidemargin is supplied, add the css if(slider.settings.mode == 'horizontal' && slider.settings.slidemargin > 0) slider.children.css('marginright', slider.settings.slidemargin); if(slider.settings.mode == 'vertical' && slider.settings.slidemargin > 0) slider.children.css('marginbottom', slider.settings.slidemargin); // if "fade" mode, add positioning and z-index css if(slider.settings.mode == 'fade'){ slider.children.css({ position: 'absolute', zindex: 0, display: 'none' }); // prepare the z-index on the showing element slider.children.eq(slider.settings.startslide).css({zindex: slider.settings.slidezindex, display: 'block'}); } // create an element to contain all slider controls (pager, start / stop, etc) slider.controls.el = $(''); // if captions are requested, add them if(slider.settings.captions) appendcaptions(); // check if startslide is last slide slider.active.last = slider.settings.startslide == getpagerqty() - 1; // if video is true, set up the fitvids plugin if(slider.settings.video) el.fitvids(); // set the default preload selector (visible) var preloadselector = slider.children.eq(slider.settings.startslide); if (slider.settings.preloadimages == "all") preloadselector = slider.children; // only check for control addition if not in "ticker" mode if(!slider.settings.ticker){ // if pager is requested, add it if(slider.settings.pager) appendpager(); // if controls are requested, add them if(slider.settings.controls) appendcontrols(); // if auto is true, and auto controls are requested, add them if(slider.settings.auto && slider.settings.autocontrols) appendcontrolsauto(); // if any control option is requested, add the controls wrapper if(slider.settings.controls || slider.settings.autocontrols || slider.settings.pager) slider.viewport.after(slider.controls.el); // if ticker mode, do not allow a pager }else{ slider.settings.pager = false; } // preload all images, then perform final dom / css modifications that depend on images being loaded loadelements(preloadselector, start); } var loadelements = function(selector, callback){ var total = selector.find('img, iframe').length; if (total == 0){ callback(); return; } var count = 0; selector.find('img, iframe').each(function(){ $(this).one('load', function() { if(++count == total) callback(); }).each(function() { if(this.complete) $(this).load(); }); }); } /** * start the slider */ var start = function(){ // if infinite loop, prepare additional slides if(slider.settings.infiniteloop && slider.settings.mode != 'fade' && !slider.settings.ticker){ var slice = slider.settings.mode == 'vertical' ? slider.settings.minslides : slider.settings.maxslides; var sliceappend = slider.children.slice(0, slice).clone().addclass('bx-clone'); var sliceprepend = slider.children.slice(-slice).clone().addclass('bx-clone'); el.append(sliceappend).prepend(sliceprepend); } // remove the loading dom element slider.loader.remove(); // set the left / top position of "el" setslideposition(); // if "vertical" mode, always use adaptiveheight to prevent odd behavior if (slider.settings.mode == 'vertical') slider.settings.adaptiveheight = true; // set the viewport height slider.viewport.height(getviewportheight()); // make sure everything is positioned just right (same as a window resize) el.redrawslider(); // onsliderload callback slider.settings.onsliderload(slider.active.index); // slider has been fully initialized slider.initialized = true; // bind the resize call to the window if (slider.settings.responsive) $(window).bind('resize', resizewindow); // if auto is true and has more than 1 page, start the show if (slider.settings.auto && slider.settings.autostart && (getpagerqty() > 1 || slider.settings.autoslideforonepage)) initauto(); // if ticker is true, start the ticker if (slider.settings.ticker) initticker(); // if pager is requested, make the appropriate pager link active if (slider.settings.pager) updatepageractive(slider.settings.startslide); // check for any updates to the controls (like hidecontrolonend updates) if (slider.settings.controls) updatedirectioncontrols(); // if touchenabled is true, setup the touch events if (slider.settings.touchenabled && !slider.settings.ticker) inittouch(); } /** * returns the calculated height of the viewport, used to determine either adaptiveheight or the maxheight value */ var getviewportheight = function(){ var height = 0; // first determine which children (slides) should be used in our height calculation var children = $(); // if mode is not "vertical" and adaptiveheight is false, include all children if(slider.settings.mode != 'vertical' && !slider.settings.adaptiveheight){ children = slider.children; }else{ // if not carousel, return the single active child if(!slider.carousel){ children = slider.children.eq(slider.active.index); // if carousel, return a slice of children }else{ // get the individual slide index var currentindex = slider.settings.moveslides == 1 ? slider.active.index : slider.active.index * getmoveby(); // add the current slide to the children children = slider.children.eq(currentindex); // cycle through the remaining "showing" slides for (i = 1; i <= slider.settings.maxslides - 1; i++){ // if looped back to the start if(currentindex + i >= slider.children.length){ children = children.add(slider.children.eq(i - 1)); }else{ children = children.add(slider.children.eq(currentindex + i)); } } } } // if "vertical" mode, calculate the sum of the heights of the children if(slider.settings.mode == 'vertical'){ children.each(function(index) { height += $(this).outerheight(); }); // add user-supplied margins if(slider.settings.slidemargin > 0){ height += slider.settings.slidemargin * (slider.settings.minslides - 1); } // if not "vertical" mode, calculate the max height of the children }else{ height = math.max.apply(math, children.map(function(){ return $(this).outerheight(false); }).get()); } if(slider.viewport.css('box-sizing') == 'border-box'){ height += parsefloat(slider.viewport.css('padding-top')) + parsefloat(slider.viewport.css('padding-bottom')) + parsefloat(slider.viewport.css('border-top-width')) + parsefloat(slider.viewport.css('border-bottom-width')); }else if(slider.viewport.css('box-sizing') == 'padding-box'){ height += parsefloat(slider.viewport.css('padding-top')) + parsefloat(slider.viewport.css('padding-bottom')); } return height; } /** * returns the calculated width to be used for the outer wrapper / viewport */ var getviewportmaxwidth = function(){ var width = '100%'; if(slider.settings.slidewidth > 0){ if(slider.settings.mode == 'horizontal'){ width = (slider.settings.maxslides * slider.settings.slidewidth) + ((slider.settings.maxslides - 1) * slider.settings.slidemargin); }else{ width = slider.settings.slidewidth; } } return width; } /** * returns the calculated width to be applied to each slide */ var getslidewidth = function(){ // start with any user-supplied slide width var newelwidth = slider.settings.slidewidth; // get the current viewport width var wrapwidth = slider.viewport.width(); // if slide width was not supplied, or is larger than the viewport use the viewport width if(slider.settings.slidewidth == 0 || (slider.settings.slidewidth > wrapwidth && !slider.carousel) || slider.settings.mode == 'vertical'){ newelwidth = wrapwidth; // if carousel, use the thresholds to determine the width }else if(slider.settings.maxslides > 1 && slider.settings.mode == 'horizontal'){ if(wrapwidth > slider.maxthreshold){ // newelwidth = (wrapwidth - (slider.settings.slidemargin * (slider.settings.maxslides - 1))) / slider.settings.maxslides; }else if(wrapwidth < slider.minthreshold){ newelwidth = (wrapwidth - (slider.settings.slidemargin * (slider.settings.minslides - 1))) / slider.settings.minslides; } } return newelwidth; } /** * returns the number of slides currently visible in the viewport (includes partially visible slides) */ var getnumberslidesshowing = function(){ var slidesshowing = 1; if(slider.settings.mode == 'horizontal' && slider.settings.slidewidth > 0){ // if viewport is smaller than minthreshold, return minslides if(slider.viewport.width() < slider.minthreshold){ slidesshowing = slider.settings.minslides; // if viewport is larger than minthreshold, return maxslides }else if(slider.viewport.width() > slider.maxthreshold){ slidesshowing = slider.settings.maxslides; // if viewport is between min / max thresholds, divide viewport width by first child width }else{ var childwidth = slider.children.first().width() + slider.settings.slidemargin; slidesshowing = math.floor((slider.viewport.width() + slider.settings.slidemargin) / childwidth); } // if "vertical" mode, slides showing will always be minslides }else if(slider.settings.mode == 'vertical'){ slidesshowing = slider.settings.minslides; } return slidesshowing; } /** * returns the number of pages (one full viewport of slides is one "page") */ var getpagerqty = function(){ var pagerqty = 0; // if moveslides is specified by the user if(slider.settings.moveslides > 0){ if(slider.settings.infiniteloop){ pagerqty = math.ceil(slider.children.length / getmoveby()); }else{ // use a while loop to determine pages var breakpoint = 0; var counter = 0 // when breakpoint goes above children length, counter is the number of pages while (breakpoint < slider.children.length){ ++pagerqty; breakpoint = counter + getnumberslidesshowing(); counter += slider.settings.moveslides <= getnumberslidesshowing() ? slider.settings.moveslides : getnumberslidesshowing(); } } // if moveslides is 0 (auto) divide children length by sides showing, then round up }else{ pagerqty = math.ceil(slider.children.length / getnumberslidesshowing()); } return pagerqty; } /** * returns the number of indivual slides by which to shift the slider */ var getmoveby = function(){ // if moveslides was set by the user and moveslides is less than number of slides showing if(slider.settings.moveslides > 0 && slider.settings.moveslides <= getnumberslidesshowing()){ return slider.settings.moveslides; } // if moveslides is 0 (auto) return getnumberslidesshowing(); } /** * sets the slider's (el) left or top position */ var setslideposition = function(){ // if last slide, not infinite loop, and number of children is larger than specified maxslides if(slider.children.length > slider.settings.maxslides && slider.active.last && !slider.settings.infiniteloop){ if (slider.settings.mode == 'horizontal'){ // get the last child's position var lastchild = slider.children.last(); var position = lastchild.position(); // set the left position setpositionproperty(-(position.left - (slider.viewport.width() - lastchild.outerwidth())), 'reset', 0); }else if(slider.settings.mode == 'vertical'){ // get the last showing index's position var lastshowingindex = slider.children.length - slider.settings.minslides; var position = slider.children.eq(lastshowingindex).position(); // set the top position setpositionproperty(-position.top, 'reset', 0); } // if not last slide }else{ // get the position of the first showing slide var position = slider.children.eq(slider.active.index * getmoveby()).position(); // check for last slide if (slider.active.index == getpagerqty() - 1) slider.active.last = true; // set the repective position if (position != undefined){ if (slider.settings.mode == 'horizontal') setpositionproperty(-position.left, 'reset', 0); else if (slider.settings.mode == 'vertical') setpositionproperty(-position.top, 'reset', 0); } } } /** * sets the el's animating property position (which in turn will sometimes animate el). * if using css, sets the transform property. if not using css, sets the top / left property. * * @param value (int) * - the animating property's value * * @param type (string) 'slider', 'reset', 'ticker' * - the type of instance for which the function is being * * @param duration (int) * - the amount of time (in ms) the transition should occupy * * @param params (array) optional * - an optional parameter containing any variables that need to be passed in */ var setpositionproperty = function(value, type, duration, params){ // use css transform if(slider.usingcss){ // determine the translate3d value var propvalue = slider.settings.mode == 'vertical' ? 'translate3d(0, ' + value + 'px, 0)' : 'translate3d(' + value + 'px, 0, 0)'; // add the css transition-duration el.css('-' + slider.cssprefix + '-transition-duration', duration / 1000 + 's'); if(type == 'slide'){ // set the property value el.css(slider.animprop, propvalue); // bind a callback method - executes when css transition completes el.bind('transitionend webkittransitionend otransitionend mstransitionend', function(){ // unbind the callback el.unbind('transitionend webkittransitionend otransitionend mstransitionend'); updateafterslidetransition(); }); }else if(type == 'reset'){ el.css(slider.animprop, propvalue); }else if(type == 'ticker'){ // make the transition use 'linear' el.css('-' + slider.cssprefix + '-transition-timing-function', 'linear'); el.css(slider.animprop, propvalue); // bind a callback method - executes when css transition completes el.bind('transitionend webkittransitionend otransitionend mstransitionend', function(){ // unbind the callback el.unbind('transitionend webkittransitionend otransitionend mstransitionend'); // reset the position setpositionproperty(params['resetvalue'], 'reset', 0); // start the loop again tickerloop(); }); } // use js animate }else{ var animateobj = {}; animateobj[slider.animprop] = value; if(type == 'slide'){ el.animate(animateobj, duration, slider.settings.easing, function(){ updateafterslidetransition(); }); }else if(type == 'reset'){ el.css(slider.animprop, value) }else if(type == 'ticker'){ el.animate(animateobj, speed, 'linear', function(){ setpositionproperty(params['resetvalue'], 'reset', 0); // run the recursive loop after animation tickerloop(); }); } } } /** * populates the pager with proper amount of pages */ var populatepager = function(){ var pagerhtml = ''; var pagerqty = getpagerqty(); // loop through each pager item for(var i=0; i < pagerqty; i++){ var linkcontent = ''; // if a buildpager function is supplied, use it to get pager link value, else use index + 1 if(slider.settings.buildpager && $.isfunction(slider.settings.buildpager)){ linkcontent = slider.settings.buildpager(i); slider.pagerel.addclass('bx-custom-pager'); }else{ linkcontent = i + 1; slider.pagerel.addclass('bx-default-pager'); } // var linkcontent = slider.settings.buildpager && $.isfunction(slider.settings.buildpager) ? slider.settings.buildpager(i) : i + 1; // add the markup to the string pagerhtml += ''; }; // populate the pager element with pager links slider.pagerel.html(pagerhtml); } /** * appends the pager to the controls element */ var appendpager = function(){ if(!slider.settings.pagercustom){ // create the pager dom element //slider.pagerel = $(''); //update by jason 20170124 slider.pagerel = $('