我使用了moment.js和moment-duration-format plugin制作了一个jQuery倒数计时器。
请注意,$('div#countdown')
在函数内部是硬编码的。该功能如此处所示。但是,如果我将硬编码引用更改为$(this),它就不起作用。 console.log($this)
返回一个空对象。
我已经尝试将$(this)设置为函数开头的变量,以防间隔创建范围问题,但没有区别。
令人困惑的部分是我之前使用过这种精确的$.fn.xxx = function
语法来实现自定义jQuery函数,并且$(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 ::
之后答案 0 :(得分:2)
问题是因为setTimeout()
中的函数在与外部函数不同的范围内运行。因此,this
不是您所期望的。您需要缓存this
引用。
另请注意,您可以通过向包含选项的函数提供对象来稍微改善逻辑。然后,您可以使用$.extend
来提供默认值。您还应该遍历this
以使用户能够提供一组对象来初始化插件。试试这个:
$.fn.countdown = function(options) {
var defaults = {
seconds: 0,
tFormat: 'hh:mm:ss',
stopAtZero: true,
complete: function() {}
};
var settings = $.extend(defaults, options);
$(this).each(function() {
var $el = $(this);
var eventTime = Date.now() + (settings.seconds * 1000);
var diffTime = eventTime - Date.now();
var duration = moment.duration(diffTime, 'milliseconds');
var interval = 0;
var counter = setInterval(function() {
$el.text(moment.duration(duration.asSeconds() - ++interval, 'seconds').format(settings.tFormat, {
trim: false
}));
if (settings.stopAtZero && interval >= settings.seconds) {
clearInterval(counter);
settings.complete();
}
}, 1000);
});
}
$('div').countdown({
seconds: 10,
complete: function() {
console.log('finished!');
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-duration-format/1.3.0/moment-duration-format.min.js"></script>
<div></div>
答案 1 :(得分:1)
您需要在更高的范围内捕获元素并在间隔中使用它。
$.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' );
答案 2 :(得分:1)
这是一个工作示例(我删除了与问题无关的moment()
和格式化代码;否则除了在适当的范围内捕获“this”之外,这是相同的。)
$.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 = 5000;
var interval = 0;
var self = this; // <-- capture the DOM element here
var counter = setInterval(function () {
// and use it here:
$(self).text((5000 - ++interval) + ' seconds');
if( stopAtZero && interval >= seconds ) clearInterval( counter );
}, 1000);
};
$('div#countdown').countdown( 30*60, 'mm:ss' );
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<div id="countdown"></div>