0

此代码在 Chrome 中完美运行,但 Firefox 表示该函数tile1未定义。可能是什么问题呢?

另外,有什么办法可以缩短这个功能?我试过在里面使用一个for循环tile1和一个if-else语句,但我没有成功。

$('div.tile').each(function(index, element) {
  for(var i=0;i<=index;i++){

  var tile1=function(){
    var one ="div.tile div.one";
    var two =" div.tile div.two";
    var three = "div.tile div.three";
    if(index==0){
      one="div.tile div.one";
      two="div.tile div.two";
      three="div.tile div.three";
    } else {
      one ="div.tile div.one"+index;
      two ="div.tile div.two"+index;
      three ="div.tile div.three"+index;
    }
      var $one=$(one);
      var $two = $(two);
      var $three=$(three);
      var oneTop = $one.top;
      var twoTop = $two.top;
      var threeTop = $three.top;
      delayRate += 3000; // delayRate 5 sec (5000) by default 

     $one
       .delay(delayRate)
       .animate({top: "-100.5%"},300,easing);   
     $two
       .delay(delayRate)
       .animate({top:"0%"},300,easing);
     $three
       .delay(delayRate)
       .animate({top:"100.5%"},300,easing);     

     $one
       .delay(12000)
       .animate({top: "-200.5%"},300,easing);
     $two
       .delay(12000)
       .animate({top:"-100.5%"},300,easing);
     $three
       .delay(12000)
       .animate({top:"0"},300,easing);

     $one
       .delay(12000)
       .animate({top: "-100.5%"},300,easing);
     $two
       .delay(12000)
       .animate({top:"0"},300,easing);
     $three
       .delay(12000)
       .animate({top:"100.5%"},300,easing);

     $one
       .delay(15000-delayRate)
       .animate({top: "0"},300,easing);
     $two
       .delay(15000-delayRate)
       .animate({top:"100.5%"},300,easing);
     $three
       .delay(15000-delayRate)
       .animate({top:"200.5%"},300,easing);

     if(i==3){
       delayRate=0;
     }
   }
 }  
 window.setInterval(tile1, 3000);
});

正如我所说的函数,index它随机出现,如 0、3、1、2,并且索引对应的有 4 个 div。

4

1 回答 1

6

不鼓励在 JavaScript 中使用函数语句。查看Mozilla 关于函数范围的页面,其中有一个关于函数语句与函数表达式的精彩部分,并指出:

可以使用 //function statements//(ECMA-262 第 3 版标准的允许扩展)或 Function 构造函数有条件地定义函数。请注意,在 ES5 strict 中不再允许此类函数语句。此外,此功能无法始终跨浏览器运行,因此您不应依赖它。

您看到使用此代码的浏览器之间的差异这一事实并不奇怪。

尝试

var tile1 = function () {
    ...
}

虽然这在这里应该对你有用,但它这样做只是因为变量定义var被提升了。随着 JavaScript 的发展和我们开始使用let而不是var,您在定义的循环之外tile1的调用中使用的将不起作用。setIntervaltile1

可能出现的问题之一是,当您i在内部函数内部使用时,您总是引用i外部范围(循环计数器)中的单个实例,其值始终等于index. (编辑:我在下面展示了如何解决这个问题。)

在循环中定义函数时要非常非常小心。您确实需要了解闭包和提升以及相关概念。有什么方法tile1可以在循环之外全局定义吗?

关于您关于简化代码结构的问题,我认为您可以定义tile1with var但我认为您不需要使用i. 尝试:

$('div.tile').each(function(index, element) {
  var tile1 = function () {
    var one ="div.tile div.one";
    .
    .
    .
    if (index === 3) {   // CHANGED I TO INDEX HERE.
      delayRate=0;
    }
  }
  window.setInterval(tile1, 3000);
});

我不确定内循环给你买了什么。

旁白:未来的 JavaScript 版本正在努力处理块范围内的函数语句;您可以在此处看到某些版本的 Chrome 支持此功能,但 Firefox 不支持。

附录

好的,现在我看到您想在tile1函数中循环三个步骤。虽然可以在函数中放置一个 for 循环,但 JavaScript 的方式是让函数每次只运行其动画的一个步骤。如果它需要某种计数器,计数器应该是外部的。一种方法是这样的:

var tile1 = function (i) {
  .
  .
  // use the value i here as needed
  .
  .
  setTimeout(function () {tile1((i + 1) % 3)}, 3000);
};
tile1(0);

它的作用是它首先用值 0 调用你的 tile 函数。然后在你在 0 处执行你想要的操作之后,你将安排下一帧在 i = 1 后 3 秒运行。然后在 2 秒左右后运行 3 秒左右,然后三秒左右之后为 0。

这里有一点漂移,所以你可能想使用setInterval. 这需要关闭。解决方案的形式是这样的:

(function () {
  var i = 0;
  var tile1 = function () {
    .
    .
    // use the value i here as needed
    .
    .
    i = (i + 1) % 3;
  };
  setInterval(tile1, 3000);
}());

这段代码很酷。这是一个匿名函数的调用,它调用setInterval来安排tile1函数每 3 秒运行一次。每次tile1运行它都使用一个非本地的值,该值i在闭包的其余代码中隐藏。每次执行都tile1使用 的正确值i,然后通过更改i为下一次调用的正确值来完成!

这两种技术都很适合在 JavaScript 中掌握。和他们一起玩。当然,第二个没有时钟漂移,所以它可能更好。为了使代码专业化,您可能希望将结果分配setInterval给一个变量,以便以后可以调用clearInterval

于 2013-06-21T04:49:15.383 回答