// Utils import { createNamespace, isDef } from '../utils'; import { raf, doubleRaf } from '../utils/dom/raf'; // Mixins import { ChildrenMixin } from '../mixins/relation'; // Components import Cell from '../cell'; import { cellProps } from '../cell/shared'; const [createComponent, bem] = createNamespace('collapse-item'); const CELL_SLOTS = ['title', 'icon', 'right-icon']; export default createComponent({ mixins: [ChildrenMixin('vanCollapse')], props: { ...cellProps, name: [Number, String], disabled: Boolean, isLink: { type: Boolean, default: true, }, }, data() { return { show: null, inited: null, }; }, computed: { currentName() { return isDef(this.name) ? this.name : this.index; }, expanded() { if (!this.parent) { return null; } const { value, accordion } = this.parent; if ( process.env.NODE_ENV !== 'production' && !accordion && !Array.isArray(value) ) { console.error('[Vant] Collapse: type of prop "value" should be Array'); return; } return accordion ? value === this.currentName : value.some((name) => name === this.currentName); }, }, created() { this.show = this.expanded; this.inited = this.expanded; }, watch: { expanded(expanded, prev) { if (prev === null) { return; } if (expanded) { this.show = true; this.inited = true; } // Use raf: flick when opened in safari // Use nextTick: closing animation failed when set `user-select: none` const nextTick = expanded ? this.$nextTick : raf; nextTick(() => { const { content, wrapper } = this.$refs; if (!content || !wrapper) { return; } const { offsetHeight } = content; if (offsetHeight) { const contentHeight = `${offsetHeight}px`; wrapper.style.height = expanded ? 0 : contentHeight; // use double raf to ensure animation can start in mobile safari doubleRaf(() => { wrapper.style.height = expanded ? contentHeight : 0; }); } else { this.onTransitionEnd(); } }); }, }, methods: { onClick() { if (this.disabled) { return; } const { parent, currentName } = this; const close = parent.accordion && currentName === parent.value; const name = close ? '' : currentName; parent.switch(name, !this.expanded); }, onTransitionEnd() { if (!this.expanded) { this.show = false; } else { this.$refs.wrapper.style.height = ''; } }, genTitle() { const { border, disabled, expanded } = this; const titleSlots = CELL_SLOTS.reduce((slots, name) => { if (this.slots(name)) { slots[name] = () => this.slots(name); } return slots; }, {}); if (this.slots('value')) { titleSlots.default = () => this.slots('value'); } return ( ); }, genContent() { if (this.inited) { return (
{this.slots()}
); } }, }, render() { return (
{this.genTitle()} {this.genContent()}
); }, });