在Vuejs中使用Transition在v-if上设置高度动画
Posted
技术标签:
【中文标题】在Vuejs中使用Transition在v-if上设置高度动画【英文标题】:Animate Height on v-if in Vuejs using Transition 【发布时间】:2017-07-24 07:09:56 【问题描述】:我正在使用以下代码通过将高度降低到 0px 来为 v-if 元素设置动画。动画效果很好。但问题是我必须指定元素的初始高度是 CSS。对于一个元素,这是可以的,但我想将此动画应用于多个元素。我怎样才能解决这个问题?这样无论高度如何,动画都可以正常工作!
<transition name="fadeHeight" mode="out-in">
<div v-if="something">
<p>something over here where the height is not constant</p>
</div>
</transition>
.fadeHeight-enter-active,
.fadeHeight-leave-active
transition: all 0.2s;
height: 230px;
.fadeHeight-enter,
.fadeHeight-leave-to
opacity: 0;
height: 0px;
【问题讨论】:
【参考方案1】:您似乎没有发布所有代码,但希望我能理解目标。
尝试将过渡移动到max-height
属性:
.fadeHeight-enter-active,
.fadeHeight-leave-active
transition: all 0.2s;
max-height: 230px;
.fadeHeight-enter,
.fadeHeight-leave-to
opacity: 0;
max-height: 0px;
只要将最大高度设置为大于最高元素,它就可以满足您的需求。请注意,您可能还想使用overflow:hidden
。如果元素的实际高度有显着变化,则此解决方案可能不是最佳解决方案,因为它会使动画持续时间/延迟显得非常不同。
https://jsfiddle.net/7ap15qq0/4/
【讨论】:
这不是一个干净的动画,不应该是接受者的答案,这只是一个 CSS hack。设置更高的 max-height 值会以一种方式延迟动画并减少另一种方式的过渡时间。 完全同意它并不完美,但它不是黑客——它直接回答了被问到的问题。答案已经指出了效果的潜在问题/变化,具体取决于相对于使用的最大高度值的大小。如果您正在寻找不同的东西,这里有一些替代方案和优缺点的详细分类:css-tricks.com/using-css-transitions-auto-dimensions 没有必要使用最大高度方法的过渡组件。因为它只贡献更多代码。【参考方案2】:@ryantdecker 有最常见的答案。我更喜欢少写代码,而是使用 class binding:
<template>
<!-- isShowing either a data or computed... -->
<div class="foo" :class="'showing': isShowing', 'hidden': !isShowing">
<p>
something over here where the height is not constant
</p>
</div>
</template>
...
<style>
.foo
height: auto;
transition: max-height 0.5s;
&.showing
max-height: 200px; //MUST BE MORE THAN height:auto
&.hidden
max-height: 0px;
</style>
可以进行更多控制的一些自定义是:
-
设置
:style="'max-height': computedHeight"
在.showing
和.hidden
类中分别使用ease-in
和ease-out
和两个不同的transitions
。
对折叠/展开的超长内容使用三次贝塞尔曲线过渡速度
当您使用不同的项目时,可以使用上面的第一个自定义项,例如图片、可以通过 devtools 看到高度并计算高度的弹性行。例如:
computed:
/**
* @return string max height of the container in pixels if shown else zero
*/
calcedHeight()
const elHeight = 80;
const maxHeight = this.isShowing ? elHeight * this.elementCount : 0
const maxHeightPx = maxHeight + 'px'
return
'max-height': maxHeightPx
此时可以很容易地用isShowing
、elHeight
和elCount
属性将其制成组件。
三次贝塞尔曲线
我给这个它自己的部分,因为它可能是关于疯狂的长元素所需要的(想想 5000px max-heights
):
&.showing
transition: all 0.6s cubic-bezier(1, 0.01, 1, 0.01);
&.hidden
transition: all 0.6s cubic-bezier(0.01, 1, 0.01, 1);
【讨论】:
【参考方案3】:如前所述 - maxheight 过渡通常是解决此问题的方法。 但在某些情况下,您可能无法使用 maxheight 过渡。 对于这些情况,您可以使用包装容器组件,该组件将在需要时进行转换。
<template>
<div
class="fluid-wrapper"
:class=" 'in-transition': transitionState "
:style="computedDimensions"
@transitionend="transitionState = 0"
>
<slot />
</div>
</template>
<script>
export default
name: 'FluidContainer',
props: ['trigger'],
data()
return
oldRect:
height: null,
width: null,
,
newRect:
height: null,
width: null,
,
transitionState: 0,
// 0: no Dimensions, no transition
// 1: oldRect Dimensions, transition is on
// 2: newRect Dimensions, transition is on
;
,
computed:
computedDimensions()
if (!this.transitionState)
return null;
return this.transitionState === 1 ? this.oldRect : this.newRect;
,
dimensionsHasChanged()
return (
this.newRect.height !== this.oldRect.height
|| this.newRect.width !== this.oldRect.width
);
,
,
watch:
trigger()
const oldStyle = getComputedStyle(this.$el);
this.oldRect.height = oldStyle.height;
this.oldRect.width = oldStyle.width;
this.$nextTick(() =>
const newStyle = getComputedStyle(this.$el);
this.newRect.height = newStyle.height;
this.newRect.width = newStyle.width;
if (this.dimensionsHasChanged)
this.transitionState = 1;
window.requestAnimationFrame(() =>
this.transitionState = 2;
);
else
this.transitionState = 0;
);
,
,
;
</script>
<style lang="scss" scoped>
.fluid-wrapper
/* overflow: hidden; */
height: fit-content;
width: fit-content;
&.in-transition
transition: all 0.3s;
</style>
用法:
<FluidContainer :trigger="some-variable">
<!-- Any Reactive Content -->
</FluidContainer>
'trigger' 道具 - 需要它才能工作。 它可以是使内部内容发生变化的任何状态。 包装器将监视触发器以检测何时发生尺寸变化并进行转换。
【讨论】:
以上是关于在Vuejs中使用Transition在v-if上设置高度动画的主要内容,如果未能解决你的问题,请参考以下文章