Какова причина некорректного отображения transition-анимации при изменении позиций двух элементов в массиве на Vue?

Как можно изменить анимацию, чтобы при нажатии на кнопку оба элемента массива перемещались одновременно, а не только левый элемент? Пример кода можно найти <a href="https://codepen.io/DazzRune/pen/LYwVOvm" rel="nofollow">здесь</a>. В текущей реализации используется следующий код: <br/> <pre><code class="html">&lt;template&gt;
    &lt;div
        v-for="(item, index) in data"
        :key="item.id"
        class="block"
        :style="`left: ${80 * index}px; top: 0px`"
    &gt;
        {{ item.id }}
    &lt;/div&gt;

    &lt;button @click="swap" style="position: absolute; top: 80px;"&gt;SWAP&lt;/button&gt;
&lt;/template&gt;</code></pre> <br/> <pre><code class="javascript">&lt;script setup&gt;
import { ref } from 'vue'

const data = ref([{ id: 0 }, { id: 1 }])

function swap() {
    ;[data.value[0], data.value[1]] = [data.value[1], data.value[0]]
}
&lt;/script&gt;</code></pre> <br/> <pre><code class="css">&lt;style&gt;
.block {
    transition: left ease-out 1s;
    position: absolute;
    width: 80px;
    height: 80px;
    border: 1px solid black;
}
&lt;/style&gt;</code></pre>
  • 27 сентября 2024 г. 14:23
Ответы на вопрос 2
Ваш код использует `absolute` позиционирование для элементов, и это может вызывать проблемы с анимацией перехода, так как элементы фактически перемещаются одна за другой, а не одновременно. Кроме того, Vue не отслеживает изменения в свойствах `style`, применяемых к элементам с помощью атрибутов, таких как `left`, что также может привести к некорректному отображению анимации.

Чтобы сделать так, чтобы оба элемента перемещались одновременно при нажатии на кнопку, можно изменить подход к позиционированию, например, использовать CSS Grid или Flexbox. Вот один из способов, как можно это реализовать:

1. Измените стиль на использование Flexbox.
2. Добавьте анимацию смены местами для всех элементов сразу.

Вот обновлённый код:

### HTML
```html
<template>
    <div class="container">
        <div
            v-for="(item, index) in data"
            :key="item.id"
            class="block"
        >
            {{ item.id }}
        </div>
    </div>
    <button @click="swap" style="margin-top: 20px;">SWAP</button>
</template>
```

### JavaScript
```javascript
<script setup>
import { ref } from 'vue'

const data = ref([{ id: 0 }, { id: 1 }])

function swap() {
    ;[data.value[0], data.value[1]] = [data.value[1], data.value[0]]
}
</script>
```

### CSS
```css
<style>
.container {
    display: flex;
    position: relative;
}

.block {
    transition: all ease-out 1s; /* Меняем left на all, чтобы анимация срабатывала на изменение всех свойств */
    width: 80px;
    height: 80px;
    border: 1px solid black;
    margin-right: 10px; /* Немного пространства между блоками */
}
</style>
```

### Объяснение:
1. **Flexbox**: Контейнер теперь использует `display: flex`, что позволяет двум элементам располагаться в одну строку.
2. **Анимация**: Мы изменили свойство `transition` на `all`, что позволит анимации сработать для любого изменения (в данном случае, изменения порядка).

Теперь при нажатии на кнопку элементы будут перемещаться полностью вместе, без задержек. Вы можете попробовать это решение в вашем проекте!
У тебя блоки перерисовываются, поэтому у левого всегда left: 0 и анимации нет 
Надо либо, добавить элементам параметр позиции:
const data = ref([{ id: 0, pos: 0 }, { id: 1, pos: 1 }])

задавать left относительно позиции:
:style="`left: ${80 * item.pos}px; top: 0px`"
ну и менять тогда так:
function swap() {
    data.value.forEach(el => {
        el.pos = el.pos === 1 ? 0 : 1
    })
}


Либо, лучше для этого лучше использовать transition-group
Похожие вопросы