Vue.js 替换列表中的转换
Vue.js transition on replacing list
我遇到了 vue.js 官方文档 here 中描述的问题,但数据不同。我想用项目和子项目创建树状结构来描述树(文件和文件夹结构就是很好的例子)。为了增强视觉效果,我想让它们滑动,但我做到了。 mode="out-in"
已经设置,没有生效。
知道如何修复此转换吗?
Vue.component('booster', {
props: {
item: {
type: Object
}
},
template: '<div class="booster" @click="$emit(\'click\')"><img :src="item.image"></div>'
});
Vue.component('boosters', {
data: function() {
return {
boosters: this.items,
path: [],
root: this.items
};
},
props: {
items: {
type: Array
},
item_up: {
type: Object,
default: function() {
return {
name: "Up",
image: "http://via.placeholder.com/128x178/000000/ffffff?text=↑"
};
}
}
},
methods: {
navigate: function(item) {
var self = this;
if (item === self.item_up && self.path.length) {
self.root = self.path.pop();
} else if ("undefined" !== typeof item.items) {
self.path.push(self.root);
self.root = [self.item_up].concat(item.items);
} else {
console.log(item.name);
}
}
},
template: '<transition-group name="slide" mode="out-in" tag="div" class="boosters"><template v-for="item in root"><booster :item="item" :key="item.name" @click="navigate(item)"></booster></template></transition-group>'
});
var vue = new Vue({
el: '#content'
});
#content {
margin: 4rem;
}
.boosters {
display: flex;
flex-wrap: wrap;
align-content: center;
}
.booster {
box-shadow: 0px 0px 6px 3px black;
box-sizing: border-box;
margin: 15px;
}
.booster img {
width: 128px;
height: 178px;
display: block;
}
.slide-enter-active, .slide-leave-active {
transition: all 0.6s ease-in-out;*/
}
.slide-move {
transition: transform 0.5s;
}
.slide-enter {
transform: translateY(-100%);
}
.slide-leave-to {
transform: translateY(100%);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.3/vue.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="content">
<boosters :items='[
{name:"First",image:"http://via.placeholder.com/128x178?text=1",items:[
{name:"Sub-first-1",image:"http://via.placeholder.com/128x178?text=1.1"},
{name:"Sub-first-2",image:"http://via.placeholder.com/128x178?text=1.2"}
]},
{name:"Second",image:"http://via.placeholder.com/128x178?text=2", items:[
{name:"Sub-second-1",image:"http://via.placeholder.com/128x178?text=2.1"},
{name:"Sub-second-2",image:"http://via.placeholder.com/128x178?text=2.2"}
]},
{name:"Third",image:"http://via.placeholder.com/128x178?text=3"}
]'>
</booster>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
</div>
</body>
</html>
为什么带模式的过渡组什么都不做?
transition-group
没有 mode
属性。它被明确地从 transition-group.js
component source:
中的道具中删除
const props = extend({
tag: String,
moveClass: String
}, transitionProps)
delete props.mode
This is unlikely to happen due to the sheer complexity - it will likely introduce too much extra code for a relatively non-critical use case, and the behavior of the transition modes on multiple items can be vague and hard to define. Even if we were to implement it, we'd probably ship it as a separate plugin instead of as part of core.
我打开了an issue to mention that in the documentation on list transition. It's now in the documentation:
Transition modes are not available, because we are no longer alternating between mutually exclusive elements.
如何使用完整列表模拟 out-in
转换
提到的一个小解决方法 by NonPolynomial in the issue 是使用 transition-delay
将进入动画延迟到离开动画完成后。
new Vue({
el: '#app',
data: {
elements: [
[1, 2, 3],
[4, 5, 6, 7]
],
index: 0
},
});
.fade-out-in-enter-active,
.fade-out-in-leave-active {
transition: opacity .5s;
}
.fade-out-in-enter-active {
transition-delay: .5s;
}
.fade-out-in-enter,
.fade-out-in-leave-to {
opacity: 0;
}
<div id="app">
<button type="button" @click="index = (index + 1) % elements.length">Swap</button>
<transition-group tag="ul" name="fade-out-in">
<li v-for="num in elements[index]" :key="num">
{{num}}
</li>
</transition-group>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
作为替代方案,Staggering List Transitions 上的文档有一个很好的示例,说明如何使用 JavaScript 处理过渡以获得完全控制。
new Vue({
el: '#staggered-list-demo',
data: {
query: '',
list: [
{ msg: 'Bruce Lee' },
{ msg: 'Jackie Chan' },
{ msg: 'Chuck Norris' },
{ msg: 'Jet Li' },
{ msg: 'Kung Fury' }
]
},
computed: {
computedList: function () {
var vm = this
return this.list.filter(function (item) {
return item.msg.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1
})
}
},
methods: {
beforeEnter: function (el) {
el.style.opacity = 0
el.style.height = 0
},
enter: function (el, done) {
var delay = el.dataset.index * 150
setTimeout(function () {
Velocity(
el,
{ opacity: 1, height: '1.6em' },
{ complete: done }
)
}, delay)
},
leave: function (el, done) {
var delay = el.dataset.index * 150
setTimeout(function () {
Velocity(
el,
{ opacity: 0, height: 0 },
{ complete: done }
)
}, delay)
}
}
})
<div id="staggered-list-demo">
<input v-model="query">
<transition-group
name="staggered-fade"
tag="ul"
v-bind:css="false"
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:leave="leave"
>
<li
v-for="(item, index) in computedList"
v-bind:key="item.msg"
v-bind:data-index="index"
>{{ item.msg }}</li>
</transition-group>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
我遇到了 vue.js 官方文档 here 中描述的问题,但数据不同。我想用项目和子项目创建树状结构来描述树(文件和文件夹结构就是很好的例子)。为了增强视觉效果,我想让它们滑动,但我做到了。 mode="out-in"
已经设置,没有生效。
知道如何修复此转换吗?
Vue.component('booster', {
props: {
item: {
type: Object
}
},
template: '<div class="booster" @click="$emit(\'click\')"><img :src="item.image"></div>'
});
Vue.component('boosters', {
data: function() {
return {
boosters: this.items,
path: [],
root: this.items
};
},
props: {
items: {
type: Array
},
item_up: {
type: Object,
default: function() {
return {
name: "Up",
image: "http://via.placeholder.com/128x178/000000/ffffff?text=↑"
};
}
}
},
methods: {
navigate: function(item) {
var self = this;
if (item === self.item_up && self.path.length) {
self.root = self.path.pop();
} else if ("undefined" !== typeof item.items) {
self.path.push(self.root);
self.root = [self.item_up].concat(item.items);
} else {
console.log(item.name);
}
}
},
template: '<transition-group name="slide" mode="out-in" tag="div" class="boosters"><template v-for="item in root"><booster :item="item" :key="item.name" @click="navigate(item)"></booster></template></transition-group>'
});
var vue = new Vue({
el: '#content'
});
#content {
margin: 4rem;
}
.boosters {
display: flex;
flex-wrap: wrap;
align-content: center;
}
.booster {
box-shadow: 0px 0px 6px 3px black;
box-sizing: border-box;
margin: 15px;
}
.booster img {
width: 128px;
height: 178px;
display: block;
}
.slide-enter-active, .slide-leave-active {
transition: all 0.6s ease-in-out;*/
}
.slide-move {
transition: transform 0.5s;
}
.slide-enter {
transform: translateY(-100%);
}
.slide-leave-to {
transform: translateY(100%);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.3/vue.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="content">
<boosters :items='[
{name:"First",image:"http://via.placeholder.com/128x178?text=1",items:[
{name:"Sub-first-1",image:"http://via.placeholder.com/128x178?text=1.1"},
{name:"Sub-first-2",image:"http://via.placeholder.com/128x178?text=1.2"}
]},
{name:"Second",image:"http://via.placeholder.com/128x178?text=2", items:[
{name:"Sub-second-1",image:"http://via.placeholder.com/128x178?text=2.1"},
{name:"Sub-second-2",image:"http://via.placeholder.com/128x178?text=2.2"}
]},
{name:"Third",image:"http://via.placeholder.com/128x178?text=3"}
]'>
</booster>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
</div>
</body>
</html>
为什么带模式的过渡组什么都不做?
transition-group
没有 mode
属性。它被明确地从 transition-group.js
component source:
const props = extend({
tag: String,
moveClass: String
}, transitionProps)
delete props.mode
This is unlikely to happen due to the sheer complexity - it will likely introduce too much extra code for a relatively non-critical use case, and the behavior of the transition modes on multiple items can be vague and hard to define. Even if we were to implement it, we'd probably ship it as a separate plugin instead of as part of core.
我打开了an issue to mention that in the documentation on list transition. It's now in the documentation:
Transition modes are not available, because we are no longer alternating between mutually exclusive elements.
如何使用完整列表模拟 out-in
转换
提到的一个小解决方法 by NonPolynomial in the issue 是使用 transition-delay
将进入动画延迟到离开动画完成后。
new Vue({
el: '#app',
data: {
elements: [
[1, 2, 3],
[4, 5, 6, 7]
],
index: 0
},
});
.fade-out-in-enter-active,
.fade-out-in-leave-active {
transition: opacity .5s;
}
.fade-out-in-enter-active {
transition-delay: .5s;
}
.fade-out-in-enter,
.fade-out-in-leave-to {
opacity: 0;
}
<div id="app">
<button type="button" @click="index = (index + 1) % elements.length">Swap</button>
<transition-group tag="ul" name="fade-out-in">
<li v-for="num in elements[index]" :key="num">
{{num}}
</li>
</transition-group>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
作为替代方案,Staggering List Transitions 上的文档有一个很好的示例,说明如何使用 JavaScript 处理过渡以获得完全控制。
new Vue({
el: '#staggered-list-demo',
data: {
query: '',
list: [
{ msg: 'Bruce Lee' },
{ msg: 'Jackie Chan' },
{ msg: 'Chuck Norris' },
{ msg: 'Jet Li' },
{ msg: 'Kung Fury' }
]
},
computed: {
computedList: function () {
var vm = this
return this.list.filter(function (item) {
return item.msg.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1
})
}
},
methods: {
beforeEnter: function (el) {
el.style.opacity = 0
el.style.height = 0
},
enter: function (el, done) {
var delay = el.dataset.index * 150
setTimeout(function () {
Velocity(
el,
{ opacity: 1, height: '1.6em' },
{ complete: done }
)
}, delay)
},
leave: function (el, done) {
var delay = el.dataset.index * 150
setTimeout(function () {
Velocity(
el,
{ opacity: 0, height: 0 },
{ complete: done }
)
}, delay)
}
}
})
<div id="staggered-list-demo">
<input v-model="query">
<transition-group
name="staggered-fade"
tag="ul"
v-bind:css="false"
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:leave="leave"
>
<li
v-for="(item, index) in computedList"
v-bind:key="item.msg"
v-bind:data-index="index"
>{{ item.msg }}</li>
</transition-group>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.2.3/velocity.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>