[Improvement] Collapse: add transition animation (#1500)

This commit is contained in:
neverland 2018-07-17 21:33:55 +08:00 committed by GitHub
parent a99e73e07e
commit 9da3e0ce5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 88 additions and 16 deletions

View File

@ -8,15 +8,18 @@
<cell :class="b('title')" is-link @click="onClick"> <cell :class="b('title')" is-link @click="onClick">
<slot name="title">{{ title }}</slot> <slot name="title">{{ title }}</slot>
</cell> </cell>
<div v-show="expanded" :class="b('content')"> <div v-show="show" ref="wrapper" :class="b('wrapper')" @transitionend="onTransitionEnd">
<div ref="content" :class="b('content')">
<slot /> <slot />
</div> </div>
</div> </div>
</div>
</template> </template>
<script> <script>
import findParent from '../mixins/find-parent'; import { raf } from '../utils/raf';
import create from '../utils/create'; import create from '../utils/create';
import findParent from '../mixins/find-parent';
export default create({ export default create({
name: 'collapse-item', name: 'collapse-item',
@ -28,6 +31,12 @@ export default create({
title: String title: String
}, },
data() {
return {
show: null
};
},
computed: { computed: {
items() { items() {
return this.parent.items; return this.parent.items;
@ -42,6 +51,10 @@ export default create({
}, },
expanded() { expanded() {
if (!this.parent) {
return null;
}
const { value } = this.parent; const { value } = this.parent;
return this.parent.accordion return this.parent.accordion
? value === this.currentName ? value === this.currentName
@ -52,17 +65,52 @@ export default create({
created() { created() {
this.findParent('van-collapse'); this.findParent('van-collapse');
this.items.push(this); this.items.push(this);
this.show = this.expanded;
}, },
destroyed() { destroyed() {
this.items.splice(this.index, 1); this.items.splice(this.index, 1);
}, },
watch: {
expanded(expanded, prev) {
if (prev === null) {
return;
}
if (expanded) {
this.show = true;
}
this.$nextTick(() => {
const { content, wrapper } = this.$refs;
if (!content || !wrapper) {
return;
}
const contentHeight = content.clientHeight + 'px';
wrapper.style.height = expanded ? 0 : contentHeight;
raf(() => {
wrapper.style.height = expanded ? contentHeight : 0;
});
});
}
},
methods: { methods: {
onClick() { onClick() {
const { parent } = this; const { parent } = this;
const name = parent.accordion && this.currentName === parent.value ? '' : this.currentName; const name = parent.accordion && this.currentName === parent.value ? '' : this.currentName;
this.parent.switch(name, !this.expanded); const expanded = !this.expanded;
this.parent.switch(name, expanded);
},
onTransitionEnd() {
if (!this.expanded) {
this.show = false;
} else {
this.$refs.wrapper.style.height = null;
}
} }
} }
}); });

View File

@ -13,8 +13,10 @@ exports[`renders demo correctly 1`] = `
<!----> <!---->
</i> </i>
</div> </div>
<div class="van-collapse-item__wrapper">
<div class="van-collapse-item__content">提供多样店铺模板,快速搭建网上商城</div> <div class="van-collapse-item__content">提供多样店铺模板,快速搭建网上商城</div>
</div> </div>
</div>
<div class="van-collapse-item van-hairline--top"> <div class="van-collapse-item van-hairline--top">
<div class="van-cell van-cell--clickable van-hairline van-collapse-item__title"> <div class="van-cell van-cell--clickable van-hairline van-collapse-item__title">
<!----> <!---->
@ -24,7 +26,9 @@ exports[`renders demo correctly 1`] = `
<!----> <!---->
</i> </i>
</div> </div>
<div class="van-collapse-item__content" style="display:none;">网店吸粉获客、会员分层营销、一机多种收款,告别经营低效和客户流失</div> <div class="van-collapse-item__wrapper" style="display:none;">
<div class="van-collapse-item__content">网店吸粉获客、会员分层营销、一机多种收款,告别经营低效和客户流失</div>
</div>
</div> </div>
<div class="van-collapse-item van-hairline--top"> <div class="van-collapse-item van-hairline--top">
<div class="van-cell van-cell--clickable van-hairline van-collapse-item__title"> <div class="van-cell van-cell--clickable van-hairline van-collapse-item__title">
@ -35,7 +39,9 @@ exports[`renders demo correctly 1`] = `
<!----> <!---->
</i> </i>
</div> </div>
<div class="van-collapse-item__content" style="display:none;">线上拓客,随时预约,贴心顺手的开单收银</div> <div class="van-collapse-item__wrapper" style="display:none;">
<div class="van-collapse-item__content">线上拓客,随时预约,贴心顺手的开单收银</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -50,8 +56,10 @@ exports[`renders demo correctly 1`] = `
<!----> <!---->
</i> </i>
</div> </div>
<div class="van-collapse-item__wrapper">
<div class="van-collapse-item__content">提供多样店铺模板,快速搭建网上商城</div> <div class="van-collapse-item__content">提供多样店铺模板,快速搭建网上商城</div>
</div> </div>
</div>
<div class="van-collapse-item van-hairline--top"> <div class="van-collapse-item van-hairline--top">
<div class="van-cell van-cell--clickable van-hairline van-collapse-item__title"> <div class="van-cell van-cell--clickable van-hairline van-collapse-item__title">
<!----> <!---->
@ -61,7 +69,9 @@ exports[`renders demo correctly 1`] = `
<!----> <!---->
</i> </i>
</div> </div>
<div class="van-collapse-item__content" style="display:none;">网店吸粉获客、会员分层营销、一机多种收款,告别经营低效和客户流失</div> <div class="van-collapse-item__wrapper" style="display:none;">
<div class="van-collapse-item__content">网店吸粉获客、会员分层营销、一机多种收款,告别经营低效和客户流失</div>
</div>
</div> </div>
<div class="van-collapse-item van-hairline--top"> <div class="van-collapse-item van-hairline--top">
<div class="van-cell van-cell--clickable van-hairline van-collapse-item__title"> <div class="van-cell van-cell--clickable van-hairline van-collapse-item__title">
@ -72,7 +82,9 @@ exports[`renders demo correctly 1`] = `
<!----> <!---->
</i> </i>
</div> </div>
<div class="van-collapse-item__content" style="display:none;">线上拓客,随时预约,贴心顺手的开单收银</div> <div class="van-collapse-item__wrapper" style="display:none;">
<div class="van-collapse-item__content">线上拓客,随时预约,贴心顺手的开单收银</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -93,10 +105,12 @@ exports[`renders demo correctly 1`] = `
<!----> <!---->
</i> </i>
</div> </div>
<div class="van-collapse-item__content" style="display:none;"> <div class="van-collapse-item__wrapper" style="display:none;">
<div class="van-collapse-item__content">
提供多样店铺模板,快速搭建网上商城 提供多样店铺模板,快速搭建网上商城
</div> </div>
</div> </div>
</div>
<div class="van-collapse-item van-hairline--top"> <div class="van-collapse-item van-hairline--top">
<div class="van-cell van-cell--clickable van-hairline van-collapse-item__title"> <div class="van-cell van-cell--clickable van-hairline van-collapse-item__title">
<!----> <!---->
@ -106,7 +120,9 @@ exports[`renders demo correctly 1`] = `
<!----> <!---->
</i> </i>
</div> </div>
<div class="van-collapse-item__content" style="display:none;">网店吸粉获客、会员分层营销、一机多种收款,告别经营低效和客户流失</div> <div class="van-collapse-item__wrapper" style="display:none;">
<div class="van-collapse-item__content">网店吸粉获客、会员分层营销、一机多种收款,告别经营低效和客户流失</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,6 +1,6 @@
import Collapse from '..'; import Collapse from '..';
import CollapseItem from '../../collapse-item'; import CollapseItem from '../../collapse-item';
import { mount } from '../../../test/utils'; import { later, mount } from '../../../test/utils';
const component = { const component = {
template: ` template: `
@ -24,7 +24,7 @@ const component = {
} }
}; };
test('basic mode', () => { test('basic mode', async() => {
const wrapper = mount(component); const wrapper = mount(component);
const titles = wrapper.findAll('.van-collapse-item__title'); const titles = wrapper.findAll('.van-collapse-item__title');
@ -34,13 +34,14 @@ test('basic mode', () => {
titles.at(1).trigger('click'); titles.at(1).trigger('click');
expect(wrapper.vm.active).toEqual(['first', 1]); expect(wrapper.vm.active).toEqual(['first', 1]);
await later();
titles.at(0).trigger('click'); titles.at(0).trigger('click');
expect(wrapper.vm.active).toEqual([1]); expect(wrapper.vm.active).toEqual([1]);
wrapper.destroy(); wrapper.destroy();
}); });
it('accordion', () => { it('accordion', async() => {
const wrapper = mount(component, { const wrapper = mount(component, {
propsData: { propsData: {
accordion: true accordion: true
@ -54,6 +55,7 @@ it('accordion', () => {
titles.at(1).trigger('click'); titles.at(1).trigger('click');
expect(wrapper.vm.active).toEqual(1); expect(wrapper.vm.active).toEqual(1);
await later();
titles.at(0).trigger('click'); titles.at(0).trigger('click');
expect(wrapper.vm.active).toEqual('first'); expect(wrapper.vm.active).toEqual('first');

View File

@ -12,6 +12,12 @@
} }
} }
&__wrapper {
overflow: hidden;
will-change: height;
transition: height .3s ease-in-out;
}
&__content { &__content {
padding: 15px; padding: 15px;
background-color: #fff; background-color: #fff;