Как перевести элемент, чтобы он действовал как одометр

У меня есть код:

  <div class = "wrap2" id = "wrap" data-num = "0">
    <span>0</span><span>1</span>...

CSS:

.wrap2[data-num = "0"] {
  transfom:translate(0, 0);
}
.wrap2[data-num = "1"] {
  transform:translate(0, -30px);
  }

https://jsfiddle.net/9t4zsuov/2/

Но я хочу действовать как одометр - цифры должны катиться только вверх, а не вниз. Есть идеи, как это сделать?

Код в jsfiddle использует случайное число. Вы хотите, чтобы они поднимались один за другим?

Bedir 11.03.2019 18:41

Да, это должно быть случайно

Czachovsky 11.03.2019 18:50
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
7
2
505
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете использовать два набора чисел и немного дополнительного javascript для достижения этого эффекта.

Если новое число меньше текущего числа, используйте второй набор чисел (цифры 0-9), которые находятся дальше вниз. Когда анимация css переходит от первого набора чисел ко второму, будет казаться, что одометр «переворачивается».

Когда анимация завершится, вернитесь к первому набору чисел без анимации (без класса перехода).

Я сделал рабочий пример на основе вашего оригинального jsfiddle.

ПРИМЕЧАНИЕ. При этом используется свойство .classList элементов DOM и событие tranistionend. Возможно, вам придется добавить префиксы поставщиков (например, webkitTransitionEnd) и реализовать собственную версию .classList, в зависимости от того, какие браузеры вам необходимо поддерживать.

document.getElementById("rand").addEventListener("click", randomize);
document.getElementById("cipa").addEventListener("transitionend", transitionEnd);

function randomize() {
  setNumber(Math.floor(Math.random() * 9));
}

function setNumber(newNumber) {
  let dupa = document.getElementById("cipa");

  // assumes dupa.dataset.num always be a valid int
  let selected = parseInt(dupa.dataset.num);

  if (newNumber === selected) return; // if same as existing, don't do anything

  // if the new number is less than the old number
  // use the second set of numbers to avoid moving "backwards"
  if (newNumber < selected) dupa.classList.add("rolledover");

  // animate to the new position
  dupa.classList.add("transitioning");
  dupa.dataset.num = "" + newNumber;
}

function transitionEnd() {
  let dupa = document.getElementById("cipa");
  // don't animate
  dupa.classList.remove("transitioning");
  dupa.classList.remove("rolledover");
}
#rand {
  margin-top: 50px;
}

.dupa1 {
  height: 30px;
  width: 30px;
  border: 1px solid #000;
  overflow: hidden;
}

.dupa2.transitioning {
  transition: all 1s ease;
}

.dupa2 span {
  height: 30px;
  width: 30px;
  display: block;
  text-align: center;
  line-height: 30px;
}

.dupa2[data-num = "0"] {
  transform: translate(0, 0);
}

.dupa2[data-num = "1"] {
  transform: translate(0, -30px);
}

.dupa2[data-num = "2"] {
  transform: translate(0, -60px);
}

.dupa2[data-num = "3"] {
  transform: translate(0, -90px);
}

.dupa2[data-num = "4"] {
  transform: translate(0, -120px);
}

.dupa2[data-num = "5"] {
  transform: translate(0, -150px);
}

.dupa2[data-num = "6"] {
  transform: translate(0, -180px);
}

.dupa2[data-num = "7"] {
  transform: translate(0, -210px);
}

.dupa2[data-num = "8"] {
  transform: translate(0, -240px);
}

.dupa2[data-num = "9"] {
  transform: translate(0, -270px);
}

.rolledover.dupa2[data-num = "0"] {
  transform: translate(0, -300px);
}

.rolledover.dupa2[data-num = "1"] {
  transform: translate(0, -330px);
}

.rolledover.dupa2[data-num = "2"] {
  transform: translate(0, -360px);
}

.rolledover.dupa2[data-num = "3"] {
  transform: translate(0, -390px);
}

.rolledover.dupa2[data-num = "4"] {
  transform: translate(0, -420px);
}

.rolledover.dupa2[data-num = "5"] {
  transform: translate(0, -450px);
}

.rolledover.dupa2[data-num = "6"] {
  transform: translate(0, -480px);
}

.rolledover.dupa2[data-num = "7"] {
  transform: translate(0, -510px);
}

.rolledover.dupa2[data-num = "8"] {
  transform: translate(0, -540px);
}

.rolledover.dupa2[data-num = "9"] {
  transform: translate(0, -570px);
}
<div class = "dupa1">
  <div class = "dupa2" id = "cipa" data-num = "0">
    <span>0</span>
    <span>1</span>
    <span>2</span>
    <span>3</span>
    <span>4</span>
    <span>5</span>
    <span>6</span>
    <span>7</span>
    <span>8</span>
    <span>9</span>
    <span>0</span>
    <span>1</span>
    <span>2</span>
    <span>3</span>
    <span>4</span>
    <span>5</span>
    <span>6</span>
    <span>7</span>
    <span>8</span>
    <span>9</span>
  </div>
</div>

<button id = "rand">rand</button>

Это неплохо, я могу думать только о другом способе использования jQuery и динамической генерации списков...

Bedir 11.03.2019 20:03

большое спасибо, это решило мою проблему. @Bedir я хочу сделать это без jquery, просто vanilla js

Czachovsky 11.03.2019 20:11
Ответ принят как подходящий

Как сказал @codyThompsonDev, область ролловера — лучший способ реализовать это. Что-то, я думаю, он упустил из виду, это то, что происходит, когда вы переходите от номера с ролловером к номеру без ролловера.

Например, предположим, что одометр случайным образом пытается докатиться до 4, затем 3, затем 1. С первого раза докатился до 4 без проблем. Во второй раз он должен перекатиться на «13» в зоне опрокидывания. Но затем он пытается откатиться до «11», которая также находится в зоне опрокидывания, заставляя его откатиться назад.

Чтобы достичь этого эффекта в таких обстоятельствах, вы должны вывести циферблат из зоны опрокидывания, а затем снова повернуть вперед. Я бы реализовал это с помощью window.requestAnimationFrame().

Я сделал скрипку, чтобы продемонстрировать это: https://jsfiddle.net/tprobinson/8k125fmz/67/

Добавьте класс debugBackground к dupa2, чтобы визуально увидеть эффект ролловера.

Я бы рекомендовал создавать классы CSS с помощью препроцессора, такого как Сасс, так как их написание вручную также может быть подвержено ошибкам.

document.getElementById("rand").addEventListener("click", randomize);

const debug = document.getElementById("debug");
const dupa = document.getElementById("cipa");

let animationInProgress = null

function setDebug(num) {
  debug.textContent = 'Number is really: ' + num
}

function animateOdometer(newNum) {
  // Add the smooth class and set the number to let it roll.
  dupa.classList.add('smooth')
  setDebug(newNum)
  dupa.dataset.num = newNum

  // In 1000 ms, remove the smooth class
  animationInProgress = window.setTimeout(() => {
    dupa.classList.remove('smooth')
    animationInProgress = null
  }, 1000)
}

function randomize() {

  let oldNum = Number.parseInt(dupa.dataset.num)
  if (oldNum === undefined || oldNum === null) {
    oldNum = 0
  }

  let newNum = Math.floor(Math.random() * 9) + 0;

  // If an animation is already in progress, cancel it
  if (animationInProgress) {
    window.clearTimeout(animationInProgress)
    dupa.classList.remove('smooth')
    animationInProgress = null
  }

  // If the new number is before our old number
  // we have to force a roll forwards
  if (newNum < oldNum) {
    newNum += 10
  }

  if (oldNum > 9) {
    // The dial was already rolled over. We need to
    // snap the dial back before rolling again.
    // Wait for a frame so we can snap the dial back
    dupa.dataset.num = oldNum - 10
    setDebug(oldNum - 10)
    dupa.classList.remove('smooth')

    window.requestAnimationFrame(() => {
      // Wait for one frame to let the snapback happen
      window.requestAnimationFrame(() => {
        // Then roll forward
        animateOdometer(newNum)
      })
    })

    return
  }

  // Roll the dial
  animateOdometer(newNum)
}
#rand,
#debug {
  margin-top: 50px;
}

.dupa1 {
  height: 30px;
  width: 30px;
  border: 1px solid #000;
  overflow: hidden;
}

.dupa2.smooth {
  transition: all 1s ease;
}

.dupa2 span {
  height: 30px;
  width: 30px;
  display: block;
  text-align: center;
  line-height: 30px;
}

.dupa2.debugBackground {
  background: linear-gradient(to bottom, #ffffff 0%, #ffffff 50%, #207cca 51%, #207cca 100%);
}

.dupa2[data-num = "0"] {
  transform: translate(0, 0);
}

.dupa2[data-num = "1"] {
  transform: translate(0, -30px);
}

.dupa2[data-num = "2"] {
  transform: translate(0, -60px);
}

.dupa2[data-num = "3"] {
  transform: translate(0, -90px);
}

.dupa2[data-num = "4"] {
  transform: translate(0, -120px);
}

.dupa2[data-num = "5"] {
  transform: translate(0, -150px);
}

.dupa2[data-num = "6"] {
  transform: translate(0, -180px);
}

.dupa2[data-num = "7"] {
  transform: translate(0, -210px);
}

.dupa2[data-num = "8"] {
  transform: translate(0, -240px);
}

.dupa2[data-num = "9"] {
  transform: translate(0, -270px);
}

.dupa2[data-num = "10"] {
  transform: translate(0, -300px);
}

.dupa2[data-num = "11"] {
  transform: translate(0, -330px);
}

.dupa2[data-num = "12"] {
  transform: translate(0, -360px);
}

.dupa2[data-num = "13"] {
  transform: translate(0, -390px);
}

.dupa2[data-num = "14"] {
  transform: translate(0, -420px);
}

.dupa2[data-num = "15"] {
  transform: translate(0, -450px);
}

.dupa2[data-num = "16"] {
  transform: translate(0, -480px);
}

.dupa2[data-num = "17"] {
  transform: translate(0, -510px);
}

.dupa2[data-num = "18"] {
  transform: translate(0, -540px);
}

.dupa2[data-num = "19"] {
  transform: translate(0, -570px);
}
<div class = "dupa1">
  <div class = "dupa2" id = "cipa" data-num = "0">
    <span>0</span>
    <span>1</span>
    <span>2</span>
    <span>3</span>
    <span>4</span>
    <span>5</span>
    <span>6</span>
    <span>7</span>
    <span>8</span>
    <span>9</span>
    <span>0</span>
    <span>1</span>
    <span>2</span>
    <span>3</span>
    <span>4</span>
    <span>5</span>
    <span>6</span>
    <span>7</span>
    <span>8</span>
    <span>9</span>
  </div>
</div>

<div id = "debug">
  Number is really: 0
</div>

<button id = "rand">rand</button>

Большое спасибо.

Но я столкнулся с другой похожей проблемой, но с массивом.

Я сделал скрипку для лучшего понимания проблемы: https://jsfiddle.net/zr2dLbge/

<div class = "wrap" id = "wrap"></div>

.wrap{
  border:1px solid #000;
  display: inline-block;
  height:30px;
  border-right: none;
}
.numbers{
   width:30px;
  height:30px;
  display:inline-block;
  overflow: hidden;
  border-right: 1px solid #000;
}
.numbers span{
  display: block;
  width:30px;
  height:30px;
  line-height: 30px;
  text-align: center;
}

.numbers[data-num = "0"] div{
  transform: translate(0, 0);
  transition: all 1s ease;
}

.numbers[data-num = "1"] div{
  transform: translate(0, -30px);
  transition: all 1s ease;
}

.numbers[data-num = "2"] div{
  transform: translate(0, -60px);
  transition: all 1s ease;
}

.numbers[data-num = "3"] div{
  transform: translate(0, -90px);
  transition: all 1s ease;
}

.numbers[data-num = "4"] div{
  transform: translate(0, -120px);
  transition: all 1s ease;
}

.numbers[data-num = "5"] div{
  transform: translate(0, -150px);
  transition: all 1s ease;
}

.numbers[data-num = "6"] div{
  transform: translate(0, -180px);
  transition: all 1s ease;
}

.numbers[data-num = "7"] div{
  transform: translate(0, -210px);
  transition: all 1s ease;
}

.numbers[data-num = "8"] div{
  transform: translate(0, -240px);
  transition: all 1s ease;
}

.numbers[data-num = "9"] div{
  transform: translate(0, -270px);
  transition: all 1s ease;
}

let arr = [];
var numbers = 1234561234;
const wrap = document.getElementById("wrap");

function toArray (val) {

  return (val).toString().split('');
}

arr = toArray(numbers);

for (let i = 0; i < arr.length; i++) {
    div = document.createElement('div'),
    div.className = "numbers";
    div.dataset.num = arr[i];
    div.dataset.x = i;
    div.innerHTML = "<div><span>0</span><span>1</span><span>2</span><span>3</span><span>4</span><span>5</span><span>6</span><span>7</span><span>8</span><span>9</span></div>"
    wrap.appendChild(div);
}


setInterval(function(){ 
arr.forEach( (k) => {
  arr[k] = Math.floor(Math.random() * 9) + 0;
})

for (let i = 0; i < arr.length; i++) {
    document.querySelector('.numbers[data-x = "'+i+'"]').dataset.num = arr[i];
}
 }, 1000);

к сожалению, в этом случае у меня не работает window.requestAnimationFrame()

Другие вопросы по теме