I am trying to hide some content after a specific time, with JavaScript / jQuery parsing the class list to figure out the time. To make it more clear, I'm giving these examples:
我试图在特定时间后隐藏一些内容,JavaScript / jQuery解析类列表以计算时间。为了更清楚,我给出了这些例子:
<div id="one" class="some-class some-other-class timeout-3500"> </div>
<div id="two" class="another-irrelevant-class timeout-2000"> </div>
The script should hide div
"one" after 3500ms, and div
"two" after 2000ms.
该脚本应在3500ms后隐藏div“one”,并在2000ms后隐藏“two”。
My code so far, combining the jQuery library with vanilla JavaScript, is as follows:
到目前为止,我的代码将jQuery库与vanilla JavaScript结合起来,如下所示:
$('div[class*="timeout-"]').each(function()
{
var classList = $(this).attr('class').split(/\s+/);
var timeoutDelay;
for (var i = 0; i < classList.length; i++)
{
if (classList[i].includes('timeout-'))
{
timeoutDelay = parseInt(classList[i].split('-').pop(), 10);
setTimeout(function()
{
$(this).hide();
}, timeoutDelay);
}
}
});
Here's a (non-working) fiddle to demonstrate: https://jsfiddle.net/56o57t0j/.
这是一个(非工作)小提琴演示:https://jsfiddle.net/56o57t0j/。
The setTimeout
fires, but $(this).hide();
does nothing. It's like nothing is selected with jQuery (which of course isn't true, since all the code is inside a selector block with each()
appended).
触发了setTimeout,但$(this).hide();什么也没做。这就像没有用jQuery选择任何东西(当然不是这样,因为所有代码都在一个选择器块内,并附加了每个())。
Any help with this? It has been troubling me since the morning. Thanks in advance.
对此有何帮助?从早上起一直困扰着我。提前致谢。
4 个解决方案
#1
1
You need to bind your timeout function with the correct scope. Scope and binding is a fairly advanced topic in JS that can be confusing at first, but since the "timeout" is being executed asynchronously, it is actually executed outside the scope of the parent "each" loop. Therefore, "this" is not known at the time of execution. If you bind the function like below, it will work:
您需要将超时功能与正确的范围绑定。范围和绑定是JS中一个相当高级的主题,一开始可能会让人感到困惑,但由于“超时”是异步执行的,它实际上是在父“每个”循环的范围之外执行的。因此,在执行时不知道“this”。如果您绑定下面的函数,它将工作:
setTimeout(function() {
$(this).hide();
}.bind(this), timeoutDelay);
I have forked your fiddle with a working example: https://jsfiddle.net/jg7m6cyu/1/
我用一个有效的例子分享你的小提琴:https://jsfiddle.net/jg7m6cyu/1/
MDN has a great article on how "bind" works. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
MDN有一篇关于“绑定”如何工作的精彩文章。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
#2
0
i think you should use the data attribute, something like this:
我认为你应该使用data属性,如下所示:
HTML
<div id="one" class="some-class some-other-class delayed" data-timeout="3500"> </div>
<div id="two" class="another-irrelevant-class delayed" data-timeout="2000"> </div>
JQUERY
$('div.delayed').each(function()
{
var timeoutDelay = $(this).data('timeout'),
el = $(this);
setTimeout(function()
{
el.hide();
}, timeoutDelay);
});
#3
0
The problem is setTimeout is called in different context then the function. So the "this" in setTimeout is not the same "this" in the function. So copying it to a variable "that" saves the function context.
问题是setTimeout在不同的上下文中调用然后是函数。所以setTimeout中的“this”与函数中的“this”不同。因此将其复制到变量“that”可以保存函数上下文。
$('div[class*="timeout-"]').each(function() {
var classList = $(this).attr('class').split(/\s+/);
var timeoutDelay;
//need to lexically bind this because setTimeout is a different calling context
var that=this;
for (var i = 0; i < classList.length; i++) {
if (classList[i].includes('timeout-')) {
timeoutDelay = parseInt(classList[i].split('-').pop(), 10);
setTimeout(function() {
$(that).hide();
}, timeoutDelay);
}
}
});
* {
font-family: "Tahoma", sans-serif;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="some-class some-other-class timeout-3500">
First div.
</div>
<div class="yet-another-div with-some-class timeout-2000">
Second div.
</div>
#4
-1
In OP this
inside setTimiout
is window
. Wrap setTimiout
call into a closure. This code will work.
在OP中,这里面的setTimiout是窗口。将setTimiout包装成一个闭包。这段代码可行。
for (var i = 0; i < classList.length; i++)
{
if (classList[i].includes('timeout-'))
{
timeoutDelay = parseInt(classList[i].split('-').pop(), 10);
(function(elem,timeout){
setTimeout(function()
{
$(elem).hide();
}, timeout);
})(this,timeoutDelay); //this comes from $(...).each
}//if
}//for
#1
1
You need to bind your timeout function with the correct scope. Scope and binding is a fairly advanced topic in JS that can be confusing at first, but since the "timeout" is being executed asynchronously, it is actually executed outside the scope of the parent "each" loop. Therefore, "this" is not known at the time of execution. If you bind the function like below, it will work:
您需要将超时功能与正确的范围绑定。范围和绑定是JS中一个相当高级的主题,一开始可能会让人感到困惑,但由于“超时”是异步执行的,它实际上是在父“每个”循环的范围之外执行的。因此,在执行时不知道“this”。如果您绑定下面的函数,它将工作:
setTimeout(function() {
$(this).hide();
}.bind(this), timeoutDelay);
I have forked your fiddle with a working example: https://jsfiddle.net/jg7m6cyu/1/
我用一个有效的例子分享你的小提琴:https://jsfiddle.net/jg7m6cyu/1/
MDN has a great article on how "bind" works. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
MDN有一篇关于“绑定”如何工作的精彩文章。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
#2
0
i think you should use the data attribute, something like this:
我认为你应该使用data属性,如下所示:
HTML
<div id="one" class="some-class some-other-class delayed" data-timeout="3500"> </div>
<div id="two" class="another-irrelevant-class delayed" data-timeout="2000"> </div>
JQUERY
$('div.delayed').each(function()
{
var timeoutDelay = $(this).data('timeout'),
el = $(this);
setTimeout(function()
{
el.hide();
}, timeoutDelay);
});
#3
0
The problem is setTimeout is called in different context then the function. So the "this" in setTimeout is not the same "this" in the function. So copying it to a variable "that" saves the function context.
问题是setTimeout在不同的上下文中调用然后是函数。所以setTimeout中的“this”与函数中的“this”不同。因此将其复制到变量“that”可以保存函数上下文。
$('div[class*="timeout-"]').each(function() {
var classList = $(this).attr('class').split(/\s+/);
var timeoutDelay;
//need to lexically bind this because setTimeout is a different calling context
var that=this;
for (var i = 0; i < classList.length; i++) {
if (classList[i].includes('timeout-')) {
timeoutDelay = parseInt(classList[i].split('-').pop(), 10);
setTimeout(function() {
$(that).hide();
}, timeoutDelay);
}
}
});
* {
font-family: "Tahoma", sans-serif;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class="some-class some-other-class timeout-3500">
First div.
</div>
<div class="yet-another-div with-some-class timeout-2000">
Second div.
</div>
#4
-1
In OP this
inside setTimiout
is window
. Wrap setTimiout
call into a closure. This code will work.
在OP中,这里面的setTimiout是窗口。将setTimiout包装成一个闭包。这段代码可行。
for (var i = 0; i < classList.length; i++)
{
if (classList[i].includes('timeout-'))
{
timeoutDelay = parseInt(classList[i].split('-').pop(), 10);
(function(elem,timeout){
setTimeout(function()
{
$(elem).hide();
}, timeout);
})(this,timeoutDelay); //this comes from $(...).each
}//if
}//for