mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-26 03:16:35 +08:00
refactor(Picker): data driven
This commit is contained in:
parent
bcb7eabff3
commit
89b029aa42
@ -9,6 +9,7 @@ import {
|
|||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import {
|
import {
|
||||||
|
isDef,
|
||||||
extend,
|
extend,
|
||||||
unitToPx,
|
unitToPx,
|
||||||
truthProp,
|
truthProp,
|
||||||
@ -32,12 +33,11 @@ import Column, { PICKER_KEY } from './PickerColumn';
|
|||||||
// Types
|
// Types
|
||||||
import type {
|
import type {
|
||||||
PickerColumn,
|
PickerColumn,
|
||||||
PickerOption,
|
|
||||||
PickerExpose,
|
PickerExpose,
|
||||||
PickerFieldNames,
|
PickerFieldNames,
|
||||||
PickerObjectColumn,
|
|
||||||
PickerToolbarPosition,
|
PickerToolbarPosition,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
import { PickerOption } from '.';
|
||||||
|
|
||||||
const [name, bem, t] = createNamespace('picker');
|
const [name, bem, t] = createNamespace('picker');
|
||||||
|
|
||||||
@ -55,7 +55,8 @@ export const pickerSharedProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const pickerProps = extend({}, pickerSharedProps, {
|
const pickerProps = extend({}, pickerSharedProps, {
|
||||||
columns: makeArrayProp<PickerOption | PickerColumn>(),
|
columns: makeArrayProp<PickerColumn | PickerColumn[]>(),
|
||||||
|
modelValue: makeArrayProp<number | string>(),
|
||||||
defaultIndex: makeNumericProp(0),
|
defaultIndex: makeNumericProp(0),
|
||||||
toolbarPosition: makeStringProp<PickerToolbarPosition>('top'),
|
toolbarPosition: makeStringProp<PickerToolbarPosition>('top'),
|
||||||
columnsFieldNames: Object as PropType<PickerFieldNames>,
|
columnsFieldNames: Object as PropType<PickerFieldNames>,
|
||||||
@ -68,20 +69,21 @@ export default defineComponent({
|
|||||||
|
|
||||||
props: pickerProps,
|
props: pickerProps,
|
||||||
|
|
||||||
emits: ['confirm', 'cancel', 'change'],
|
emits: ['confirm', 'cancel', 'change', 'update:modelValue'],
|
||||||
|
|
||||||
setup(props, { emit, slots }) {
|
setup(props, { emit, slots }) {
|
||||||
const hasOptions = ref(false);
|
const hasOptions = ref(false);
|
||||||
const formattedColumns = ref<PickerObjectColumn[]>([]);
|
const selectedValues = ref(props.modelValue);
|
||||||
|
const currentColumns = ref<PickerColumn[]>([]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
text: textKey,
|
text: textKey,
|
||||||
values: valuesKey,
|
value: valueKey,
|
||||||
children: childrenKey,
|
children: childrenKey,
|
||||||
} = extend(
|
} = extend(
|
||||||
{
|
{
|
||||||
text: 'text',
|
text: 'text',
|
||||||
values: 'values',
|
value: 'value',
|
||||||
children: 'children',
|
children: 'children',
|
||||||
},
|
},
|
||||||
props.columnsFieldNames
|
props.columnsFieldNames
|
||||||
@ -95,186 +97,78 @@ export default defineComponent({
|
|||||||
|
|
||||||
const dataType = computed(() => {
|
const dataType = computed(() => {
|
||||||
const firstColumn = props.columns[0];
|
const firstColumn = props.columns[0];
|
||||||
if (typeof firstColumn === 'object') {
|
if (Array.isArray(firstColumn)) {
|
||||||
|
return 'multiple';
|
||||||
|
}
|
||||||
if (childrenKey in firstColumn) {
|
if (childrenKey in firstColumn) {
|
||||||
return 'cascade';
|
return 'cascade';
|
||||||
}
|
}
|
||||||
if (valuesKey in firstColumn) {
|
return 'default';
|
||||||
return 'object';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 'plain';
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const findOption = (options: PickerOption[], value: number | string) =>
|
||||||
|
options.find((option) => option[valueKey] === value);
|
||||||
|
|
||||||
const formatCascade = () => {
|
const formatCascade = () => {
|
||||||
const formatted: PickerObjectColumn[] = [];
|
const formatted: PickerColumn[] = [];
|
||||||
|
|
||||||
let cursor: PickerObjectColumn = {
|
let cursor: PickerOption | undefined = {
|
||||||
[childrenKey]: props.columns,
|
[childrenKey]: props.columns,
|
||||||
};
|
};
|
||||||
|
let columnIndex = 0;
|
||||||
|
|
||||||
while (cursor && cursor[childrenKey]) {
|
while (cursor && cursor[childrenKey]) {
|
||||||
const children = cursor[childrenKey];
|
const options: PickerOption[] = cursor[childrenKey];
|
||||||
let defaultIndex = cursor.defaultIndex ?? +props.defaultIndex;
|
const value = selectedValues.value[columnIndex];
|
||||||
|
|
||||||
while (children[defaultIndex] && children[defaultIndex].disabled) {
|
cursor = isDef(value) ? findOption(options, value) : undefined;
|
||||||
if (defaultIndex < children.length - 1) {
|
|
||||||
defaultIndex++;
|
if (!cursor && options.length) {
|
||||||
} else {
|
const firstValue = options[0][valueKey];
|
||||||
defaultIndex = 0;
|
selectedValues.value[columnIndex] = firstValue;
|
||||||
break;
|
cursor = findOption(options, firstValue);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
formatted.push({
|
|
||||||
[valuesKey]: cursor[childrenKey],
|
|
||||||
className: cursor.className,
|
|
||||||
defaultIndex,
|
|
||||||
});
|
|
||||||
|
|
||||||
cursor = children[defaultIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
formattedColumns.value = formatted;
|
|
||||||
};
|
|
||||||
|
|
||||||
const format = () => {
|
|
||||||
const { columns } = props;
|
|
||||||
|
|
||||||
if (dataType.value === 'plain') {
|
|
||||||
formattedColumns.value = [{ [valuesKey]: columns }];
|
|
||||||
} else if (dataType.value === 'cascade') {
|
|
||||||
formatCascade();
|
|
||||||
} else {
|
|
||||||
formattedColumns.value = columns as PickerObjectColumn[];
|
|
||||||
}
|
|
||||||
|
|
||||||
hasOptions.value = formattedColumns.value.some(
|
|
||||||
(item) => item[valuesKey] && item[valuesKey].length !== 0
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// get indexes of all columns
|
|
||||||
const getIndexes = () => children.map((child) => child.state.index);
|
|
||||||
|
|
||||||
// set options of column by index
|
|
||||||
const setColumnValues = (index: number, options: PickerOption[]) => {
|
|
||||||
const column = children[index];
|
|
||||||
if (column) {
|
|
||||||
column.setOptions(options);
|
|
||||||
hasOptions.value = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onCascadeChange = (columnIndex: number) => {
|
|
||||||
let cursor: PickerObjectColumn = {
|
|
||||||
[childrenKey]: props.columns,
|
|
||||||
};
|
|
||||||
const indexes = getIndexes();
|
|
||||||
|
|
||||||
for (let i = 0; i <= columnIndex; i++) {
|
|
||||||
cursor = cursor[childrenKey][indexes[i]];
|
|
||||||
}
|
|
||||||
|
|
||||||
while (cursor && cursor[childrenKey]) {
|
|
||||||
columnIndex++;
|
columnIndex++;
|
||||||
setColumnValues(columnIndex, cursor[childrenKey]);
|
formatted.push(options);
|
||||||
cursor = cursor[childrenKey][cursor.defaultIndex || 0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return formatted;
|
||||||
};
|
};
|
||||||
|
|
||||||
// get column instance by index
|
const selectedOptions = computed(() =>
|
||||||
const getChild = (index: number) => children[index];
|
currentColumns.value.map((options, index) =>
|
||||||
|
findOption(options, selectedValues.value[index])
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
// get column value by index
|
const onChange = (value: number | string, columnIndex: number) => {
|
||||||
const getColumnValue = (index: number) => {
|
selectedValues.value[columnIndex] = value;
|
||||||
const column = getChild(index);
|
|
||||||
if (column) {
|
|
||||||
return column.getValue();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// set column value by index
|
|
||||||
const setColumnValue = (index: number, value: string) => {
|
|
||||||
const column = getChild(index);
|
|
||||||
if (column) {
|
|
||||||
column.setValue(value);
|
|
||||||
if (dataType.value === 'cascade') {
|
if (dataType.value === 'cascade') {
|
||||||
onCascadeChange(index);
|
currentColumns.value = formatCascade();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// get column option index by column index
|
emit('change', {
|
||||||
const getColumnIndex = (index: number) => {
|
columnIndex,
|
||||||
const column = getChild(index);
|
selectedValues: selectedValues.value,
|
||||||
if (column) {
|
selectedOptions: selectedOptions.value,
|
||||||
return column.state.index;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// set column option index by column index
|
|
||||||
const setColumnIndex = (columnIndex: number, optionIndex: number) => {
|
|
||||||
const column = getChild(columnIndex);
|
|
||||||
if (column) {
|
|
||||||
column.setIndex(optionIndex);
|
|
||||||
if (dataType.value === 'cascade') {
|
|
||||||
onCascadeChange(columnIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// get options of column by index
|
|
||||||
const getColumnValues = (index: number) => {
|
|
||||||
const column = getChild(index);
|
|
||||||
if (column) {
|
|
||||||
return column.state.options;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// get values of all columns
|
|
||||||
const getValues = () => children.map((child) => child.getValue());
|
|
||||||
|
|
||||||
// set values of all columns
|
|
||||||
const setValues = (values: string[]) => {
|
|
||||||
values.forEach((value, index) => {
|
|
||||||
setColumnValue(index, value);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// set indexes of all columns
|
|
||||||
const setIndexes = (indexes: number[]) => {
|
|
||||||
indexes.forEach((optionIndex, columnIndex) => {
|
|
||||||
setColumnIndex(columnIndex, optionIndex);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const emitAction = (event: 'confirm' | 'cancel') => {
|
|
||||||
if (dataType.value === 'plain') {
|
|
||||||
emit(event, getColumnValue(0), getColumnIndex(0));
|
|
||||||
} else {
|
|
||||||
emit(event, getValues(), getIndexes());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onChange = (columnIndex: number) => {
|
|
||||||
if (dataType.value === 'cascade') {
|
|
||||||
onCascadeChange(columnIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dataType.value === 'plain') {
|
|
||||||
emit('change', getColumnValue(0), getColumnIndex(0));
|
|
||||||
} else {
|
|
||||||
emit('change', getValues(), columnIndex);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const confirm = () => {
|
const confirm = () => {
|
||||||
children.forEach((child) => child.stopMomentum());
|
children.forEach((child) => child.stopMomentum());
|
||||||
emitAction('confirm');
|
emit('confirm', {
|
||||||
|
selectedValues: selectedValues.value,
|
||||||
|
selectedOptions: selectedOptions.value,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const cancel = () => emitAction('cancel');
|
const cancel = () =>
|
||||||
|
emit('cancel', {
|
||||||
|
selectedValues: selectedValues.value,
|
||||||
|
selectedOptions: selectedOptions.value,
|
||||||
|
});
|
||||||
|
|
||||||
const renderTitle = () => {
|
const renderTitle = () => {
|
||||||
if (slots.title) {
|
if (slots.title) {
|
||||||
@ -324,19 +218,19 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const renderColumnItems = () =>
|
const renderColumnItems = () =>
|
||||||
formattedColumns.value.map((item, columnIndex) => (
|
currentColumns.value.map((options, columnIndex) => (
|
||||||
<Column
|
<Column
|
||||||
v-slots={{ option: slots.option }}
|
v-slots={{ option: slots.option }}
|
||||||
|
value={selectedValues.value[columnIndex]}
|
||||||
textKey={textKey}
|
textKey={textKey}
|
||||||
|
options={options}
|
||||||
readonly={props.readonly}
|
readonly={props.readonly}
|
||||||
|
valueKey={valueKey}
|
||||||
allowHtml={props.allowHtml}
|
allowHtml={props.allowHtml}
|
||||||
className={item.className}
|
|
||||||
itemHeight={itemHeight.value}
|
itemHeight={itemHeight.value}
|
||||||
defaultIndex={item.defaultIndex ?? +props.defaultIndex}
|
|
||||||
swipeDuration={props.swipeDuration}
|
swipeDuration={props.swipeDuration}
|
||||||
initialOptions={item[valuesKey]}
|
|
||||||
visibleItemCount={props.visibleItemCount}
|
visibleItemCount={props.visibleItemCount}
|
||||||
onChange={() => onChange(columnIndex)}
|
onChange={(value: number | string) => onChange(value, columnIndex)}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -371,22 +265,51 @@ export default defineComponent({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(() => props.columns, format, { immediate: true });
|
watch(
|
||||||
|
() => props.columns,
|
||||||
|
() => {
|
||||||
|
const { columns } = props;
|
||||||
|
|
||||||
useExpose<PickerExpose>({
|
switch (dataType.value) {
|
||||||
confirm,
|
case 'multiple':
|
||||||
getValues,
|
currentColumns.value = columns;
|
||||||
setValues,
|
break;
|
||||||
getIndexes,
|
case 'cascade':
|
||||||
setIndexes,
|
currentColumns.value = formatCascade();
|
||||||
getColumnIndex,
|
break;
|
||||||
setColumnIndex,
|
default:
|
||||||
getColumnValue,
|
currentColumns.value = [columns];
|
||||||
setColumnValue,
|
break;
|
||||||
getColumnValues,
|
}
|
||||||
setColumnValues,
|
|
||||||
|
currentColumns.value.forEach((options, index) => {
|
||||||
|
if (selectedValues.value[index] === undefined && options.length) {
|
||||||
|
selectedValues.value[index] = options[0][valueKey];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
hasOptions.value = currentColumns.value.some(
|
||||||
|
(options) => !!options.length
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(value) => {
|
||||||
|
selectedValues.value = value;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(selectedValues, () => {
|
||||||
|
if (selectedValues.value !== props.modelValue) {
|
||||||
|
emit('update:modelValue', selectedValues.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
useExpose<PickerExpose>({ confirm });
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<div class={bem()}>
|
<div class={bem()}>
|
||||||
{props.toolbarPosition === 'top' ? renderToolbar() : null}
|
{props.toolbarPosition === 'top' ? renderToolbar() : null}
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
import { ref, watch, reactive, defineComponent, type InjectionKey } from 'vue';
|
import { ref, reactive, defineComponent, type InjectionKey, watch } from 'vue';
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import { deepClone } from '../utils/deep-clone';
|
|
||||||
import {
|
import {
|
||||||
clamp,
|
clamp,
|
||||||
isObject,
|
|
||||||
unknownProp,
|
|
||||||
numericProp,
|
numericProp,
|
||||||
makeArrayProp,
|
makeArrayProp,
|
||||||
makeNumberProp,
|
|
||||||
preventDefault,
|
preventDefault,
|
||||||
createNamespace,
|
createNamespace,
|
||||||
makeRequiredProp,
|
makeRequiredProp,
|
||||||
@ -40,21 +36,18 @@ function getElementTranslateY(element: Element) {
|
|||||||
|
|
||||||
export const PICKER_KEY: InjectionKey<PickerColumnProvide> = Symbol(name);
|
export const PICKER_KEY: InjectionKey<PickerColumnProvide> = Symbol(name);
|
||||||
|
|
||||||
const isOptionDisabled = (option: PickerOption) =>
|
|
||||||
isObject(option) && option.disabled;
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name,
|
name,
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
|
value: numericProp,
|
||||||
textKey: makeRequiredProp(String),
|
textKey: makeRequiredProp(String),
|
||||||
|
options: makeArrayProp<PickerOption>(),
|
||||||
readonly: Boolean,
|
readonly: Boolean,
|
||||||
|
valueKey: makeRequiredProp(String),
|
||||||
allowHtml: Boolean,
|
allowHtml: Boolean,
|
||||||
className: unknownProp,
|
|
||||||
itemHeight: makeRequiredProp(Number),
|
itemHeight: makeRequiredProp(Number),
|
||||||
defaultIndex: makeNumberProp(0),
|
|
||||||
swipeDuration: makeRequiredProp(numericProp),
|
swipeDuration: makeRequiredProp(numericProp),
|
||||||
initialOptions: makeArrayProp<PickerOption>(),
|
|
||||||
visibleItemCount: makeRequiredProp(numericProp),
|
visibleItemCount: makeRequiredProp(numericProp),
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -70,15 +63,13 @@ export default defineComponent({
|
|||||||
const wrapper = ref<HTMLElement>();
|
const wrapper = ref<HTMLElement>();
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
index: props.defaultIndex,
|
|
||||||
offset: 0,
|
offset: 0,
|
||||||
duration: 0,
|
duration: 0,
|
||||||
options: deepClone(props.initialOptions),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const touch = useTouch();
|
const touch = useTouch();
|
||||||
|
|
||||||
const count = () => state.options.length;
|
const count = () => props.options.length;
|
||||||
|
|
||||||
const baseOffset = () =>
|
const baseOffset = () =>
|
||||||
(props.itemHeight * (+props.visibleItemCount - 1)) / 2;
|
(props.itemHeight * (+props.visibleItemCount - 1)) / 2;
|
||||||
@ -87,24 +78,22 @@ export default defineComponent({
|
|||||||
index = clamp(index, 0, count());
|
index = clamp(index, 0, count());
|
||||||
|
|
||||||
for (let i = index; i < count(); i++) {
|
for (let i = index; i < count(); i++) {
|
||||||
if (!isOptionDisabled(state.options[i])) return i;
|
if (!props.options[i].disabled) return i;
|
||||||
}
|
}
|
||||||
for (let i = index - 1; i >= 0; i--) {
|
for (let i = index - 1; i >= 0; i--) {
|
||||||
if (!isOptionDisabled(state.options[i])) return i;
|
if (!props.options[i].disabled) return i;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
const setIndex = (index: number, emitChange?: boolean) => {
|
const updateValueByIndex = (index: number) => {
|
||||||
index = adjustIndex(index) || 0;
|
index = adjustIndex(index);
|
||||||
|
|
||||||
const offset = -index * props.itemHeight;
|
const offset = -index * props.itemHeight;
|
||||||
const trigger = () => {
|
const trigger = () => {
|
||||||
if (index !== state.index) {
|
const { value } = props.options[index];
|
||||||
state.index = index;
|
if (value !== props.value) {
|
||||||
|
emit('change', value);
|
||||||
if (emitChange) {
|
|
||||||
emit('change', index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -118,13 +107,6 @@ export default defineComponent({
|
|||||||
state.offset = offset;
|
state.offset = offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
const setOptions = (options: PickerOption[]) => {
|
|
||||||
if (JSON.stringify(options) !== JSON.stringify(state.options)) {
|
|
||||||
state.options = deepClone(options);
|
|
||||||
setIndex(props.defaultIndex);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onClickItem = (index: number) => {
|
const onClickItem = (index: number) => {
|
||||||
if (moving || props.readonly) {
|
if (moving || props.readonly) {
|
||||||
return;
|
return;
|
||||||
@ -132,14 +114,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
transitionEndTrigger = null;
|
transitionEndTrigger = null;
|
||||||
state.duration = DEFAULT_DURATION;
|
state.duration = DEFAULT_DURATION;
|
||||||
setIndex(index, true);
|
updateValueByIndex(index);
|
||||||
};
|
|
||||||
|
|
||||||
const getOptionText = (option: PickerOption) => {
|
|
||||||
if (isObject(option) && props.textKey in option) {
|
|
||||||
return option[props.textKey];
|
|
||||||
}
|
|
||||||
return option;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getIndexByOffset = (offset: number) =>
|
const getIndexByOffset = (offset: number) =>
|
||||||
@ -153,7 +128,7 @@ export default defineComponent({
|
|||||||
const index = getIndexByOffset(distance);
|
const index = getIndexByOffset(distance);
|
||||||
|
|
||||||
state.duration = +props.swipeDuration;
|
state.duration = +props.swipeDuration;
|
||||||
setIndex(index, true);
|
updateValueByIndex(index);
|
||||||
};
|
};
|
||||||
|
|
||||||
const stopMomentum = () => {
|
const stopMomentum = () => {
|
||||||
@ -230,10 +205,10 @@ export default defineComponent({
|
|||||||
|
|
||||||
const index = getIndexByOffset(state.offset);
|
const index = getIndexByOffset(state.offset);
|
||||||
state.duration = DEFAULT_DURATION;
|
state.duration = DEFAULT_DURATION;
|
||||||
setIndex(index, true);
|
updateValueByIndex(index);
|
||||||
|
|
||||||
// compatible with desktop scenario
|
// compatible with desktop scenario
|
||||||
// use setTimeout to skip the click event Emitted after touchstart
|
// use setTimeout to skip the click event emitted after touchstart
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
moving = false;
|
moving = false;
|
||||||
}, 0);
|
}, 0);
|
||||||
@ -244,17 +219,17 @@ export default defineComponent({
|
|||||||
height: `${props.itemHeight}px`,
|
height: `${props.itemHeight}px`,
|
||||||
};
|
};
|
||||||
|
|
||||||
return state.options.map((option, index: number) => {
|
return props.options.map((option, index) => {
|
||||||
const text = getOptionText(option);
|
const text = option[props.textKey];
|
||||||
const disabled = isOptionDisabled(option);
|
const { disabled } = option;
|
||||||
|
const value: string | number = option[props.valueKey];
|
||||||
const data = {
|
const data = {
|
||||||
role: 'button',
|
role: 'button',
|
||||||
style: optionStyle,
|
style: optionStyle,
|
||||||
tabindex: disabled ? -1 : 0,
|
tabindex: disabled ? -1 : 0,
|
||||||
class: bem('item', {
|
class: bem('item', {
|
||||||
disabled,
|
disabled,
|
||||||
selected: index === state.index,
|
selected: value === props.value,
|
||||||
}),
|
}),
|
||||||
onClick: () => onClickItem(index),
|
onClick: () => onClickItem(index),
|
||||||
};
|
};
|
||||||
@ -272,39 +247,23 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const setValue = (value: string) => {
|
|
||||||
const { options } = state;
|
|
||||||
for (let i = 0; i < options.length; i++) {
|
|
||||||
if (getOptionText(options[i]) === value) {
|
|
||||||
return setIndex(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getValue = (): PickerOption => state.options[state.index];
|
|
||||||
|
|
||||||
setIndex(state.index);
|
|
||||||
|
|
||||||
useParent(PICKER_KEY);
|
useParent(PICKER_KEY);
|
||||||
useExpose({
|
useExpose({ stopMomentum });
|
||||||
state,
|
|
||||||
setIndex,
|
|
||||||
getValue,
|
|
||||||
setValue,
|
|
||||||
setOptions,
|
|
||||||
stopMomentum,
|
|
||||||
});
|
|
||||||
|
|
||||||
watch(() => props.initialOptions, setOptions);
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.defaultIndex,
|
() => props.value,
|
||||||
(value) => setIndex(value)
|
(value) => {
|
||||||
|
const index = props.options.findIndex(
|
||||||
|
(option) => option[props.valueKey] === value
|
||||||
|
);
|
||||||
|
const offset = -adjustIndex(index) * props.itemHeight;
|
||||||
|
state.offset = offset;
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<div
|
<div
|
||||||
class={[bem(), props.className]}
|
class={bem()}
|
||||||
onTouchstart={onTouchStart}
|
onTouchstart={onTouchStart}
|
||||||
onTouchmove={onTouchMove}
|
onTouchmove={onTouchMove}
|
||||||
onTouchend={onTouchEnd}
|
onTouchend={onTouchEnd}
|
||||||
|
@ -35,13 +35,18 @@ import { Toast } from 'vant';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
setup() {
|
setup() {
|
||||||
const columns = ['Delaware', 'Florida', 'Georqia', 'Indiana', 'Maine'];
|
const columns = [
|
||||||
|
{ text: 'Delaware', value: 'Delaware' },
|
||||||
const onConfirm = (value, index) => {
|
{ text: 'Florida', value: 'Florida' },
|
||||||
Toast(`Value: ${value}, Index: ${index}`);
|
{ text: 'Georqia', value: 'Georqia' },
|
||||||
|
{ text: 'Indiana', value: 'Indiana' },
|
||||||
|
{ text: 'Maine', value: 'Maine' },
|
||||||
|
];
|
||||||
|
const onConfirm = (option, index) => {
|
||||||
|
Toast(`Value: ${option.value}, Index: ${index}`);
|
||||||
};
|
};
|
||||||
const onChange = (value, index) => {
|
const onChange = (option, index) => {
|
||||||
Toast(`Value: ${value}, Index: ${index}`);
|
Toast(`Value: ${option.value}, Index: ${index}`);
|
||||||
};
|
};
|
||||||
const onCancel = () => Toast('Cancel');
|
const onCancel = () => Toast('Cancel');
|
||||||
|
|
||||||
@ -55,12 +60,6 @@ export default {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### Default Index
|
|
||||||
|
|
||||||
```html
|
|
||||||
<van-picker title="Title" :columns="columns" :default-index="2" />
|
|
||||||
```
|
|
||||||
|
|
||||||
### Multiple Columns
|
### Multiple Columns
|
||||||
|
|
||||||
```html
|
```html
|
||||||
@ -71,14 +70,18 @@ export default {
|
|||||||
export default {
|
export default {
|
||||||
setup() {
|
setup() {
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
[
|
||||||
values: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
|
{ text: 'Monday', value: 'Monday' },
|
||||||
defaultIndex: 2,
|
{ text: 'Tuesday', value: 'Tuesday' },
|
||||||
},
|
{ text: 'Wednesday', value: 'Wednesday' },
|
||||||
{
|
{ text: 'Thursday', value: 'Thursday' },
|
||||||
values: ['Morning', 'Afternoon', 'Evening'],
|
{ text: 'Friday', value: 'Friday' },
|
||||||
defaultIndex: 1,
|
],
|
||||||
},
|
[
|
||||||
|
{ text: 'Morning', value: 'Morning' },
|
||||||
|
{ text: 'Afternoon', value: 'Afternoon' },
|
||||||
|
{ text: 'Evening', value: 'Evening' },
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
return { columns };
|
return { columns };
|
||||||
|
@ -43,13 +43,21 @@ import { Toast } from 'vant';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
setup() {
|
setup() {
|
||||||
const columns = ['杭州', '宁波', '温州', '绍兴', '湖州', '嘉兴', '金华'];
|
const columns = [
|
||||||
|
{ text: '杭州', value: 'Hangzhou' },
|
||||||
const onConfirm = (value, index) => {
|
{ text: '宁波', value: 'Ningbo' },
|
||||||
Toast(`当前值: ${value}, 当前索引: ${index}`);
|
{ text: '温州', value: 'Wenzhou' },
|
||||||
|
{ text: '绍兴', value: 'Shaoxing' },
|
||||||
|
{ text: '湖州', value: 'Huzhou' },
|
||||||
|
{ text: '嘉兴', value: 'Jiaxing' },
|
||||||
|
{ text: '金华', value: 'Jinhua' },
|
||||||
|
{ text: '衢州', value: 'Quzhou' },
|
||||||
|
];
|
||||||
|
const onConfirm = (option, index) => {
|
||||||
|
Toast(`当前值: ${option.value}, 当前索引: ${index}`);
|
||||||
};
|
};
|
||||||
const onChange = (value, index) => {
|
const onChange = (option, index) => {
|
||||||
Toast(`当前值: ${value}, 当前索引: ${index}`);
|
Toast(`当前值: ${option.value}, 当前索引: ${index}`);
|
||||||
};
|
};
|
||||||
const onCancel = () => Toast('取消');
|
const onCancel = () => Toast('取消');
|
||||||
|
|
||||||
@ -63,17 +71,9 @@ export default {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### 默认选中项
|
|
||||||
|
|
||||||
单列选择时,可以通过 `default-index` 属性设置初始选中项的索引。
|
|
||||||
|
|
||||||
```html
|
|
||||||
<van-picker title="标题" :columns="columns" :default-index="2" />
|
|
||||||
```
|
|
||||||
|
|
||||||
### 多列选择
|
### 多列选择
|
||||||
|
|
||||||
`columns` 属性可以通过对象数组的形式配置多列选择,对象中可以配置选项数据、初始选中项等,详细格式见[下方表格](#/zh-CN/picker#column-shu-ju-jie-gou)。
|
`columns` 属性可以通过二维数组的形式配置多列选择。
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<van-picker title="标题" :columns="columns" />
|
<van-picker title="标题" :columns="columns" />
|
||||||
@ -84,15 +84,19 @@ export default {
|
|||||||
setup() {
|
setup() {
|
||||||
const columns = [
|
const columns = [
|
||||||
// 第一列
|
// 第一列
|
||||||
{
|
[
|
||||||
values: ['周一', '周二', '周三', '周四', '周五'],
|
{ text: '周一', value: 'Monday' },
|
||||||
defaultIndex: 2,
|
{ text: '周二', value: 'Tuesday' },
|
||||||
},
|
{ text: '周三', value: 'Wednesday' },
|
||||||
|
{ text: '周四', value: 'Thursday' },
|
||||||
|
{ text: '周五', value: 'Friday' },
|
||||||
|
],
|
||||||
// 第二列
|
// 第二列
|
||||||
{
|
[
|
||||||
values: ['上午', '下午', '晚上'],
|
{ text: '上午', value: 'Morning' },
|
||||||
defaultIndex: 1,
|
{ text: '下午', value: 'Afternoon' },
|
||||||
},
|
{ text: '晚上', value: 'Evening' },
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
return { columns };
|
return { columns };
|
||||||
|
@ -1,23 +1,51 @@
|
|||||||
export const dateColumns = {
|
export const basicColumns = {
|
||||||
'zh-CN': [
|
'zh-CN': [
|
||||||
{
|
{ text: '杭州', value: 'Hangzhou' },
|
||||||
values: ['周一', '周二', '周三', '周四', '周五'],
|
{ text: '宁波', value: 'Ningbo' },
|
||||||
defaultIndex: 2,
|
{ text: '温州', value: 'Wenzhou' },
|
||||||
},
|
{ text: '绍兴', value: 'Shaoxing' },
|
||||||
{
|
{ text: '湖州', value: 'Huzhou' },
|
||||||
values: ['上午', '下午', '晚上'],
|
{ text: '嘉兴', value: 'Jiaxing' },
|
||||||
defaultIndex: 1,
|
{ text: '金华', value: 'Jinhua' },
|
||||||
},
|
{ text: '衢州', value: 'Quzhou' },
|
||||||
],
|
],
|
||||||
'en-US': [
|
'en-US': [
|
||||||
{
|
{ text: 'Delaware', value: 'Delaware' },
|
||||||
values: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
|
{ text: 'Florida', value: 'Florida' },
|
||||||
defaultIndex: 2,
|
{ text: 'Georqia', value: 'Georqia' },
|
||||||
},
|
{ text: 'Indiana', value: 'Indiana' },
|
||||||
{
|
{ text: 'Maine', value: 'Maine' },
|
||||||
values: ['Morning', 'Afternoon', 'Evening'],
|
],
|
||||||
defaultIndex: 1,
|
};
|
||||||
},
|
|
||||||
|
export const dateColumns = {
|
||||||
|
'zh-CN': [
|
||||||
|
[
|
||||||
|
{ text: '周一', value: 'Monday' },
|
||||||
|
{ text: '周二', value: 'Tuesday' },
|
||||||
|
{ text: '周三', value: 'Wednesday' },
|
||||||
|
{ text: '周四', value: 'Thursday' },
|
||||||
|
{ text: '周五', value: 'Friday' },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{ text: '上午', value: 'Morning' },
|
||||||
|
{ text: '下午', value: 'Afternoon' },
|
||||||
|
{ text: '晚上', value: 'Evening' },
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'en-US': [
|
||||||
|
[
|
||||||
|
{ text: 'Monday', value: 'Monday' },
|
||||||
|
{ text: 'Tuesday', value: 'Tuesday' },
|
||||||
|
{ text: 'Wednesday', value: 'Wednesday' },
|
||||||
|
{ text: 'Thursday', value: 'Thursday' },
|
||||||
|
{ text: 'Friday', value: 'Friday' },
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{ text: 'Morning', value: 'Morning' },
|
||||||
|
{ text: 'Afternoon', value: 'Afternoon' },
|
||||||
|
{ text: 'Evening', value: 'Evening' },
|
||||||
|
],
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -25,27 +53,45 @@ export const cascadeColumns = {
|
|||||||
'zh-CN': [
|
'zh-CN': [
|
||||||
{
|
{
|
||||||
text: '浙江',
|
text: '浙江',
|
||||||
|
value: 'Zhejiang',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
text: '杭州',
|
text: '杭州',
|
||||||
children: [{ text: '西湖区' }, { text: '余杭区' }],
|
value: 'Hangzhou',
|
||||||
|
children: [
|
||||||
|
{ text: '西湖区', value: 'Xihu' },
|
||||||
|
{ text: '余杭区', value: 'Yuhang' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: '温州',
|
text: '温州',
|
||||||
children: [{ text: '鹿城区' }, { text: '瓯海区' }],
|
value: 'Wenzhou',
|
||||||
|
children: [
|
||||||
|
{ text: '鹿城区', value: 'Lucheng' },
|
||||||
|
{ text: '瓯海区', value: 'Ouhai' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: '福建',
|
text: '福建',
|
||||||
|
value: 'Fujian',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
text: '福州',
|
text: '福州',
|
||||||
children: [{ text: '鼓楼区' }, { text: '台江区' }],
|
value: 'Fuzhou',
|
||||||
|
children: [
|
||||||
|
{ text: '鼓楼区', value: 'Gulou' },
|
||||||
|
{ text: '台江区', value: 'Taijiang' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: '厦门',
|
text: '厦门',
|
||||||
children: [{ text: '思明区' }, { text: '海沧区' }],
|
value: 'Xiamen',
|
||||||
|
children: [
|
||||||
|
{ text: '思明区', value: 'Siming' },
|
||||||
|
{ text: '海沧区', value: 'Haicang' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -53,27 +99,45 @@ export const cascadeColumns = {
|
|||||||
'en-US': [
|
'en-US': [
|
||||||
{
|
{
|
||||||
text: 'Zhejiang',
|
text: 'Zhejiang',
|
||||||
|
value: 'Zhejiang',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
text: 'Hangzhou',
|
text: 'Hangzhou',
|
||||||
children: [{ text: 'Xihu' }, { text: 'Yuhang' }],
|
value: 'Hangzhou',
|
||||||
|
children: [
|
||||||
|
{ text: 'Xihu', value: 'Xihu' },
|
||||||
|
{ text: 'Yuhang', value: 'Yuhang' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Wenzhou',
|
text: 'Wenzhou',
|
||||||
children: [{ text: 'Lucheng' }, { text: 'Ouhai' }],
|
value: 'Wenzhou',
|
||||||
|
children: [
|
||||||
|
{ text: 'Lucheng', value: 'Lucheng' },
|
||||||
|
{ text: 'Ouhai', value: 'Ouhai' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Fujian',
|
text: 'Fujian',
|
||||||
|
value: 'Fujian',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
text: 'Fuzhou',
|
text: 'Fuzhou',
|
||||||
children: [{ text: 'Gulou' }, { text: 'Taijiang' }],
|
value: 'Fuzhou',
|
||||||
|
children: [
|
||||||
|
{ text: 'Gulou', value: 'Gulou' },
|
||||||
|
{ text: 'Taijiang', value: 'Taijiang' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Xiamen',
|
text: 'Xiamen',
|
||||||
children: [{ text: 'Siming' }, { text: 'Haicang' }],
|
value: 'Xiamen',
|
||||||
|
children: [
|
||||||
|
{ text: 'Siming', value: 'Siming' },
|
||||||
|
{ text: 'Haicang', value: 'Haicang' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -1,11 +1,17 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import VanPicker from '..';
|
import VanPicker, { PickerOption, PickerChangeEventParams } from '..';
|
||||||
import VanField from '../../field';
|
import VanField from '../../field';
|
||||||
import VanPopup from '../../popup';
|
import VanPopup from '../../popup';
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { dateColumns, cascadeColumns, cascadeColumnsCustomKey } from './data';
|
import {
|
||||||
|
dateColumns,
|
||||||
|
cascadeColumns,
|
||||||
|
cascadeColumnsCustomKey,
|
||||||
|
basicColumns,
|
||||||
|
} from './data';
|
||||||
import { useTranslate } from '../../../docs/site/use-translate';
|
import { useTranslate } from '../../../docs/site/use-translate';
|
||||||
import { Toast } from '../../toast';
|
import { Toast } from '../../toast';
|
||||||
|
import { PickerConfirmEventParams } from '../types';
|
||||||
|
|
||||||
const t = useTranslate({
|
const t = useTranslate({
|
||||||
'zh-CN': {
|
'zh-CN': {
|
||||||
@ -15,6 +21,7 @@ const t = useTranslate({
|
|||||||
chooseCity: '选择城市',
|
chooseCity: '选择城市',
|
||||||
showToolbar: '展示顶部栏',
|
showToolbar: '展示顶部栏',
|
||||||
dateColumns: dateColumns['zh-CN'],
|
dateColumns: dateColumns['zh-CN'],
|
||||||
|
basicColumns: basicColumns['zh-CN'],
|
||||||
defaultIndex: '默认选中项',
|
defaultIndex: '默认选中项',
|
||||||
disableOption: '禁用选项',
|
disableOption: '禁用选项',
|
||||||
cascadeColumns: cascadeColumns['zh-CN'],
|
cascadeColumns: cascadeColumns['zh-CN'],
|
||||||
@ -22,16 +29,6 @@ const t = useTranslate({
|
|||||||
setColumnValues: '动态设置选项',
|
setColumnValues: '动态设置选项',
|
||||||
customChildrenKey: '自定义 Columns 结构',
|
customChildrenKey: '自定义 Columns 结构',
|
||||||
customChildrenColumns: cascadeColumnsCustomKey['zh-CN'],
|
customChildrenColumns: cascadeColumnsCustomKey['zh-CN'],
|
||||||
textColumns: [
|
|
||||||
'杭州',
|
|
||||||
'宁波',
|
|
||||||
'温州',
|
|
||||||
'绍兴',
|
|
||||||
'湖州',
|
|
||||||
'嘉兴',
|
|
||||||
'金华',
|
|
||||||
'衢州',
|
|
||||||
],
|
|
||||||
disabledColumns: [
|
disabledColumns: [
|
||||||
{ text: '杭州', disabled: true },
|
{ text: '杭州', disabled: true },
|
||||||
{ text: '宁波' },
|
{ text: '宁波' },
|
||||||
@ -41,8 +38,7 @@ const t = useTranslate({
|
|||||||
浙江: ['杭州', '宁波', '温州', '嘉兴', '湖州'],
|
浙江: ['杭州', '宁波', '温州', '嘉兴', '湖州'],
|
||||||
福建: ['福州', '厦门', '莆田', '三明', '泉州'],
|
福建: ['福州', '厦门', '莆田', '三明', '泉州'],
|
||||||
},
|
},
|
||||||
toastContent: (value: string, index: number) =>
|
toastContent: (value: string) => `当前值:${value}`,
|
||||||
`当前值:${value}, 当前索引:${index}`,
|
|
||||||
},
|
},
|
||||||
'en-US': {
|
'en-US': {
|
||||||
city: 'City',
|
city: 'City',
|
||||||
@ -51,6 +47,7 @@ const t = useTranslate({
|
|||||||
chooseCity: 'Choose City',
|
chooseCity: 'Choose City',
|
||||||
showToolbar: 'Show Toolbar',
|
showToolbar: 'Show Toolbar',
|
||||||
dateColumns: dateColumns['en-US'],
|
dateColumns: dateColumns['en-US'],
|
||||||
|
basicColumns: basicColumns['en-US'],
|
||||||
defaultIndex: 'Default Index',
|
defaultIndex: 'Default Index',
|
||||||
disableOption: 'Disable Option',
|
disableOption: 'Disable Option',
|
||||||
cascadeColumns: cascadeColumns['en-US'],
|
cascadeColumns: cascadeColumns['en-US'],
|
||||||
@ -58,7 +55,6 @@ const t = useTranslate({
|
|||||||
setColumnValues: 'Set Column Values',
|
setColumnValues: 'Set Column Values',
|
||||||
customChildrenKey: 'Custom Columns Fields',
|
customChildrenKey: 'Custom Columns Fields',
|
||||||
customChildrenColumns: cascadeColumnsCustomKey['en-US'],
|
customChildrenColumns: cascadeColumnsCustomKey['en-US'],
|
||||||
textColumns: ['Delaware', 'Florida', 'Georqia', 'Indiana', 'Maine'],
|
|
||||||
disabledColumns: [
|
disabledColumns: [
|
||||||
{ text: 'Delaware', disabled: true },
|
{ text: 'Delaware', disabled: true },
|
||||||
{ text: 'Florida' },
|
{ text: 'Florida' },
|
||||||
@ -96,16 +92,16 @@ const columns = computed(() => {
|
|||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
const onChange1 = (value: string, index: number) => {
|
const onChange1 = ({ selectedValues }: PickerChangeEventParams) => {
|
||||||
Toast(t('toastContent', value, index));
|
Toast(t('toastContent', selectedValues.join(',')));
|
||||||
};
|
};
|
||||||
|
|
||||||
const onChange2 = (values: string[]) => {
|
const onChange2 = (values: string[]) => {
|
||||||
picker.value.setColumnValues(1, t('column3')[values[0]]);
|
picker.value.setColumnValues(1, t('column3')[values[0]]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onConfirm = (value: string, index: number) => {
|
const onConfirm = ({ selectedValues }: PickerConfirmEventParams) => {
|
||||||
Toast(t('toastContent', value, index));
|
Toast(t('toastContent', selectedValues.join(',')));
|
||||||
};
|
};
|
||||||
|
|
||||||
const onCancel = () => Toast(t('cancel'));
|
const onCancel = () => Toast(t('cancel'));
|
||||||
@ -128,17 +124,9 @@ const onConfirm2 = (value: string) => {
|
|||||||
<demo-block card :title="t('basicUsage')">
|
<demo-block card :title="t('basicUsage')">
|
||||||
<van-picker
|
<van-picker
|
||||||
:title="t('title')"
|
:title="t('title')"
|
||||||
:columns="t('textColumns')"
|
:columns="t('basicColumns')"
|
||||||
@change="onChange1"
|
|
||||||
/>
|
|
||||||
</demo-block>
|
|
||||||
|
|
||||||
<demo-block card :title="t('defaultIndex')">
|
|
||||||
<van-picker
|
|
||||||
:title="t('title')"
|
|
||||||
:columns="t('textColumns')"
|
|
||||||
:default-index="2"
|
|
||||||
@change="onChange1"
|
@change="onChange1"
|
||||||
|
@confirm="onConfirm"
|
||||||
/>
|
/>
|
||||||
</demo-block>
|
</demo-block>
|
||||||
|
|
||||||
@ -155,6 +143,8 @@ const onConfirm2 = (value: string) => {
|
|||||||
<van-picker :title="t('title')" :columns="t('cascadeColumns')" />
|
<van-picker :title="t('title')" :columns="t('cascadeColumns')" />
|
||||||
</demo-block>
|
</demo-block>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
<demo-block card :title="t('disableOption')">
|
<demo-block card :title="t('disableOption')">
|
||||||
<van-picker :title="t('title')" :columns="t('disabledColumns')" />
|
<van-picker :title="t('title')" :columns="t('disabledColumns')" />
|
||||||
</demo-block>
|
</demo-block>
|
||||||
@ -196,5 +186,5 @@ const onConfirm2 = (value: string) => {
|
|||||||
:columns="t('customChildrenColumns')"
|
:columns="t('customChildrenColumns')"
|
||||||
:columns-field-names="customFieldName"
|
:columns-field-names="customFieldName"
|
||||||
/>
|
/>
|
||||||
</demo-block>
|
</demo-block> -->
|
||||||
</template>
|
</template>
|
||||||
|
@ -9,9 +9,8 @@ export type {
|
|||||||
PickerOption,
|
PickerOption,
|
||||||
PickerInstance,
|
PickerInstance,
|
||||||
PickerFieldNames,
|
PickerFieldNames,
|
||||||
PickerObjectColumn,
|
|
||||||
PickerObjectOption,
|
|
||||||
PickerToolbarPosition,
|
PickerToolbarPosition,
|
||||||
|
PickerChangeEventParams,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
|
@ -6,42 +6,24 @@ export type PickerToolbarPosition = 'top' | 'bottom';
|
|||||||
|
|
||||||
export type PickerFieldNames = {
|
export type PickerFieldNames = {
|
||||||
text?: string;
|
text?: string;
|
||||||
values?: string;
|
value?: string;
|
||||||
children?: string;
|
children?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PickerObjectOption = {
|
export type PickerOption = {
|
||||||
text?: string | number;
|
text?: string | number;
|
||||||
|
value?: string | number;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
// for custom filed names
|
|
||||||
[key: PropertyKey]: any;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type PickerOption = string | number | PickerObjectOption;
|
|
||||||
|
|
||||||
export type PickerObjectColumn = {
|
|
||||||
values?: PickerOption[];
|
|
||||||
children?: PickerColumn;
|
children?: PickerColumn;
|
||||||
className?: unknown;
|
className?: unknown;
|
||||||
defaultIndex?: number;
|
|
||||||
// for custom filed names
|
// for custom filed names
|
||||||
[key: PropertyKey]: any;
|
[key: PropertyKey]: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PickerColumn = PickerOption[] | PickerObjectColumn;
|
export type PickerColumn = PickerOption[];
|
||||||
|
|
||||||
export type PickerExpose = {
|
export type PickerExpose = {
|
||||||
confirm: () => void;
|
confirm: () => void;
|
||||||
getValues: <T = PickerOption>() => T[];
|
|
||||||
setValues: (values: string[]) => void;
|
|
||||||
getIndexes: () => number[];
|
|
||||||
setIndexes: (indexes: number[]) => void;
|
|
||||||
getColumnIndex: (index: number) => number;
|
|
||||||
setColumnIndex: (columnIndex: number, optionIndex: number) => void;
|
|
||||||
getColumnValue: <T = PickerOption>(index: number) => T;
|
|
||||||
setColumnValue: (index: number, value: string) => void;
|
|
||||||
getColumnValues: <T = PickerOption>(index: number) => T[];
|
|
||||||
setColumnValues: (index: number, options: PickerOption[]) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PickerColumnProvide = {
|
export type PickerColumnProvide = {
|
||||||
@ -59,3 +41,14 @@ export type PickerColumnProvide = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type PickerInstance = ComponentPublicInstance<PickerProps, PickerExpose>;
|
export type PickerInstance = ComponentPublicInstance<PickerProps, PickerExpose>;
|
||||||
|
|
||||||
|
export type PickerConfirmEventParams = {
|
||||||
|
selectedValues: Array<number | string>;
|
||||||
|
selectedOptions: PickerOption[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PickerCancelEventParams = PickerConfirmEventParams;
|
||||||
|
|
||||||
|
export type PickerChangeEventParams = PickerConfirmEventParams & {
|
||||||
|
columnIndex: number;
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user