import { ref, watch, computed } from 'vue'; import { pickerProps, PICKER_KEY } from './shared'; // Utils import { unitToPx, preventDefault, createNamespace } from '../utils'; import { BORDER_UNSET_TOP_BOTTOM } from '../utils/constant'; // Composition import { useChildren } from '@vant/use'; import { useExpose } from '../composables/use-expose'; // Components import Loading from '../loading'; import PickerColumn from './PickerColumn'; const [createComponent, bem, t] = createNamespace('picker'); export default createComponent({ props: { ...pickerProps, columns: { type: Array, default: () => [], }, defaultIndex: { type: [Number, String], default: 0, }, toolbarPosition: { type: String, default: 'top', }, valueKey: { type: String, default: 'text', }, }, emits: ['confirm', 'cancel', 'change'], setup(props, { emit, slots }) { const formattedColumns = ref([]); const { children, linkChildren } = useChildren(PICKER_KEY); linkChildren(); const itemHeight = computed(() => unitToPx(props.itemHeight)); const dataType = computed(() => { const { columns } = props; const firstColumn = columns[0] || {}; if (firstColumn.children) { return 'cascade'; } if (firstColumn.values) { return 'object'; } return 'text'; }); const formatCascade = () => { const formatted = []; let cursor = { children: props.columns }; while (cursor && cursor.children) { const { children } = cursor; let defaultIndex = cursor.defaultIndex ?? +props.defaultIndex; while (children[defaultIndex] && children[defaultIndex].disabled) { if (defaultIndex < children.length - 1) { defaultIndex++; } else { defaultIndex = 0; break; } } formatted.push({ values: cursor.children, className: cursor.className, defaultIndex, }); cursor = children[defaultIndex]; } formattedColumns.value = formatted; }; const format = () => { const { columns } = props; if (dataType.value === 'text') { formattedColumns.value = [{ values: columns }]; } else if (dataType.value === 'cascade') { formatCascade(); } else { formattedColumns.value = columns; } }; // get indexes of all columns const getIndexes = () => children.map((child) => child.state.index); // set options of column by index const setColumnValues = (index, options) => { const column = children[index]; if (column) { column.setOptions(options); } }; const onCascadeChange = (columnIndex) => { let cursor = { children: props.columns }; const indexes = getIndexes(); for (let i = 0; i <= columnIndex; i++) { cursor = cursor.children[indexes[i]]; } while (cursor && cursor.children) { columnIndex++; setColumnValues(columnIndex, cursor.children); cursor = cursor.children[cursor.defaultIndex || 0]; } }; // get column instance by index const getColumn = (index) => children[index]; // get column value by index const getColumnValue = (index) => { const column = getColumn(index); return column && column.getValue(); }; // set column value by index const setColumnValue = (index, value) => { const column = getColumn(index); if (column) { column.setValue(value); if (dataType.value === 'cascade') { onCascadeChange(index); } } }; // get column option index by column index const getColumnIndex = (index) => (getColumn(index) || {}).state.index; // set column option index by column index const setColumnIndex = (columnIndex, optionIndex) => { const column = getColumn(columnIndex); if (column) { column.setIndex(optionIndex); if (props.dataType === 'cascade') { onCascadeChange(columnIndex); } } }; // get options of column by index const getColumnValues = (index) => (children[index] || {}).state.options; // get values of all columns const getValues = () => children.map((child) => child.getValue()); // set values of all columns const setValues = (values) => { values.forEach((value, index) => { setColumnValue(index, value); }); }; // set indexes of all columns const setIndexes = (indexes) => { indexes.forEach((optionIndex, columnIndex) => { setColumnIndex(columnIndex, optionIndex); }); }; const emitAction = (event) => { if (dataType.value === 'text') { emit(event, getColumnValue(0), getColumnIndex(0)); } else { emit(event, getValues(), getIndexes()); } }; const onChange = (columnIndex) => { if (dataType.value === 'cascade') { onCascadeChange(columnIndex); } if (dataType.value === 'text') { emit('change', getColumnValue(0), getColumnIndex(0)); } else { emit('change', getValues(), columnIndex); } }; const confirm = () => { children.forEach((child) => child.stopMomentum()); emitAction('confirm'); }; const cancel = () => { emitAction('cancel'); }; const renderTitle = () => { if (slots.title) { return slots.title(); } if (props.title) { return