列表旋转与有限的元素 [英] List rotation with limited elements

查看:112
本文介绍了列表旋转与有限的元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

里面有列表(卡片)的div container >。当我将它悬停时,卡片开始移动( translateX动画)。 容器宽度 300px ,elements count in container:3 ,每个元素 width:100px



因此,您可以在容器中看到3个元素 overflow:hidden 。我想做什么?是,当没有元素在第三个元素后面显示 translateX动画-100px = 100px 空格时,它将从紧跟在最后的列表中的1个元素开始,没有空白空间。



现在,我不知道如何在没有重复的情况下完成这项工作。



这里是我目前所拥有的:
小提琴(悬停卡片可查看翻译动画)



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



UPD 2:
我发现cs:go使用我想写在html \ css \ js上的动画。以下是视频: youtube.com



html:

 < div class = 容器 > 
< 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纯黑色;
overflow:hidden;
}
.card
{
float:left;
height:100px;
width:100px;
background-color:blue;
box-sizing:border-box;
border:2px纯红色;
颜色:白色;
font-size:23px;
}
.cards:hover
{
transform:translateX(-100px);
转换时长:3s;
动画持续时间:3秒;
animation-fill-mode:forwards;
}


解决方案


从最后一个列表中的1个元素开始,没有
空格


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


我不知道如何不重复

blockquote>

这是一个DIY(自己动手做)的想法..


  1. 主要技巧是显示至少一个项目少于您的总数。如果你有3张卡片,只显示2.如果你有4张卡片,只显示3.为什么,因为你需要重新定位一张卡片,当它离开视野并在最后包裹它。如果您显示的卡片数量与您拥有的卡片数量完全相同,那么您无法打破半卡片并将其包裹,直到第一张卡片看不见时,您会看到一些空白区域。你明白了吗?

  2. 不要使用 translate ,否则在编写脚本时最终会让事情变得复杂。保持简单。

  3. 不要为卡片使用包装。为什么?因为,我们将重新定位已经看不见的牌。当我们这样做时,下一张卡片将占据它的位置,并立即离开视线,从而使您的进一步困难。

  4. 为了简单起见,请使用绝对相对于其容器的定位。首先,让所有卡片堆叠在 top:0;然后左键:0;

  5. 接下来使用Javascript来定位 left 属性 width 并线性排列。

  6. 使用 requestAnimationFrame 来控制动画。

  7. 跟踪最左侧的卡片及其左侧位置。当这张牌离开视图( 0为宽度)时, appendChild 这张牌到它的容器。这会将卡移动到卡的末尾。此外,根据列表中的最后一张卡,将左侧的属性更改为它。 / li>

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

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



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



摘录:

var list = document.querySelector('。cardList'),//缓存容器cards = document.querySelectorAll('。card'),//缓存卡片列表start = document.getElementById('start'),/ / buttons stop = document.getElementById('stop'),reset = document.getElementById('reset'),raf,init = 0,counter = 0,lastCard,currentIteration = 0,//通用变量设置= {//设置对象以帮助将事物配置为宽度:100,高度:100,速度:2,迭代:2,计数:卡片。 length}; start.addEventListener('click',startClick); //点击buttonstop.addEventListener('click',stopClick)上的点击事件; reset.addEventListener('click',resetClick); initialize(); //初始化以在开始函数初始化卡片initialize(){//循环所有卡片并根据宽度和索引位置设置左侧属性[] .forEach.call(cards,function(elem,idx){elem.style。 left =(settings.width * idx)+'px';}); init = - (settings.width); //初始化视图cutoff lastCard = cards [settings.count - 1]; //识别最后一个卡片计数器= 0; currentIteration = 0; //重置一些计数器settings.speed = +(document.getElementById('speed')。value); settings.iterations = +(document.getElementById('iter').value);} function startClick(){initialize(); raf = window.requestAnimationFrame(keyframes); //开始动画} function stopClick(){window.cancelAnimationFrame(raf); } //停止动画函数resetClick(){//停止动画并重新初始化卡片以重新启动window.cancelAnimationFrame(raf); document.getElementById('speed')。value ='2'; document.getElementById('iter')。value ='2';初始化(); } //实际动画functionfunction keyframes(){var currentCard,currentLeft = 0,newLeft = 0; //遍历所有卡片并根据速度减少左边属性[] .forEach.call(cards,function(elem,idx){elem.style.left =(parseInt(elem.style.left) - settings.speed)+ 'px';}); currentCard =卡片[counter]; //识别最左边的卡currentLeft = parseInt(currentCard.style.left); //获取它的左边位置if(currentLeft< = init){//检查它是否已经离开视图//计算最后一张牌的位置newLeft = parseInt(lastCard.style.left)+ settings.width; list.appendChild(currentCard); //将卡片移动到列表的结尾currentCard.style.left = newLeft +'px'; //根据最后一张卡lastCard = currentCard更改左侧位置; //将其设置为下一次迭代的最后一张卡片counter =(counter + 1)%settings.count; ((settings.iterations> 0)&&(counter> =(settings.count - 1))){currentIteration ++; //设置下一个卡片索引。 //检查重复迭代的设置}} if(currentIteration> = settings.iterations){return; } //何时停止raf = window.requestAnimationFrame(keyframes); //请求另一个动画帧};

* {尺寸:边框;填充:0;保证金:0; } .cardList {position:relative; height:100px;宽度:300px; margin:10px; border:2px solid#33e;溢出:隐藏;白色空间:nowrap; } .card {position:absolute;左:0; top:0; text-align:center; height:100px;宽度:100px; line-height:100px;背景颜色:#99e; font-family:monospace; font-size:2em;颜色:#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 =speedtype =numbermin =1max =8value =2/> x< / label> &安培; NBSP; |&安培; NBSP; < label> Iterations< input id =itertype =numbermin =0max =8value =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>开始< / button>< button id =stop>停止< / button> < button id =reset>重设< / button>

p> 小提琴: http://jsfiddle.net/abhitalks/1hkw1v0w/



注意:我在演示中忽略了一些内容。尤其是,尽管卡片的宽度和高度是设置对象的一部分,但目前它保持不变。您可以轻松使用settings对象来设置卡的尺寸。

编辑:

按照操作的评论

如果您想更好地控制滚动距离,持续时间和计时功能(easing),然后你可以使用一个库自己实现这些。有几个这样的好库是 Robert Penner的Easing Functions GSGD的一个jQuery插件。虽然你可以用纯Javascript实现所有这些,但是如果你使用像jQuery这样的库,会更容易。



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



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



片段2:



  var $ cardList = $('。cardList')。first(),$ cards = $('。card'),$速度= $('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;填充:0;保证金:0; } .cardList {height:100px; width:302px;位置:相对; margin:10px; border:1px solid#33e;溢出:隐藏;白色空间:nowrap; } .card {display:inline-block; text-align:center; height:100px;宽度:100px; line-height:100px;背景颜色:#99e; font-family:monospace; font-size:2em;颜色:#444; border-left:1px solid#33e; border-right:1px solid#33e;}。cardList :: before,.cardList :: after {content:'';显示:块; z-index:100; width:0px; height:0px; transform:translateX(-50%); border-left:8px实体透明; border-right:8px透明; } .cardList :: before {position:absolute; top:0px;剩下:50%; border-top:12px solid#33e;}。cardList :: after {position:absolute; bottom:0px;剩下: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>速度:< / label> &安培; NBSP; |&安培; NBSP; < label>< input name =speedtype =radiovalue ='6000'/>慢< / label> < label>< input name =speedtype =radiovalue ='5000'checked /> Medium< / label> < label>< input name =speedtype =radiovalue ='3000'/> Fast<! - >< - >< div class =card> 1< / div><! -   - >< div class =card> 2< >< div class =card> 3< / div><! - >< div class =card> 4< < / div>< button id =spin> Spin< / button>  

小提琴2: http://jsfiddle.net/abhitalks/c50upco5/


I have div container with list (cards) inside. When I hover it, cards start to moving (translateX animation). container's width is 300px, elements count in container:3, each element width:100px.

So you can see 3 elements in container together overflow:hidden. What I want to make?, is that when there is no element to show translateX animation -100px = 100px blank space after third element, it start from 1 elements in the list immediately after last, with no blank space.

For now, I have no idea how it could be done without duplicates and etc.

Here is what I have at the moment: Fiddle (Hover cards to see translation animation)

UPD 1: The code and data (cards count, container size) was taken for example, i'll try to explain better what i want: My goal is to built list of cards and after button was pressed, the list will start moving (like in example with translateX animation) for some time (for example translateX: 12491px, animation-duration: 15s;) and stops. But problem is that amount of crads in the list would be in range of 3-40 cards (each card is 100px width & height). So, when i'll set translateX: 12491px for example, it will be out of range and after the last card in the list would appear blank space. I want first and last card to be tied somehow and after the last card immediately appears first card in the list and etc.. Maybe i am searching for solution in a wrong way, but i guess you understand the main idea.

UPD 2: I found that cs:go uses animation that i wanted to write on html\css\js. Here is video: 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

This is beyond CSS and you will need Javascript for that. Because, you have tagged the question with Javascript and not jQuery, my answer would be limited to pure Javascript only. Look ma, no JQuery ;)

I have no idea how it could be done without duplicates

Here is a DIY (do it yourself) idea..

  1. The main trick is to show at least one item less than the total you have. If you have 3 cards, show only 2. If you have 4 cards, show only 3. Why, because you need to re-position a card when it goes out of view and wrap it back at the end. If you show exactly the same number of cards that you have, then you cannot break half-a-card and wrap it and you will see some blank space until the first one goes out of view. You get the idea?
  2. Do not use translate or you will end up complicating things for yourself while scripting it out. Keep things simple.
  3. Do not use a wrapper for your cards. Why? Because, we will be re-positioning the cards which have gone out of view. When we do that, the next card will take up its place and immediately go out of view making things further difficult for you.
  4. To keep things simple, arrange your cards with absolute positioning relative to its container. To start with, let all cards stack up at top:0; and left: 0;.
  5. Next wire-up Javascript to position the left property based on the width of each card and arrange them linearly.
  6. Use requestAnimationFrame to control the animation.
  7. Keep track of the left-most card and its left position. When this goes out of view (which is 0 minus width), appendChild this card to its container. This will move the card to the end of cards. Also, change the left property to it based on the last card in the list.
  8. That' all there is to it.

Below is a demo. To make it easy for you to experiment, I have used a settings object to keep the configurable properties which you can easily tweak and see. Look closely at the code and you will find it simple to understand. You can set the iterations settings to 0 to make the animation infinite.

Also, note that you do not need to duplicate or fake the cards. Try the demo and add as many cards you want to.

The inline code comments in the snippet, will further help you understand each line of code and relate to the steps above.

Snippet:

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/

Note: I have left out a few things in the demo. Especially, although width and height of the cards is part of the settings object, but currently it left fixed. You can easily use the settings object to make the dimensions of the cards configurable as well.


Edit:

(as per Op's comment)

If you want a greater control over distance to scroll, duration and timing-functions (easing), then you could implement those yourself using a library. A couple of such good libraries are the Robert Penner's Easing Functions and a jQuery plugin from GSGD. Although you can implement all of that with pure Javascript, it would be easier if you use a library like jQuery.

Catch here is that in order to do so effectively, you must then duplicate the cards. You can do so easily by cloning the entire list a couple of times.

Although you have not tagged this question with jQuery, here is a small demo (using jQuery to get it done quickly) where you can configure the speed and the distance.

Snippet 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/

这篇关于列表旋转与有限的元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆