<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'ом, но это не решает основной проблемы.
Есть решение на vue 2.<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>
Но оно не работает на vue 3, пробовал переписать - не хватило мозгов, да и хочется какое-то решение попроще.