import { createNamespace, isDef } from '../utils'; import { raf, doubleRaf } from '../utils/dom/raf'; import Cell from '../cell'; import { cellProps } from '../cell/shared'; import { ChildrenMixin } from '../mixins/relation'; 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 } = this.parent; return this.parent.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 } = this; const name = parent.accordion && this.currentName === parent.value ? '' : this.currentName; this.parent.switch(name, !this.expanded); }, onTransitionEnd() { if (!this.expanded) { this.show = false; } else { this.$refs.wrapper.style.height = ''; } } }, render() { const { 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'); } const Title = ( ); const Content = this.inited && (
{this.slots()}
); return (
{Title} {Content}
); } });