在鼠标事件上触发关键帧

huangapple go评论88阅读模式
英文:

Triggering keyframe on mouseEvent

问题

我试图在鼠标悬停事件上触发CSS动画。不幸的是,它不按预期工作。

这是我尝试过的内容。我试图在鼠标悬停时实现与CSS中的关键帧声明相同的运动。

在Firefox + Chrome(移动版)中按预期工作,但在Chrome(PC版)中不起作用。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="container" class="svg-container">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 100">
            <rect x="0" y="0" width="530" height="200" fill="#EFEFEF"></rect>
            <g class="crcl">
                <circle class="circ" cx="10" cy="50" r="10" fill="blue"></circle>
            </g>
        </svg>
    </div>
</body>

</html>
const element = document.querySelector('.circ');
element.addEventListener('mouseover', function() {
    console.log(1);
    element.style.animation = "move 1000ms infinite ease-in-out alternate";
});
element.addEventListener('mouseout', function() {
    //mouseout triggers automatically following mouseover without provocation
    console.log(2);
    element.style.animation = "none";
});
.circ {
    pointer-events: all;
}
.rect {
    pointer-events: none;
}
@keyframes move {
    0% {
        transform: translateX(0);
    }
    100% {
        transform: translateX(500px);
    }
}

希望这对你有所帮助。

英文:

I am trying to trigger a CSS animation on mouseover event. Sadly, it does not work as desired.

This is what I tried. I am trying to achieve the same motion on mouseover as the keyframe declaration within CSS would.

It works as desired in Firefox +Chrome(mobile) but not in Chrome (PC).

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const element = document.querySelector(&#39;.circ&#39;);
element.addEventListener(&#39;mouseover&#39;, function() {
console.log(1);
	element.style.animation = &quot;move 1000ms infinite ease-in-out alternate&quot;;
});
element.addEventListener(&#39;mouseout&#39;, function() {
//mouseout triggers automatically following mouseover without provocation
console.log(2); 
	element.style.animation = &quot;none&quot;;
});

<!-- language: lang-css -->

.circ {
     pointer-events: all;
}
 .rect {
     pointer-events: none;
}
 @keyframes move {
     0% {
         transform: translateX(0);
    }
     100% {
         transform: translateX(500px);
    }
}

<!-- language: lang-html -->

&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;

&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;title&gt;Document&lt;/title&gt;
&lt;/head&gt;

&lt;body&gt;
  &lt;div id=&quot;container&quot; class=&quot;svg-container&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 600 100&quot;&gt;
      &lt;rect x=&quot;0&quot; y=&quot;0&quot; width=&quot;530&quot; height=&quot;200&quot; fill=&quot;#EFEFEF&quot;&gt;&lt;/rect&gt;
      &lt;g class=&quot;crcl&quot;&gt;  
        &lt;circle class=&quot;circ&quot; cx=&quot;10&quot; cy=&quot;50&quot; r=&quot;10&quot; fill=&quot;blue&quot;&gt;&lt;/circle&gt;
      &lt;/g&gt;
    &lt;/svg&gt;
  &lt;/div&gt;

&lt;/body&gt;

&lt;/html&gt;

<!-- end snippet -->

答案1

得分: 0

以下是您要翻译的内容:

"The animation actually works but it constantly resets itself.

The problem: your attaching the event listener to the animated circle.
As this circle will start to move on mouseover it will almost immediately trigger the mouseout event.

You should probably start and stop the animation when hovering the svg or rect instead.

const svg = document.querySelector('svg');
const element = document.querySelector('.circ');
svg.addEventListener('mouseover', function() {
    element.style.animation = "move 1000ms infinite ease-in-out alternate";
});
svg.addEventListener('mouseout', function() {
//mouseout triggers automatically following mouseover without provocation
    element.style.animation = "none";
});
.circ {
     pointer-events: all;
}
.rect {
     pointer-events: none;
}
@keyframes move {
     0% {
         transform: translateX(0);
    }
     100% {
         transform: translateX(500px);
    }
}
<div id="container" class="svg-container">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 100">
      <rect x="0" y="0" width="530" height="200" fill="#EFEFEF"></rect>
      <g class="crcl">  
        <circle class="circ" cx="10" cy="50" r="10" fill="blue"></circle>
      </g>
    </svg>
</div>

Example2: start animation on hover; stop on click

const svg = document.querySelector("svg");
const circles = document.querySelectorAll(".circ");

circles.forEach((circ) => {
  circ.addEventListener("mouseover", (e) => {
    let current = e.currentTarget;
    current.classList.add("running");
  });
});

svg.addEventListener("click", function() {
  togglePlayState(circles);
});

function togglePlayState(els) {
  els.forEach((el) => {
    let style = window.getComputedStyle(el);
    if (style.animationPlayState === "running") {
      el.classList.add("paused");
      el.classList.remove("running");
    } else if (el.classList.contains('paused')) {
      el.classList.remove("paused");
      el.classList.add("running");
    }
  });
}
.circ {
  pointer-events: all;
}

.rect {}

.ani {
  animation: move 1000ms infinite ease-in-out alternate;
  animation-play-state: paused;
}

.running {
  animation-play-state: running;
}

.paused {
  animation-play-state: paused;
}

@keyframes move {
  0% {
    transform: translateX(0);
  }
  100% {
    transform: translateX(500px);
  }
}
<div id="container" class="svg-container">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 100">
      <rect x="0" y="0" width="530" height="200" fill="#EFEFEF"></rect>
      <g class="crcl">  
        <circle class="circ ani" cx="10" cy="50" r="10" fill="blue"></circle>
        <circle class="circ ani" cx="10" cy="75" r="10" fill="green"></circle>
      </g>
    </svg>
</div>
英文:

The animation actually works but it constantly resets itself.

The problem: your attaching the event listener to the animated circle.
As this circle will start to move on mouseover it will almost immediately trigger the mouseout event.

You should probably start and stop the animation when hovering the svg or rect instead.

<!-- begin snippet: js hide: false console: false babel: false -->

<!-- language: lang-js -->

const svg = document.querySelector(&#39;svg&#39;);
const element = document.querySelector(&#39;.circ&#39;);
svg.addEventListener(&#39;mouseover&#39;, function() {
    element.style.animation = &quot;move 1000ms infinite ease-in-out alternate&quot;;
});
svg.addEventListener(&#39;mouseout&#39;, function() {
//mouseout triggers automatically following mouseover without provocation
    element.style.animation = &quot;none&quot;;
});

<!-- language: lang-css -->

.circ {
     pointer-events: all;
}
 .rect {
     pointer-events: none;
}
 @keyframes move {
     0% {
         transform: translateX(0);
    }
     100% {
         transform: translateX(500px);
    }
}

<!-- language: lang-html -->

  &lt;div id=&quot;container&quot; class=&quot;svg-container&quot;&gt;
    &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 600 100&quot;&gt;
      &lt;rect x=&quot;0&quot; y=&quot;0&quot; width=&quot;530&quot; height=&quot;200&quot; fill=&quot;#EFEFEF&quot;&gt;&lt;/rect&gt;
      &lt;g class=&quot;crcl&quot;&gt;  
        &lt;circle class=&quot;circ&quot; cx=&quot;10&quot; cy=&quot;50&quot; r=&quot;10&quot; fill=&quot;blue&quot;&gt;&lt;/circle&gt;
      &lt;/g&gt;
    &lt;/svg&gt;
  &lt;/div&gt;

<!-- end snippet -->

Example2: start animation on hover; stop on click

<!-- begin snippet: js hide: true console: false babel: false -->

<!-- language: lang-js -->

const svg = document.querySelector(&quot;svg&quot;);
const circles = document.querySelectorAll(&quot;.circ&quot;);

circles.forEach((circ) =&gt; {
  circ.addEventListener(&quot;mouseover&quot;, (e) =&gt; {
    let current = e.currentTarget;
    current.classList.add(&quot;running&quot;);
    //current.style.animation = &quot;move 1000ms infinite ease-in-out alternate&quot;;
  });
});


svg.addEventListener(&quot;click&quot;, function() {
  togglePlayState(circles);
});

function togglePlayState(els) {
  els.forEach((el) =&gt; {
    let style = window.getComputedStyle(el);
    if (style.animationPlayState === &quot;running&quot;) {
      //el.style.animationPlayState = &quot;paused&quot;;
      el.classList.add(&quot;paused&quot;);
      el.classList.remove(&quot;running&quot;);

    } else if (el.classList.contains(&#39;paused&#39;)) {
      //el.style.animationPlayState = &quot;running&quot;;
      el.classList.remove(&quot;paused&quot;);
      el.classList.add(&quot;running&quot;);
    }
  });
}

<!-- language: lang-css -->

.circ {
  pointer-events: all;
}

.rect {}

.ani {
  animation: move 1000ms infinite ease-in-out alternate;
  animation-play-state: paused;
}

.running {
  animation-play-state: running;
}

.paused {
  animation-play-state: paused;
}

@keyframes move {
  0% {
    transform: translateX(0);
  }
  100% {
    transform: translateX(500px);
  }
}

<!-- language: lang-html -->

&lt;div id=&quot;container&quot; class=&quot;svg-container&quot;&gt;
  &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 600 100&quot;&gt;
      &lt;rect x=&quot;0&quot; y=&quot;0&quot; width=&quot;530&quot; height=&quot;200&quot; fill=&quot;#EFEFEF&quot;&gt;&lt;/rect&gt;
      &lt;g class=&quot;crcl&quot;&gt;  
        &lt;circle class=&quot;circ ani&quot; cx=&quot;10&quot; cy=&quot;50&quot; r=&quot;10&quot; fill=&quot;blue&quot;&gt;&lt;/circle&gt;
        &lt;circle class=&quot;circ ani&quot; cx=&quot;10&quot; cy=&quot;75&quot; r=&quot;10&quot; fill=&quot;green&quot;&gt;&lt;/circle&gt;
      &lt;/g&gt;
    &lt;/svg&gt;
&lt;/div&gt;

<!-- end snippet -->

答案2

得分: 0

以下是翻译的代码部分:

可以通过在接收keyframe元素上叠加与之完全相同的透明元素来实现所需的效果然后在叠加元素上添加监听器以对底部元素进行编程移动

例如

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->
const data = [
    [0, 0], //底部用于操作 i=0,叠加用于 i=1
    [1, 1],
    [2, 2]
];

const svg = d3.select('svg');

const grp =
    svg
    .append('g')
    .classed('all', true);

const circ = grp
    .selectAll('g')
    .data(data)
    .join('g')
    .attr('id', (_, i) => i)
    .attr('transform', (_, i) => `translate(0 ${20*(i+1)})`)
    .selectAll('circle')
    .data(function(_, i) {
        return data[i]
    })
    .join('circle')
    .attr('id', function(_, i) {
        return d3.select(this).node().parentNode.id + i
    })
    .attr('cx', (_, i) => 20)
    .attr('cy', (_, i) => 20)
    .attr('r', '5')
    .attr('fill', (_, i) => { if (i === 0) { return 'blue' } else { return 'transparent' } }); //底部蓝色,叠加透明

d3.selectAll('svg g.all g circle:nth-of-type(2)').on('mouseover', function(_, i) {
        d3.select(
                d3.select(this).node().parentElement.firstChild
            ).style('animation', 'move 1000ms infinite ease-in-out alternate')
            
    })
    .on('mouseout', function(_, i) {
        d3.select(
            d3.select(this).node().parentElement.firstChild
        ).style('animation', 'none')
    })

<!-- language: lang-css -->
#container>svg>g>g>circle:nth-child(1) {
    pointer-events: none;
}

@keyframes move {
    0% {
        transform: translateX(0);
    }
    100% {
        transform: translateX(500px);
    }
}

<!-- language: lang-html -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>
    <link rel="stylesheet" href="style.css">
    <title>Document</title>
</head>

<body>
    <div id="container" class="svg-container">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 100">
        <rect x="0" y="0" width="530" height="200" fill="#EFEFEF"></rect>
      </svg>
    </div>
</body>
<script src="prod.js"></script>

</html>

<!-- end snippet -->

请注意,我已经移除了注释部分以保持简洁。如果您需要任何特定的翻译或更多信息,请随时告诉我。

英文:

It is possible to achieve the desired effect with existing mouseover and mouseout by overlaying the exact same transparent element as the recipient keyframe element. Then add a listener on the overlaid element to program the movement on the bottom element.

Such as

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const data = [
[0, 0], //bottom for action i=0, top for overlaying i=1
[1, 1],
[2, 2]
];
const svg = d3.select(&#39;svg&#39;);
const grp =
svg
.append(&#39;g&#39;)
.classed(&#39;all&#39;, true);
const circ = grp
.selectAll(&#39;g&#39;)
.data(data)
.join(&#39;g&#39;)
.attr(&#39;id&#39;, (_, i) =&gt; i)
.attr(&#39;transform&#39;, (_, i) =&gt; `translate(0 ${20*(i+1)})`)
.selectAll(&#39;circle&#39;)
.data(function(_, i) {
return data[i]
})
.join(&#39;circle&#39;)
.attr(&#39;id&#39;, function(_, i) {
return d3.select(this).node().parentNode.id + i
})
.attr(&#39;cx&#39;, (_, i) =&gt; 20)
.attr(&#39;cy&#39;, (_, i) =&gt; 20)
.attr(&#39;r&#39;, &#39;5&#39;)
.attr(&#39;fill&#39;, (_, i) =&gt; { if (i === 0) { return &#39;blue&#39; } else { return &#39;transparent&#39; } }); //bottom blue, overlay transparent
d3.selectAll(&#39;svg g.all g circle:nth-of-type(2)&#39;).on(&#39;mouseover&#39;, function(_, i) {
d3.select(
d3.select(this).node().parentElement.firstChild
).style(&#39;animation&#39;, &#39;move 1000ms infinite ease-in-out alternate&#39;)
})
.on(&#39;mouseout&#39;, function(_, i) {
d3.select(
d3.select(this).node().parentElement.firstChild
).style(&#39;animation&#39;, &#39;none&#39;)
})

<!-- language: lang-css -->

#container&gt;svg&gt;g&gt;g&gt;circle:nth-child(1) {
pointer-events: none;
}
@keyframes move {
0% {
transform: translateX(0);
}
100% {
transform: translateX(500px);
}
}

<!-- language: lang-html -->

&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot;&gt;
&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;https://d3js.org/d3.v7.min.js&quot;&gt;&lt;/script&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&gt;
&lt;title&gt;Document&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div id=&quot;container&quot; class=&quot;svg-container&quot;&gt;
&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 600 100&quot;&gt;
&lt;rect x=&quot;0&quot; y=&quot;0&quot; width=&quot;530&quot; height=&quot;200&quot; fill=&quot;#EFEFEF&quot;&gt;&lt;/rect&gt;
&lt;/svg&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;script src=&quot;prod.js&quot;&gt;&lt;/script&gt;
&lt;/html&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年8月4日 04:50:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/76831526.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定