javascript - 使用 JavaScript 在循环中等待 transitionend

标签 javascript css transition transitionend

我太习惯于使用 jQuery 了,以至于我似乎无法弄清楚如何在纯 Javascript 中做到这一点。我不想使用 jQuery,因为这是我在网站上使用的唯一代码段,而且库对于这个目的来说太大了。

这是 jQuery 脚本(有效):http://jsfiddle.net/1jt6dhzu/2/

$(document).ready(function () {
    var whatAmI = ["Fruit", "Not a vegetable", "A phone", "Yummie in tummy"];
    var j, i = 4,
        n = whatAmI.length;

    function changeSubTitle() {
        setTimeout(function () {
            j = Math.floor(Math.random() * n - 1);
            if (j >= i) j += 1;

            $(".page-header > h2").animate({
                "opacity": 0
            }, 700, function () {
                $(this).children("span").text(whatAmI[j]);
                $(this).animate({
                    "opacity": 1
                }, 700, changeSubTitle);
            });
        }, 1000);
        i = j;
    }
    changeSubTitle();
});

我想将它换成 vanilla JS。大部分循环可以保留,但是必须更换超时和回调。我想因为我不需要 IE9 支持我可以用 css3 转换和添加类来做到这一点。 This is what I have so far :

h2 {
    opacity: 1;
    transition: opacity 700ms;
}
h2.fade-out {
    opacity: 0;
}


document.addEventListener("DOMContentLoaded", function () {
    var whatAmI = ["Fruit", "Not a vegetable", "A phone", "Yummie in tummy"];
    var j, i = 4,
        n = whatAmI.length,
        heading = document.querySelector(".page-header > h2");

    function changeSubTitle() {
        setTimeout(function () {
            j = Math.floor(Math.random() * n - 1);
            if (j >= i) j += 1;

            heading.classList.add("fade-out");

            setTimeout(function () {
                heading.children("span")[0].innerHTML = whatAmI[j];
                heading.classList.remove("fade-out");
                setTimeout(changeSubTitle, 700);
            }, 700);
        }, 1000);
        i = j;
    }
    changeSubTitle();
});

不幸的是,这不起作用。为 transitionend 上的事件换掉超时(除了最外层的超时)可能会更好。但我不确定如何实现这个跨浏览器(IE 10 及更高版本,以及其他主要浏览器)。

最佳答案

除了删除以特定于 jQuery 的方式实现的 children 方法之外,您几乎完成了所有正确的事情。与我之前发布的相反,JS 确实有一个 children 函数,它返回一个 HTMLCollection 但它不能通过提供类型作为参数来基于元素类型进行过滤。它返回所有子节点,我们必须通过使用子元素的索引或检查元素的类型来选择正确的子节点。

对于这个例子(并且为了简单起见),替换

heading.children("span")[0].innerHTML = whatAmI[j];

heading.children[0].innerHTML = whatAmI[j]; // since span is the first and only child

heading.querySelector("span").innerHTML = whatAmI[j];

它应该按预期工作。

document.addEventListener("DOMContentLoaded", function() {
  var whatAmI = ["Fruit", "Not a vegetable", "A phone", "Yummie in tummy"];
  var j, i = 2,
    n = whatAmI.length,
    heading = document.querySelector(".page-header > h2");

  function changeSubTitle() {
    setTimeout(function() {
      j = Math.floor(Math.random() * (n - 1));
      if (j >= i) j += 1;

      heading.classList.add("fade-out");

      setTimeout(function() {
        heading.querySelector("span").innerHTML = whatAmI[j];
        heading.classList.remove("fade-out");
        setTimeout(changeSubTitle, 700);
      }, 700);
      i = j;
    }, 1000);
  }
  changeSubTitle();
});
h2 {
  opacity: 1;
  transition: opacity 700ms;
}
h2.fade-out {
  opacity: 0;
}
<header class="page-header">
  <h1>Bananas</h1>

  <h2><span>A phone</span></h2>

</header>


使用 transitionend:

transitionend是一个单一的事件监听器,只要元素属性的转换结束,它就会被附加并触发。它会在添加和删除淡出类之后被触发,因此,我们必须手动检查触发事件时元素的状态,然后根据它采取行动。

这里我使用了 getComputedStyle属性检查元素的 opacity 状态,如果它处于淡出状态,则更改文本并删除淡出类(或)否则,调用 changeSubTitle 函数再次。

if (window.getComputedStyle(heading).opacity == 0) {
  heading.querySelector("span").innerHTML = whatAmI[j];
  heading.classList.remove("fade-out");
} else
  changeSubTitle();

document.addEventListener("DOMContentLoaded", function() {
  var whatAmI = ["Fruit", "Not a vegetable", "A phone", "Yummie in tummy"];
  var j, i = 2,
    n = whatAmI.length,
    heading = document.querySelector(".page-header > h2");

  function changeSubTitle() {
    setTimeout(function() {
      j = Math.floor(Math.random() * (n - 1));
      if (j >= i) j += 1;

      heading.classList.add("fade-out");
      i = j;
    }, 1000);
  }
  heading.addEventListener('transitionend', function() {
    if (window.getComputedStyle(heading).opacity == 0) {
      heading.querySelector("span").innerHTML = whatAmI[j];
      heading.classList.remove("fade-out");
    } else
      changeSubTitle();
  });
  changeSubTitle();
});
h2 {
  opacity: 1;
  transition: opacity 700ms;
}
h2.fade-out {
  opacity: 0;
}
<header class="page-header">
  <h1>Bananas</h1>

  <h2><span>A phone</span></h2>

</header>

或者(就像您评论的那样),您也可以检查元素上存在的类,然后做出相应的决定。与我之前的方法相比,这似乎是一种更简单的方法。

if (heading.classList.contains("fade-out")) {
  heading.querySelector("span").innerHTML = whatAmI[j];
  heading.classList.remove("fade-out");
} else
  changeSubTitle();

document.addEventListener("DOMContentLoaded", function() {
  var whatAmI = ["Fruit", "Not a vegetable", "A phone", "Yummie in tummy"];
  var j, i = 2,
    n = whatAmI.length,
    heading = document.querySelector(".page-header > h2");

  function changeSubTitle() {
    setTimeout(function() {
      j = Math.floor(Math.random() * (n - 1));
      if (j >= i) j += 1;

      heading.classList.add("fade-out");
      i = j;
    }, 1000);
  }
  heading.addEventListener('transitionend', function() {
    if (heading.classList.contains("fade-out")) {
      heading.querySelector("span").innerHTML = whatAmI[j];
      heading.classList.remove("fade-out");
    } else
      changeSubTitle();
  });
  changeSubTitle();
});
h2 {
  opacity: 1;
  transition: opacity 700ms;
}
h2.fade-out {
  opacity: 0;
}
<header class="page-header">
  <h1>Bananas</h1>

  <h2><span>A phone</span></h2>

</header>


以上两个片段都已经在最新版本的 Firefox、Chrome、Opera、IE11 和 IE10 中进行了测试(使用仿真)。它也应该适用于 Mac 上最新版本的 Safari。对于 Windows,我认为 Safari 版本在 5.1.x 时停止并且仍然只触发 webkitTransitionEnd 事件。为了迎合这些浏览器,this SO thread 中提到的方法可以使用。

关于javascript - 使用 JavaScript 在循环中等待 transitionend,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32423531/

相关文章:

javascript - PHP 停止表单重新加载显示错误 Js

java - 我可以从js前端访问spring mvc存储​​的 session 变量吗

javascript - 在 react 中加载脚本

css - @font-face 的离线字体转换器

android - TextView 的多种过渡效果 (Android)

uinavigationcontroller - 在转换期间使用 popViewController 闪烁白色的问题

javascript - 从使用 map 创建的对象中获取最高值

html - 强制子 div 使用父样式

css - 谷歌浏览器无法在 3d 转换元素上应用不透明度过渡

jQuery Mobile,打开对话框