style property attribute javascript html html5 css3 translate-animation

javascript - property - input title



Rotación de listas con elementos limitados. (6)

Tengo container div con lista (tarjetas) dentro. Cuando lo muevo, las tarjetas comienzan a moverse ( translateX animation ). el width container es de 300px , los elementos cuentan en el container:3 , el width:100px cada elemento width:100px .

Así que puedes ver 3 elementos en contenedor juntos overflow:hidden . ¿Qué quiero hacer? Es que cuando no hay ningún elemento para mostrar la animación translateX -100px = 100px espacio en blanco después del tercer elemento, comienza desde 1 elementos en la lista inmediatamente después del último, sin espacio en blanco.

Por ahora, no tengo idea de cómo se podría hacer sin duplicados y etc.

Aquí está lo que tengo en este momento: Fiddle (tarjetas de desplazamiento para ver la animación de traducción)

UPD 1: el código y los datos (conteo de cartas, tamaño del contenedor) se tomaron, por ejemplo, intentaré explicar mejor lo que quiero: mi objetivo es construir una lista de cartas y después de presionar el botón, la lista comenzará a moverse ( como en el ejemplo con la animación translateX) durante un tiempo (por ejemplo, translateX: 12491px , animation-duration: 15s ;) y se detiene. Pero el problema es que la cantidad de cunas en la lista estaría en el rango de 3 a 40 tarjetas (cada tarjeta es de 100 px de ancho y alto). Entonces, cuando establezca translateX: 12491px por ejemplo, estará fuera de rango y después de la última tarjeta de la lista aparecerá un espacio en blanco. Quiero que la primera y la última tarjeta estén empatadas de alguna manera y después de la última tarjeta aparece inmediatamente la primera tarjeta en la lista y etc. Tal vez esté buscando una solución de manera incorrecta, pero creo que entiende la idea principal.

UPD 2: Encontré que cs: go usa la animación que quería escribir en html / css / js. Aquí está el 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; }


comience desde 1 elementos en la lista inmediatamente después del último, sin espacio en blanco

Esto está más allá de CSS y necesitarás Javascript para eso. Debido a que ha etiquetado la pregunta con Javascript y no con jQuery, mi respuesta se limitaría solo a Javascript puro. Mira ma, no JQuery;)

No tengo idea de cómo se podría hacer sin duplicados.

Aquí hay una idea de bricolaje ( hazlo tú mismo ) ..

  1. El truco principal es mostrar al menos un elemento menos que el total que tiene. Si tiene 3 cartas, muestre solo 2. Si tiene 4 cartas, muestre solo 3. Por qué, ya que necesita volver a colocar una tarjeta cuando está fuera de la vista y envolverla al final. Si muestra exactamente el mismo número de tarjetas que tiene, entonces no puede romper la mitad de una tarjeta y envolverla, y verá algo de espacio en blanco hasta que la primera salga de la vista. ¿Tienes la idea?
  2. No uses translate o terminarás complicándote las cosas mientras lo escribes. Mantén las cosas simples.
  3. No utilice un envoltorio para sus tarjetas. ¿Por qué? Porque, estaremos reubicando las tarjetas que han quedado fuera de vista. Cuando hagamos eso, la próxima carta ocupará su lugar e inmediatamente se perderá de vista, lo que le dificultará aún más las cosas.
  4. Para simplificar las cosas, organice sus tarjetas con una posición absolute relación con su contenedor. Para empezar, deja que todas las cartas se apilen en la top:0; and left: 0; top:0; and left: 0; .
  5. A continuación, conecte Javascript para colocar la propiedad left según el width de cada tarjeta y organizarlas de forma lineal.
  6. Utilice requestAnimationFrame para controlar la animación.
  7. Lleve un registro de la tarjeta más a la izquierda y su posición left . Cuando esto salga de la vista ( que es 0 menos el ancho ), appendChild esta tarjeta a su contenedor. Esto moverá la tarjeta al final de las tarjetas. Además, cambie la propiedad de la left según la última tarjeta de la lista.
  8. Eso es todo lo que hay que hacer.

A continuación se muestra una demostración. Para facilitarle la experimentación, he utilizado un objeto de configuración para mantener las propiedades configurables que puede modificar y ver fácilmente. Mire detenidamente el código y lo encontrará fácil de entender. Puede establecer la configuración de iterations en 0 para que la animación sea infinita.

Además, tenga en cuenta que no necesita duplicar o falsificar las tarjetas. Prueba la demo y agrega tantas tarjetas como quieras.

Los comentarios de código en línea en el fragmento, le ayudarán a comprender cada línea de código y se relacionarán con los pasos anteriores.

Retazo:

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/

Nota: He dejado fuera algunas cosas en la demo. Especialmente, aunque el ancho y el alto de las tarjetas es parte del objeto de configuración, pero actualmente se quedó fijo. Puede usar fácilmente el objeto de configuración para hacer que las dimensiones de las tarjetas también sean configurables.

Editar:

( según el comentario de Op )

Si desea un mayor control sobre la distancia para desplazarse, la duración y las funciones de tiempo (flexibilización), entonces puede implementarlas utilizando una biblioteca. Un par de bibliotecas tan buenas son las funciones de flexibilización de Robert Penner y un complemento jQuery de GSGD . Aunque puede implementar todo eso con Javascript puro, sería más fácil si usara una biblioteca como jQuery.

La captura aquí es que para hacerlo de manera efectiva, debe duplicar las tarjetas. Puede hacerlo fácilmente clonando la lista completa un par de veces.

Aunque no haya etiquetado esta pregunta con jQuery, aquí hay una pequeña demostración ( usando jQuery para hacerlo rápidamente ) donde puede configurar la velocidad y la distancia.

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


Aquí hay una técnica simple que manipula el Dom para crear el efecto deseado.

Javascript:

document.querySelector(''.cards'').addEventListener(''mousedown'', function(e) { if (e.clientX < (this.offsetWidth >> 1)) { this.appendChild(this.removeChild(this.firstElementChild)); } else { this.insertBefore(this.lastElementChild, this.firstElementChild); }});

luego, en css use el selector nth-of-type para posicionar los elementos según sea necesario. Aquí está tu fiddle

Si está utilizando el mouseover, es posible que deba esperar a que aparezca el evento de transición antes de volver a disparar.


Si no desea modificar los elementos dom, puede aprovechar la propiedad de order de flex-item ;

para hacer esto todavía necesitarías un poco de JS para agregar esta propiedad después de que la animación haya terminado;

También cambié a animación en lugar de transición, así que restablece automáticamente la propiedad de transformación al final de la animación.

$(''.cards'').mouseenter(function() { setTimeout(function() { $(''.card'').first().css("order", "2"); }, 3000); }); $(''.cards'').mouseleave(function() { $(''.card'').first().css("order", "-1"); });

.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; flex: 0 0 25%; } .cards:hover { animation: trans 3s; } /**/ .cards { width: 400px; height: 100%; display: flex; transition: transform 3s; } @keyframes trans { 0% { transform: translateX(0) } 100% { transform: translateX(-100px) } }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script> <div class="container"> <div class="cards"> <div class="card">1</div> <div class="card">2</div> <div class="card">3</div> </div> </div>

fiddle

Pero si está de acuerdo con usar JS, le sugiero que manipule el orden de los elementos DOM directamente, tomando el primer elemento hijo de .cards y .cards al final de la lista al final de cada animación;

prueba esto:

var anim; $(''.cards'').mouseenter(function(){ anim = setInterval(function(){ $(''.cards'').append($(''.card'').first()) },3000) }); $(''.cards'').mouseleave(function(){ clearInterval(anim) });

.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; /**/ flex:0 0 25%; } .cards:hover{ animation: trans 3s infinite; } /**/ .cards{ width:400px; height:100%; display:flex; } @keyframes trans { 0% { transform: translateX(0) } 100% { transform: translateX(-100px) } }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script> <div class="container"> <div class="cards"> <div class="card"> 1 </div> <div class="card"> 2 </div> <div class="card"> 3 </div> </div> </div>

en caso de que quiera que una tarjeta esté presente al mismo tiempo, tanto al principio como al final de la lista de tarjetas, deberá hacer una copia profunda / clon del elemento;

Aquí hay un ejemplo ;


Here es el mismo efecto que mencionaste, con un pequeño ajuste en tu CSS y una mano útil de jQuery.

CSS

Cambie su selector para que la animación translateX aplique en cada una de las cajas .card cuando se .card su padre inmediato, y no las .cards (que es el padre inmediato de la .card s). Esto se debe a que querría que las cartas se muevan hacia la izquierda y no la ventana a través de la cual aparecen mientras se realiza el movimiento.

Es decir,

.cards:hover .card { transform: translateX(-100px); transition-duration: 1.5s; animation-duration: 1.5s; animation-fill-mode: forwards; }

jQuery

var $container = $(''.container''); var cardWidth = 100; $container.on(''mouseenter'', function (e) { e.preventDefault(); var $card0Clone = $(''.card'').eq(0).clone(); // clone of the first .card element $(''.cards'').append($card0Clone); updateWidth(); }); $container.on(''mouseleave'', function (e) { e.preventDefault(); var $cards = $(''.card''); $cards.eq(0).remove(); // remove the last .card element }); function updateWidth() { $(''.cards'').width(($(''.card'').length) * cardWidth); // no of cards in the queue times the width of each card would result in a container fit enough for all of them }

Código explicado

A medida que se mueve en el puntero del mouse, se crea un clon de la primera tarjeta y se anexa al final de la colección de tarjetas. Además, a medida que mueva el mouse fuera del área .card , la .card original ( que se clonó anteriormente ) se eliminará de la cabecera de la cola, lo que generará un efecto cíclico.

El verdadero truco, sin embargo, es con la función updateWidth . Cada vez que el mouse ingresa al .container el ancho del .card inmediato de .card s (es decir, .cards div) se actualiza, de modo que .cards div es lo suficientemente ancho como para caber en todos los .card s, y por lo tanto, asegurándose de que cada una de las tarjetas se empuja entre sí y permanece en una línea en el momento en que se realiza la animación de traducción .


Echa un vistazo a esta demostración

Aquí usé JQuery, puedes configurar tu animación usando dos variables

var translateX = 1000; //adjust the whole distance to translate var stepSpeed = 100; //adjust the speed of each step transition in milliseconds

Después de configurar sus variables, en el evento de clic de las tarjetas haga lo siguiente:

  1. Obtenga el número de los pasos necesarios basados ​​en translateX
  2. Bucle para el número de pasos
  3. Dentro de cada bucle (cada paso), mueva las cartas 1 paso hacia la izquierda, luego coloque la primera tarjeta al final de las cartas para formar el bucle conectado, luego regrese las cartas a su posición inicial

Aquí está el código:

var stepsNumber = translateX/100; for(var i=0; i< stepsNumber; i++) { $(''.cards'').animate({''left'' : -100}, stepSpeed,function(){ $(''.cards div:last'').after($(''.cards div:first'')); $(''.cards'').css({''left'' : ''0px''}); }); }


Actualización 2:

Escribí un plugin jquery que puede actuar de la forma que quieras:

puede agregar tantas tarjetas como desee, en este momento, "translateX" es aleatorio (el guión elegirá aleatoriamente la tarjeta final)

enlace a la demo

Actualizar:

Lo sé, usé duplicados, pero ahora mi código funciona en tres tarjetas:

  • He añadido tres tarjetas "falsas"
  • Cada carta "real" tiene su propia animación.
  • las tarjetas "falsas" se superpondrán con las reales una vez que finalice su ciclo ( "cuando no haya ningún elemento que mostrar" como usted pidió)

compruebe el fragmento:

.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 { width: 600px; } .container:hover .card1{ animation: 1600ms slide1 infinite linear; } .container:hover .card2{ animation: 1600ms slide2 infinite linear; } .container:hover .card3{ animation: 1600ms slide3 infinite linear; } .fakecard{z-index:-1000;} .container:hover .fakecard{ animation: 1600ms fakeslide infinite linear; } @keyframes slide1 { 0% { transform: translateX(0px); } 33% { transform: translateX(-100px); } 33.1% { transform: translateX(+200px); } 100% { transform: translateX(0px); } } @keyframes slide2 { 0% { transform: translateX(0px); } 66% { transform: translateX(-200px); } 66.1% { transform: translateX(100px); } 100% { transform: translateX(0px); } } @keyframes slide3 { 0% { transform: translateX(0px); } 99% { transform: translateX(-300px); } 99.1% { transform: translateX(+300px); } 100% { transform: translateX(0px); } } @keyframes fakeslide { 0% { transform: translateX(0px); } 99% { transform: translateX(-300px); } 99.1% { transform: translateX(+300px); } 100% { transform: translateX(0px); } }

<div class="container"> <div class="cards"> <div class="card card1"> 1 </div> <div class="card card2"> 2 </div> <div class="card card3"> 3 </div> <div class="card fakecard"> 1 (fake) </div> <div class="card fakecard"> 2 (fake) </div> <div class="card fakecard"> 3 (fake) </div> </div> </div>

Respuesta anterior:

¿Es esto lo que estás tratando de lograr?

No creo que puedas hacerlo sin duplicados ...

Si no, ¿puedes explicar mejor lo que estás tratando de lograr aquí?

[código cortado eliminado]