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

另外,有什么方法可以缩短此功能?我尝试在tile1if-else语句中使用for循环,但未成功。

$('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。

最佳答案

不鼓励在JavaScript中使用函数语句。查看Mozilla's page on function scope,其中有很多关于函数语句与函数表达式的内容,并指出:


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


您发现使用此代码的浏览器之间存在差异,这一事实不足为奇。

尝试

var tile1 = function () {
    ...
}


尽管这应该对您有用,但这仅是因为使用var的变量定义已被提升。随着JavaScript的发展,我们开始使用let而不是var,在定义tile1的循环之外的setInterval调用中使用tile1无效。

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

在循环内定义函数时,务必非常非常小心。您确实需要了解封闭和吊装以及相关概念。有什么方法可以在循环外全局定义index

关于简化代码结构的问题,我认为您可以使用tile1定义tile1,但是我认为您不需要使用var进行内部循环。尝试:

$('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版本正在努力在块范围内处理函数语句。您可以看到here某些版本的Chrome(但Firefox)不支持此功能。

附录

好的,现在我看到您想在i函数中循环执行三个步骤。尽管可以在函数内部放入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秒后运行。然后在3秒钟后的2秒运行。 ,然后三秒钟左右的时间为0。

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

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


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

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

10-06 15:26