@Now159

Как сделать плавное сворачивание и разворачивание списка?

<template>
  <div>
    <button @click="toggleShowMore">{{ showMoreText }}</button>
    <transition-group name="fade">
      <div v-for="(item, index) in visibleItems" :key="index" class="list-item" >
        {{ item.name }} - {{ item.description }}
      </div>
    </transition-group>

  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';

const items = ref([]);
const showMore = ref(false);
const visibleItems = ref([]);

const showMoreText = ref('Показать еще');

const toggleShowMore = () => {
  showMore.value = !showMore.value;
  updateVisibleItems();
};

const updateVisibleItems = () => {
  if (showMore.value) {
    visibleItems.value = items.value;
    showMoreText.value = 'Скрыть';
  } else {
    visibleItems.value = items.value.slice(0, 0);
    setTimeout(() =>  showMoreText.value = 'Показать еще', 900);
  }

};

onMounted(() => {
  items.value = [
    { name: 'Item 1', description: 'Description 1' },
    { name: 'Item 2', description: 'Description 2' },
    { name: 'Item 3', description: 'Description 3' },
    { name: 'Item 3', description: 'Description 4' },
    { name: 'Item 4', description: 'Description 5' },
    { name: 'Item 5', description: 'Description 6' },
    { name: 'Item 6', description: 'Description 7' },
    { name: 'Item 7', description: 'Description 8' },
    { name: 'Item 8', description: 'Description 9' },
    { name: 'Item 9', description: 'Description 10' }
  ];

  // Изначально показываем только первые 3 элемента
  visibleItems.value = items.value.slice(0, 0);
});
</script>

<style scoped>
.list-item {
  margin-top: 10px;


}
.fade-enter-active,
.fade-leave-active {
  animation: fadeAnimation 0.9s  forwards;

}
.fade-enter,
.fade-leave-to {
  animation: fadeRAnimation 0.9s  forwards;

}
@keyframes fadeAnimation {
  from {
    max-height: 0;
  }
  to {
    max-height: 1000px;
  }
}
@keyframes fadeRAnimation {
  from {
    max-height: 1000px;
  }
  to {
    max-height: 0;
  }
}

</style>


есть такой код, открытие закрытие списка на vue3, нужно чтобы список плавно разворачивался вниз и сворачивался без изменения расстояния между итемами в процессе свертывания (просто эффект задвигания)
Допустим есть 3 итема я нажимаю идет плавный разворот до максимума, нажимаю список плавно сворачивается до 3ех
Сейчас у меня почти так но список в процессе свертывания изменяет расстояние между итемами и перед закрытием появляется не понятная задержка, которую я попробовал вылечить setTimeout, но это не решает основной проблемы

может посоветуете специальные библиотеки для этого или как решить

есть собственное решение на vue2, но не работает на vue 3, пробовал переписать не хватило мозгов) да и хочется какое то решение попроще

<script>
export default {
  name: "smooth-deployment",
  render(h) {
    const items = this.$slots.default;
    const gridStyle = this.isGrid ? `display: grid; grid-template-columns: repeat(7, 1fr);
     row-gap: ${this.gridGapRow}px;  column-gap: ${this.gridGapColumn}px;  grid-column: 1 / span ${this.gridColumns};` : ''
    return h('div', [
      items.slice(0, this.minShow),
      h('div', {
        ref: 'dropdown',
        attrs: {
          style: `overflow: hidden; transition: height ${this.duration}ms; ${gridStyle}`,
        },
      }, items.slice(this.minShow)),
    ]);
  },
  props: {
    minShow: Number,
    showAll: Boolean,
    duration: {
      type: Number,
      default: 500,
    },
    isGrid: {
      type: Boolean,
      default: false,
    },
    gridColumns: {
      type: Number,

    },
    gridGapRow: {
      type: Number,
      default: 20,
    },
    gridGapColumn: {
      type: Number,
      default: 20,
    },
  },
  watch: {
    showAll(val) {
      this[val ? 'open' : 'close']();
    },
  },
  mounted() {
    if (!this.showAll) {
      this.$refs.dropdown.style.height = '0px';
    }
  },
  methods: {
    open() {
      const el = this.$refs.dropdown;

      if (this.timeout) {
        clearTimeout(this.timeout);
      }

      el.style.height = `${el.scrollHeight}px`;

      this.timeout = setTimeout(() => {
        el.style.height = 'auto';
        this.timeout = null;
      }, this.duration);
    },
    close() {
      const el = this.$refs.dropdown;

      if (this.timeout) {
        clearTimeout(this.timeout);
      }

      el.style.height = `${el.scrollHeight}px`;
      setTimeout(() => el.style.height = '0px', 25);

      this.timeout = setTimeout(() => {
        this.timeout = null;
      }, this.duration);
    },
  },
}
</script>
  • Вопрос задан
  • 122 просмотра
Решения вопроса 1
0xD34F
@0xD34F Куратор тега Vue.js
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы