С помощью setTimeout добавлять класс

Необходимо добавлять класс, по очереди, блокам которые находятся в v-for, каждые n-секунд и удалять предыдущим. Чтобы, к примеру, каждую секунду появляся новый блок, а старый удалялся и так зациклить.

<div v-for="(block, index) in blocks" :key="index" class="blockItem">{{block.title}}</div>
data: () => ({
    blocks: [
      {
        title: 'Раз',
      },
      {
        title: 'Два',
      },
      {
        title: 'Три',
      },
    ],
  }),

Как это реализовать?


Ответы (1 шт):

Автор решения: Mikalai Parakhnevich

Чтобы оперировать данными из массива, необходимо полагаться, что каждый элемент имеет уникальный идентификатор.

Создаем в data переменную - idActiveBlock, в которой будем хранить индекс активного элемента из массива blocks (того, элемента, которому нужно присвоить класс css - active). В template добавляем соответствующие выражения, которые будут формировать классы для элементов из массива, полагаясь на данные:

<div v-for="block in blocks" :key="block.id" :class="['blockItem', {active: block.id === idActiveBlock}]">
  {{block.title}}
</div>

Создаем функцию, которая будет отвечать за изменение индекса активного элемента, в которой после манипуляций с индексом, формируем отложенный запуск этой же функции еще раз, через заданный промежуток времени.

Для управления отображением можно использовать css стили.

Для наглядности пример:

new Vue({
  el: '#app',
  data: () => ({
    run: false,
    timer: null,
    idActiveBlock: 0,
    blocks: [{
        id: 1,
        title: 'Раз',
      },
      {
        id: 2,
        title: 'Два',
      },
      {
        id: 3,
        title: 'Три',
      },
    ],
  }),
  methods: {
    toggleStart() {
      this.run = !this.run
      if (this.run) {
        this.editParamsActiveBloks()
      } else {
        clearTimeout(this.timer)
      }
    },
    editParamsActiveBloks() {
      this.idActiveBlock = this.idActiveBlock < this.blocks.length ? this.idActiveBlock + 1 : 1
      const idNextActiveElement = this.blocks[this.idActiveBlock - 1].id || 0
      if (this.run) {
        this.timer = setTimeout(this.editParamsActiveBloks, 1000);
      }
    },
  },
})
.flex {
  display: flex;
}

.blockItem {
  padding: 20px;
  opacity: .2;
  background: #eee;
}

.active {
  background: #42b883;
  opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  Индекс активного блока = {{idActiveBlock}}
  <div class="flex">
    <div v-for="block in blocks" :key="block.id" :class="['blockItem', {active: block.id === idActiveBlock}]">
      {{block.title}}
    </div>
  </div>
  <button @click="toggleStart">
    <template v-if="run">Стоп</template>
    <template v-else>Старт</template>
  </button>
</div>

→ Ссылка