全局变量,延迟和此

时间:2019-07-10 10:17:17

标签: jquery

我编写了这种简单的机制来向菜单添加一些交互性和效果:

var $body = $('body');
var $theNav = $('.the-nav-wrapper');
var $theMenuBar = $('.the-menu-bar');
var $menuOpener = $('.menu-opener');

$menuOpener.on('click', function() {
   $(this).toggleClass('becomeMenuCloser textAppears');     
   $theNav.toggleClass('open');
   $body.toggleClass('preventScroll');
   $theMenuBar.toggleClass('bringOnTop');
   $(this).toggleText('Menu', 'Close');    
});

这很好。

在菜单编码的每一行中,我决定要在类becomeMenuCloser textAppears的切换之间添加一个延迟,以便首先切换becomeMenuCloser,然后在短暂的延迟之后切换{{ 1}}被切换。

我修改了负责切换类的特定代码行,如下所示:

textAppears

这不起作用。 它同时切换两个类。然后我尝试了这个:

$(this).toggleClass('becomeMenuCloser').delay(1300).toggleClass('textAppears');

这也不起作用。 然后我尝试了这个:

$(this).toggleClass('becomeMenuCloser').promise().done(function(){
   $(this).toggleClass('textAppears'); 
});

这也不起作用,因为它的代码永远不会进入setTimeout,并且随后也不会切换第二个类。

经过反复试验(以及一些挫折和思考),我偶然发现解决我的问题的方法是删除$(this).toggleClass('becomeMenuCloser'); setTimeout(function() { $(this).toggleClass('textAppears'); }, 610); 并将其替换为缓存的变量$(this),就像下面的代码一样:

$menuOpener

这有效。

问题是:

1)为什么在这种情况下$(this).toggleClass('becomeMenuCloser') setTimeout(function() { $menuOpener.toggleClass('textAppears'); }, 310); 是问题所在?我真的很想了解这里缺少的线索。

2)我也不明白为什么使用$(this)可以解决问题。

3)当将元素存储为全局变量时,我是否应该仅使用全局变量并省略$menuOpener

嘿,谢谢!

1 个答案:

答案 0 :(得分:2)

那是因为存在不同的上下文。

检查以下示例: Jsfiddle(click on the div text and check the console)

示例1: 在第一个功能中,第一个console.log打印

  

上下文1 id:foo

第二个打印时

  

上下文2 ID:未定义

由于上下文切换(不再指向dom元素)。

//example 1
    function context() {
      var div = $("#foo");
      div.on('click', function() {
        $(this).toggleClass('becomeMenuCloser');
        console.log("context 1 id:" + this.id);//foo
        setTimeout(function() {
          console.log("context 2 id:" + this.id);//undefined
          div.toggleClass('textAppears');
        }, 610);
      })
    }
    context();

现在,在第二个示例中,我们使用箭头功能(()=>)保留上下文,因此在超时功能中也使用相同的“ this”实例,因此控制台两次都打印正确的ID。

在第一个功能中,第一个console.log打印

  

上下文1 id:foo

和第二个相同

  

上下文2 id:foo

//example 2
function context2() {
  var div = $("#foo2");
  div.on('click', function() {
    $(this).toggleClass('becomeMenuCloser');
    console.log("context 1 id:" + this.id);//foo
    setTimeout(() => {
      console.log("context 2 id:" + this.id);//foo
      div.toggleClass('textAppears');
    }, 610);
  })
}
context2();