文本淡化效果与Animate.css - 无法解释的行为

时间:2017-08-14 22:46:47

标签: javascript css

目标是在div标签中显示一些文本(html),对其他元素触发的鼠标过/关事件具有淡入/淡出效果。 我使用了Animate.css解决方案并遇到了很多问题,特别是当元素快速连续盘旋时。 当我尝试构建一个更简单的模型时,不使用jQuery,与原始解决方案不同,代码行为的一部分对我来说是莫名其妙的 - 请参阅下面的示例。它按预期工作,但如果省略以下行document.getElementById("info").innerHTML="animate.css has ended; was triggered by "+e.target.id+" on "+e.type+" event.";,则无法识别触发动画功能的事件,并且文本隐藏在mouseOver上。由于将元素的innerHTML更改为我的理解与animationend事件无关,希望有人可以解释此代码行为。

// (e), event is used to differentiate between mouseOver and mouseOut
function animate(e){
	// start mesage
	document.getElementById("info").innerHTML=e.target.id+" fired "+e.type+"; animate.css is starting...";
	// setting animation type based on the triggering event
	var animation = "animated fadeIn";
	if (e.type=="mouseout"){
	animation = "animated fadeOut";
	}
	// triggering animation by applying the animation classes
	document.getElementById("info").setAttribute("class", animation);
	// setting animation end callback
	this.addEventListener("animationend", function(){
	// end message. If the line below is commented, the message is deleted regardless of the event that fired it (it is expected to be deleted on mouseOut only)
	document.getElementById("info").innerHTML="animate.css has ended; was triggered by "+e.target.id+" on "+e.type+" event.";
	// removing (regenerating) the animation classes		
	document.getElementById("info").removeAttribute("class");
	// deletes the message on mouseOut	
	if (e.type=="mouseout"){
	document.getElementById("info").innerHTML="null";
	}
	});
}	

// all svg path elements will trigger the animate(event) function on mouseOver and mouseOut
var petals = document.querySelectorAll("path");
for(i=0;i<petals.length; i++){
//changes the default mouse cursor into a hand
petals[i].style="cursor: pointer;";
//mouseOver
petals[i].addEventListener("mouseover", function (event){
animate(event);
});
//mouseOut
petals[i].addEventListener("mouseout", function (event){
animate(event);
});
}
<style>
html, body {
	height: 100%;
	margin: 0px;
}
#info {
	height: 15%;
	/*	background-color: darkgreen;
	color: gainsboro;*/
	font-family: monospace;
	font-size: 5.5vh;
	padding: 2%;
}
/* animate.css: */
.animated {
	animation-duration: 2s;
	animation-fill-mode: both;
}
.animated.fadeOut {
	animation-duration: 3s;
}
 @keyframes fadeOut {
 from {
 opacity: 1;
}
 to {
 opacity: 0;
}
}
.fadeOut {
	animation-name: fadeOut;
}
 @keyframes fadeIn {
 from {
 opacity: 0;
}
 to {
 opacity: 1;
}
}
.fadeIn {
	animation-name: fadeIn;
}
</style>
<div id="info"> info </div>
<div style="height: 70%; background-color:papayawhip; padding: 1.5%;">
	<svg width="100%" height="100%" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
	 viewBox="0 0 318.3 258.1" style="enable-background:new 0 0 318.3 258.1;" xml:space="preserve">
		<style type="text/css">
.darkred{
fill: darkred;
stroke-width: 1;
}
.darkred:hover{
fill: red;
stroke: black;
}
.red{
fill: red;
}
.red:hover {
fill: orange;
stroke: black;
}
.orange{
fill: orange;
}
.orange:hover {
fill: yellow;
stroke: black;
}

</style>
		<path id="petal-1" class="darkred" d="M159.1,1c53.3,42.7,53.3,85.3,0,128V1z"/>
		<path id="petal-2" class="orange" d="M213.8,8.8c31.9,54.7,13.6,94.8-54.7,120.3L213.8,8.8z"/>
		<path id="petal-3" class="red" d="M262,31c6.6,60.1-27.7,92.8-102.8,98.1L262,31z"/>
		<path id="petal-4" class="darkred" d="M297.7,65c-19.5,58.3-65.7,79.6-138.6,64L297.7,65z"/>
		<path id="petal-5" class="orange" d="M316.7,106.8c-43.3,49.4-95.8,56.8-157.6,22.2L316.7,106.8z"/>
		<path id="petal-6" class="red" d="M316.7,151.3c-61.8,34.6-114.3,27.2-157.6-22.2L316.7,151.3z"/>
		<path id="petal-7" class="darkred" d="M297.7,193c-72.9,15.6-119-5.7-138.6-64L297.7,193z"/>
		<path id="petal-8" class="orange" d="M262,227.1c-75.1-5.3-109.4-37.9-102.8-98.1L262,227.1z"/>
		<path id="petal-9" class="red" d="M213.8,249.3c-68.4-25.5-86.6-65.6-54.7-120.3L213.8,249.3z"/>
		<path id="petal-10" class="darkred" d="M159.1,257c-53.3-42.7-53.3-85.3,0-128V257z"/>
		<path id="petal-11" class="orange" d="M104.4,249.3c-31.9-54.7-13.6-94.8,54.7-120.3L104.4,249.3z"/>
		<path id="petal-12" class="red" d="M56.3,227.1C49.7,167,84,134.3,159.1,129L56.3,227.1z"/>
		<path id="petal-13" class="darkred" d="M20.5,193c19.5-58.3,65.7-79.6,138.6-64L20.5,193z"/>
		<path id="petal-14" class="orange" d="M1.5,151.3c43.3-49.4,95.8-56.8,157.6-22.2L1.5,151.3z"/>
		<path id="petal-15" class="red" d="M1.5,106.8C63.3,72.2,115.8,79.6,159.1,129L1.5,106.8z"/>
		<path id="petal-16" class="darkred" d="M20.5,65c72.9-15.6,119,5.7,138.6,64L20.5,65z"/>
		<path id="petal-17" class="orange" d="M56.3,31c75.1,5.3,109.4,37.9,102.8,98.1L56.3,31z"/>
		<path id="petal-18" class="red" d="M104.4,8.8C172.7,34.3,191,74.4,159.1,129L104.4,8.8z"/>
	</svg>
</div>

2 个答案:

答案 0 :(得分:1)

您正在观察的行为不是由未被识别的事件引起的,而是由于回调函数的执行顺序。

让我试着解释一下......

当你注释掉document.getElementById("info").innerHTML="animate.css has ended; was triggered by "+e.target.id+" on "+e.type+" event.";行时,这就是你得到的:

设置

对于每个mouseovermouseout事件,您都在调用两个函数:

  1. animate(e),在div中显示一些文字,然后启动动画。
  2. 匿名function()animationend上执行,会检查e.type == 'mouseout'。如果是,它会将div中的文本更改为&#39; null&#39;否则,它将不会更改文本。 (如果你注释掉上面提到的那一行。)
  3. 然而,这很重要,第一个函数在触发事件时立即调用,第二个函数是仅在动画结束后调用的回调函数。

    快速连续地悬停在元素上

    当你将鼠标悬停在花瓣A上并快速跳到花瓣B时,你可能没有意识到,但实际上发生了三个事件:

    1. 花瓣A上发生mouseover事件
    2. 花瓣A上发生mouseout事件
    3. 花瓣B上发生mouseovoer事件
    4. 这些事件中的每一个都将最终调用两个函数,但是,因为第二个函数仅在动画完成后调用,所以函数按以下顺序执行:

      1. mouseover(花瓣A)致电animate(e)
      2. mouseout(花瓣A)致电aminate(e)
      3. mouseover(花瓣B)致电animate(e)
      4. 来自animationend(花瓣A)的
      5. mouseover致电匿名function()
      6. 来自animationend(花瓣A)的
      7. mouseout致电匿名function()
      8. 来自animationend(花瓣B)的
      9. mouseover致电匿名function()
      10. 让我们来看看这会如何影响div中的文字:

        • 步骤1-3 ,div会显示事件目标ID,事件类型,并且&#39; animate.css正在开始......&#39;。

        • 第4步 div中的任何内容都不会更改,因为事件类型为mouseover。 div将继续显示事件目标ID,事件类型,并且&#39; animate.css正在按预期开始......&#39;

        • 步骤5 ,div中的文字将更改为&#39; null&#39;,因为动画是由mouseout事件触发的。

        • 第6步时,div中的任何内容都不会更改,因为事件类型为mouseover。因此div将继续显示&#39; null&#39; ...

        概念证明

        为了证明这一点,您可以将事件目标ID添加到文本中,并且您将看到它是前一个导致&#39; null&#39;要显示,而不是你正在盘旋的花瓣。或者,如果if {} else {}不等于animationend,请使用e.type更改mouseout上div中的文字,并且您会发现这里没有混淆它是哪个事件。

        if (e.type=="mouseout"){
            document.getElementById("info").innerHTML="null " + e.target.id;
        } else {
            document.getElementById("info").innerHTML="This is the animationend of a " + e.type + " event";
        } 
        

        重要提示:

        除非您明确删除,否则不会删除添加到DOM的事件侦听器,或者使用once: true选项添加它。

        由于您要在每个animationendmouseover事件中添加一个事件监听器来监听mouseout,而不会将其删除,因此您最终将会触发数十个触发该事件的事件监听器animationend上的回调函数。

        通过将once: true选项添加为addEventListener()的参数,可以轻松解决此问题。一旦调用回调函数,这将自动删除侦听器。

        function animate(e){
        
            document.getElementById("info").innerHTML=e.target.id+" fired "+e.type+"; animate.css is starting...";
        
            var animation = "animated fadeIn";
            if (e.type=="mouseout"){
                animation = "animated fadeOut";
            }       
            document.getElementById("info").setAttribute("class", animation);
        
            this.addEventListener("animationend", function() {                  
                document.getElementById("info").removeAttribute("class");
        
                if (e.type=="mouseout"){
                    document.getElementById("info").innerHTML="null ";
                }
        
            }, {once: true}); // Add this option to automatically remove event listener once invoked
        }
        

答案 1 :(得分:0)

Chava G,非常感谢您抽出宝贵时间并详细分析代码的实施方式。在绞尽脑汁之后,我想我有了这个主意......

我知道addEventListener方法的“once”选项,但不知道如何实现它。我不知道相同的事件监听器被附加而不是替换,这解释了性能问题和开发人员工具中的一些代码重复消息,我不知道如何解决。除了this.addEventListener(“animationend”,function())之外,这似乎引用了窗口对象......

如何将animationend事件仅附加到info div而不是尝试删除它?顺便说一下,如果交替动画具有不同的名称,例如animationIn和animationOut,不需要清除动画类的animationend事件,如下面的项目版本所示。然而,在Firefox中,鼠标悬停动画在悬停在多个元素上时仅应用一次,而在IE中,每个元素都是动画的。这是一个特定于浏览器的问题,还是我的编码又出现了问题?

// (e), event is used to differentiate between mouseOver and mouseOut
function animate(e){
	
	// start mesage
	document.getElementById("info").innerHTML=e.target.id+" fired "+e.type+"; animate.css is starting...";
	// setting animation type based on the triggering event
	var animation = "animated ";
	if (e.type=="mouseout"){
	animation += animationOut;
	}
	else{
	animation += animationIn;	
	}
	// triggering animation by applying the animation classes
	document.getElementById("info").setAttribute("class", animation);

}
	
// all svg path elements will trigger the animate(event) function on mouseOver and mouseOut
var petals = document.querySelectorAll("path");
for(i=0;i<petals.length; i++){
//changes the default mouse cursor into a hand
petals[i].setAttribute("style", "cursor: pointer;");
//mouseOver
petals[i].addEventListener("mouseover", function (event){
animate(event);
});
//mouseOut
petals[i].addEventListener("mouseout", function (event){
animate(event);
});
}
html, body {
	font-family: monospace;
	height: 100%;
	margin: 0px;
}
#container-info {
	position: relative;
	overflow: hidden;
}
#info {
	height: 10%;
	/*	background-color: darkgreen;
	color: gainsboro;*/
	font-size: 5.5vmin;
	padding: 2%;
}
#blossom {
	height: 65%;
	background-color: papayawhip;
	padding: 1.5%;
}
.transitions-menu {
	display: inline-block;
	padding: 0.5%;
	background-color: papayawhip;
	font-size: 2vw;
	color: darkred;
	border: 1px solid darkred;
}
select {
	background-color: BurlyWood;
	font-family: monospace;
	font-size: 1em;
	color: darkred;
}
<link rel="stylesheet"
  href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css">
<div class="transitions-menu">animationIn =
	<select onchange = "animationIn = this.value; animationOut = animationIn.replace(/In/i, 'Out'); document.getElementsByName('out')[0].selectedIndex = this.selectedIndex;">
<script type="text/javascript">  
var animationIn = "fadeIn"; 
animations = [
"bounceIn",
"bounceInDown",
"bounceInLeft",
"bounceInRight",
"bounceInUp",
"fadeIn",
"fadeInDown",
"fadeInDownBig",
"fadeInLeft",
"fadeInLeftBig",
"fadeInRight",
"fadeInRightBig",
"fadeInUp",
"fadeInUpBig",
"flipInX",
"flipInY",
"lightSpeedIn",
"rollIn",
"rotateIn",
"rotateInDownLeft",
"rotateInDownRight",
"rotateInUpLeft",
"rotateInUpRight",
"slideInDown",
"slideInLeft",
"slideInRight",
"slideInUp",
"zoomIn",
"zoomInDown",
"zoomInLeft",
"zoomInRight",
"zoomInUp",
//////////////////////////////////////		
"bounce",
"flash",
"headShake",
"hinge",
// has no Out equivalent "jackInTheBox",
"jello",
"pulse",
"rubberBand",
"shake",
"swing",
"tada",
"wobble"
];
for (i=0; i<animations.length;i++){
	if (animations[i] != animationIn){
	document.write('<option value="' + animations[i]+ '">' + animations[i]+ '</option>\n');
	}
	else {
	document.write('<option value="' + animations[i]+ '" selected>' + animations[i]+ '</option>\n');	
	}
}
</script>
</select>
</div>
<div class="transitions-menu">animationOut =
<select name="out" onchange = "animationOut = this.value">
<script type="text/javascript">  
//	var animationOut = "fadeOutRight"; 
var animationOut = animationIn.replace(/In/, "Out");

for (i=0; i<animations.length;i++){
var optName = animations[i].replace(/In/, "Out");	
	if (animations[i] != animationIn){
	document.write('<option value="' + optName + '">' + optName + '</option>\n');
	}
	else {
	document.write('<option value="' + optName + '" selected>' + optName + '</option>\n');	
	}
}
</script>
</select>
</div>

<div id="container-info">
	<div id="info"> info </div>
</div>

<div id="blossom">
	<svg width="100%" height="100%" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
	 viewBox="0 0 318.3 258.1" style="enable-background:new 0 0 318.3 258.1;" xml:space="preserve">
		<style type="text/css">
.darkred{
fill: darkred;
stroke-width: 1;
}
.darkred:hover{
fill: red;
stroke: black;
}
.red{
fill: red;
}
.red:hover {
fill: orange;
stroke: black;
}
.orange{
fill: orange;
}
.orange:hover {
fill: yellow;
stroke: black;
}

</style>
		<path id="petal-1" class="darkred" d="M159.1,1c53.3,42.7,53.3,85.3,0,128V1z"/>
		<path id="petal-2" class="orange" d="M213.8,8.8c31.9,54.7,13.6,94.8-54.7,120.3L213.8,8.8z"/>
		<path id="petal-3" class="red" d="M262,31c6.6,60.1-27.7,92.8-102.8,98.1L262,31z"/>
		<path id="petal-4" class="darkred" d="M297.7,65c-19.5,58.3-65.7,79.6-138.6,64L297.7,65z"/>
		<path id="petal-5" class="orange" d="M316.7,106.8c-43.3,49.4-95.8,56.8-157.6,22.2L316.7,106.8z"/>
		<path id="petal-6" class="red" d="M316.7,151.3c-61.8,34.6-114.3,27.2-157.6-22.2L316.7,151.3z"/>
		<path id="petal-7" class="darkred" d="M297.7,193c-72.9,15.6-119-5.7-138.6-64L297.7,193z"/>
		<path id="petal-8" class="orange" d="M262,227.1c-75.1-5.3-109.4-37.9-102.8-98.1L262,227.1z"/>
		<path id="petal-9" class="red" d="M213.8,249.3c-68.4-25.5-86.6-65.6-54.7-120.3L213.8,249.3z"/>
		<path id="petal-10" class="darkred" d="M159.1,257c-53.3-42.7-53.3-85.3,0-128V257z"/>
		<path id="petal-11" class="orange" d="M104.4,249.3c-31.9-54.7-13.6-94.8,54.7-120.3L104.4,249.3z"/>
		<path id="petal-12" class="red" d="M56.3,227.1C49.7,167,84,134.3,159.1,129L56.3,227.1z"/>
		<path id="petal-13" class="darkred" d="M20.5,193c19.5-58.3,65.7-79.6,138.6-64L20.5,193z"/>
		<path id="petal-14" class="orange" d="M1.5,151.3c43.3-49.4,95.8-56.8,157.6-22.2L1.5,151.3z"/>
		<path id="petal-15" class="red" d="M1.5,106.8C63.3,72.2,115.8,79.6,159.1,129L1.5,106.8z"/>
		<path id="petal-16" class="darkred" d="M20.5,65c72.9-15.6,119,5.7,138.6,64L20.5,65z"/>
		<path id="petal-17" class="orange" d="M56.3,31c75.1,5.3,109.4,37.9,102.8,98.1L56.3,31z"/>
		<path id="petal-18" class="red" d="M104.4,8.8C172.7,34.3,191,74.4,159.1,129L104.4,8.8z"/>
	</svg>
</div>