悬停时滚动 link 文本 - 无尽的选取框效果

Scrolling link text on hover - endless marquee effect

我正在为 link 寻找一种高效且流畅的解决方案,它可以像字幕效果一样在内联块框内滚动文本。

 $(document).ready(function() {
    
    function scroll(ele){
     var s = $(ele).text().substr(1)+$(ele).text().substr(0,1);
     $(ele).text(s);
    }

    scrollInterval = null;
    function startScrolling(e) {
        if (!scrollInterval) {
            scrollInterval = setInterval(function(){
                scroll(e)
            },100);
        }
    }

    function stopScrolling(e) {
        clearInterval(scrollInterval);
        scrollInterval = null;
    }

    $(".mali").hover(function(){
        startScrolling($(this));
    });

    $(".mali").mouseout(function(){
        stopScrolling($(this));
    });

    $(".mali").mousedown(function(){
        stopScrolling($(this));
    });

  });
.mali {
        display: inline-block;
        background: black;
        color: white;
        padding: 10px;  
      }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Something <a href="#" class="mali">something&nbsp;darkside</a>, Something something complete.

到目前为止,我的解决方案实际上是在另一个线程的 stackoverlow 上找到的,并尝试使用它。

不过有两个问题。

1.) 由于这基本上是使用间隔循环遍历单个字母,因此效果不是很流畅。效果是口吃。

有没有人知道如何让它更流畅?也许在那种情况下根本不要使用这种方法,而可能使用 CSS 过渡来为文本设置动画?

2.) 有没有人有关于如何在我悬停后 return 到初始状态的巧妙解决方案?我想要悬停时的效果,但是当将鼠标从 link 移开时,它应该动画回到初始文本状态。

谢谢, 马特

2) 您可以保存初始状态,然后再还原它:

$(document).ready(function() {
    
    function scroll(ele){
     var s = $(ele).text().substr(1)+$(ele).text().substr(0,1);
     $(ele).text(s);
    }

    scrollInterval = null;
    function startScrolling(e) {
        if (!scrollInterval) {
            $(e).data("text", $(e).text());
            scrollInterval = setInterval(function(){
                scroll(e)
            },100);
        }
    }

    function stopScrolling(e) {
        clearInterval(scrollInterval);
        scrollInterval = null;
        $(e).text($(e).data("text"));
    }

    $(".mali").hover(function(){
        startScrolling($(this));
    });

    $(".mali").mouseout(function(){
        stopScrolling($(this));
    });

    $(".mali").mousedown(function(){
        stopScrolling($(this));
    });

  });
.mali {
        display: inline-block;
        background: black;
        color: white;
        padding: 10px;  
        transition: all .2s;
      }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Something <a href="#" class="mali">something&nbsp;darkside</a>, Something something complete.

1) 作为一个流畅的动画,我认为这是一个 PoC。也许它会帮助你进一步的想法。

$(document).ready(function() {
    // Those global data could be stored in element's data.
    var indent = 0,
        width = 0,
        padding = 10;
    function scroll(ele){
      // Every iteration decrease indent by value
      indent -= 1;
      
      // If is indent greater than or equal than real width
      // (width with padding) reset indent.
      if(-indent >= width+padding)
        indent = 0;
       
       // Aplly property
      $(ele).css("text-indent", indent);
    }

    var scrollInterval = null;
    function startScrolling(e) {
        if (!scrollInterval) {
            // Get text and real width
            let text = $(e).text();
            width = $(e).width()
          
            $(e)
              // Set real width & height, so that container stays
              .width($(e).width())
              .height($(e).height())
              
              // Save text to data for reset
              .data("text", text)
              
              // Add 2 spans with text:
              // <span>text</span><span>text</span>
              // Where second span has defined padding on the left
              .html($("<span>").text(text))
              .append($("<span>").text(text).css("padding-left", padding+"px"));
             
           resumeScrolling(e);
        }
    }

    function stopScrolling(e) {
        pauseScrolling(e);
        
        // Reset
        $(e)
          // Revert real text and reset indent
          .text($(e).data("text"))
          .css("text-indent", indent = 0);
    }

    function pauseScrolling(e) {
        clearInterval(scrollInterval);
        scrollInterval = null;
    }

    function resumeScrolling(e) {
        if (!scrollInterval) {
          // Every 30ms repeat animation. It must be at least 25x per second
          // so it runs smoothly. (So 1 - 40).
          scrollInterval = setInterval(function(){
            scroll(e)
          },30);
       }
    }

    $(".mali").hover(function(){
        startScrolling($(this));
    });

    $(".mali").mouseout(function(){
        stopScrolling($(this));
    });

    $(".mali").mousedown(function(){
        stopScrolling($(this));
    });

    $("#start").click(function(){
      startScrolling($(".mali"));
    });
    $("#stop").click(function(){
      stopScrolling($(".mali"));
    });
    $("#pause").click(function(){
      pauseScrolling($(".mali"));
    });
    $("#resume").click(function(){
      resumeScrolling($(".mali"));
    });

  });
.mali {
  display: inline-block;
  background: black;
  color: white;
  padding: 10px;
  /*
  This could help, but you can't reset text-indent without animation.
  transition: all .1s;
  */
  overflow: hidden;
  vertical-align: middle;
}

/* When you hover element, new span elements
can't take pointer events, so your elements
stays hovered. */
.mali span {
  pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Something <a href="#" class="mali">something&nbsp;darkside</a>, Something something complete.

<br><br>
<button id="start">Start</button>
<button id="stop">Stop</button>
<button id="pause">Pause</button>
<button id="resume">Resume</button>

背后的想法是:

  • 创建元素 overflow:hidden; 这样文本就不会溢出
  • 设置固定维度
  • 里面有重复的文字
  • 每 x 毫秒更改一次文本缩进(x < 40 以便平滑,必须至少为 25fps)
  • 当它溢出时,重置它,这样它就可以无限循环