jQuery 在 setInterval/setTimeOut 函数中使用 $(this) 作为起点遍历 DOM?

jQuery traversing the DOM using $(this) as a starting point inside setInterval/setTimeOut function?

提问人:thothlike 提问时间:5/8/2021 最后编辑:thothlike 更新时间:5/10/2021 访问量:89

问:

我一直在试图了解如何(在jQuery中)使用$(this)作为setInterval / setTimeOut函数中的起点遍历DOM,并遇到了一些我发现令人困惑的行为。

似乎不可能在 setInterval/setTimeOut 函数中使用 $(this) 作为起点遍历 DOM

为什么?
jQuery/javaScript 人 - 继续吧。

用于说明行为的示例代码:

j查询:

// set this code anywhere (inside/outside - document.ready/named-function/...) and run it
var autoTimer = setInterval(function(){
    // INSERT EXAMPLE TEST-CODE FROM BELOW HERE
}, 10000)

尝试的测试代码:

// from inside the setInterval/setTimeOut function above
// if $(this)
if($(this).length !== 0) {
    alert('hello');
} // alerts hello

// from inside the setInterval/setTimeOut function above
// if html-tag (body/head/html)
if($('body').length !== 0) {
    alert('hello');
} // alerts hello

// from inside the setInterval/setTimeOut function above
// if className
if($('.className').length !== 0) {
    alert('hello');
} // alerts hello

// from inside the setInterval/setTimeOut function above
// if id
if($('#id').length !== 0) {
    alert('hello');
} // alerts hello

因此,它可以很好地找到文档中的特定元素,除了 $(this) 之外,您还可以从那里遍历 DOM

即。

// from inside the setInterval/setTimeOut function above
if ($('.className').find(something).length !== 0)... // works just fine

当您想使用 $(this) 作为遍历的起点时,问题就来了

遍历测试代码尝试使用 $(this) 作为起点:

// from inside the setInterval/setTimeOut function above
// traversing up the DOM
if($(this).parents('body').length !== 0) {
    alert('hello');
} // no alert (same with closest/parentsUntil/etc up the DOM)

// from inside the setInterval/setTimeOut function above
// traversing sideways in the DOM
if($(this).siblings('body').length !== 0) {
    alert('hello');
} // no alert (same with next/prev/etc sideways in the DOM)

// from inside the setInterval/setTimeOut function above
// traversing down the DOM
if($(this).find('body').length !== 0) {
    alert('hello');
} // no alert (same with children down the DOM)

因此,从 $(this) 'body'(或其他任何与此相关的内容)开始似乎在任何地方(向上/向下/横向)都不存在,从上面的任何其他起点来看都是不正确的

我还尝试使用命名的全局函数,如下所示:

// set outside/inside document.ready
function testCode() {
    // INSERT EXAMPLE TRAVERSING TEST-CODE FROM ABOVE HERE
}

// set this code anywhere (inside/outside - document.ready/named-function/...) and run it
var autoTimer = setInterval(testCode, 10000) // no alert

// set this code anywhere (inside/outside - document.ready/named-function/...) and run it
var autoTimer = setInterval(function(){
    testCode();
}, 10000) // no alert

因此,再次重申我的问题:
为什么在jQuery中似乎不可能使用$(this)作为起点在setInterval / setTimeOut中遍历DOM(向上/向下/横向)?

对于这种行为,有哪些可能的黑客/变通方法/等?

黑客/变通方法/等可能的无解决方案。

这个使用 $.proxy 的答案仅在您使用旧版本的 jQuery 时才有效 - 但由于本文档证明“此 API 已在 jQuery 3.3 中弃用”......目前,这不是一个解决方案。

绑定方法也不是,因为正如文档所证明的那样,“从 jQuery 3.0 开始,.bind() 已被弃用”并被 on 方法取代(但我看不出我如何在这里使用 .on() 产生任何效果 - 但也许这只是由于我缺乏想象力)。

javascript jquery setinterval dom-traversal

评论

0赞 JLRishe 5/8/2021
请向我们展示显示问题的实际代码。您向我们展示了很多代码,但实际上没有一个代码包含在 .如果你没有真正向我们展示你的代码,就很难向你展示如何补救你的代码。thissetTimeout
0赞 thothlike 5/8/2021
我试图让它更通用,因为这种行为让我感到困惑,我想要更通用的基本解释,为什么它没有按预期工作(在下面接受的答案中得到它 + 让实际代码工作的用例),但这就是为什么提供的更通用的代码(哦,它是 setInterval 而不是 setTimeout - 尽管我怀疑两者的答案是相同的):) - 但根据建议编辑被添加到问题中

答:

1赞 JLRishe 5/8/2021 #1

这是一个基本的范围问题,与jQuery关系不大。this

最直接的方法是将回调之外的另一个变量赋值:this

var that = this;

setInterval(function () {
    $(that).parents();
}, 1000);

如果你不关心 IE,或者你有一个构建过程,你可以使用箭头函数,它使用从它外部的作用域:this

setInterval(() => {
    $(this).parents();
}, 1000);

我个人的偏好是完全避免使用,因为它的所有鹦鹉行为都给你带来了如此多的悲伤。从您的示例中尚不清楚您的价值来自哪里,但这里有一些方法可以避免它:thisthis

// inside .each()
$('a').each(function (_, el) {
    $(el).parents();
});

// inside event handler
$('a').on('click', function (event) {
    $(event.target).parents();
});

评论

0赞 thothlike 5/8/2021
好。。。完全按照预期工作......我会研究你的替代方案 - 但非常感谢你......你不知道我花了多少时间在搜索/阅读和尝试建议的解决方案得到我的赞成和复选标记:)