简体   繁体   中英

javascript scoping? - jquery plugin countdown timer

Hi I am having a problem where scoping seems to be lost. What I am doing wrong?

Suppose the logic is that 1 second is decreased from every counter and not from the last counter only. What I am doing wrong?

<html>
<head>
    <link rel="stylesheet" href="http://static.jquery.com/files/rocker/css/reset.css" type="text/css" />
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
    <script type="text/javascript">
        (function($){
            $.fn.extend({

                countdown: function(options) {

                var defaults = {
                    daysSelector : 'span.days',
                    hoursSelector : 'span.hours',
                    minutesSelector : 'span.minutes',
                    secondsSelector : 'span.seconds'
                }

                var options =  $.extend(defaults, options);
                var _this  = $(this);

                tick =  function()
                {
                    var days = _this.find(options.daysSelector);
                    var hours = _this.find(options.hoursSelector);
                    var minutes = _this.find(options.minutesSelector);
                    var seconds = _this.find(options.secondsSelector);
                    console.log(_this);
                    var currentSeconds=seconds.text();
                    currentSeconds--;
                    if(currentSeconds<0)
                    {
                        seconds.text("59");
                        var currentMinutes=minutes.text();
                        currentMinutes--;
                        if(currentMinutes<0)
                        {
                            (minutes).text("59");
                            var currentHours=(hours).text();
                            currentHours--;
                            if(currentHours<0)
                            {
                                (hours).text("23"); 
                                var currentDays=(hours).text();
                                currentDays--;
                            }
                            else
                            {
                                if(currentHours.toString().length==1)
                                {
                                    (hours).text('0'+currentHours);
                                }
                                else
                                {
                                    (hours).text(currentHours);
                                }
                            }
                        }
                        else
                        {
                            if(currentMinutes.toString().length==1)
                            {
                                (minutes).text('0'+currentMinutes);
                            }
                            else
                            {
                                (minutes).text(currentMinutes);
                            }
                        }
                    }
                    else
                    {
                        if(currentSeconds.toString().length==1)
                        {
                            seconds.text('0'+currentSeconds);
                        }
                        else
                        {
                            seconds.text(currentSeconds);
                        }
                    }   
                }

                return this.each(function() 
                {
                    console.log(_this);
                    setInterval("this.tick()",1000);
                });
            }
        });

        })(jQuery);

        $(document).ready(function()
        {
            $("#timer1").countdown();
            $("#timer2").countdown();
            $("#timer3").countdown();
        });

    </script>


</head>

<body>

    <div id="timer1">
        <span class="days">1</span>
        <span class="hours">18</span>
        <span class="minutes">6</span>
        <span class="seconds">45</span>
    </div>

    <div id="timer2">
        <span class="days">2</span>
        <span class="hours">28</span>
        <span class="minutes">1</span>
        <span class="seconds">59</span>
    </div>

    <div id="timer3">
        <span class="days">10</span>
        <span class="hours">0</span>
        <span class="minutes">59</span>
        <span class="seconds">59</span>
    </div>


</body>

If I have to guess what the issue is... only 1 timer actually counts down and the other two doesn't?

That's because the extended countdown timer function you have never passes the name (id) of the countdown timer through to the function. So it always only executes the last one since the last one is what was called...last.

You'd need to send through the name (id) of the div for it to count down all 3 simultaneously.

You declared tick in global scope. Make it local:

var tick =  function()...

and don't pass a string to setInterval :

setInterval(tick,1000);

A better structure of your plugin would be to declare the tick function only once and pass the current element (or the time fields) as argument:

(function($){
     var tick = function(days, hours, minutes, seconds) {
         //...
     };

     $.fn.countdown = function(options) {

            var defaults = {
                daysSelector : 'span.days',
                hoursSelector : 'span.hours',
                minutesSelector : 'span.minutes',
                secondsSelector : 'span.seconds'
            }

            var options =  $.extend(defaults, options);

            return this.each(function(){
                var days = $(this).find(options.daysSelector);
                var hours = $(this).find(options.hoursSelector);
                var minutes = $(this).find(options.minutesSelector);
                var seconds = $(this).find(options.secondsSelector);
                setInterval(function() {
                    tick(days, hours, minutes, seconds);
                },1000);
            });
       };
}(jQuery));

Then your plugin also works if you select multiple elements at once:

$("#timer1, #timer2, #timer3").countdown();

which would not work otherwise (see here http://jsfiddle.net/fkling/kvqWR/5/ ).

Working DEMO

It might also be better to have only setInterval going on which iterates over selected elements and performs the operation. The fewer timers you have, the better. Have a look at this example: http://jsfiddle.net/fkling/kvqWR/4/

I edited your code

(function($){
            $.fn.extend({

                countdown: function(options) {

                var defaults = {
                    daysSelector : 'span.days',
                    hoursSelector : 'span.hours',
                    minutesSelector : 'span.minutes',
                    secondsSelector : 'span.seconds'
                }

                var options =  $.extend(defaults, options);
                var _this  = $(this);

               var tick =  function()
                {
                    var    days = _this.find(options.daysSelector);
                    var    hours = _this.find(options.hoursSelector);
                    var    minutes = _this.find(options.minutesSelector);
                    var    seconds = _this.find(options.secondsSelector);
                    console.log(_this);
                    var currentSeconds=seconds.text();
                    currentSeconds--;
                    if(currentSeconds<0)
                    {
                        seconds.text("59");
                        var currentMinutes=minutes.text();
                        currentMinutes--;
                        if(currentMinutes<0)
                        {
                            (minutes).text("59");
                            var currentHours=(hours).text();
                            currentHours--;
                            if(currentHours<0)
                            {
                                (hours).text("23");    
                                var currentDays=(hours).text();
                                currentDays--;
                            }
                            else
                            {
                                if(currentHours.toString().length==1)
                                {
                                    (hours).text('0'+currentHours);
                                }
                                else
                                {
                                    (hours).text(currentHours);
                                }
                            }
                        }
                        else
                        {
                            if(currentMinutes.toString().length==1)
                            {
                                (minutes).text('0'+currentMinutes);
                            }
                            else
                            {
                                (minutes).text(currentMinutes);
                            }
                        }
                    }
                    else
                    {
                        if(currentSeconds.toString().length==1)
                        {
                            seconds.text('0'+currentSeconds);
                        }
                        else
                        {
                            seconds.text(currentSeconds);
                        }
                    }    
                }

                return _this.each(function() 
                {
                    console.log(_this);
                    setInterval(tick,1000);
                });
            }
        });

        })(jQuery);

        $(document).ready(function()
        {
            $("#timer1").countdown();
            $("#timer2").countdown();
            $("#timer3").countdown();
        });

tick was global and that was the problem (also never pass code to be evalued to setInterval!

Fiddle here: http://jsfiddle.net/kvqWR/1/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM