import { ref, watch, computed, nextTick, defineComponent, ExtractPropTypes, } from 'vue'; // Utils import { cellProps } from '../cell/Cell'; import { createNamespace, extend, pick, truthProp } from '../utils'; import { COLLAPSE_KEY } from '../collapse/Collapse'; // Composables import { raf, doubleRaf, useParent } from '@vant/use'; import { useExpose } from '../composables/use-expose'; import { useLazyRender } from '../composables/use-lazy-render'; // Components import { Cell } from '../cell'; const [name, bem] = createNamespace('collapse-item'); const CELL_SLOTS = ['icon', 'title', 'value', 'label', 'right-icon'] as const; const props = extend({}, cellProps, { name: [Number, String], isLink: truthProp, disabled: Boolean, readonly: Boolean, }); export type CollapseItemProps = ExtractPropTypes; export default defineComponent({ name, props, setup(props, { slots }) { const wrapperRef = ref(); const contentRef = ref(); const { parent, index } = useParent(COLLAPSE_KEY); if (!parent) { if (process.env.NODE_ENV !== 'production') { console.error( '[Vant] must be a child component of .' ); } return; } const name = computed(() => props.name ?? index.value); const expanded = computed(() => parent.isExpanded(name.value)); const show = ref(expanded.value); const lazyRender = useLazyRender(show); const onTransitionEnd = () => { if (!expanded.value) { show.value = false; } else if (wrapperRef.value) { wrapperRef.value.style.height = ''; } }; watch(expanded, (value, oldValue) => { if (oldValue === null) { return; } if (value) { show.value = true; } // Use raf: flick when opened in safari // Use nextTick: closing animation failed when set `user-select: none` const tick = value ? nextTick : raf; tick(() => { if (!contentRef.value || !wrapperRef.value) { return; } const { offsetHeight } = contentRef.value; if (offsetHeight) { const contentHeight = `${offsetHeight}px`; wrapperRef.value.style.height = value ? '0' : contentHeight; // use double raf to ensure animation can start doubleRaf(() => { wrapperRef.value!.style.height = value ? contentHeight : '0'; }); } else { onTransitionEnd(); } }); }); const toggle = (newValue = !expanded.value) => { parent.toggle(name.value, newValue); }; const onClickTitle = () => { if (!props.disabled && !props.readonly) { toggle(); } }; const renderTitle = () => { const { border, disabled, readonly } = props; const attrs = pick( props, Object.keys(cellProps) as Array ); if (readonly) { attrs.isLink = false; } if (disabled || readonly) { attrs.clickable = false; } return ( ); }; const renderContent = lazyRender(() => (
{slots.default?.()}
)); useExpose({ toggle }); return () => (
{renderTitle()} {renderContent()}
); }, });