VueJS JS-only 转换钩子需要 setTimeout 才能使 CSS 转换工作
Posted
技术标签:
【中文标题】VueJS JS-only 转换钩子需要 setTimeout 才能使 CSS 转换工作【英文标题】:VueJS JS-only transition hook requires setTimeout for CSS transition to work 【发布时间】:2019-08-10 21:38:54 【问题描述】:我正在为 VueJS 上的 <transition-group>
元素使用纯 JS 钩子,我对 enter
钩子的实际工作方式感到非常困惑。根据文档,我知道我将不得不call done()
to avoid events being called synchronously:
使用纯 javascript 转换时,
enter
和leave
挂钩需要done
回调。否则,钩子将被同步调用,并且过渡将立即完成。
但是,即使我使用它,它似乎也阻止了 CSS 过渡在 进入过渡 中发生。我找到的唯一解决方案是使用window.setTimeout
设置样式,我认为这是代码异味。这是没有超时的代码和有超时的代码之间的快速视觉比较(有超时的代码是想要的效果):
Broken enter 过渡(没有左侧填充和不透明度的过渡):
所需的输入转换:
在下面的示例中,我使用 <transition-group>
显示一个列表,并希望使用 JS-hooks 以便我可以在单个列表项上创建交错填充。除了在enter
转换中,填充属性上的 CSS 转换不起作用之外,它似乎可以工作。
new Vue(
el: '#app',
data:
items: [
'Lorem',
'Ipsum',
'Dolor',
'Sit',
'Amet'
],
toggle: false
,
computed:
filteredItems: function()
if (!this.toggle)
return [];
return this.items;
,
methods:
toggleItems: function()
this.toggle = !this.toggle;
,
beforeEnter: function(el)
el.style.paddingLeft = '0px';
el.style.opacity = '0';
,
enter: function(el, done)
el.style.paddingLeft = `$10 * +el.dataset.indexpx`;
el.style.opacity = '1';
done();
,
beforeLeave: function(el)
el.style.paddingLeft = '0px';
el.style.opacity = '0';
)
ul
list-style: none;
margin: 0;
padding: 0;
ul li
transition: all 500ms ease-in-out;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button @click="toggleItems">
Toggle items
</button>
<transition-group
tag="ul"
@before-enter="beforeEnter"
@enter="enter"
@before-leave="beforeLeave">
<li
v-for="(item, i) in filteredItems"
v-bind:key="i"
v-bind:data-index="i">
item
</li>
</transition-group>
</div>
如果您将enter
方法中的所有逻辑封装在任意超时中,那么它可以工作:
enter: function(el, done)
window.setTimeout(() =>
el.style.paddingLeft = `$10 * +el.dataset.indexpx`;
el.style.opacity = '1';
done();
, 100);
,
这就是我有点困惑的地方:enter
钩子不等待beforeEnter
先完成吗?工作的sn-p如下
【问题讨论】:
你不应该在enter
方法中调用done
。 done
仅在 JavaScript 转换中需要回调。您正在使用混合 CSS 过渡和 javascript
【参考方案1】:
将@enter
挂钩更改为@after-enter
应该可以解决问题
我不知道为什么 @enter
钩子不起作用,因为查看文档 应该 但这至少应该摆脱超时而不是黑客 p>
new Vue(
el: '#app',
data:
items: [
'Lorem',
'Ipsum',
'Dolor',
'Sit',
'Amet'
],
toggle: false
,
computed:
filteredItems: function()
if (!this.toggle)
return [];
return this.items;
,
methods:
toggleItems: function()
this.toggle = !this.toggle;
,
beforeEnter: function(el)
el.style.paddingLeft = '0px';
el.style.opacity = '0';
,
afterEnter: function(el)
el.style.paddingLeft = `$10 * +el.dataset.indexpx`;
el.style.opacity = '1';
,
beforeLeave: function(el)
el.style.paddingLeft = '0px';
el.style.opacity = '0';
)
ul
list-style: none;
margin: 0;
padding: 0;
ul li
transition: all 500ms ease-in-out;
li.v-enter-active
transition: none
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button @click="toggleItems">
Toggle items
</button>
<transition-group
tag="ul"
@before-enter="beforeEnter"
@after-enter="afterEnter"
@before-leave="beforeLeave">
<li v-for="(item, i) in filteredItems" v-bind:key="i" v-bind:data-index="i">
item
</li>
</transition-group>
</div>
附带说明,如果您使用的是 SCSS 或 SASS,则可以使用它而不是 JavaScript 来实现这一点
【讨论】:
感谢您的回答 :) 尽管这确实解决了问题,但您会注意到在列表项实际过渡之前存在一些延迟。我怀疑after-enter
挂钩被称为有点晚了。
@Terry 嗨,我现在刚刚编辑了答案,这是因为 @before-enter
和 @after-enter
的转换正在运行/执行,所以它需要 1s 一半的时间是不可见的,添加一个新的 ccs 规则可以解决这个问题。以上是关于VueJS JS-only 转换钩子需要 setTimeout 才能使 CSS 转换工作的主要内容,如果未能解决你的问题,请参考以下文章
Vuejs:使用keep alive的子routerview组件的生命周期钩子