How to animate overflowing text to scroll to the end of the text when hovering and animate back to original position when mouse leaves?

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

How to animate overflowing text to scroll to the end of the text when hovering and animate back to original position when mouse leaves?

问题

我正在尝试在悬停在具有溢出文本的容器上时实现滚动文本的动画效果。目前,当鼠标悬停在容器上时,动画会滚动到文本的末尾,但当鼠标离开时,文本突然返回到原始位置。我希望在鼠标离开时也能实现回到原始位置的动画效果。

import { useEffect, useRef, useState } from 'react';
import classes from './test.module.css';

const Test = () => {
    const textRef = useRef(null);
    const containerRef = useRef(null);

    const [isHovered, setIsHovered] = useState(false);
    const [isOverflowing, setIsOverflowing] = useState(false);

    const onMouseEnter = () => {
        setIsHovered(true);
    };

    const onMouseLeave = () => {
        setIsHovered(false);
    };

    useEffect(() => {
        const textWidth = textRef.current.offsetWidth;
        const containerWidth = containerRef.current.offsetWidth;

        if (textWidth > containerWidth) {
            setIsOverflowing(true);
        }
    }, []);

    return (
        <div>
            <div
                ref={containerRef}
                className={classes.animated}
                onMouseEnter={onMouseEnter}
                onMouseLeave={onMouseLeave}
            >
                <h3
                    className={isHovered && isOverflowing ? classes.textAnimated : classes.text}
                    ref={textRef}
                >
                    This is some very very very long text
                </h3>
            </div>
        </div>
    );
};

export default Test;
.animated {
    margin: 200px;
    position: relative;
    white-space: nowrap;
    max-width: 300px;
    width: 100%;
    overflow: hidden;
    background: #0c0c0c;
    display: inline-block;
    position: relative;
    border: 1px solid white;
}

.textAnimated {
    color: #fff;
    animation: textScroll 3s linear forwards;
    display: inline-block;
    position: relative;
}

.text {
    color: #fff;
    display: inline-block;
    position: relative;
}

@keyframes textScroll {
    0% {
        transform: translateX(0);
        left: 0;
    }
    10% {
        transform: translateX(0);
        left: 0;
    }
    90% {
        transform: translateX(calc(-100%));
        left: 100%;
    }
    100% {
        transform: translateX(calc(-100%));
        left: 100%;
    }
}
英文:

I am trying to animate scrolling text when hovering over a container that has overflowing text. Right now I have the animation scrolling to the end of the text when hovering over the container, but when the mouse leaves, the text just suddenly goes back to original position. I want it to also animate back to original position when the mouse leaves.

import {useEffect, useRef, useState} from &#39;react&#39;;
import classes from &#39;./test.module.css&#39;;

const Test = () =&gt; {
    const textRef = useRef(null);
    const containerRef = useRef(null);

    const [isHovered, setIsHovered] = useState(false);
    const [isOverflowing, setIsOverflowing] = useState(false);

    const onMouseEnter = () =&gt; {
        setIsHovered(true);
    };

    const onMouseLeave = () =&gt; {
        setIsHovered(false);
    };

    useEffect(() =&gt; {
        const textWidth = textRef.current.offsetWidth;
        const containerWidth = containerRef.current.offsetWidth;

        if (textWidth &gt; containerWidth) {
            setIsOverflowing(true);
        }
    }, []);

    return (
        &lt;div&gt;
            &lt;div ref={containerRef} className={classes.animated} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}&gt;
                &lt;h3 className={isHovered &amp;&amp; isOverflowing ? classes.textAnimated : classes.text} ref={textRef}&gt;
                    This is some very very very long text
                &lt;/h3&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    );
};

export default Test;

.animated {
    margin: 200px;
    position: relative;
    white-space: nowrap;
    max-width: 300px;
    width: 100%;
    overflow: hidden;
    background: #0c0c0c;
    display: inline-block;
    position: relative;
    border: 1px solid white;
}

.textAnimated {
    color: #fff;
    animation: textScroll 3s linear forwards;
    display: inline-block;
    position: relative;
}

.text {
    color: #fff;
    display: inline-block;
    position: relative;
}

@keyframes textScroll {
    0% {
        transform: translateX(0);
        left: 0;
    }
    10% {
        transform: translateX(0);
        left: 0;
    }
    90% {
        transform: translateX(calc(-100%));
        left: 100%;
    }
    100% {
        transform: translateX(calc(-100%));
        left: 100%;
    }
}

答案1

得分: 0

请考虑使用 transition 而不是 animation。在悬停时,transition 对于在两个状态之间进行视觉插值非常有用,正如此处的情况一样:

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

<!-- language: lang-js -->
const { useEffect, useRef, useState } = React;

const Test = () => {
  const textRef = useRef(null);
  const containerRef = useRef(null);

  const [isOverflowing, setIsOverflowing] = useState(false);

  useEffect(() => {
    const textWidth = textRef.current.offsetWidth;
    const containerWidth = containerRef.current.offsetWidth;

    if (textWidth > containerWidth) {
      setIsOverflowing(true);
    }
  }, []);

  return (
    <div>
      <div ref={containerRef} className="animated">
        <h3 className={isOverflowing ? 'textAnimated' : 'text'} ref={textRef}>
          This is some very very very long text
        </h3>
      </div>
    </div>
  );
};

ReactDOM.createRoot(document.getElementById('app')).render(<Test/>);

<!-- language: lang-css -->
.animated {
    margin: 200px;
    position: relative;
    white-space: nowrap;
    max-width: 100px;
    width: 100%;
    overflow: hidden;
    background: #0c0c0c;
    display: inline-block;
    position: relative;
    border: 1px solid white;
}

.textAnimated {
    color: #fff;
    display: inline-block;
    position: relative;
    left: 0;
    transition: transform 3s linear, left 3s linear;
}
.animated:hover .textAnimated {
  transform: translateX(-100%);
  left: 100%;
}

.text {
    color: #fff;
    display: inline-block;
    position: relative;
}

<!-- language: lang-html -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js" integrity="sha512-8Q6Y9XnTbOE+JNvjBQwJ2H8S+UV4uA6hiRykhdtIyDYZ2TprdNmWOUaKdGzOhyr4dCyk287OejbPvwl7lrfqrQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js" integrity="sha512-MOCpqoRoisCTwJ8vQQiciZv0qcpROCidek3GTFS6KTk2+y7munJIlKCVkFCYY+p3ErYFXCjmFjnfTTRSC1OHWQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

<div id="app"></div>

<!-- end snippet -->

注意:以上代码片段中包含了HTML、JavaScript和CSS部分。如果需要进一步的翻译,请提供具体的文本或指令。

英文:

Consider using transition rather than animation. transition is useful for visual interpolation between two states, as would be the case here on hover:

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

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

const {useEffect, useRef, useState} = React;

const Test = () =&gt; {
  const textRef = useRef(null);
  const containerRef = useRef(null);

  const [isOverflowing, setIsOverflowing] = useState(false);

  useEffect(() =&gt; {
    const textWidth = textRef.current.offsetWidth;
    const containerWidth = containerRef.current.offsetWidth;

    if (textWidth &gt; containerWidth) {
      setIsOverflowing(true);
    }
  }, []);

  return (
    &lt;div&gt;
      &lt;div ref={containerRef} className=&quot;animated&quot;&gt;
        &lt;h3 className={isOverflowing ? &#39;textAnimated&#39; : &#39;text&#39;} ref={textRef}&gt;
          This is some very very very long text
         &lt;/h3&gt;
       &lt;/div&gt;
    &lt;/div&gt;
  );
};

ReactDOM.createRoot(document.getElementById(&#39;app&#39;)).render(&lt;Test/&gt;);

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

.animated {
    margin: 200px;
    position: relative;
    white-space: nowrap;
    max-width: 100px;
    width: 100%;
    overflow: hidden;
    background: #0c0c0c;
    display: inline-block;
    position: relative;
    border: 1px solid white;
}

.textAnimated {
    color: #fff;
    display: inline-block;
    position: relative;
    left: 0;
    transition: transform 3s linear, left 3s linear;
}
.animated:hover .textAnimated {
  transform: translateX(-100%);
  left: 100%;
}

.text {
    color: #fff;
    display: inline-block;
    position: relative;
}

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

&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js&quot; integrity=&quot;sha512-8Q6Y9XnTbOE+JNvjBQwJ2H8S+UV4uA6hiRykhdtIyDYZ2TprdNmWOUaKdGzOhyr4dCyk287OejbPvwl7lrfqrQ==&quot; crossorigin=&quot;anonymous&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js&quot; integrity=&quot;sha512-MOCpqoRoisCTwJ8vQQiciZv0qcpROCidek3GTFS6KTk2+y7munJIlKCVkFCYY+p3ErYFXCjmFjnfTTRSC1OHWQ==&quot; crossorigin=&quot;anonymous&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/script&gt;

&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年6月29日 08:05:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/76577371.html
匿名

发表评论

匿名网友

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

确定