import { reactive, Teleport, PropType, TeleportProps, CSSProperties, defineComponent, } from 'vue'; // Utils import { truthProp, unknownProp, getZIndexStyle, createNamespace, } from '../utils'; import { DROPDOWN_KEY, DropdownMenuProvide, } from '../dropdown-menu/DropdownMenu'; // Composables import { useParent } from '@vant/use'; import { useExpose } from '../composables/use-expose'; // Components import { Cell } from '../cell'; import { Icon } from '../icon'; import { Popup } from '../popup'; const [name, bem] = createNamespace('dropdown-item'); export type DropdownItemOption = { text: string; icon?: string; value: number | string; }; export default defineComponent({ name, props: { title: String, disabled: Boolean, teleport: [String, Object] as PropType, lazyRender: truthProp, modelValue: unknownProp, titleClass: unknownProp, options: { type: Array as PropType, default: () => [], }, }, emits: ['open', 'opened', 'close', 'closed', 'change', 'update:modelValue'], setup(props, { emit, slots }) { const state = reactive({ showPopup: false, transition: true, showWrapper: false, }); const { parent } = useParent(DROPDOWN_KEY); if (!parent) { if (process.env.NODE_ENV !== 'production') { console.error( '[Vant] must be a child component of .' ); } return; } const getEmitter = (name: 'open' | 'close' | 'opened') => () => emit(name); const onOpen = getEmitter('open'); const onClose = getEmitter('close'); const onOpened = getEmitter('opened'); const onClosed = () => { state.showWrapper = false; emit('closed'); }; const onClickWrapper = (event: MouseEvent) => { // prevent being identified as clicking outside and closed when using teleport if (props.teleport) { event.stopPropagation(); } }; const toggle = ( show = !state.showPopup, options: { immediate?: boolean } = {} ) => { if (show === state.showPopup) { return; } state.showPopup = show; state.transition = !options.immediate; if (show) { state.showWrapper = true; } }; const renderTitle = () => { if (slots.title) { return slots.title(); } if (props.title) { return props.title; } const match = props.options.find( (option) => option.value === props.modelValue ); return match ? match.text : ''; }; const renderOption = (option: DropdownItemOption) => { const { activeColor } = parent.props; const active = option.value === props.modelValue; const onClick = () => { state.showPopup = false; if (option.value !== props.modelValue) { emit('update:modelValue', option.value); emit('change', option.value); } }; return ( {active && ( )} ); }; const renderContent = () => { const { offset } = parent; const { zIndex, overlay, duration, direction, closeOnClickOverlay, } = parent.props; const style: CSSProperties = getZIndexStyle(zIndex); if (direction === 'down') { style.top = `${offset.value}px`; } else { style.bottom = `${offset.value}px`; } return (
{props.options.map(renderOption)} {slots.default?.()}
); }; useExpose({ state, toggle, renderTitle }); return () => { if (props.teleport) { return {renderContent()}; } return renderContent(); }; }, });