Vuejs transition css 只能向下滑动
Vuejs transition css only slide down
我已经搜索了很长时间来解决这个问题,但我似乎找不到解决这个问题的最佳方法。基本上我有一个手风琴,当用户打开它时,它应该以一个很好的过渡轻轻地滑下来。
我很确定只有 css 才有可能做到这一点。如果我错了请纠正我,但是 css 转换在性能方面比 js 转换更好。
现在 HTML 我面临的问题是:
<transition name="slide-down">
<ul v-if="isDisplayingOpeningHours" class="mt-2 text-sm flex flex-col space-y-2">
<li v-for="i in 10" :key="i"> <!-- just for testing purposes -->
element
</li>
</ul>
</transition>
而 css 是:
.slide-down-enter-active, .slide-down-leave-active {
transition: all .5s;
}
.slide-down-enter-to, .slide-down-leave {
overflow: hidden;
max-height: 100%;
}
.slide-down-enter, .slide-down-leave-to {
overflow: hidden;
max-height: 0;
}
这导致过渡不流畅。滑下来好像没什么问题,但是滑上去的时候真的很卡,一点都不流畅!。如果我设置 max-height: 10rem
它并没有让它变得更好。我希望有人可以调试帮助我解决这个问题,也许可以教育我更多关于 vue 转换和 js 与 css 转换的知识。
编辑:
只是为了澄清,过渡本身应该只 css。手风琴的开头是用 js 的,这很好。另外,如果能看到一个使用原生 vue-transition 组件的过渡示例,那就太好了。
编辑 2:
这是一个与我有同样问题的codesandbox。
https://codesandbox.io/s/frosty-bash-lmc2f?file=/src/components/HelloWorld.vue
另一个更新!!!
为了实现 JS 转换你可以看看 official document to learn. Anyways, I am not going to implement fancy timing mechanism, but in simplest form, JS collapse transition in react will look something like following, I included it in existing codesandbox:
<template>
...
<div>
<button @click="jsOpen = !jsOpen">Open JS list</button>
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
v-on:enter-cancelled="enterCancelled"
v-on:before-leave="beforeLeave"
v-on:leave="leave"
v-on:after-leave="afterLeave"
v-on:level-cancelled="leaveCancelled"
v-bind:css="false"
>
<ul v-if="jsOpen" class="mt-2 text-sm flex flex-col space-y-2">
<li v-for="i in 10" :key="i">item-{{ i }}</li>
</ul>
</transition>
</div>
</template>
<script>
export default {
...
methods: {
beforeEnter(el) {
el.style.height = 0;
el.style.overflow = "hidden";
},
enter(el, done) {
const increaseHeight = () => {
if (el.clientHeight < el.scrollHeight) {
const height = `${parseInt(el.style.height) + 5}px`;
el.style.height = height;
} else {
clearInterval(this.enterInterval);
done();
}
};
this.enterInterval = setInterval(increaseHeight, 10);
},
afterEnter(el) {},
enterCancelled(el) {
clearInterval(this.enterInterval);
},
beforeLeave(el) {},
leave(el, done) {
const decreaseHeight = () => {
if (el.clientHeight > 0) {
const height = `${parseInt(el.style.height) - 5}px`;
el.style.height = height;
} else {
clearInterval(this.leaveInterval);
done();
}
};
this.leaveInterval = setInterval(decreaseHeight, 10);
},
afterLeave(el) {},
leaveCancelled(el) {
clearInterval(this.leaveInterval);
},
},
};
</script>
更新:
在了解了 OP 的要求后,我尝试尝试不同的东西,我偶然发现了 this article on css-tricks which explains in much more details about transition, from that article another non-js solution proposed would look like following, I included it in existing stackblitz:
.scale-enter-active,
.scale-leave-active {
transform-origin: top;
transition: transform 0.3s ease-in-out;
}
.scale-enter-to,
.scale-leave-from {
transform: scaleY(1);
}
.scale-enter-from,
.scale-leave-to {
transform: scaleY(0);
}
此处不是高度,而是针对 y-axis 进行缩放。 IT 还有一个副作用,它首先将容器扩展到完整大小,然后再更新(缩放)内容。
Vuev3.x
-leave
和 -enter
类 在 V3 are renamed to -leave-from
and -enter-from
. Take a look at this stackblitz.
.slidedown-enter-active,
.slidedown-leave-active {
transition: max-height 0.5s ease-in-out;
}
.slidedown-enter-to,
.slidedown-leave-from {
overflow: hidden;
max-height: 1000px;
}
.slidedown-enter-from,
.slidedown-leave-to {
overflow: hidden;
max-height: 0;
}
Vuev2.x
问题是您将 max-height
指定为 100%,使用的值将大于您预期的 max-height。将您的风格更新为:
.slide-down-enter-active,
.slide-down-leave-active {
transition: max-height 0.5s ease-in-out;
}
.slide-down-enter-to,
.slide-down-leave {
overflow: hidden;
max-height: 1000px;
}
.slide-down-enter,
.slide-down-leave-to {
overflow: hidden;
max-height: 0;
}
它应该可以工作。看看这个 codesandbox 演示。
我已经搜索了很长时间来解决这个问题,但我似乎找不到解决这个问题的最佳方法。基本上我有一个手风琴,当用户打开它时,它应该以一个很好的过渡轻轻地滑下来。
我很确定只有 css 才有可能做到这一点。如果我错了请纠正我,但是 css 转换在性能方面比 js 转换更好。
现在 HTML 我面临的问题是:
<transition name="slide-down">
<ul v-if="isDisplayingOpeningHours" class="mt-2 text-sm flex flex-col space-y-2">
<li v-for="i in 10" :key="i"> <!-- just for testing purposes -->
element
</li>
</ul>
</transition>
而 css 是:
.slide-down-enter-active, .slide-down-leave-active {
transition: all .5s;
}
.slide-down-enter-to, .slide-down-leave {
overflow: hidden;
max-height: 100%;
}
.slide-down-enter, .slide-down-leave-to {
overflow: hidden;
max-height: 0;
}
这导致过渡不流畅。滑下来好像没什么问题,但是滑上去的时候真的很卡,一点都不流畅!。如果我设置 max-height: 10rem
它并没有让它变得更好。我希望有人可以调试帮助我解决这个问题,也许可以教育我更多关于 vue 转换和 js 与 css 转换的知识。
编辑:
只是为了澄清,过渡本身应该只 css。手风琴的开头是用 js 的,这很好。另外,如果能看到一个使用原生 vue-transition 组件的过渡示例,那就太好了。
编辑 2:
这是一个与我有同样问题的codesandbox。
https://codesandbox.io/s/frosty-bash-lmc2f?file=/src/components/HelloWorld.vue
另一个更新!!! 为了实现 JS 转换你可以看看 official document to learn. Anyways, I am not going to implement fancy timing mechanism, but in simplest form, JS collapse transition in react will look something like following, I included it in existing codesandbox:
<template>
...
<div>
<button @click="jsOpen = !jsOpen">Open JS list</button>
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
v-on:enter-cancelled="enterCancelled"
v-on:before-leave="beforeLeave"
v-on:leave="leave"
v-on:after-leave="afterLeave"
v-on:level-cancelled="leaveCancelled"
v-bind:css="false"
>
<ul v-if="jsOpen" class="mt-2 text-sm flex flex-col space-y-2">
<li v-for="i in 10" :key="i">item-{{ i }}</li>
</ul>
</transition>
</div>
</template>
<script>
export default {
...
methods: {
beforeEnter(el) {
el.style.height = 0;
el.style.overflow = "hidden";
},
enter(el, done) {
const increaseHeight = () => {
if (el.clientHeight < el.scrollHeight) {
const height = `${parseInt(el.style.height) + 5}px`;
el.style.height = height;
} else {
clearInterval(this.enterInterval);
done();
}
};
this.enterInterval = setInterval(increaseHeight, 10);
},
afterEnter(el) {},
enterCancelled(el) {
clearInterval(this.enterInterval);
},
beforeLeave(el) {},
leave(el, done) {
const decreaseHeight = () => {
if (el.clientHeight > 0) {
const height = `${parseInt(el.style.height) - 5}px`;
el.style.height = height;
} else {
clearInterval(this.leaveInterval);
done();
}
};
this.leaveInterval = setInterval(decreaseHeight, 10);
},
afterLeave(el) {},
leaveCancelled(el) {
clearInterval(this.leaveInterval);
},
},
};
</script>
更新: 在了解了 OP 的要求后,我尝试尝试不同的东西,我偶然发现了 this article on css-tricks which explains in much more details about transition, from that article another non-js solution proposed would look like following, I included it in existing stackblitz:
.scale-enter-active,
.scale-leave-active {
transform-origin: top;
transition: transform 0.3s ease-in-out;
}
.scale-enter-to,
.scale-leave-from {
transform: scaleY(1);
}
.scale-enter-from,
.scale-leave-to {
transform: scaleY(0);
}
此处不是高度,而是针对 y-axis 进行缩放。 IT 还有一个副作用,它首先将容器扩展到完整大小,然后再更新(缩放)内容。
Vuev3.x
-leave
和 -enter
类 在 V3 are renamed to -leave-from
and -enter-from
. Take a look at this stackblitz.
.slidedown-enter-active,
.slidedown-leave-active {
transition: max-height 0.5s ease-in-out;
}
.slidedown-enter-to,
.slidedown-leave-from {
overflow: hidden;
max-height: 1000px;
}
.slidedown-enter-from,
.slidedown-leave-to {
overflow: hidden;
max-height: 0;
}
Vuev2.x
问题是您将 max-height
指定为 100%,使用的值将大于您预期的 max-height。将您的风格更新为:
.slide-down-enter-active,
.slide-down-leave-active {
transition: max-height 0.5s ease-in-out;
}
.slide-down-enter-to,
.slide-down-leave {
overflow: hidden;
max-height: 1000px;
}
.slide-down-enter,
.slide-down-leave-to {
overflow: hidden;
max-height: 0;
}
它应该可以工作。看看这个 codesandbox 演示。