【问题标题】:Javascript different variable scope on AJAX callAJAX调用上的Javascript不同的变量范围
【发布时间】:2012-01-24 15:35:14
【问题描述】:

我编写的一个简单滑块脚本中的变量范围存在问题(由于带宽低,我不想使用现成的解决方案)。在静态加载的页面 (http) 以及通过 AJAX 加载的内容上调用滑块脚本。在静态加载的页面(所以没有 AJAX)上,脚本似乎运行良好。但是,当通过 AJAX 调用时,调用的方法找不到 DOM 的元素,这会停止滑块所需的必要动画。

所有事件都通过偶数委托处理(使用 jQuery 的 on() 函数),但这并没有提供任何解决方案。我很确定它与脚本的结构和变量范围有关,但无法确定如何更改结构。所以我正在寻找一种适用于两种情况的解决方案(称为正常或通过 AJAX)。

我尝试在每个函数中声明所需的变量,但这导致了一些错误的错误,例如我为动画设置的间隔的乘积,因为函数范围。希望有人可以在正确的方向上帮助我。

// Slider function
(function (window, undefined) {
    var console = window.console || undefined, // Prevent a JSLint complaint 
        doc = window.document,
        Slider = window.Slider = window.Slider || {},
        $doc = $(doc),
        sliderContainer = doc.getElementById('slider_container'),
        $sliderContainer = $(sliderContainer),
        $sliderContainerWidth = $sliderContainer.width(),
        slider = doc.getElementById('slider'),
        $slider = $(slider),
        $sliderChildren = $slider.children(),
        $slideCount = $sliderChildren.size(),
        $sliderWidth = $sliderContainerWidth * $slideCount;
    $sliderControl = $(doc.getElementById('slider_control')),
    $prevButton = $(doc.getElementById('prev')),
    $nextButton = $(doc.getElementById('next')),
    speed = 2000,
    interval,
    intervalSpeed = 5000,
    throttle = true,
    throttleSpeed = 2000;

    if (sliderContainer == null) return; // If slider is not found on page return           

    // Set widths according to the container and amount of children 
    Slider.setSliderWidth = function () {
        $slider.width($sliderWidth);
        $sliderChildren.width($sliderContainerWidth);
    };

    // Does the animation
    Slider.move = function (dir) {
        // Makes use of variables such as $sliderContainer, $sliderContainer width, etc.
    };

    // On ajax call
    $doc.on('ajaxComplete', document, function () {
        Slider.setSliderWidth();
    });

    // On doc ready
    $(document).ready(function () {
        Slider.setSliderWidth();
        interval = window.setInterval('Slider.move("right")', intervalSpeed);
    });

    // Handler for previous button
    $doc.on('click', '#prev', function (e) {
        e.preventDefault();
        Slider.move('left');
    });

    // Handler for next button
    $doc.on('click', '#next', function (e) {
        e.preventDefault();
        Slider.move('right');
    });

    // Handler for clearing the interval on hover and showing next and pervious button  
    $doc.on('hover', '#slider_container', function (e) {
        if (e.type === 'mouseenter') {
            window.clearInterval(interval);
            $sliderControl.children().fadeIn(400);
        }
    });

    // Handler for resuming the interval and fading out the controls
    $doc.on('hover', '#slider_control', function (e) {
        if (e.type !== 'mouseenter') {
            interval = window.setInterval('Slider.move("right")', intervalSpeed);
            $sliderControl.children().fadeOut(400);
        }
    });
})(window);

HTML 示例结构:

<div id="slider_control">
   <a id="next" href="#next"></a>
   <a id="prev" href="#prev"></a>
</div>
<div id="slider_container">
   <ul id="slider">
      <li style="background-color:#f00;">1</li>
      <li style="background-color:#282">2</li>
      <li style="background-color:#ff0">3</li>
   </ul>
</div>

【问题讨论】:

  • 看到这么多行代码很难理解。您应该尝试仅将代码放在最有可能出现问题的地方。
  • 我认为问题出在结构上,所以我认为最好显示所有内容。我会尽量缩短

标签: javascript jquery ajax variables scope


【解决方案1】:

我注意到你有

Slider.setSliderWidth = function() {
    $slider.width($sliderWidth);
    $sliderChildren.width($sliderContainerWidth);
};

在 ajax 完成时调用。

您是否通过 ajax 更新 DOM 以提供一个您可以通过 doc.getElementById('slider') 获得的新 DOM 元素?那么你的 var slider 和 jquery var $slider 很可能指向不再存在的东西(即使有一个以 slider 为 id 的 dom 元素)。为了纠正,每当调用替换该元素的 ajax 时,重新初始化 slider$slider 以使用与您相同的初始化指向新的 jquery 包装元素。

slider = doc.getElementById('slider');
$slider = $(slider);

编辑:

我不确定您将如何处理变量范围问题,但请看一下这个示例。

<pre>
<script> 
(function(){
   var a  = "something";
   function x (){
      a += "else";
   }
   function y() {
      a = "donut";
   }
   function print (){
      document.write(a +"\n");
   }
   print ();
   x();
   print ();
   y();
   print ();
   x();
   print ();
})();
document.write(typeof(a) + "\n");
</script>
</pre>

它输出到pre标签

something
somethingelse
donut
donutelse
undefined

这与您已经在做的并没有什么不同。只要a 不是方法的参数并且没有在嵌套范围内使用 var 声明,那么在function(window,undefined){ ...} 方法中定义的代码中对a 的所有引用都将引用a,假设@ 987654336@ 由var 在本地定义到该方法。有意义吗?

【讨论】:

  • 没错!我注意到了这一点,但是确保每个函数使用相同的变量而不创建自己的变量的最佳解决方案是什么,这会产生不需要的行为。在 ajaxComplete 函数中重新初始化是否可以解决?
  • 所有变量(window.Slider 位除外)似乎都在function(window,undefined){...} 方法的范围内。除非您在其中一个函数中不小心在它们前面引入了var,否则应该没问题。
  • 其次,您可能不需要 window.Slider 引用,除非您需要在其他地方引用它。您可以在setInterval 中使用函数,因此window.setInterval(function(){Slider.move("right")},intervalSpeed); 应该可以工作,而Slider 将是本地范围内的函数,而不是window.Slider
  • 在不通过 AJAX 加载滑块的情况下是这种情况,但在 AJAX 加载时,我在函数开头声明的变量及其 DOM 值为空。
  • JayC,你对窗口引用的权利,这导致了区间乘法的问题。 A 删除它,它按预期工作
【解决方案2】:

首先,您当然可以使用 jQuery 方法替换所有 getElementById。即用$('#next')替换$(doc.getElementById('next'))

【讨论】:

  • 我们在这里偏离主题,但那行代码只执行一次。那么这真的很重要吗?
【解决方案3】:

我认为当您使用on 时,它不会像您假设的那样搜索选择器的元素。所以你必须使用:

$doc.on('click', '#slider_control #prev',function(e){
    e.preventDefault();
    Slider.move('left');
});

【讨论】:

  • 我认为这不是问题,请参阅 JayC 的回答
【解决方案4】:

等等,什么是通过 Ajax 加载的?滑块 html 代码?在这种情况下,Slider 已经“创建”了,并且您的许多变量将指向任何地方(因为在初始化变量时这些 DOM 元素并不存在)。他们也永远不会这样做。

【讨论】:

  • 确实是约赫姆。我对此并不清楚,但事实就是如此。我现在正在寻找重新初始化变量的最佳解决方案,以便每个函数在滑块的 AJAX 加载后都可以使用相同的变量
  • 也许你不应该重新声明你的变量。为什么不在你的回调例程中简单地使用$('#slider_control')
  • 这是可能的,但不同功能之间不会有差异吗?
  • 函数 $('#slider_control') 在当前 DOM 中及时查看具有给定 ID 的元素。 (回调)函数下一次运行时,它可能指向一个新创建的元素。
猜你喜欢
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
  • 1970-01-01
  • 2013-01-16
  • 2015-06-14
  • 2010-11-16
  • 2015-12-28
  • 1970-01-01
相关资源
最近更新 更多