草庐IT

javascript - 具有有限元素的列表轮换

coder 2023-08-01 原文

我有 div container里面有列表(卡片)。当我将它悬停时,卡片开始移动(translateX animation)。 containerwidth300px , 元素计入 container:3 , 每个元素 width:100px .

所以你可以一起看到容器中的 3 个元素 overflow:hidden .我想做什么?,是当没有元素显示时 translateX 动画 -100px = 100px 第三个元素后的空格,它从列表中的 1 个元素开始,紧随其后,没有空格。

目前,我不知道如何在没有重复等的情况下完成它。

这是我目前所拥有的:
Fiddle (悬停卡片看翻译动画)

更新 1:
以代码和数据(卡片数量,容器大小)为例,我将尝试更好地解释我想要的内容:我的目标是建立卡片列表,按下按钮后,列表将开始移动(如示例使用 translateX 动画)一段时间(例如 translateX: 12491px ,动画持续时间: 15s ;)然后停止。但问题是列表中的 crad 数量将在 3-40 张卡片的范围内(每张卡片的宽度和高度为 100 像素)。所以,当我设置 translateX: 12491像素例如,它将超出范围,并且在列表中的最后一张卡片之后会出现空白。我希望第一张和最后一张卡以某种方式绑定(bind),并且在最后一张卡立即出现在列表中的第一张卡等之后。也许我正在以错误的方式寻找解决方案,但我想你理解主要思想。

更新 2:
我发现 cs:go 使用了我想在 html\css\js 上编写的动画。这是视频:youtube.com

html:

<div class="container">
    <div class="cards">
        <div class="card">
        1
    </div>
    <div class="card">
        2
    </div>
    <div class="card">
        3
    </div>
    </div>
</div>

CSS:
.container
{
    width:300px;
        height: 100px;
    border: 2px solid black;
    overflow: hidden;
}
.card
{
    float:left;
    height: 100px;
    width: 100px;
    background-color:blue;
    box-sizing: border-box;
    border: 2px solid red;
    color: white;
    font-size: 23px;
}
.cards:hover
{
    transform: translateX(-100px);
    transition-duration: 3s;
    animation-duration: 3s;
    animation-fill-mode: forwards;
}

最佳答案

start from 1 elements in the list immediately after last, with no blank space



这超出了 CSS,您将需要 Javascript。因为,您使用 Javascript 而不是 jQuery 标记了问题,所以我的回答仅限于纯 Javascript。看,没有 JQuery ;)

I have no idea how it could be done without duplicates



这是一个 DIY(自己动手)的想法。
  • 主要技巧是显示至少比您拥有的总数少一项。如果您有 3 张卡片,则只显示 2 张。如果您有 4 张卡片,则仅显示 3 张。为什么,因为您需要在卡片消失时重新定位并在最后将其包裹回去。如果您展示的卡片数量与您所拥有的卡片数量完全相同,那么您将无法打破半张卡片并将其包装起来,您将看到一些空白区域,直到第一张卡片消失为止。你明白吗?
  • 不要使用 translate否则您最终会在编写脚本时为自己复杂化。保持简单。
  • 不要为您的卡片使用 wrapper 。为什么?因为,我们将重新定位已经消失的卡片。当我们这样做时,下一张卡片将占据它的位置并立即消失,让您的事情变得更加困难。
  • 为简单起见,请使用 absolute 排列您的卡片相对于其容器的定位。首先,让所有卡片堆叠在 top:0; and left: 0; .
  • 接下来连接 Javascript 以定位 left属性基于 width每张卡片并线性排列。
  • 使用requestAnimationFrame来控制动画。
  • 跟踪最左边的卡片及其left位置。当它消失时(即 0 减去宽度),appendChild这张卡到它的容器中。这会将卡片移动到卡片的末尾。此外,更改 left属性基于列表中的最后一张卡片。
  • 这就是它的全部。

  • 下面是一个演示。为了方便您进行实验,我使用了一个设置对象来保留您可以轻松调整和查看的可配置属性。仔细看代码,你会发现它很容易理解。您可以设置iterations设置为 0使动画无限。

    另外,请注意,您不需要复制或伪造卡片。尝试演示并添加任意数量的卡片。

    片段中的内联代码注释将进一步帮助您理解每一行代码并与上述步骤相关。

    片段:

    var list = document.querySelector('.cardList'), // cache the container
        cards = document.querySelectorAll('.card'), // cache the list of cards
        start = document.getElementById('start'),   // buttons
        stop = document.getElementById('stop'), 
        reset = document.getElementById('reset'), 
        raf, init = 0, counter = 0, lastCard, currentIteration = 0, // general purpose variables
        settings = { // settings object to help make things configurable
            'width': 100, 'height': 100, 'speed': 2, 
            'iterations': 2, 'count': cards.length 
        }
    ;
    start.addEventListener('click', startClick); // wire up click event on buttons
    stop.addEventListener('click', stopClick);
    reset.addEventListener('click', resetClick);
    initialize(); // initialize to arrange the cards at start
    
    function initialize() {
        // loop thru all cards and set the left property as per width and index position
        [].forEach.call(cards, function(elem, idx) { 
            elem.style.left = (settings.width * idx) + 'px';
        }); 
        init = -(settings.width); // initialize the view cutoff
        lastCard = cards[settings.count - 1]; // identify the last card
        counter = 0; currentIteration = 0; // reset some counters
        settings.speed = +(document.getElementById('speed').value);
        settings.iterations = +(document.getElementById('iter').value);
    }
    function startClick() { 
        initialize(); raf = window.requestAnimationFrame(keyframes); // start animating
    }
    function stopClick() { window.cancelAnimationFrame(raf); } // stop animating
    function resetClick() { // stop animating and re-initialize cards to start again
        window.cancelAnimationFrame(raf); 
        document.getElementById('speed').value = '2';
        document.getElementById('iter').value = '2';
        initialize(); 
    }
    
    // actual animation function
    function keyframes() {
        var currentCard, currentLeft = 0, newLeft = 0;
        // iterate all cards and decrease the left property based on speed
        [].forEach.call(cards, function(elem, idx) {
            elem.style.left = (parseInt(elem.style.left) - settings.speed) + 'px';
        }); 
        currentCard = cards[counter]; // identify left-most card
        currentLeft = parseInt(currentCard.style.left); // get its left position
        if (currentLeft <= init) { // check if it has gone out of view
            // calculate position of last card
            newLeft = parseInt(lastCard.style.left) + settings.width;
            list.appendChild(currentCard); // move the card to end of list
            currentCard.style.left = newLeft + 'px'; // change left position based on last card
            lastCard = currentCard; // set this as the last card for next iteration
            counter = (counter + 1) % settings.count; // set the next card index
            if ((settings.iterations > 0) && (counter >= (settings.count - 1))) { 
                currentIteration++; // check settings for repeat iterations
            }
        }
        if (currentIteration >= settings.iterations) { return; } // when to stop
        raf = window.requestAnimationFrame(keyframes); // request another animation frame
    };
    * { box-sizing: border-box; padding: 0; margin: 0; }
    .cardList { 
        position: relative; height: 100px; width: 300px; 
        margin: 10px; border: 2px solid #33e; 
        overflow: hidden; white-space: nowrap; 
    }
    .card { 
        position: absolute; left: 0; top: 0; text-align: center;
        height: 100px; width: 100px; line-height: 100px;
        background-color: #99e; 
        font-family: monospace; font-size: 2em; color: #444;
        border-left: 1px solid #33e; border-right: 1px solid #33e;
    }
    
    div.controls, button { margin: 10px; padding: 8px; font-family: monospace; }
    div.controls input { width: 48px; padding: 2px; text-align: center; font-family: monospace; }
    <div class="controls">
        <label>Speed <input id="speed" type="number" min="1" max="8" value="2" />x</label>
        &nbsp;|&nbsp;
        <label>Iterations <input id="iter" type="number" min="0" max="8" value="2" /></label>
    </div>
    <div class="cardList">
        <div class="card">1</div>
        <div class="card">2</div>
        <div class="card">3</div>
        <div class="card">4</div>
    </div>
    <button id="start">Start</button>
    <button id="stop">Stop</button>
    <button id="reset">Reset</button>


    fiddle :http://jsfiddle.net/abhitalks/1hkw1v0w/

    注:我在演示中遗漏了一些东西。特别是,虽然卡片的宽度和高度是设置对象的一部分,但目前它是固定的。您可以轻松地使用设置对象来使卡片的尺寸也可配置。

    编辑:

    (根据 Op 的评论)

    如果您想更好地控制滚动距离、持续时间和计时功能(缓动),那么您可以使用库自己实现这些功能。 Robert Penner's Easing Functions 是几个这样好的库。和 a jQuery plugin from GSGD .尽管您可以使用纯 Javascript 实现所有这些,但如果您使用像 jQuery 这样的库会更容易。

    这里要注意的是,为了有效地做到这一点,您必须复制卡片。您可以通过多次克隆整个列表来轻松做到这一点。

    虽然您没有用 jQuery 标记这个问题,但这里有一个小演示(使用 jQuery 快速完成),您可以在其中配置速度和距离。

    片段 2:

    var $cardList 	= $('.cardList').first(), 
        $cards 		= $('.card'), 
        $speed 		= $('input[name=speed]'), 
        width 		= 100, 
        randomize 	= true, 
        distance 	= 20 * width 
    ;
    
    for (var i = 0; i < 50; i++) {
        $cards.clone().appendTo($cardList);
    }
    
    function spin() {
        var newMargin = 0, newDistance = distance, 
            speed = +($speed.filter(':checked').val());
        if (randomize) {
            newDistance = Math.floor(Math.random() * $cards.length * 5);
    		newDistance += $cards.length * 5;
            newDistance *= width;
        } 
    	newMargin = -(newDistance);
        $cards.first().animate({
            marginLeft: newMargin
        }, speed);
    }
    
    $('#spin').click(function() {
        $cards.first().css('margin-left', 0);
        spin();
        return false;
    });
    * { box-sizing: border-box; padding: 0; margin: 0; }
    .cardList { 
        height: 100px; width: 302px; position: relative;
        margin: 10px; border: 1px solid #33e; 
        overflow: hidden; white-space: nowrap; 
    }
    .card { 
        display: inline-block; text-align: center;
        height: 100px; width: 100px; line-height: 100px;
        background-color: #99e; 
        font-family: monospace; font-size: 2em; color: #444;
        border-left: 1px solid #33e; border-right: 1px solid #33e;
    }
    .cardList::before, .cardList::after {
        content: ''; display: block; z-index: 100;
        width: 0px; height: 0px; transform: translateX(-50%);
    	border-left: 8px solid transparent;
    	border-right: 8px solid transparent;    
    }
    .cardList::before {
        position: absolute; top: 0px; left: 50%;
    	border-top: 12px solid #33e;
    }
    .cardList::after {
        position: absolute; bottom: 0px; left: 50%;
    	border-bottom: 12px solid #33e;
    }
    div.controls, button { margin: 10px; padding: 8px; font-family: monospace; }
    div.controls input { width: 48px; padding: 2px; text-align: center; font-family: monospace; }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div class="controls">
        <label>Speed: </label>
        &nbsp;|&nbsp;
        <label><input name="speed" type="radio" value='6000' />Slow</label>
        <label><input name="speed" type="radio" value='5000' checked />Medium</label>
        <label><input name="speed" type="radio" value='3000' />Fast</label>
    </div>
    <div class="cardList"><!--
        --><div class="card">1</div><!--
        --><div class="card">2</div><!--
        --><div class="card">3</div><!--
        --><div class="card">4</div><!--
    --></div>
    <button id="spin">Spin</button>


    fiddle 2:http://jsfiddle.net/abhitalks/c50upco5/

    关于javascript - 具有有限元素的列表轮换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33412192/

    有关javascript - 具有有限元素的列表轮换的更多相关文章

    1. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

      我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

    2. ruby - RVM 使用列表[0] - 2

      是否有类似“RVMuse1”或“RVMuselist[0]”之类的内容而不是键入整个版本号。在任何时候,我们都会看到一个可能包含5个或更多ruby的列表,我们可以轻松地键入一个数字而不是X.X.X。这也有助于rvmgemset。 最佳答案 这在RVM2.0中是可能的=>https://docs.google.com/document/d/1xW9GeEpLOWPcddDg_hOPvK4oeLxJmU3Q5FiCNT7nTAc/edit?usp=sharing-知道链接的任何人都可以发表评论

    3. ruby-on-rails - Rails 3.1 中具有相同形式的多个模型? - 2

      我正在使用Rails3.1并在一个论坛上工作。我有一个名为Topic的模型,每个模型都有许多Post。当用户创建新主题时,他们也应该创建第一个Post。但是,我不确定如何以相同的形式执行此操作。这是我的代码:classTopic:destroyaccepts_nested_attributes_for:postsvalidates_presence_of:titleendclassPost...但这似乎不起作用。有什么想法吗?谢谢! 最佳答案 @Pablo的回答似乎有你需要的一切。但更具体地说...首先改变你View中的这一行对此#

    4. ruby - 在哈希的键数组中追加元素 - 2

      查看我的Ruby代码:h=Hash.new([])h[0]=:word1h[1]=h[1]输出是:Hash={0=>:word1,1=>[:word2,:word3],2=>[:word2,:word3]}我希望有Hash={0=>:word1,1=>[:word2],2=>[:word3]}为什么要附加第二个哈希元素(数组)?如何将新数组元素附加到第三个哈希元素? 最佳答案 如果您提供单个值作为Hash.new的参数(例如Hash.new([]),完全相同的对象将用作每个缺失键的默认值。这就是您所拥有的,那是你不想要的。您可以改用

    5. 「Python|Selenium|场景案例」如何定位iframe中的元素? - 2

      本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决

    6. ruby - 具有两个参数的 block - 2

      我从用户Hirolau那里找到了这段代码:defsum_to_n?(a,n)a.combination(2).find{|x,y|x+y==n}enda=[1,2,3,4,5]sum_to_n?(a,9)#=>[4,5]sum_to_n?(a,11)#=>nil我如何知道何时可以将两个参数发送到预定义方法(如find)?我不清楚,因为有时它不起作用。这是重新定义的东西吗? 最佳答案 如果您查看Enumerable#find的文档,您会发现它只接受一个block参数。您可以将它发送两次的原因是因为Ruby可以方便地让您根据它的“并行赋

    7. ruby-on-rails - 在 RSpec 中,如何以任意顺序期望具有不同参数的多条消息? - 2

      RSpec似乎按顺序匹配方法接收的消息。我不确定如何使以下代码工作:allow(a).toreceive(:f)expect(a).toreceive(:f).with(2)a.f(1)a.f(2)a.f(3)我问的原因是a.f的一些调用是由我的代码的上层控制的,所以我不能对这些方法调用添加期望。 最佳答案 RSpecspy是测试这种情况的一种方式。要监视一个方法,用allowstub,除了方法名称之外没有任何约束,调用该方法,然后expect确切的方法调用。例如:allow(a).toreceive(:f)a.f(2)a.f(1)

    8. ruby - Hanami link_to 助手只呈现最后一个元素 - 2

      我是HanamiWorld的新人。我已经写了这段代码:moduleWeb::Views::HomeclassIndexincludeWeb::ViewincludeHanami::Helpers::HtmlHelperdeftitlehtml.headerdoh1'Testsearchengine',id:'title'hrdiv(id:'test')dolink_to('Home',"/",class:'mnu_orizontal')link_to('About',"/",class:'mnu_orizontal')endendendendend我在模板上调用了title方法。htm

    9. ruby-on-rails - 具有同名的模块和类 - 2

      我有一个模块stat存在于目录结构中:lib/stat_creator/stat/在lib/stat_creator/stat.rb中,我在lib/stat_creator/stat/目录中有我需要的文件,以及:moduleStatCreatormoduleStatendend当我使用该模块时,我将这些类称为StatCreator::Stat::Foo.new现在我想要一个存在于应用程序中的根Stat类。我在app/models中制作了我的Stat类,并在routes.rb中进行了设置。但是,如果我转到Rails控制台并尝试在应用程序/模型中使用Stat类,例如:Stat.by_use

    10. ruby - 将n维数组的每个元素乘以Ruby中的数字 - 2

      在Ruby中,是否有一种简单的方法可以将n维数组中的每个元素乘以一个数字?这样:[1,2,3,4,5].multiplied_by2==[2,4,6,8,10]和[[1,2,3],[1,2,3]].multiplied_by2==[[2,4,6],[2,4,6]]?(很明显,我编写了multiplied_by函数以区别于*,它似乎连接了数组的多个副本,不幸的是这不是我需要的)。谢谢! 最佳答案 它的长格式等价物是:[1,2,3,4,5].collect{|n|n*2}其实并没有那么复杂。你总是可以使你的multiply_by方法:c

    随机推荐