多元素动画
上面讲的都是针对单个元素进行动画,如果你将Animate
嵌套使用,那么父Animate
组件还能充当动画管理者,它可以控制所有子Animate
组件的动画。
<div>
<button ev-click={self.set.bind(self, 'show', !self.get('show'))}>切换</button>
<Animate>
<Animate v-if={self.get('show')} key="show">show</Animate>
<Animate v-else key="hide">hide</Animate>
</Animate>
</div>
多元素动画,你必须为每一个子
Animate
组件指定一个唯一的key
Animate
多元素动画时,会默认给离开的元素设置position: absolute
,所以你会看到上述例子中,动画元素是重叠的。如果你不想元素离开时绝对定位,你可以设置动画管理者Animate
组件的a:move
为false
。
a:move
的作用下面会讲到
动画模式
Animate
管理的子元素,进入/离开是同时进行的,通过动画模式属性a:mode
,你可以改变这一规则。它的取值为:
both
默认模式,同时进入/离开out-in
旧元素离开后,新元素再进入in-out
新元素进入后,旧元素再离开
使用out-in
的例子
<Animate a:mode="out-in" a:move={false}>
<Animate a:tag="button" v-if={!self.get('disabled')}
ev-click={self.set.bind(self, 'disabled', true)}
key="on"
class="static"
>on</Animate>
<Animate a:tag="button" v-else
ev-click={self.set.bind(self, 'disabled', false)}
key="off"
class="static"
>off</Animate>
</Animate>
列表动画
多元素动画最常见的使用场景是列表渲染。例如:
.list div {
display: inline-block;
padding: 5px 10px;
border: 1px solid #eee;
margin: 5px;
}
.list-enter, .list-leave {
opacity: 0;
transform: translateY(20px);
}
.list-enter-active, .list-leave-active, .list-move {
transition: all 1s;
}
<div>
<button ev-click={self.add.bind(self)}>添加</button>
<button ev-click={self.remove.bind(self)}>删除</button>
<Animate a:move={false} class="list">
<Animate v-for={self.get('list')}
key={value}
a:transition="list"
>{value}</Animate>
</Animate>
</div>
Intact.extend({
template: template,
defaults: function() {
this.nextNum = 6;
return {
list: [1, 2, 3, 4, 5]
};
},
randomIndex: function() {
return Math.floor(Math.random() * this.get('list').length);
},
add: function() {
var list = this.get('list').slice(0);
list.splice(this.randomIndex(), 0, this.nextNum++);
this.set('list', list);
},
remove: function() {
this.get('list').splice(this.randomIndex(), 1);
this.update();
}
});
列表位移动画
上述例子存在一个问题:元素插入和删除时,兄弟元素的位置是瞬间移动的,这样显得很突兀。通过设置列表位移动画,可以使兄弟元素的移动也加入动画。而该功能默认是开启的,就是上面提到的a:move
属性。它对应的css类名为animate-move
,你只需要为该类名添加transition
样式即可。
.animate-move {
transition: transform 1s;
}
<div>
<button ev-click={self.shuffle.bind(self)}>打乱</button>
<button ev-click={self.add.bind(self)}>添加</button>
<button ev-click={self.remove.bind(self)}>删除</button>
<Animate class="list">
<Animate v-for={self.get('list')} key={value} a:transition="list">
{value}
</Animate>
</Animate>
</div>
Intact.extend({
template: template,
defaults: function() {
this.nextNum = 6;
return {
list: [1, 2, 3, 4, 5]
};
},
shuffle: function() {
this.set('list', _.shuffle(this.get('list')));
},
randomIndex: function() {
return Math.floor(Math.random() * this.get('list').length);
},
add: function() {
var list = this.get('list').slice(0);
list.splice(this.randomIndex(), 0, this.nextNum++);
this.set('list', list);
},
remove: function() {
this.get('list').splice(this.randomIndex(), 1);
this.update();
}
});
动画模式与列表动画结合
动画模式a:mode
不仅仅只支持单个元素,对于列表动画也支持。
<div>
<button ev-click={self.addAndRemove.bind(self)}>添加一个同时删除一个</button>
<Animate a:mode="in-out" class="list">
<Animate v-for={self.get('list')} key={value} a:transition="list">
{value}
</Animate>
</Animate>
</div>
Intact.extend({
template: template,
defaults: function() {
this.nextNum = 6;
return {
list: [1, 2, 3, 4, 5]
};
},
randomIndex: function(num) {
return Math.floor(Math.random() * (this.get('list').length + num));
},
addAndRemove: function() {
var list = this.get('list').slice(0);
var addIndex = this.randomIndex(0);
var removeIndex = this.randomIndex(1);
while (removeIndex === addIndex) removeIndex = this.randomIndex(1);
list.splice(addIndex, 0, this.nextNum++);
list.splice(removeIndex, 1);
this.set('list', list);
}
});
Animate
仅支持DOM元素的动画,暂不支持组件的动画