$(这)在自定义jQuery函数中不起作用

$(这)在自定义jQuery函数中不起作用,jquery,momentjs,Jquery,Momentjs,我使用moment.js和创建了一个jQuery倒计时计时器 请注意,$'divcountdown'在函数中是硬编码的。该函数的工作方式如下所示。但是如果我把硬编码的引用改成$this,它就不起作用了。log$返回一个空对象 我曾尝试在函数开始时将$this设置为一个变量,以防间隔造成范围问题,但没有任何区别 令人困惑的是,我以前在自定义jQuery函数中使用过精确的$.fn.xxx=函数语法,$this在这些函数中工作得很好。这个特殊功能的某些地方让它绊倒了 <script>

我使用moment.js和创建了一个jQuery倒计时计时器

请注意,$'divcountdown'在函数中是硬编码的。该函数的工作方式如下所示。但是如果我把硬编码的引用改成$this,它就不起作用了。log$返回一个空对象

我曾尝试在函数开始时将$this设置为一个变量,以防间隔造成范围问题,但没有任何区别

令人困惑的是,我以前在自定义jQuery函数中使用过精确的$.fn.xxx=函数语法,$this在这些函数中工作得很好。这个特殊功能的某些地方让它绊倒了

<script>
    $.fn.countdown = function ( seconds, tFormat, stopAtZero ) {
        tFormat = (typeof tFormat !== 'undefined') ? tFormat : 'hh:mm:ss';
        stopAtZero = (typeof stopAtZero !== 'undefined') ? stopAtZero : true;
        var eventTime = Date.now() + ( seconds * 1000 );
        var diffTime = eventTime - Date.now();
        var duration = moment.duration( diffTime, 'milliseconds' );
        var interval = 0;
        var counter = setInterval(function () {
            $('div#countdown').text( moment.duration( duration.asSeconds() - ++interval, 'seconds' ).format( tFormat, { trim: false }) );
            if( stopAtZero && interval >= seconds ) clearInterval( counter );
        }, 1000);
    };

    $('div#countdown').countdown( 30*60, 'mm:ss' );
</script>

<div id="countdown"></div>

编辑:已解决。功能正常。它只需要在Div之后或文档加载之后::headdesk::

问题在于setTimeout中的函数在与外部函数不同的范围内运行。因此,这不是你所期望的。您需要缓存此引用的数据

还请注意,通过向包含选项的函数提供一个对象,可以稍微改进逻辑。然后可以使用$.extend提供默认值。您还应该循环使用它,使用户能够提供一组对象来初始化插件。试试这个:

$.fn.countdown=函数选项{ var默认值={ 秒:0, t格式:“hh:mm:ss”, 停在零位:是的, 完成:函数{} }; 变量设置=$.extenddefaults,选项; $this.eachfunction{ var$el=$this; var eventTime=Date.now+settings.seconds*1000; var diffTime=eventTime-Date.now; var duration=矩.durationdiffTime,“毫秒”; var区间=0; var计数器=setIntervalfunction{ $el.textmoment.durationduration.asSeconds-++间隔,“秒”。formatsettings.tFormat{ 修剪:假 }; 如果settings.stopAtZero&&interval>=settings.seconds{ clearIntervalcounter; 设置。完成; } }, 1000; }; } $‘div’。倒计时{ 秒:10, 完成:功能{ console.log'finished!'; } };
问题是因为setTimeout中的函数在与外部函数不同的作用域下运行。因此,这不是你所期望的。您需要缓存此引用的数据

还请注意,通过向包含选项的函数提供一个对象,可以稍微改进逻辑。然后可以使用$.extend提供默认值。您还应该循环使用它,使用户能够提供一组对象来初始化插件。试试这个:

$.fn.countdown=函数选项{ var默认值={ 秒:0, t格式:“hh:mm:ss”, 停在零位:是的, 完成:函数{} }; 变量设置=$.extenddefaults,选项; $this.eachfunction{ var$el=$this; var eventTime=Date.now+settings.seconds*1000; var diffTime=eventTime-Date.now; var duration=矩.durationdiffTime,“毫秒”; var区间=0; var计数器=setIntervalfunction{ $el.textmoment.durationduration.asSeconds-++间隔,“秒”。formatsettings.tFormat{ 修剪:假 }; 如果settings.stopAtZero&&interval>=settings.seconds{ clearIntervalcounter; 设置。完成; } }, 1000; }; } $‘div’。倒计时{ 秒:10, 完成:功能{ console.log'finished!'; } };
您需要在更高的范围内捕获元素,并在时间间隔内使用它

$.fn.countdown = function ( seconds, tFormat, stopAtZero ) {
    tFormat = (typeof tFormat !== 'undefined') ? tFormat : 'hh:mm:ss';
    stopAtZero = (typeof stopAtZero !== 'undefined') ? stopAtZero : true;

    //Capture this here, where it points at  $('div#countdown')
    var elem = $(this);
    //writes countdown
    console.log(elem.attr('id'));

    var eventTime = Date.now() + ( seconds * 1000 );
    var diffTime = eventTime - Date.now();
    var duration = moment.duration( diffTime, 'milliseconds' );
    var interval = 0;
    var counter = setInterval(function () {

        //this here points at window

        //writes countdown
        console.log(elem.attr('id'));

        //now use your captured element here.
        elem.text( moment.duration( duration.asSeconds() - ++interval, 'seconds' ).format( tFormat, { trim: false }) );
        if( stopAtZero && interval >= seconds ) clearInterval( counter );
    }, 1000);
};

$('div#countdown').countdown( 30*60, 'mm:ss' );

您需要在更高的范围内捕获元素,并在时间间隔内使用它

$.fn.countdown = function ( seconds, tFormat, stopAtZero ) {
    tFormat = (typeof tFormat !== 'undefined') ? tFormat : 'hh:mm:ss';
    stopAtZero = (typeof stopAtZero !== 'undefined') ? stopAtZero : true;

    //Capture this here, where it points at  $('div#countdown')
    var elem = $(this);
    //writes countdown
    console.log(elem.attr('id'));

    var eventTime = Date.now() + ( seconds * 1000 );
    var diffTime = eventTime - Date.now();
    var duration = moment.duration( diffTime, 'milliseconds' );
    var interval = 0;
    var counter = setInterval(function () {

        //this here points at window

        //writes countdown
        console.log(elem.attr('id'));

        //now use your captured element here.
        elem.text( moment.duration( duration.asSeconds() - ++interval, 'seconds' ).format( tFormat, { trim: false }) );
        if( stopAtZero && interval >= seconds ) clearInterval( counter );
    }, 1000);
};

$('div#countdown').countdown( 30*60, 'mm:ss' );

下面是一个工作示例,我删除了与问题时刻和格式代码无关的代码;否则,除了在适当的范围内捕获之外,这是相同的

$.fn.countdown=功能秒,t格式,停止为零{ tFormat=typeof tFormat!=“未定义”?tFormat:'hh:mm:ss'; stopAtZero=stopAtZero的类型!=“未定义”?stopAtZero:true; var eventTime=Date.now+seconds*1000; var diffTime=eventTime-Date.now; var持续时间=5000; var区间=0; var self=此;/=秒清除间隔计数器; }, 1000; }; $'divcountdown'。倒计时30*60,'mm:ss';
下面是一个工作示例,我删除了与问题时刻和格式代码无关的代码;否则,除了在适当的范围内捕获之外,这是相同的

$.fn.countdown=功能秒,t格式,停止为零{ tFormat=typeof tFormat!=“未定义”?tFormat:'hh:mm:ss'; stopAtZero=stopAtZero的类型!=“未定义”?stopAtZero:true; var eventTime=Date.now+seconds*1000; var diffTime=eventTime-Date.now; var持续时间=5000; var区间=0; var self=此;/=秒清除间隔计数器; }, 1000; }; $'divcountdown'。倒计时30*60,'mm:ss'; 这是陈

ge的含义取决于范围;在窗口级别、倒计时函数和设置间隔内,您将有一个不同的设置。典型的解决方法是使用var self=this来捕获实际要使用的引用,并在子函数中引用self。不过,在您的例子中,像您在这里所做的那样,显式引用您想要的DOM元素可能是最好的解决方案。将函数的第一行设置为:target=$this;然后在setIntervalRelated中使用target,这会根据范围改变含义;在窗口级别、倒计时函数和设置间隔内,您将有一个不同的设置。典型的解决方法是使用var self=this来捕获实际要使用的引用,并在子函数中引用self。不过,在您的例子中,像您在这里所做的那样,显式引用您想要的DOM元素可能是最好的解决方案。将函数的第一行设置为:target=$this;然后在setIntervalRelated中使用target,我已经尝试过了。这没什么区别。注意问题的第三段即使按照您的建议尝试捕获elem,console.logelem返回Object[]是的,elem是一个对象吗?您希望它做什么?console.logelem.id返回函数的前两行未定义的值。将变量设置为$this,然后console.log该变量。console.logelem返回了对象[]。console.logelem.id返回未定义我已经尝试过了。这没什么区别。注意问题的第三段即使按照您的建议尝试捕获elem,console.logelem返回Object[]是的,elem是一个对象吗?您希望它做什么?console.logelem.id返回函数的前两行未定义的值。将变量设置为$this,然后console.log该变量。console.logelem返回了对象[]。console.logelem.id返回Undefinedry,感谢您的建议。请注意下面一个几乎相同的答案中的注释。您可以调查一下代码的其他方面是否存在任何问题吗。正如您从我刚才编辑的答案片段中看到的,它工作得很好。请注意,您同时依赖于moment.js和moment-duration-format.js—您需要确保在页面中以及在正确的位置包含这两个文件order@StephenR,罗里斯的作品。运行代码段。如果你说的不正确,你需要解释你的做法有什么不同,以及为什么你的做法不起作用。这是正确的答案。似乎不是这样-我只是更新了小提琴,它仍然有效。当然,你可以提供一个函数在设置对象中执行。我为你的理论更新了答案,谢谢你的建议。请注意下面一个几乎相同的答案中的注释。您可以调查一下代码的其他方面是否存在任何问题吗。正如您从我刚才编辑的答案片段中看到的,它工作得很好。请注意,您同时依赖于moment.js和moment-duration-format.js—您需要确保在页面中以及在正确的位置包含这两个文件order@StephenR,罗里斯的作品。运行代码段。如果你说的不正确,你需要解释你的做法有什么不同,以及为什么你的做法不起作用。这是正确的答案。似乎不是这样-我只是更新了小提琴,它仍然有效。当然,你可以提供一个函数在设置对象中执行。我为你更新了答案