v-if에서 원활한 vue 축소 전환
v-iff smoothly를 사용하여 콘텐츠를 표시하거나 숨기려는 vue 전환에 어려움을 겪고 있습니다.css 클래스나 트랜지션은 이해하지만 불투명도나 번역 등을 사용하여 내용을 '원만하게' 표시할 수 있습니다.그러나 애니메이션이 완성되면(또는 시작과 동시에), 아래의 HTML 섹션은 '정지'되는 것처럼 보입니다.
Bootstrap 4의 'bootstrap' 클래스와 같은 효과를 얻으려고 합니다.여기서 상단 버튼 중 하나를 클릭해 주세요.https://getbootstrap.com/docs/4.0/components/collapse/
숨겨진 섹션이 나타나거나 사라짐에 따라 모든 html 컨텐츠가 "슬라이드"됩니다.
v-if를 사용하여 표시되는 컨텐츠에 대해 Vue 전환을 사용하여 이것이 가능합니까?vue 이행 문서의 모든 샘플은 이행이 시작되거나 완료되면 다음과 같은html '점프'가 발생합니다.
max-height를 사용하는 순수 js 솔루션을 본 적이 있습니다.https://jsfiddle.net/wideboy32/7ap15qq0/134/
vue를 사용하여 테스트했습니다.https://jsfiddle.net/wideboy32/eywraw8t/303737/
.smooth-enter-active, .smooth-leave-active {
transition: max-height .5s;
}
.smooth-enter, .smooth-leave-to {
max-height: 0 .5s;
}
감사합니다!
나도 비슷한 일이 있었다.JS 없이는 할 수 없다는 것을 알았습니다.커스텀 트랜지션 컴포넌트(Reusable Transitions)를 작성하면 다음과 같이 동작합니다.
Vue.component('transition-collapse-height', {
template: `<transition
enter-active-class="enter-active"
leave-active-class="leave-active"
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
@before-leave="beforeLeave"
@leave="leave"
@after-leave="afterLeave"
>
<slot />
</transition>`,
methods: {
/**
* @param {HTMLElement} element
*/
beforeEnter(element) {
requestAnimationFrame(() => {
if (!element.style.height) {
element.style.height = '0px';
}
element.style.display = null;
});
},
/**
* @param {HTMLElement} element
*/
enter(element) {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
element.style.height = `${element.scrollHeight}px`;
});
});
},
/**
* @param {HTMLElement} element
*/
afterEnter(element) {
element.style.height = null;
},
/**
* @param {HTMLElement} element
*/
beforeLeave(element) {
requestAnimationFrame(() => {
if (!element.style.height) {
element.style.height = `${element.offsetHeight}px`;
}
});
},
/**
* @param {HTMLElement} element
*/
leave(element) {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
element.style.height = '0px';
});
});
},
/**
* @param {HTMLElement} element
*/
afterLeave(element) {
element.style.height = null;
},
},
});
new Vue({
el: '#app',
data: () => ({
isOpen: true,
}),
methods: {
onClick() {
this.isOpen = !this.isOpen;
}
}
});
.enter-active,
.leave-active {
overflow: hidden;
transition: height 1s linear;
}
.content {
background: grey;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button @click="onClick">
open/hide
</button>
<transition-collapse-height>
<div v-show="isOpen" class="content">
<br/>
<br/>
<br/>
<br/>
</div>
</transition-collapse-height>
</div>
max-height를 애니메이션으로 만들려면 애니메이션화할 요소의 max-height 크기를 입력하고 max-height 정의에 s(또는 초)를 넣을 때 두 번째 클래스를 수정해야 합니다.
p{
max-height: 20px;
}
.smooth-enter-active, .smooth-leave-active {
transition: max-height .5s;
}
.smooth-enter, .smooth-leave-to {
max-height: 0;
}
bs4 collapse 같은 것을 원하는 경우 vue 웹사이트 내의 예는 다음과 같습니다.
.smooth-enter-active, .smooth-leave-active {
transition: opacity .5s;
}
.smooth-enter, .smooth-leave-to {
opacity: 0
}
편집 : 콘텐츠의 높이를 먼저 파악한 후 내부에 설정함으로써 원하는 작업을 수행할 수 있습니다..*-enter-to
그리고..*-leave
반.이를 위한 한 가지 방법은 다음과 같습니다.
https://jsfiddle.net/rezaxdi/sxgyj1f4/3/
또한 v-if나 v-show는 완전히 잊고 훨씬 부드러운 높이 값을 사용하여 요소를 숨길 수 있습니다.
https://jsfiddle.net/rezaxdi/tgfabw65/9/
웹 애니메이션 API를 기반으로 한 Vue3 솔루션은 데모를 참조하십시오. Alexandr Vysotsky가 이전에 여기에 게시한 솔루션과 다소 유사하지만 이 솔루션도 블록의 초기 높이를 유지합니다.
이 블로그 투고부터 시작해, 어떻게든 개선했습니다(대부분의 경우, 이행 종료 후의 컨텐츠 블록의 초기 스타일을 유지하기 위해서).가장 큰 변화는 Web Animation API로의 전환입니다.Web Animation API는 순수 CSS 애니메이션만큼 성능이 뛰어나고 훨씬 더 많은 컨트롤을 제공합니다.이것에 의해, 원래의 솔루션으로부터 모든 퍼포먼스 최적화 해킹이 배제되었습니다.
<script setup lang="ts">
interface Props {
duration?: number;
easingEnter?: string;
easingLeave?: string;
opacityClosed?: number;
opacityOpened?: number;
}
const props = withDefaults(defineProps<Props>(), {
duration: 250,
easingEnter: "ease-in-out",
easingLeave: "ease-in-out",
opacityClosed: 0,
opacityOpened: 1,
});
const closed = "0px";
interface initialStyle {
height: string;
width: string;
position: string;
visibility: string;
overflow: string;
paddingTop: string;
paddingBottom: string;
borderTopWidth: string;
borderBottomWidth: string;
marginTop: string;
marginBottom: string;
}
function getElementStyle(element: HTMLElement) {
return {
height: element.style.height,
width: element.style.width,
position: element.style.position,
visibility: element.style.visibility,
overflow: element.style.overflow,
paddingTop: element.style.paddingTop,
paddingBottom: element.style.paddingBottom,
borderTopWidth: element.style.borderTopWidth,
borderBottomWidth: element.style.borderBottomWidth,
marginTop: element.style.marginTop,
marginBottom: element.style.marginBottom,
};
}
function prepareElement(element: HTMLElement, initialStyle: initialStyle) {
const { width } = getComputedStyle(element);
element.style.width = width;
element.style.position = "absolute";
element.style.visibility = "hidden";
element.style.height = "";
let { height } = getComputedStyle(element);
element.style.width = initialStyle.width;
element.style.position = initialStyle.position;
element.style.visibility = initialStyle.visibility;
element.style.height = closed;
element.style.overflow = "hidden";
return initialStyle.height && initialStyle.height != closed
? initialStyle.height
: height;
}
function animateTransition(
element: HTMLElement,
initialStyle: initialStyle,
done: () => void,
keyframes: Keyframe[] | PropertyIndexedKeyframes | null,
options?: number | KeyframeAnimationOptions
) {
const animation = element.animate(keyframes, options);
// Set height to 'auto' to restore it after animation
element.style.height = initialStyle.height;
animation.onfinish = () => {
element.style.overflow = initialStyle.overflow;
done();
};
}
function getEnterKeyframes(height: string, initialStyle: initialStyle) {
return [
{
height: closed,
opacity: props.opacityClosed,
paddingTop: closed,
paddingBottom: closed,
borderTopWidth: closed,
borderBottomWidth: closed,
marginTop: closed,
marginBottom: closed,
},
{
height,
opacity: props.opacityOpened,
paddingTop: initialStyle.paddingTop,
paddingBottom: initialStyle.paddingBottom,
borderTopWidth: initialStyle.borderTopWidth,
borderBottomWidth: initialStyle.borderBottomWidth,
marginTop: initialStyle.marginTop,
marginBottom: initialStyle.marginBottom,
},
];
}
function enterTransition(element: Element, done: () => void) {
const HTMLElement = element as HTMLElement;
const initialStyle = getElementStyle(HTMLElement);
const height = prepareElement(HTMLElement, initialStyle);
const keyframes = getEnterKeyframes(height, initialStyle);
const options = { duration: props.duration, easing: props.easingEnter };
animateTransition(HTMLElement, initialStyle, done, keyframes, options);
}
function leaveTransition(element: Element, done: () => void) {
const HTMLElement = element as HTMLElement;
const initialStyle = getElementStyle(HTMLElement);
const { height } = getComputedStyle(HTMLElement);
HTMLElement.style.height = height;
HTMLElement.style.overflow = "hidden";
const keyframes = getEnterKeyframes(height, initialStyle).reverse();
const options = { duration: props.duration, easing: props.easingLeave };
animateTransition(HTMLElement, initialStyle, done, keyframes, options);
}
</script>
<template>
<Transition :css="false" @enter="enterTransition" @leave="leaveTransition">
<slot />
</Transition>
</template>
언급URL : https://stackoverflow.com/questions/52020624/smooth-vue-collapse-transition-on-v-if
'programing' 카테고리의 다른 글
자바 날짜에서 연도, 월, 일 등을 가져와 자바에서의 그레고리력 날짜와 비교하고 싶습니다.이게 가능합니까? (0) | 2022.08.27 |
---|---|
C - %x 형식 지정자 (0) | 2022.08.15 |
Set과 List의 차이점은 무엇입니까? (0) | 2022.08.15 |
Lodash ReferenceError: _는 Vue에서는 정의되어 있지 않습니다.다른 곳에서도 동작합니다. (0) | 2022.08.15 |
pty와 tty는 무슨 뜻입니까? (0) | 2022.08.15 |