Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.

Γεια σας παίδες....

Έχω ένα θεματάκι με ένα jquery.plugin (slider) που φτιάχνω.
Γενικά έχω ξεκινήσει να φτιάχνω τα προσωπικά μου tools με τα οποία θα παίζω σε κάθε μου δουλειά.

Το θέμα στην περίπτωση αυτή είναι ένας jQuery slider και το χάσιμο μέσα στα instances του slider.

Ας ξεκινήσω με ένα κομμάτι κώδικα:
 

$.slider = function(){
      _init: function(){
          this._initEvents();
      },
      _initEvents : function(){
          this.$startPauseButton.on('click.container', $.proxy(this._startPauseToggleSlider, this));
      },
      _startPauseToggleSlider: function(){
           if(this.isPlay === true){ this.__timer.clear(this); return ; }
           this.timerId = this.__timer.resume(); 
      },
      __timer: {
          start: function(that){
              return setTimeout(..., delay)
          },
          resume: function(){ return this.start()// generate remaining time and start new timer}
          clear: function(that){ window.clearTimeout(that.timerId) }
     }
} 

Η μέθοδος _init τρέχει μία φόρα στο πρόγραμμα και είναι o constructor 

Κάποια στιγμή στο παραπάνω κώδικα χάνω το timerId και έτσι δεν μπορώ να κάνω Pause - Resume τον slider..
Αυτό το bug το εντόπισα όταν έτρεξα το παρακάτω

$('#sliderContainer').slider({/*some options*/});
$('#slider2Container').slider({/*some options*/});

Δηλαδή όταν έβαλα 2 sliders μέσα στην σελίδα.

Νομίζω ότι εφόσον κάνει bind ο Proxy την μέθοδο _startPauseSlider κατά το click τότε το current instance περνάει σαν ένα απλό var στην μέθοδο και μετά λειτουργεί σαν ένα διαφορετικό (fake) instance.

Έτσι την επόμενη φορά που θα πατηθεί το κουμπί για να σταματήσει ο Slider το πρόγραμμα δεν θα έχει το ενημερωμένο id του timer.

Έχει κανείς καμία ιδέα για το πως θα λύσω το προβλημα αυτό?
Έχω σκεφτεί να χρησιμοποιήσω global vars έξω από το plugin αλλά θα ήθελα να έιναι η τελευταία μου λύση αυτό.


* Τον κώδικα τον έγραψα τώρα αν έχω κάνει κανένα λάθος συγχωρέστε :)

Δημοσ.

Δείξε λίγο παραπάνω κώδικα.

 

Πρώτον μιλάμε για jQuery plugin και όχι jQuery UI widget έτσι;

 

Δεύτερον μιλάμε για υποστήριξη πολλαπλών instances -- αν δε χρησιμοποιείς κάποιο per-instance storage δεν είναι δυνατόν να δουλέψει.

 

Τυπικά αυτό που κάνουν τα plugins είναι να αποθηκεύουν την όποια per-instance πληροφορία τους χρειάζεται στο $(targetElement).data(), κάνε και συ το ίδιο.

  • Like 1
Δημοσ.

Δείξε λίγο παραπάνω κώδικα.

 

Πρώτον μιλάμε για jQuery plugin και όχι jQuery UI widget έτσι;

 

Δεύτερον μιλάμε για υποστήριξη πολλαπλών instances -- αν δε χρησιμοποιείς κάποιο per-instance storage δεν είναι δυνατόν να δουλέψει.

 

Τυπικά αυτό που κάνουν τα plugins είναι να αποθηκεύουν την όποια per-instance πληροφορία τους χρειάζεται στο $(targetElement).data(), κάνε και συ το ίδιο.

 

Είναι καθαρά Jquery Plugin και όχι jQuery.UI plugin

 

Απλά χρησιμοποιώ το velocityjs ή το gsap κατ' επιλογή για να κάνω accelerate τα animations..

 

Θα κάνω share τον κώδικα μόλις γυρίσω από την δουλειά κατά τις 8 - 9 η ώρα...

 

Δημοσ. (επεξεργασμένο)

Στην _initEvents έχω το πρόβλημα με τo startStopButton

Εδώ είναι το js για τον slider 

;(function($, window, undefined){
    'use strict';
    $.chSlider = function(option, element){
        this.$el = $( element );
        if(this.$el.attr('data-options')){
            $.chSlider.defaults = $.extend(true, {}, $.chSlider.defaults, $.parseJSON(this.$el.data('options').replace(/'/g,"\"")));
        }
        this._init();
    }

    $.chSlider.defaults = {
        animationEngine: 'jquery',
        height: '450', // Mixed Var - String and Int
        easing: 'easeInSine',
        autoplay: false,
        transitionDelay: 600,
        navigation: true,
        delay: 10000,
        loadingBar: true,
        startStopButton: {
            active: true,
            start: 'Start',
            stop: 'Pause'
        },
        theme: 'grayscale'
    };

    $.chSlider.prototype = {
        _init: function( options ){
            this.options = $.extend( true, {}, $.chSlider.defaults, options);
            // Generate some cache storage and some init actions
            this._generateCache();
            // Initialize Events
            this._initEvents();
            if(this.options.autoplay === true){
                this._autoplaySlider();
            }
        },
        getDelay: function(){
           return this.options.delay;
        },
        _generateCache: function(){
            // Target container
            this.$container = this.$el;
            // The ul list
            this.$list = this.$container.children('div').children( 'ul' );
            // The list items
            this.$items = this.$list.children('li');
            // The div inside container and parent of ul
            this.$inner = this.$list.parent('div');
            // The number of list items
            this.itemsCount = this.$items.length;
            // The current number of li
            this.current = 0;
            // The prev active slide of current
            this.old = 0;
            // If is current animated
            this.isAnimating = false;
            // Create and render the buttons, navigation, loading bars etc
            if(this.itemsCount > 1){
                this.$navPrev = $( '<span class="fws-prev"><</span>' ).hide();
                this.$navNext = $( '<span class="fws-next">></span>' );
                if(this.options.navigation === true){
                    $( '<nav class="fws-nav" />' ).append( this.$navPrev, this.$navNext ).appendTo( this.$container );
                }
                if(this.options.autoplay === true && this.options.startStopButton.active === true){
                    this.$startStopButton = $( '<span class="fws-startstopButton">' + this.options.startStopButton.stop + '</span>');
                    this.$container.append(this.$startStopButton);
                }
                if(this.options.autoplay === true && this.options.loadingBar === true){
                    this.$loadingBar = $('<div class="fws-loading-container"></div>');
                    this.$loadingBarInner = $('<div class="fws-loading-inner"></div>');
                    this.$loadingBar.append(this.$loadingBarInner).appendTo(this.$container);
                }
            }

            switch (this.options.animationEngine){
                case 'jquery' : break;
                case 'velocityjs' : break;
                case 'gsap' : break;
                default : this.options.animationEngine = 'jquery'; break;
            }

            // Some Init Css Actions
            this.$container.addClass('fullSliderContainer fws-' + this.options.theme);
            this.$inner.addClass('fullSliderInner');
            this.$container.css('height', this.options.height);
            this.$list.css('width', this.itemsCount * 100 + '%');
            this.$items.css('width', 100 / this.itemsCount + '%');
            var maxHeight = 0;
            var self = this;
            var count = this.itemsCount;
            this.$items.each(function(){
                var $this = $(this),
                    src = $this.attr('data-background');
                if(src){
                    var image = new Image();
                    image.onload = function(){
                        $this.css( 'background-image', 'url(' + src + ')' );
                        $this.css( 'background-repeat', 'no-repeat' );
                        $this.css( 'background-size', 'cover' );
                        var center = ($this.attr('data-center')) ? $this.attr('data-center') : 'center center';
                        $this.css( 'background-position', center );
                    };
                    image.src = src;
                }

            });
            this.$items.css('height', this.options.height + 'px');
        },
        _initEvents: function(){
            var self = this;
            if(this.itemsCount > 1){
            // Nav Click
            this.$navPrev.on('click.fullSliderContainer', $.proxy(this._navigate, this, 'prev'));
            this.$navNext.on('click.fullSliderContainer', $.proxy(this._navigate, this, 'next'));
            if(this.options.startStopButton.active === true){
                this.$startStopButton.on('click.fullSliderContainer', $.proxy(this._pauseResumeAction, this));
            }
            //if(this.options.hoverPause === true){
            //    this.$container.on('mouseenter.fullSliderContainer', $.proxy(this._pause, this));
            //    this.$container.on('mouseleave.fullSliderContainer', $.proxy(this._resume, this));
            //}
            // Dots
            }
        },
        _navigate: function( direction ){ // Navigate event
            if(this.isAnimating){
                return false;
            }
            this.isAnimating = true;
            this.old = this.current;
            this.isStop = false;
            if(direction === 'next' && this.current < this.itemsCount - 1){ ++this.current; }
            if(direction === 'prev' && this.current > 0){ --this.current; }
            this._slide();
        },
        _pauseResumeAction: function(){
            if(this.isStop === true){ this._resume(); return ; }
            else{ this._pause(); }
        },
        _pause: function(){
            this.isStop = true;
            this.loadingBarInstance = this.$loadingBarInner.width();
            if(this.options.startStopButton.active === true){
                this._toggleStartStopButton();
            }
            if(this.options.animationEngine === 'velocityjs'){
                this.$loadingBarInner.velocity('stop');
            }else if(this.options.animationEngine === 'jquery'){
                this.$loadingBarInner.clearQueue().stop().css('width', this.loadingBarInstance + 'px');
            }else if(this.options.animationEngine === 'gsap'){
                if(!this.tweenMaxLoadingAnimation.paused()){
                    this.tweenMaxLoadingAnimation.pause();
                }
            }
            console.log(this.$container.attr('id') + ' ' + this.timerId + ' Pause');
            this.__timer.pause(this.timerId);
            this.remainingTime = this.__timer.getRemainingTime();
        },
        _resume: function(){
            this.isStop = false;
            if(this.options.startStopButton.active === true){
                this._toggleStartStopButton();
            }
            if(this.options.animationEngine === 'velocityjs'){
                this.$loadingBarInner.velocity({width: '100%'}, this.remainingTime, this.options.easing);
            }else if(this.options.animationEngine === 'jquery'){
                this.$loadingBarInner.animate({width: '100%'}, this.remainingTime, this.options.easing);
            }else if(this.options.animationEngine === 'gsap'){
                if(this.tweenMaxLoadingAnimation.paused()){
                    this.tweenMaxLoadingAnimation.resume();
                }
            }
            this.timerId = this.__timer.resume(true);
        },
        _toggleStartStopButton: function(){
            switch (this.isStop){
                case false: this.$startStopButton.text(this.options.startStopButton.stop); break;
                case true: this.$startStopButton.text(this.options.startStopButton.start); break;
            }
        },
        _slide: function(){
            this._toggleNavControls();
            var translateVal = -1 * this.current * 100 / this.itemsCount;
            if(this.options.animationEngine === 'velocityjs'){
                this.$list.velocity({marginLeft: -1 * this.current * 100 + '%'}, this.options.transitionDelay, this.options.easing );
            }else if(this.options.animationEngine === 'jquery'){
                this.$list.animate({marginLeft: -1 * this.current * 100 + '%'},  this.options.transitionDelay, this.options.easing );
            }else if(this.options.animationEngine === 'gsap'){
                TweenMax.to(this.$list, this.options.transitionDelay / 1000, {marginLeft: -1 * this.current * 100 + '%', ease: this.options.easing});
            }
            var transitionendfn = $.proxy( function(){ this.isAnimating = false; }, this);
            if(this.options.autoplay === true){ this._clearAutoplaySlider(); }
            transitionendfn.call();
        },
        _jump : function( position ){
            if(position === this.current || this.isAnimating){ return false; }
            this.isAnimating = false;
            this.old = this.current;
            this.current = position;
            this._slide();
        },
        _toggleNavControls: function(){
            switch(this.current){
                case 0: this.$navNext.show(); this.$navPrev.hide(); break;
                case this.itemsCount - 1 : this.$navNext.hide(); this.$navPrev.show(); break;
                default : this.$navNext.show(); this.$navPrev.show(); break;
            }
        },
        _autoplaySlider: function(){
            if(this.options.loadingBar === true){
                this._loadingBarResetAnimation();
                this._loadingBarStartAnimation();
            }
            this.timerId = this.__timer.start( $.proxy(this._autoplaySliderStart, this), this.options.delay + this.options.transitionDelay, this.$container.attr('id') );
            console.log(this.$container.attr('id') + ' ' + this.timerId);
        },
        _clearAutoplaySlider: function(){
            this.__timer.clear(this.timerId); // Clear timeout
            this._autoplaySlider();
        },
        _autoplaySliderStart: function(){

            if(this.itemsCount - 1 > this.current){
                this._jump(this.current + 1);
            }else{
                this._jump(0);
            }
        },
        _loadingBarStartAnimation: function(){
            if(this.options.animationEngine === 'velocityjs'){
                 this.$loadingBarInner.velocity({width: '100%'}, this.options.delay + this.options.transitionDelay, this.options.easing);
            }else if(this.options.animationEngine === 'jquery'){
                 this.$loadingBarInner.animate({width: '100%'}, this.options.delay + this.options.transitionDelay, this.options.easing);
            }else if(this.options.animationEngine === 'gsap'){
                this.tweenMaxLoadingAnimation = new TweenMax.to(this.$loadingBarInner, (this.options.delay + this.options.transitionDelay) / 1000, {width: '100%', ease: this.options.easing});
            }
        },
        _loadingBarResetAnimation: function(){
            if(this.options.animationEngine === 'velocityjs'){
                this.$loadingBarInner.velocity('stop').css({width: '0%'});
            }else if(this.options.animationEngine === 'jquery'){
                this.$loadingBarInner.clearQueue().stop().css({width: '0%'});
            }else if(this.options.animationEngine === 'gsap'){
                if(this.tweenMaxLoadingAnimation){
                    this.tweenMaxLoadingAnimation.kill();
                    this.$loadingBarInner.css({width: '0%'});
                }
            }
        },
        __timer: {
            start: function(callback, delay, id){
                this.timerId = null;
                this.callback = callback;
                this.delay = delay;
                this.pauseDate = null;
                this.startDate = new Date();
                this.resume(false);
                return this.timerId;
            },
            getRemainingTime : function(){
                var pauseTime, startTime;
                if(this.startDate){ startTime = this.startDate.getTime(); }
                if(this.pauseDate){ pauseTime = this.pauseDate.getTime(); }
                return this.delay - ( pauseTime - startTime );
            },
            pause: function(id){
                window.clearTimeout(id);
                this.pauseDate = new Date();
            },
            resume: function(remainingTime){
                var delay = remainingTime ? this.getRemainingTime() : this.delay;
                this.timerId = window.setTimeout(this.callback, delay);
                return this.timerId;
            },
            clear: function(id){ window.clearTimeout(id); }
        },
        destroy: function(){
            if(this.itemsCount > 1){ this.$navPrev.parent().remove(); }
            this.$list.css('width', 'auto');
            this.$items.css('width', 'auto');
        }
    };

    $.fn.chSlider = function(options){
            this.each(function(){
               var instance = $.data(this, 'fullWidthContainer');
               if(instance){
                   instance._init();
               }else{
                   instance = $.data(this, 'fullWidthContainer', new $.chSlider(options, this));
               }
            });
        return this;
    };
})(jQuery, window);

Εδώ το html

<div id="fullSlider" class="fsContainer" data-options="{'height':200, 'animationEngine':'gsap', 'easing':'easeInOutQuint', 'transitionDelay':1200, 'autoplay': true}">
        <div>
            <ul>
                <li data-background="images/1.jpg" data-center="center center"><a href="#">aaa</a></li>
                <li data-background="images/2.png"><a href="#">acc</a></li>
                <li data-background="images/3.jpg"><a href="#">av</a></li>
            </ul>
        </div>
    </div>
    <div id="fullSlider2" class="fsContainer" data-options="{'height':200, 'animationEngine':'jquery', 'easing':'easeInOutQuint', 'transitionDelay':1200, 'autoplay': true}">
        <div>
            <ul>
                <li data-background="images/1.jpg" data-center="center center"><a href="#">aaa</a></li>
                <li data-background="images/2.png"><a href="#">acc</a></li>
                <li data-background="images/3.jpg"><a href="#">av</a></li>
            </ul>
        </div>
    </div>
    <div id="fullSlider3" class="fsContainer" data-options="{'height':200, 'animationEngine':'velocityjs', 'easing':'easeInOutQuint', 'transitionDelay':1200, 'autoplay': true}">
        <div>
            <ul>
                <li data-background="images/1.jpg" data-center="center center"><a href="#">aaa</a></li>
                <li data-background="images/2.png"><a href="#">acc</a></li>
                <li data-background="images/3.jpg"><a href="#">av</a></li>
            </ul>
        </div>
    </div>
<script>
    (function($){
        $('#fullSlider, #fullSlider2, #fullSlider3').chSlider();

    })(jQuery);
</script>

Και εδώ το css

.fullSliderContainer{
    position: relative;
    margin: 0 0 10px;
    overflow: hidden;
    padding: 0px 0 0px;
}

.fullSliderContainer ul{
    margin: 0;
    padding: 0;
    white-space: nowrap;
    list-style-type: none;
}

.fullSliderContainer ul li{
    float: left;
    display: block;
    margin: 0;
    padding: 0;
    position: relative;
}

.fullSliderContainer ul li > a,
.fullSliderContainer ul li > div {
    display: block;
    text-align: center;
    outline: none;
}


.fullSliderContainer ul li > a img {
    border: none;
    display: block;
    margin: 0 auto;
    max-width: 75%;
}

.fullSliderContainer nav span {
    position: absolute;
    bottom: 10px;
    width: 30px;
    height: 30px;
    line-height: 30px;
    font-size: 20px;
    text-align: center;
    margin-top: -50px;
    cursor: pointer;
    font-weight: normal;
}

.fullSliderContainer nav span.fws-next {
    right: 0px;
}

.fullSliderContainer nav span.fws-prev {
    left: 0px;
}

.fws-startstopButton{
    position: absolute;
    bottom: 10px;
    right: 32px;
    width: 100px;
    height: 30px;
    line-height: 30px;
    text-align: center;
    cursor: pointer;
}

.fws-loading-container{
    position: absolute;
    width: 100%;
    height: 10px;
    bottom: 0px;
    left: 0px;
}

.fws-loading-inner{
    position: relative;
    width: 0%;
    height: 10px;
}

/* Themes */
.fullSliderContainer.fws-grayscale nav span{
    background: rgba(255,255,255, 0.6);
    color: rgba(0, 0, 0, 0.6);
}

.fullSliderContainer.fws-grayscale nav span:hover{
    background: rgba(0, 0, 0, 0.6);
    color: rgba(255,255,255, 0.6);
}

.fws-loading-container{
    background: rgba(255,255,255, 0.6);
}

.fws-loading-inner{
    background: rgba(0, 0, 0, 0.6);
}

.fws-startstopButton{
    background: rgba(255,255,255, 0.6);
    color: rgba(0, 0, 0, 0.6);
}
Επεξ/σία από chrism4111

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...