我的过渡小组有问题。 问题是我正在尝试渲染按某种条件过滤的列表。在我的示例中-取决于最小/最大范围。
如何解决?
最初,我尝试使用转换组内部渲染的Array的计算值。但是很明显,每次更新范围滑块值时,它都会返回新数组。因此,我尝试使用@input
事件处理程序来更新仅在需要更新时才应呈现的列表。
最让我感到困惑的是,我尝试为@enter
@enter-to
@leave
@leave-to
事件设置过渡组挂钩,并且正确触发了它们。就一次。我也尝试使其变为JS驱动,但即使我设置了:css="false" :duration="500"
,过渡组也设置了CSS类。
我做了一个简单的例子来说明这个问题。 codesandbox.io
我希望列表(数组)得到更新,然后触发转换组的内容重新呈现。并执行FLIP动画。 但是问题在于,如果用作过滤条件的值快速更改(例如,用户使用鼠标拖动范围滑块),则根本不会执行动画,或者会导致滞后。从左向右拖动范围滑块(动画效果不佳)时,可以准确观看行为,这与从右向左拖动范围滑块时看到的行为有所不同(第一个元素不执行动画)。 另请注意,如果单击滑块以设置值-动画将按预期执行。
答案 0 :(得分:0)
Ref:“并且执行了FLIP动画” ...
考虑到您想翻转项目,我根本不会使用<transition-group>
。
我将使用3d旋转效果(我猜这是您想要的),并根据项目道具和范围值之间的关系,使用计算属性来控制旋转角度。
这里是:
Vue.config.devtools = false;
Vue.config.productionTip = false;
Vue.component('rotatingButton', {
template: `
<div>
<div class="flipper">
<div
class="items"
:style="{ transform: \`rotateX(\${rotation}deg)\` }">
<div v-for="item in items"
:key="item.ID"
:class="[item.value, 'item']"
v-text="item.value" />
</div>
</div>
<input type="range" v-model="range" min="0" max="1500">
<div class="color-range">
<div v-for="item in items"
:style="{width: \`\${(item.max - item.min)/15}%\`,
left: \`\${item.min/15}%\`,
backgroundColor: item.barColor }"
/>
</div>
</div>`,
data: () => ({
range: 100,
items: [{
ID: 0,
min: 0,
max: 500,
value: "first",
barColor: '#369'
}, {
ID: 1,
min: 500,
max: 700,
value: "second",
barColor: "#900"
}, {
ID: 2,
min: 700,
max: 1500,
value: "third",
barColor: "#393"
}
],
}),
computed: {
rotation() {
return this.range < this.items[0].max ? 0 : (this.range < this.items[1].max ? 90 : 180);
}
}
})
new Vue({
el: '#app'
});
#app {
text-align: center;
margin-top: 60px;
}
.flipper {
perspective: 210px;
height: 30px;
width: 150px;
line-height: 30px;
margin: 15px auto;
}
.items {
height: 100%;
perspective-origin: 150% 150%;
transform-style: preserve-3d;
transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.item {
display: block;
position: absolute;
width: 100%;
height: 100%;
border: 1px solid rgba(33,66,99,.33);
font: 25px monospace;
color: rgba(33,66,99,.33);
background-color: white;
}
.first { transform: translateZ(15px); }
.second { transform: rotateX(-90deg) translateZ(15px); }
.third { transform: rotateX(180deg) translateZ(15px); }
.fourth { transform: rotateX(90deg) translateZ(15px); }
.color-range {
padding: 0 1rem;
position: relative;
height: 4px;
}
input[type="range"] {width: 100%; margin: 0;}
.color-range > div {
position: absolute;
top: 0;
height: 100%;
opacity: .65;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<rotating-button />
</div>
如果需要,该示例可以扩展为处理大量项目:
Vue.config.devtools = false;
Vue.config.productionTip = false;
Vue.component('rotatingButton', {
template: `
<div>
<div class="flipper">
<div
class="items"
:style="{ transform: \`rotateX(\${rotation}deg)\` }">
<div v-for="(item, key) in items"
v-show="range > key -1 && range < key + 3"
:key="key"
:class="['item', \`key-\${key}\`]"
v-text="item + 1" />
</div>
</div>
<div class="inputs">
<input type="range" v-model="range" min="1" :max="max" step=".01">
<input type="number" v-model="max">
</div>
<pre>{{logger}}</pre>
</div>`,
data: () => ({
range: 10,
max: 15,
}),
computed: {
items() {
return _.times(this.max);
},
rotation() {
return Math.floor(((Number(this.range) * 9) + 36) * 1e3) / 1e2;
},
logger() {
return JSON.stringify({
range: Number(this.range),
items: Number(this.max),
rotation: this.rotation
}, true, 2);
}
},
})
new Vue({
el: '#app'
});
#app {
text-align: center;
}
.flipper {
perspective: 210px;
height: 30px;
width: 150px;
line-height: 30px;
margin: 15px auto;
}
.items {
height: 100%;
perspective-origin: 150% 150%;
transform-style: preserve-3d;
transition: transform 0.1s ease-in-out;
}
.item {
display: block;
position: absolute;
width: 100%;
height: 100%;
border: 1px solid rgba(33, 66, 99, .42);
font: 25px monospace;
color: rgba(33, 66, 99, .42);
background-color: white;
transform-style: preserve-3d;
}
.item {
transform: translateZ(15px);
}
.inputs {
display: flex;
padding: 0 1rem;
}
input[type="range"] {
flex-grow: 1;
margin: 0 1rem 0 0;
}
input[type="number"] {
font-size: 1.5rem;
width: 100px;
}
.item:nth-child(4n + 1) {
transform: rotateX(-90deg) translateZ(15px);
}
.item:nth-child(4n + 2) {
transform: rotateX(180deg) translateZ(15px);
}
.item:nth-child(4n + 3) {
transform: rotateX(90deg) translateZ(15px);
}
.color-range>div {
position: absolute;
top: 0;
height: 100%;
opacity: .65;
}
pre {
text-align: left;
background-color: #def;
border: 1px solid #ccc;
border-radius: .25rem;
padding: 1rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<rotating-button />
</div>