VueJS 仅 JS 转换挂钩需要 setTimeout 才能使 CSS 转换正常工作
VueJS JS-only transition hook requires setTimeout for CSS transition to work
我正在为 VueJS 上的 <transition-group>
元素使用纯 JS 钩子,我对 enter
钩子的实际工作方式感到非常困惑。根据文档,我知道我必须 call done()
to avoid events being called synchronously:
When using JavaScript-only transitions, the done
callbacks are required for the enter
and leave
hooks. Otherwise, the hooks will be called synchronously and the transition will finish immediately.
然而,即使我使用它,它似乎也阻止了 CSS 转换在 进入转换 中发生。我找到的唯一解决方案是使用 window.setTimeout
设置样式,我认为这是一种代码味道。这是没有超时的代码和有超时的代码之间的快速视觉比较(有超时的是预期的效果):
损坏的输入过渡(左填充和不透明度没有过渡):
所需的进入转换:
在下面的示例中,我使用 <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.index}px`;
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.index}px`;
el.style.opacity = '1';
done();
}, 100);
},
这就是我有点困惑的地方:enter
挂钩不会先等待 beforeEnter
完成吗?工作片段如下
将 @enter
挂钩更改为 @after-enter
应该可以解决这个问题
我不知道为什么 @enter
挂钩对此不起作用,因为查看文档它 应该 但这至少应该摆脱超时而不是黑客
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.index}px`;
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,则可以使用 SCSS 而不是 JavaScript
我正在为 VueJS 上的 <transition-group>
元素使用纯 JS 钩子,我对 enter
钩子的实际工作方式感到非常困惑。根据文档,我知道我必须 call done()
to avoid events being called synchronously:
When using JavaScript-only transitions, the
done
callbacks are required for theenter
andleave
hooks. Otherwise, the hooks will be called synchronously and the transition will finish immediately.
然而,即使我使用它,它似乎也阻止了 CSS 转换在 进入转换 中发生。我找到的唯一解决方案是使用 window.setTimeout
设置样式,我认为这是一种代码味道。这是没有超时的代码和有超时的代码之间的快速视觉比较(有超时的是预期的效果):
损坏的输入过渡(左填充和不透明度没有过渡):
所需的进入转换:
在下面的示例中,我使用 <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.index}px`;
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.index}px`;
el.style.opacity = '1';
done();
}, 100);
},
这就是我有点困惑的地方:enter
挂钩不会先等待 beforeEnter
完成吗?工作片段如下
将 @enter
挂钩更改为 @after-enter
应该可以解决这个问题
我不知道为什么 @enter
挂钩对此不起作用,因为查看文档它 应该 但这至少应该摆脱超时而不是黑客
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.index}px`;
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,则可以使用 SCSS 而不是 JavaScript