mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
Merge branch 'next' of github.com:youzan/vant into next
This commit is contained in:
commit
3c3f58a7be
@ -4,22 +4,47 @@
|
|||||||
|
|
||||||
本文档提供了从 Vant 3 到 Vant 4 的升级指南。
|
本文档提供了从 Vant 3 到 Vant 4 的升级指南。
|
||||||
|
|
||||||
### 为什么会有 Vant 4.0 ?
|
## API 调整
|
||||||
|
|
||||||
为了支持 **暗色模式**,我们对 Vant 中的 **样式变量** 进行了一些不兼容更新,因此发布了新的大版本。
|
### Picker 组件重构
|
||||||
|
|
||||||
如果你的项目没有使用主题定制,那样式变量的调整对你没有任何影响,只需要花几分钟去适配 API 调整,即可完成升级。
|
在之前的版本中,Picker 组件的 API 设计存在较大问题,比如:
|
||||||
|
|
||||||
如果你的项目使用了主题定制,请完整阅读此文档,并进行迁移。
|
- columns 数据格式定义不合理,容易产生误解
|
||||||
|
- 数据流不清晰,暴露了过多的实例方法来对数据进行操作
|
||||||
|
|
||||||
### API 调整
|
为了解决上述问题,我们在 v4 版本中对 Picker 组件进行了重构。
|
||||||
|
|
||||||
4.0 版本对少量 API 进行了不兼容调整:
|
#### 主要变更
|
||||||
|
|
||||||
#### Picker
|
- 支持通过 `v-model` 绑定当前选中的值,移除 `default-index` 属性
|
||||||
|
- 重新定义了 `columns` 属性的结构
|
||||||
|
- 移除了操作内部数据的实例方法,仅保留 `confirm` 方法
|
||||||
|
- 调整了 `confirm`、`cancel`、`change` 事件的参数
|
||||||
|
- 重命名 `item-height` 属性为 `option-height`
|
||||||
|
- 重命名 `visible-item-count` 属性为 `visible-option-num`
|
||||||
|
|
||||||
- `default` 插槽重命名为 `toolbar`
|
详细用法请参见 [Picker 组件文档](#/zh-CN/picker)。
|
||||||
- 移除了 `value-key` 属性,使用 `columnsFieldNames` 属性代替
|
|
||||||
|
### Area 组件重构
|
||||||
|
|
||||||
|
Area 组件是基于 Picker 组件进行封装的,因此本次升级也对 Area 组件进行了内部逻辑的重构,并优化了部分 API 设计。
|
||||||
|
|
||||||
|
#### 主要变更
|
||||||
|
|
||||||
|
- 支持通过 `v-model` 绑定当前选中的值
|
||||||
|
- 移除 `reset` 方法,现在可以通过修改 `v-model` 来进行重置
|
||||||
|
- 移除 `is-oversea-code` 属性
|
||||||
|
- 调整所有事件的参数,与 Picker 组件保持一致
|
||||||
|
- 重命名 `value` 属性我 `modelValue`
|
||||||
|
- 重命名 `item-height` 属性为 `option-height`
|
||||||
|
- 重命名 `visible-item-count` 属性为 `visible-option-num`
|
||||||
|
|
||||||
|
详细用法请参见 [Area 组件文档](#/zh-CN/area)。
|
||||||
|
|
||||||
|
### 其他 API 调整
|
||||||
|
|
||||||
|
4.0 版本中,以下 API 进行了不兼容更新:
|
||||||
|
|
||||||
#### Tabs
|
#### Tabs
|
||||||
|
|
||||||
|
@ -2,16 +2,12 @@ import {
|
|||||||
ref,
|
ref,
|
||||||
watch,
|
watch,
|
||||||
computed,
|
computed,
|
||||||
reactive,
|
|
||||||
nextTick,
|
|
||||||
onMounted,
|
|
||||||
defineComponent,
|
defineComponent,
|
||||||
type PropType,
|
type PropType,
|
||||||
type ExtractPropTypes,
|
type ExtractPropTypes,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import { deepClone } from '../utils/deep-clone';
|
|
||||||
import {
|
import {
|
||||||
pick,
|
pick,
|
||||||
extend,
|
extend,
|
||||||
@ -20,52 +16,24 @@ import {
|
|||||||
createNamespace,
|
createNamespace,
|
||||||
} from '../utils';
|
} from '../utils';
|
||||||
import { pickerSharedProps } from '../picker/Picker';
|
import { pickerSharedProps } from '../picker/Picker';
|
||||||
|
import { INHERIT_PROPS, INHERIT_SLOTS, formatDataForCascade } from './utils';
|
||||||
// Composables
|
|
||||||
import { useExpose } from '../composables/use-expose';
|
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import { Picker, PickerInstance } from '../picker';
|
import { Picker } from '../picker';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { AreaList, AreaColumnType, AreaColumnOption } from './types';
|
import type { AreaList } from './types';
|
||||||
|
|
||||||
const [name, bem] = createNamespace('area');
|
const [name, bem] = createNamespace('area');
|
||||||
|
|
||||||
const EMPTY_CODE = '000000';
|
|
||||||
const INHERIT_SLOTS = [
|
|
||||||
'title',
|
|
||||||
'cancel',
|
|
||||||
'confirm',
|
|
||||||
'toolbar',
|
|
||||||
'columns-top',
|
|
||||||
'columns-bottom',
|
|
||||||
] as const;
|
|
||||||
const INHERIT_PROPS = [
|
|
||||||
'title',
|
|
||||||
'loading',
|
|
||||||
'readonly',
|
|
||||||
'itemHeight',
|
|
||||||
'swipeDuration',
|
|
||||||
'visibleItemCount',
|
|
||||||
'cancelButtonText',
|
|
||||||
'confirmButtonText',
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
const isOverseaCode = (code: string) => code[0] === '9';
|
|
||||||
|
|
||||||
const areaProps = extend({}, pickerSharedProps, {
|
const areaProps = extend({}, pickerSharedProps, {
|
||||||
value: String,
|
modelValue: String,
|
||||||
columnsNum: makeNumericProp(3),
|
columnsNum: makeNumericProp(3),
|
||||||
columnsPlaceholder: makeArrayProp<string>(),
|
columnsPlaceholder: makeArrayProp<string>(),
|
||||||
areaList: {
|
areaList: {
|
||||||
type: Object as PropType<AreaList>,
|
type: Object as PropType<AreaList>,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
isOverseaCode: {
|
|
||||||
type: Function as PropType<(code: string) => boolean>,
|
|
||||||
default: isOverseaCode,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type AreaProps = ExtractPropTypes<typeof areaProps>;
|
export type AreaProps = ExtractPropTypes<typeof areaProps>;
|
||||||
@ -75,262 +43,54 @@ export default defineComponent({
|
|||||||
|
|
||||||
props: areaProps,
|
props: areaProps,
|
||||||
|
|
||||||
emits: ['change', 'confirm', 'cancel'],
|
emits: ['change', 'confirm', 'cancel', 'update:modelValue'],
|
||||||
|
|
||||||
setup(props, { emit, slots }) {
|
setup(props, { emit, slots }) {
|
||||||
const pickerRef = ref<PickerInstance>();
|
const codes = ref<string[]>([]);
|
||||||
|
const columns = computed(() => formatDataForCascade(props));
|
||||||
const state = reactive({
|
const onChange = (...args: unknown[]) => emit('change', ...args);
|
||||||
code: props.value,
|
|
||||||
columns: [{ values: [] }, { values: [] }, { values: [] }],
|
|
||||||
});
|
|
||||||
|
|
||||||
const areaList = computed(() => {
|
|
||||||
const { areaList } = props;
|
|
||||||
return {
|
|
||||||
province: areaList.province_list || {},
|
|
||||||
city: areaList.city_list || {},
|
|
||||||
county: areaList.county_list || {},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const placeholderMap = computed(() => {
|
|
||||||
const { columnsPlaceholder } = props;
|
|
||||||
return {
|
|
||||||
province: columnsPlaceholder[0] || '',
|
|
||||||
city: columnsPlaceholder[1] || '',
|
|
||||||
county: columnsPlaceholder[2] || '',
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const getDefaultCode = () => {
|
|
||||||
if (props.columnsPlaceholder.length) {
|
|
||||||
return EMPTY_CODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { county, city } = areaList.value;
|
|
||||||
|
|
||||||
const countyCodes = Object.keys(county);
|
|
||||||
if (countyCodes[0]) {
|
|
||||||
return countyCodes[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
const cityCodes = Object.keys(city);
|
|
||||||
if (cityCodes[0]) {
|
|
||||||
return cityCodes[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
|
||||||
};
|
|
||||||
|
|
||||||
const getColumnValues = (type: AreaColumnType, code?: string) => {
|
|
||||||
let column: AreaColumnOption[] = [];
|
|
||||||
if (type !== 'province' && !code) {
|
|
||||||
return column;
|
|
||||||
}
|
|
||||||
|
|
||||||
const list = areaList.value[type];
|
|
||||||
column = Object.keys(list).map((listCode) => ({
|
|
||||||
code: listCode,
|
|
||||||
name: list[listCode],
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (code) {
|
|
||||||
// oversea code
|
|
||||||
if (type === 'city' && props.isOverseaCode(code)) {
|
|
||||||
code = '9';
|
|
||||||
}
|
|
||||||
column = column.filter((item) => item.code.indexOf(code!) === 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (placeholderMap.value[type] && column.length) {
|
|
||||||
// set columns placeholder
|
|
||||||
let codeFill = '';
|
|
||||||
if (type === 'city') {
|
|
||||||
codeFill = EMPTY_CODE.slice(2, 4);
|
|
||||||
} else if (type === 'county') {
|
|
||||||
codeFill = EMPTY_CODE.slice(4, 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
column.unshift({
|
|
||||||
code: code + codeFill,
|
|
||||||
name: placeholderMap.value[type],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return column;
|
|
||||||
};
|
|
||||||
|
|
||||||
// get index by code
|
|
||||||
const getIndex = (type: AreaColumnType, code: string) => {
|
|
||||||
let compareNum = code.length;
|
|
||||||
if (type === 'province') {
|
|
||||||
compareNum = props.isOverseaCode(code) ? 1 : 2;
|
|
||||||
}
|
|
||||||
if (type === 'city') {
|
|
||||||
compareNum = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
code = code.slice(0, compareNum);
|
|
||||||
|
|
||||||
const list = getColumnValues(
|
|
||||||
type,
|
|
||||||
compareNum > 2 ? code.slice(0, compareNum - 2) : ''
|
|
||||||
);
|
|
||||||
|
|
||||||
for (let i = 0; i < list.length; i++) {
|
|
||||||
if (list[i].code.slice(0, compareNum) === code) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
const setValues = () => {
|
|
||||||
const picker = pickerRef.value;
|
|
||||||
|
|
||||||
if (!picker) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let code = state.code || getDefaultCode();
|
|
||||||
const province = getColumnValues('province');
|
|
||||||
const city = getColumnValues('city', code.slice(0, 2));
|
|
||||||
picker.setColumnValues(0, province);
|
|
||||||
picker.setColumnValues(1, city);
|
|
||||||
|
|
||||||
if (
|
|
||||||
city.length &&
|
|
||||||
code.slice(2, 4) === '00' &&
|
|
||||||
!props.isOverseaCode(code)
|
|
||||||
) {
|
|
||||||
[{ code }] = city;
|
|
||||||
}
|
|
||||||
|
|
||||||
picker.setColumnValues(2, getColumnValues('county', code.slice(0, 4)));
|
|
||||||
picker.setIndexes([
|
|
||||||
getIndex('province', code),
|
|
||||||
getIndex('city', code),
|
|
||||||
getIndex('county', code),
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
// parse output columns data
|
|
||||||
const parseValues = (values: AreaColumnOption[]) =>
|
|
||||||
values.map((value, index) => {
|
|
||||||
if (value) {
|
|
||||||
value = deepClone(value);
|
|
||||||
|
|
||||||
if (!value.code || value.name === props.columnsPlaceholder[index]) {
|
|
||||||
value.code = '';
|
|
||||||
value.name = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
});
|
|
||||||
|
|
||||||
const getValues = () => {
|
|
||||||
if (pickerRef.value) {
|
|
||||||
const values = pickerRef.value
|
|
||||||
.getValues<AreaColumnOption>()
|
|
||||||
.filter(Boolean);
|
|
||||||
return parseValues(values);
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
};
|
|
||||||
|
|
||||||
const getArea = () => {
|
|
||||||
const values = getValues();
|
|
||||||
const area = {
|
|
||||||
code: '',
|
|
||||||
country: '',
|
|
||||||
province: '',
|
|
||||||
city: '',
|
|
||||||
county: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!values.length) {
|
|
||||||
return area;
|
|
||||||
}
|
|
||||||
|
|
||||||
const names = values.map((item) => item.name);
|
|
||||||
const validValues = values.filter((value) => value.code);
|
|
||||||
|
|
||||||
area.code = validValues.length
|
|
||||||
? validValues[validValues.length - 1].code
|
|
||||||
: '';
|
|
||||||
|
|
||||||
if (props.isOverseaCode(area.code)) {
|
|
||||||
area.country = names[1] || '';
|
|
||||||
area.province = names[2] || '';
|
|
||||||
} else {
|
|
||||||
area.province = names[0] || '';
|
|
||||||
area.city = names[1] || '';
|
|
||||||
area.county = names[2] || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return area;
|
|
||||||
};
|
|
||||||
|
|
||||||
const reset = (newCode = '') => {
|
|
||||||
state.code = newCode;
|
|
||||||
setValues();
|
|
||||||
};
|
|
||||||
|
|
||||||
const onChange = (values: AreaColumnOption[], index: number) => {
|
|
||||||
state.code = values[index].code;
|
|
||||||
setValues();
|
|
||||||
|
|
||||||
if (pickerRef.value) {
|
|
||||||
const parsedValues = parseValues(pickerRef.value.getValues());
|
|
||||||
emit('change', parsedValues, index);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onConfirm = (values: AreaColumnOption[], index: number) => {
|
|
||||||
setValues();
|
|
||||||
emit('confirm', parseValues(values), index);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onCancel = (...args: unknown[]) => emit('cancel', ...args);
|
const onCancel = (...args: unknown[]) => emit('cancel', ...args);
|
||||||
|
const onConfirm = (...args: unknown[]) => emit('confirm', ...args);
|
||||||
onMounted(setValues);
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.value,
|
codes,
|
||||||
(value) => {
|
(newCodes) => {
|
||||||
state.code = value;
|
const lastCode = newCodes.length ? newCodes[newCodes.length - 1] : '';
|
||||||
setValues();
|
if (lastCode && lastCode !== props.modelValue) {
|
||||||
}
|
emit('update:modelValue', lastCode);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
watch(() => props.areaList, setValues, { deep: true });
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.columnsNum,
|
() => props.modelValue,
|
||||||
() => nextTick(setValues)
|
(newCode) => {
|
||||||
|
const lastCode = codes.value.length
|
||||||
|
? codes.value[codes.value.length - 1]
|
||||||
|
: '';
|
||||||
|
if (newCode && newCode !== lastCode) {
|
||||||
|
codes.value = [
|
||||||
|
`${newCode.slice(0, 2)}0000`,
|
||||||
|
`${newCode.slice(0, 4)}00`,
|
||||||
|
newCode,
|
||||||
|
].slice(0, +props.columnsNum);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
useExpose({ reset, getArea, getValues });
|
return () => (
|
||||||
|
<Picker
|
||||||
return () => {
|
v-model={codes.value}
|
||||||
const columns = state.columns.slice(0, +props.columnsNum);
|
v-slots={pick(slots, INHERIT_SLOTS)}
|
||||||
|
class={bem()}
|
||||||
return (
|
columns={columns.value}
|
||||||
<Picker
|
onChange={onChange}
|
||||||
v-slots={pick(slots, INHERIT_SLOTS)}
|
onCancel={onCancel}
|
||||||
ref={pickerRef}
|
onConfirm={onConfirm}
|
||||||
class={bem()}
|
{...pick(props, INHERIT_PROPS)}
|
||||||
columns={columns}
|
/>
|
||||||
columnsFieldNames={{ text: 'name' }}
|
);
|
||||||
onChange={onChange}
|
|
||||||
onCancel={onCancel}
|
|
||||||
onConfirm={onConfirm}
|
|
||||||
{...pick(props, INHERIT_PROPS)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -75,12 +75,23 @@ export default {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### Initial Value
|
### Model Value
|
||||||
|
|
||||||
To have a selected value,simply pass the `code` of target area to `value` property.
|
Bind the currently selected area code via `v-model`.
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<van-area title="Title" :area-list="areaList" value="110101" />
|
<van-area v-model="value" title="Title" :area-list="areaList" />
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const value = ref('330302');
|
||||||
|
return { value };
|
||||||
|
},
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### Columns Number
|
### Columns Number
|
||||||
@ -109,7 +120,7 @@ To have a selected value,simply pass the `code` of target area to `value` prop
|
|||||||
|
|
||||||
| Attribute | Description | Type | Default |
|
| Attribute | Description | Type | Default |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| value | the `code` of selected area | _string_ | - |
|
| v-model | the `code` of selected area | _string_ | - |
|
||||||
| title | Toolbar title | _string_ | - |
|
| title | Toolbar title | _string_ | - |
|
||||||
| confirm-button-text | Text of confirm button | _string_ | `Confirm` |
|
| confirm-button-text | Text of confirm button | _string_ | `Confirm` |
|
||||||
| cancel-button-text | Text of cancel button | _string_ | `Cancel` |
|
| cancel-button-text | Text of cancel button | _string_ | `Cancel` |
|
||||||
@ -117,40 +128,18 @@ To have a selected value,simply pass the `code` of target area to `value` prop
|
|||||||
| columns-placeholder | Placeholder of columns | _string[]_ | `[]` |
|
| columns-placeholder | Placeholder of columns | _string[]_ | `[]` |
|
||||||
| loading | Whether to show loading prompt | _boolean_ | `false` |
|
| loading | Whether to show loading prompt | _boolean_ | `false` |
|
||||||
| readonly | Whether to be readonly | _boolean_ | `false` |
|
| readonly | Whether to be readonly | _boolean_ | `false` |
|
||||||
| item-height | Option height, supports `px` `vw` `vh` `rem` unit, default `px` | _number \| string_ | `44` |
|
| option-height | Option height, supports `px` `vw` `vh` `rem` unit, default `px` | _number \| string_ | `44` |
|
||||||
| columns-num | Level of picker | _number \| string_ | `3` |
|
| columns-num | Level of picker | _number \| string_ | `3` |
|
||||||
| visible-item-count | Count of visible columns | _number \| string_ | `6` |
|
| visible-option-num | Count of visible columns | _number \| string_ | `6` |
|
||||||
| swipe-duration | Duration of the momentum animation,unit `ms` | _number \| string_ | `1000` |
|
| swipe-duration | Duration of the momentum animation,unit `ms` | _number \| string_ | `1000` |
|
||||||
| is-oversea-code | The method to validate oversea code | _() => boolean_ | - |
|
|
||||||
|
|
||||||
### Events
|
### Events
|
||||||
|
|
||||||
| Event | Description | Arguments |
|
| Event | Description | Arguments |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| confirm | Emitted when the confirm button is clicked | _result: ConfirmResult_ |
|
| confirm | Emitted when the confirm button is clicked | _{ selectedValues, selectedOptions }_ |
|
||||||
| cancel | Emitted when the cancel button is clicked | - |
|
| cancel | Emitted when the cancel button is clicked | _{ selectedValues, selectedOptions }_ |
|
||||||
| change | Emitted when current option changed | current values,column index |
|
| change | Emitted when current option is changed | _{ selectedValues, selectedOptions, columnIndex }_ |
|
||||||
|
|
||||||
### ConfirmResult
|
|
||||||
|
|
||||||
An array that contains selected area objects.
|
|
||||||
|
|
||||||
```js
|
|
||||||
[
|
|
||||||
{
|
|
||||||
code: '330000',
|
|
||||||
name: 'Zhejiang Province',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: '330100',
|
|
||||||
name: 'Hangzhou',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: '330105',
|
|
||||||
name: 'Xihu District',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
```
|
|
||||||
|
|
||||||
### Slots
|
### Slots
|
||||||
|
|
||||||
@ -163,14 +152,6 @@ An array that contains selected area objects.
|
|||||||
| columns-top | Custom content above columns | - |
|
| columns-top | Custom content above columns | - |
|
||||||
| columns-bottom | Custom content below columns | - |
|
| columns-bottom | Custom content below columns | - |
|
||||||
|
|
||||||
### Methods
|
|
||||||
|
|
||||||
Use [ref](https://v3.vuejs.org/guide/component-template-refs.html) to get Area instance and call instance methods.
|
|
||||||
|
|
||||||
| Name | Description | Attribute | Return value |
|
|
||||||
| ----- | ------------------------- | --------------- | ------------ |
|
|
||||||
| reset | Reset all options by code | _code?: string_ | - |
|
|
||||||
|
|
||||||
### Types
|
### Types
|
||||||
|
|
||||||
The component exports the following type definitions:
|
The component exports the following type definitions:
|
||||||
|
@ -77,12 +77,23 @@ export default {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### 选中省市区
|
### 控制选中项
|
||||||
|
|
||||||
如果想选中某个省市区,需要传入一个 `value` 属性,绑定对应的地区码。
|
通过 `v-model` 绑定当前选中的地区码。
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<van-area title="标题" :area-list="areaList" value="110101" />
|
<van-area v-model="value" title="标题" :area-list="areaList" />
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const value = ref('330302');
|
||||||
|
return { value };
|
||||||
|
},
|
||||||
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### 配置显示列
|
### 配置显示列
|
||||||
@ -111,7 +122,7 @@ export default {
|
|||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 |
|
| 参数 | 说明 | 类型 | 默认值 |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| value | 当前选中项对应的地区码 | _string_ | - |
|
| v-model | 当前选中项对应的地区码 | _string_ | - |
|
||||||
| title | 顶部栏标题 | _string_ | - |
|
| title | 顶部栏标题 | _string_ | - |
|
||||||
| confirm-button-text | 确认按钮文字 | _string_ | `确认` |
|
| confirm-button-text | 确认按钮文字 | _string_ | `确认` |
|
||||||
| cancel-button-text | 取消按钮文字 | _string_ | `取消` |
|
| cancel-button-text | 取消按钮文字 | _string_ | `取消` |
|
||||||
@ -119,40 +130,18 @@ export default {
|
|||||||
| columns-placeholder | 列占位提示文字 | _string[]_ | `[]` |
|
| columns-placeholder | 列占位提示文字 | _string[]_ | `[]` |
|
||||||
| loading | 是否显示加载状态 | _boolean_ | `false` |
|
| loading | 是否显示加载状态 | _boolean_ | `false` |
|
||||||
| readonly | 是否为只读状态,只读状态下无法切换选项 | _boolean_ | `false` |
|
| readonly | 是否为只读状态,只读状态下无法切换选项 | _boolean_ | `false` |
|
||||||
| item-height | 选项高度,支持 `px` `vw` `vh` `rem` 单位,默认 `px` | _number \| string_ | `44` |
|
| option-height | 选项高度,支持 `px` `vw` `vh` `rem` 单位,默认 `px` | _number \| string_ | `44` |
|
||||||
| columns-num | 显示列数,3-省市区,2-省市,1-省 | _number \| string_ | `3` |
|
| columns-num | 显示列数,3-省市区,2-省市,1-省 | _number \| string_ | `3` |
|
||||||
| visible-item-count | 可见的选项个数 | _number \| string_ | `6` |
|
| visible-option-num | 可见的选项个数 | _number \| string_ | `6` |
|
||||||
| swipe-duration | 快速滑动时惯性滚动的时长,单位 `ms` | _number \| string_ | `1000` |
|
| swipe-duration | 快速滑动时惯性滚动的时长,单位 `ms` | _number \| string_ | `1000` |
|
||||||
| is-oversea-code | 根据地区码校验海外地址,海外地址会划分至单独的分类 | _() => boolean_ | - |
|
|
||||||
|
|
||||||
### Events
|
### Events
|
||||||
|
|
||||||
| 事件 | 说明 | 回调参数 |
|
| 事件 | 说明 | 回调参数 |
|
||||||
| ------- | ------------------ | ------------------------------ |
|
| --- | --- | --- |
|
||||||
| confirm | 点击完成按钮时触发 | _result: ConfirmResult_ |
|
| confirm | 点击完成按钮时触发 | _{ selectedValues, selectedOptions }_ |
|
||||||
| cancel | 点击取消按钮时触发 | - |
|
| cancel | 点击取消按钮时触发 | _{ selectedValues, selectedOptions }_ |
|
||||||
| change | 选项改变时触发 | 所有列选中值,当前列对应的索引 |
|
| change | 选项改变时触发 | _{ selectedValues, selectedOptions, columnIndex }_ |
|
||||||
|
|
||||||
### ConfirmResult 格式
|
|
||||||
|
|
||||||
confirm 事件返回的数据整体为一个数组,数组每一项对应一列选项中被选中的数据。
|
|
||||||
|
|
||||||
```js
|
|
||||||
[
|
|
||||||
{
|
|
||||||
code: '110000',
|
|
||||||
name: '北京市',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: '110100',
|
|
||||||
name: '北京市',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
code: '110101',
|
|
||||||
name: '东城区',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
```
|
|
||||||
|
|
||||||
### Slots
|
### Slots
|
||||||
|
|
||||||
@ -165,20 +154,12 @@ confirm 事件返回的数据整体为一个数组,数组每一项对应一列
|
|||||||
| columns-top | 自定义选项上方内容 | - |
|
| columns-top | 自定义选项上方内容 | - |
|
||||||
| columns-bottom | 自定义选项下方内容 | - |
|
| columns-bottom | 自定义选项下方内容 | - |
|
||||||
|
|
||||||
### 方法
|
|
||||||
|
|
||||||
通过 ref 可以获取到 Area 实例并调用实例方法,详见[组件实例方法](#/zh-CN/advanced-usage#zu-jian-shi-li-fang-fa)。
|
|
||||||
|
|
||||||
| 方法名 | 说明 | 参数 | 返回值 |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| reset | 根据地区码重置所有选项,若不传地区码,则重置到第一项 | _code?: string_ | - |
|
|
||||||
|
|
||||||
### 类型定义
|
### 类型定义
|
||||||
|
|
||||||
组件导出以下类型定义:
|
组件导出以下类型定义:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import type { AreaProps, AreaList, AreaInstance, AreaColumnOption } from 'vant';
|
import type { AreaProps, AreaList, AreaInstance } from 'vant';
|
||||||
```
|
```
|
||||||
|
|
||||||
`AreaInstance` 是组件实例的类型,用法如下:
|
`AreaInstance` 是组件实例的类型,用法如下:
|
||||||
|
@ -1 +0,0 @@
|
|||||||
// 已迁移至 https://github.com/youzan/vant/tree/dev/packages/vant-area-data
|
|
@ -7,14 +7,14 @@ import { useTranslate } from '../../../docs/site/use-translate';
|
|||||||
|
|
||||||
const t = useTranslate({
|
const t = useTranslate({
|
||||||
'zh-CN': {
|
'zh-CN': {
|
||||||
title2: '选中省市区',
|
title2: '控制选中项',
|
||||||
title3: '配置显示列',
|
title3: '配置显示列',
|
||||||
title4: '配置列占位提示文字',
|
title4: '配置列占位提示文字',
|
||||||
columnsPlaceholder: ['请选择', '请选择', '请选择'],
|
columnsPlaceholder: ['请选择', '请选择', '请选择'],
|
||||||
areaList,
|
areaList,
|
||||||
},
|
},
|
||||||
'en-US': {
|
'en-US': {
|
||||||
title2: 'Initial Value',
|
title2: 'Model Value',
|
||||||
title3: 'Columns Number',
|
title3: 'Columns Number',
|
||||||
title4: 'Columns Placeholder',
|
title4: 'Columns Placeholder',
|
||||||
columnsPlaceholder: ['Choose', 'Choose', 'Choose'],
|
columnsPlaceholder: ['Choose', 'Choose', 'Choose'],
|
||||||
@ -31,7 +31,7 @@ const value = ref('330302');
|
|||||||
</demo-block>
|
</demo-block>
|
||||||
|
|
||||||
<demo-block card :title="t('title2')">
|
<demo-block card :title="t('title2')">
|
||||||
<van-area :title="t('title')" :area-list="t('areaList')" :value="value" />
|
<van-area v-model="value" :title="t('title')" :area-list="t('areaList')" />
|
||||||
</demo-block>
|
</demo-block>
|
||||||
|
|
||||||
<demo-block card :title="t('title3')">
|
<demo-block card :title="t('title3')">
|
||||||
|
@ -4,7 +4,7 @@ import _Area from './Area';
|
|||||||
export const Area = withInstall(_Area);
|
export const Area = withInstall(_Area);
|
||||||
export default Area;
|
export default Area;
|
||||||
export type { AreaProps } from './Area';
|
export type { AreaProps } from './Area';
|
||||||
export type { AreaList, AreaInstance, AreaColumnOption } from './types';
|
export type { AreaList, AreaInstance } from './types';
|
||||||
|
|
||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
|
@ -8,23 +8,4 @@ export type AreaList = {
|
|||||||
province_list: Record<string, string>;
|
province_list: Record<string, string>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AreaColumnOption = {
|
export type AreaInstance = ComponentPublicInstance<AreaProps>;
|
||||||
name: string;
|
|
||||||
code: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type AreaColumnType = 'province' | 'county' | 'city';
|
|
||||||
|
|
||||||
export type AreaExpose = {
|
|
||||||
reset: (newCode?: string) => void;
|
|
||||||
getArea: () => {
|
|
||||||
code: string;
|
|
||||||
country: string;
|
|
||||||
province: string;
|
|
||||||
city: string;
|
|
||||||
county: string;
|
|
||||||
};
|
|
||||||
getValues: () => AreaColumnOption[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type AreaInstance = ComponentPublicInstance<AreaProps, AreaExpose>;
|
|
||||||
|
103
packages/vant/src/area/utils.ts
Normal file
103
packages/vant/src/area/utils.ts
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import type { AreaProps } from '.';
|
||||||
|
import type { PickerOption } from '../picker';
|
||||||
|
|
||||||
|
const EMPTY_CODE = '000000';
|
||||||
|
|
||||||
|
export const INHERIT_SLOTS = [
|
||||||
|
'title',
|
||||||
|
'cancel',
|
||||||
|
'confirm',
|
||||||
|
'toolbar',
|
||||||
|
'columns-top',
|
||||||
|
'columns-bottom',
|
||||||
|
] as const;
|
||||||
|
export const INHERIT_PROPS = [
|
||||||
|
'title',
|
||||||
|
'loading',
|
||||||
|
'readonly',
|
||||||
|
'optionHeight',
|
||||||
|
'swipeDuration',
|
||||||
|
'visibleOptionNum',
|
||||||
|
'cancelButtonText',
|
||||||
|
'confirmButtonText',
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const makeOption = (
|
||||||
|
text = '',
|
||||||
|
value = EMPTY_CODE,
|
||||||
|
children?: PickerOption[]
|
||||||
|
): PickerOption => ({
|
||||||
|
text,
|
||||||
|
value,
|
||||||
|
children,
|
||||||
|
});
|
||||||
|
|
||||||
|
export function formatDataForCascade({
|
||||||
|
areaList,
|
||||||
|
columnsNum,
|
||||||
|
columnsPlaceholder: placeholder,
|
||||||
|
}: AreaProps) {
|
||||||
|
const {
|
||||||
|
city_list: city,
|
||||||
|
county_list: county,
|
||||||
|
province_list: province,
|
||||||
|
} = areaList;
|
||||||
|
const showCity = columnsNum > 1;
|
||||||
|
const showCounty = columnsNum > 2;
|
||||||
|
|
||||||
|
const getProvinceChildren = () => {
|
||||||
|
if (showCity) {
|
||||||
|
return placeholder.length
|
||||||
|
? [makeOption(placeholder[0], EMPTY_CODE, showCounty ? [] : undefined)]
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const provinceMap = new Map<string, PickerOption>();
|
||||||
|
Object.keys(province).forEach((code) => {
|
||||||
|
provinceMap.set(
|
||||||
|
code.slice(0, 2),
|
||||||
|
makeOption(province[code], code, getProvinceChildren())
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const cityMap = new Map<string, PickerOption>();
|
||||||
|
if (showCity) {
|
||||||
|
const getCityChildren = () => {
|
||||||
|
if (showCounty) {
|
||||||
|
return placeholder.length ? [makeOption(placeholder[1])] : [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.keys(city).forEach((code) => {
|
||||||
|
const option = makeOption(city[code], code, getCityChildren());
|
||||||
|
cityMap.set(code.slice(0, 4), option);
|
||||||
|
|
||||||
|
const province = provinceMap.get(code.slice(0, 2));
|
||||||
|
if (province) {
|
||||||
|
province.children!.push(option);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showCounty) {
|
||||||
|
Object.keys(county).forEach((code) => {
|
||||||
|
const city = cityMap.get(code.slice(0, 4));
|
||||||
|
if (city) {
|
||||||
|
city.children!.push(makeOption(county[code], code));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const options = Array.from(provinceMap.values()) as PickerOption[];
|
||||||
|
|
||||||
|
if (placeholder.length) {
|
||||||
|
const county = showCounty ? [makeOption(placeholder[2])] : undefined;
|
||||||
|
const city = showCity
|
||||||
|
? [makeOption(placeholder[1], EMPTY_CODE, county)]
|
||||||
|
: undefined;
|
||||||
|
options.unshift(makeOption(placeholder[0], EMPTY_CODE, city));
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
@ -291,8 +291,8 @@ export default {
|
|||||||
| filter | Option filter | _(type: string, values: string[]) => string[]_ | - |
|
| filter | Option filter | _(type: string, values: string[]) => string[]_ | - |
|
||||||
| formatter | Option text formatter | _(type: string, value: string) => string_ | - |
|
| formatter | Option text formatter | _(type: string, value: string) => string_ | - |
|
||||||
| columns-order | Array for ordering columns, where item can be set to<br> `year`, `month`, `day`, `hour` and `minute` | _string[]_ | - |
|
| columns-order | Array for ordering columns, where item can be set to<br> `year`, `month`, `day`, `hour` and `minute` | _string[]_ | - |
|
||||||
| item-height | Option height, supports `px` `vw` `vh` `rem` unit, default `px` | _number \| string_ | `44` |
|
| option-height | Option height, supports `px` `vw` `vh` `rem` unit, default `px` | _number \| string_ | `44` |
|
||||||
| visible-item-count | Count of visible columns | _number \| string_ | `6` |
|
| visible-option-num | Count of visible columns | _number \| string_ | `6` |
|
||||||
| swipe-duration | Duration of the momentum animation,unit `ms` | _number \| string_ | `1000` |
|
| swipe-duration | Duration of the momentum animation,unit `ms` | _number \| string_ | `1000` |
|
||||||
|
|
||||||
### DatePicker Props
|
### DatePicker Props
|
||||||
|
@ -300,8 +300,8 @@ export default {
|
|||||||
| filter | 选项过滤函数 | _(type: string, values: string[]) => string[]_ | - |
|
| filter | 选项过滤函数 | _(type: string, values: string[]) => string[]_ | - |
|
||||||
| formatter | 选项格式化函数 | _(type: string, value: string) => string_ | - |
|
| formatter | 选项格式化函数 | _(type: string, value: string) => string_ | - |
|
||||||
| columns-order | 自定义列排序数组, 子项可选值为<br> `year`、`month`、`day`、`hour`、`minute` | _string[]_ | - |
|
| columns-order | 自定义列排序数组, 子项可选值为<br> `year`、`month`、`day`、`hour`、`minute` | _string[]_ | - |
|
||||||
| item-height | 选项高度,支持 `px` `vw` `vh` `rem` 单位,默认 `px` | _number \| string_ | `44` |
|
| option-height | 选项高度,支持 `px` `vw` `vh` `rem` 单位,默认 `px` | _number \| string_ | `44` |
|
||||||
| visible-item-count | 可见的选项个数 | _number \| string_ | `6` |
|
| visible-option-num | 可见的选项个数 | _number \| string_ | `6` |
|
||||||
| swipe-duration | 快速滑动时惯性滚动的时长,单位`ms` | _number \| string_ | `1000` |
|
| swipe-duration | 快速滑动时惯性滚动的时长,单位`ms` | _number \| string_ | `1000` |
|
||||||
|
|
||||||
### DatePicker Props
|
### DatePicker Props
|
||||||
|
@ -20,6 +20,14 @@ import {
|
|||||||
HAPTICS_FEEDBACK,
|
HAPTICS_FEEDBACK,
|
||||||
BORDER_UNSET_TOP_BOTTOM,
|
BORDER_UNSET_TOP_BOTTOM,
|
||||||
} from '../utils';
|
} from '../utils';
|
||||||
|
import {
|
||||||
|
isValuesEqual,
|
||||||
|
getColumnsType,
|
||||||
|
findOptionByValue,
|
||||||
|
formatCascadeColumns,
|
||||||
|
getFirstEnabledOption,
|
||||||
|
assignDefaultFields,
|
||||||
|
} from './utils';
|
||||||
|
|
||||||
// Composables
|
// Composables
|
||||||
import { useChildren } from '@vant/use';
|
import { useChildren } from '@vant/use';
|
||||||
@ -32,10 +40,9 @@ import Column, { PICKER_KEY } from './PickerColumn';
|
|||||||
// Types
|
// Types
|
||||||
import type {
|
import type {
|
||||||
PickerColumn,
|
PickerColumn,
|
||||||
PickerOption,
|
|
||||||
PickerExpose,
|
PickerExpose,
|
||||||
|
PickerOption,
|
||||||
PickerFieldNames,
|
PickerFieldNames,
|
||||||
PickerObjectColumn,
|
|
||||||
PickerToolbarPosition,
|
PickerToolbarPosition,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
@ -46,17 +53,17 @@ export const pickerSharedProps = {
|
|||||||
loading: Boolean,
|
loading: Boolean,
|
||||||
readonly: Boolean,
|
readonly: Boolean,
|
||||||
allowHtml: Boolean,
|
allowHtml: Boolean,
|
||||||
itemHeight: makeNumericProp(44),
|
optionHeight: makeNumericProp(44),
|
||||||
showToolbar: truthProp,
|
showToolbar: truthProp,
|
||||||
swipeDuration: makeNumericProp(1000),
|
swipeDuration: makeNumericProp(1000),
|
||||||
visibleItemCount: makeNumericProp(6),
|
visibleOptionNum: makeNumericProp(6),
|
||||||
cancelButtonText: String,
|
cancelButtonText: String,
|
||||||
confirmButtonText: String,
|
confirmButtonText: String,
|
||||||
};
|
};
|
||||||
|
|
||||||
const pickerProps = extend({}, pickerSharedProps, {
|
const pickerProps = extend({}, pickerSharedProps, {
|
||||||
columns: makeArrayProp<PickerOption | PickerColumn>(),
|
columns: makeArrayProp<PickerOption | PickerColumn>(),
|
||||||
defaultIndex: makeNumericProp(0),
|
modelValue: makeArrayProp<number | string>(),
|
||||||
toolbarPosition: makeStringProp<PickerToolbarPosition>('top'),
|
toolbarPosition: makeStringProp<PickerToolbarPosition>('top'),
|
||||||
columnsFieldNames: Object as PropType<PickerFieldNames>,
|
columnsFieldNames: Object as PropType<PickerFieldNames>,
|
||||||
});
|
});
|
||||||
@ -68,213 +75,77 @@ 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 selectedValues = ref(props.modelValue);
|
||||||
const formattedColumns = ref<PickerObjectColumn[]>([]);
|
|
||||||
|
|
||||||
const {
|
|
||||||
text: textKey,
|
|
||||||
values: valuesKey,
|
|
||||||
children: childrenKey,
|
|
||||||
} = extend(
|
|
||||||
{
|
|
||||||
text: 'text',
|
|
||||||
values: 'values',
|
|
||||||
children: 'children',
|
|
||||||
},
|
|
||||||
props.columnsFieldNames
|
|
||||||
);
|
|
||||||
|
|
||||||
const { children, linkChildren } = useChildren(PICKER_KEY);
|
const { children, linkChildren } = useChildren(PICKER_KEY);
|
||||||
|
|
||||||
linkChildren();
|
linkChildren();
|
||||||
|
|
||||||
const itemHeight = computed(() => unitToPx(props.itemHeight));
|
const fields = computed(() => assignDefaultFields(props.columnsFieldNames));
|
||||||
|
const optionHeight = computed(() => unitToPx(props.optionHeight));
|
||||||
|
const columnsType = computed(() =>
|
||||||
|
getColumnsType(props.columns, fields.value)
|
||||||
|
);
|
||||||
|
|
||||||
const dataType = computed(() => {
|
const currentColumns = computed<PickerColumn[]>(() => {
|
||||||
const firstColumn = props.columns[0];
|
const { columns } = props;
|
||||||
if (typeof firstColumn === 'object') {
|
switch (columnsType.value) {
|
||||||
if (childrenKey in firstColumn) {
|
case 'multiple':
|
||||||
return 'cascade';
|
return columns as PickerColumn[];
|
||||||
}
|
case 'cascade':
|
||||||
if (valuesKey in firstColumn) {
|
return formatCascadeColumns(columns, fields.value, selectedValues);
|
||||||
return 'object';
|
default:
|
||||||
}
|
return [columns];
|
||||||
}
|
}
|
||||||
return 'plain';
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const formatCascade = () => {
|
const hasOptions = computed(() =>
|
||||||
const formatted: PickerObjectColumn[] = [];
|
currentColumns.value.some((options) => options.length)
|
||||||
|
);
|
||||||
|
|
||||||
let cursor: PickerObjectColumn = {
|
const selectedOptions = computed(() =>
|
||||||
[childrenKey]: props.columns,
|
currentColumns.value.map((options, index) =>
|
||||||
};
|
findOptionByValue(options, selectedValues.value[index], fields.value)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
while (cursor && cursor[childrenKey]) {
|
const onChange = (value: number | string, columnIndex: number) => {
|
||||||
const children = cursor[childrenKey];
|
selectedValues.value[columnIndex] = value;
|
||||||
let defaultIndex = cursor.defaultIndex ?? +props.defaultIndex;
|
|
||||||
|
|
||||||
while (children[defaultIndex] && children[defaultIndex].disabled) {
|
if (columnsType.value === 'cascade') {
|
||||||
if (defaultIndex < children.length - 1) {
|
// reset values after cascading
|
||||||
defaultIndex++;
|
selectedValues.value.forEach((value, index) => {
|
||||||
} else {
|
const options = currentColumns.value[index];
|
||||||
defaultIndex = 0;
|
if (!options.find((option) => option[fields.value.value] === value)) {
|
||||||
break;
|
selectedValues.value[index] = options.length
|
||||||
|
? options[0][fields.value.value]
|
||||||
|
: undefined;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
formatted.push({
|
|
||||||
[valuesKey]: cursor[childrenKey],
|
|
||||||
className: cursor.className,
|
|
||||||
defaultIndex,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
cursor = children[defaultIndex];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
formattedColumns.value = formatted;
|
emit('change', {
|
||||||
};
|
columnIndex,
|
||||||
|
selectedValues: selectedValues.value,
|
||||||
const format = () => {
|
selectedOptions: selectedOptions.value,
|
||||||
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++;
|
|
||||||
setColumnValues(columnIndex, cursor[childrenKey]);
|
|
||||||
cursor = cursor[childrenKey][cursor.defaultIndex || 0];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// get column instance by index
|
|
||||||
const getChild = (index: number) => children[index];
|
|
||||||
|
|
||||||
// get column value by index
|
|
||||||
const getColumnValue = (index: number) => {
|
|
||||||
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') {
|
|
||||||
onCascadeChange(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// get column option index by column index
|
|
||||||
const getColumnIndex = (index: number) => {
|
|
||||||
const column = getChild(index);
|
|
||||||
if (column) {
|
|
||||||
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,27 +195,26 @@ 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 }}
|
||||||
textKey={textKey}
|
value={selectedValues.value[columnIndex]}
|
||||||
|
fields={fields.value}
|
||||||
|
options={options}
|
||||||
readonly={props.readonly}
|
readonly={props.readonly}
|
||||||
allowHtml={props.allowHtml}
|
allowHtml={props.allowHtml}
|
||||||
className={item.className}
|
optionHeight={optionHeight.value}
|
||||||
itemHeight={itemHeight.value}
|
|
||||||
defaultIndex={item.defaultIndex ?? +props.defaultIndex}
|
|
||||||
swipeDuration={props.swipeDuration}
|
swipeDuration={props.swipeDuration}
|
||||||
initialOptions={item[valuesKey]}
|
visibleOptionNum={props.visibleOptionNum}
|
||||||
visibleItemCount={props.visibleItemCount}
|
onChange={(value: number | string) => onChange(value, columnIndex)}
|
||||||
onChange={() => onChange(columnIndex)}
|
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
|
|
||||||
const renderMask = (wrapHeight: number) => {
|
const renderMask = (wrapHeight: number) => {
|
||||||
if (hasOptions.value) {
|
if (hasOptions.value) {
|
||||||
const frameStyle = { height: `${itemHeight.value}px` };
|
const frameStyle = { height: `${optionHeight.value}px` };
|
||||||
const maskStyle = {
|
const maskStyle = {
|
||||||
backgroundSize: `100% ${(wrapHeight - itemHeight.value) / 2}px`,
|
backgroundSize: `100% ${(wrapHeight - optionHeight.value) / 2}px`,
|
||||||
};
|
};
|
||||||
return [
|
return [
|
||||||
<div class={bem('mask')} style={maskStyle} />,
|
<div class={bem('mask')} style={maskStyle} />,
|
||||||
@ -357,7 +227,7 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const renderColumns = () => {
|
const renderColumns = () => {
|
||||||
const wrapHeight = itemHeight.value * +props.visibleItemCount;
|
const wrapHeight = optionHeight.value * +props.visibleOptionNum;
|
||||||
const columnsStyle = { height: `${wrapHeight}px` };
|
const columnsStyle = { height: `${wrapHeight}px` };
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -371,21 +241,39 @@ export default defineComponent({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(() => props.columns, format, { immediate: true });
|
watch(
|
||||||
|
currentColumns,
|
||||||
|
(columns) => {
|
||||||
|
columns.forEach((options, index) => {
|
||||||
|
if (selectedValues.value[index] === undefined && options.length) {
|
||||||
|
selectedValues.value[index] =
|
||||||
|
getFirstEnabledOption(options)[fields.value.value];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
useExpose<PickerExpose>({
|
watch(
|
||||||
confirm,
|
() => props.modelValue,
|
||||||
getValues,
|
(newValues) => {
|
||||||
setValues,
|
if (!isValuesEqual(newValues, selectedValues.value)) {
|
||||||
getIndexes,
|
selectedValues.value = newValues;
|
||||||
setIndexes,
|
}
|
||||||
getColumnIndex,
|
},
|
||||||
setColumnIndex,
|
{ deep: true }
|
||||||
getColumnValue,
|
);
|
||||||
setColumnValue,
|
watch(
|
||||||
getColumnValues,
|
selectedValues,
|
||||||
setColumnValues,
|
(newValues) => {
|
||||||
});
|
if (!isValuesEqual(newValues, props.modelValue)) {
|
||||||
|
emit('update:modelValue', selectedValues.value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
useExpose<PickerExpose>({ confirm });
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<div class={bem()}>
|
<div class={bem()}>
|
||||||
|
@ -1,18 +1,21 @@
|
|||||||
import { ref, watch, reactive, defineComponent, type InjectionKey } from 'vue';
|
import {
|
||||||
|
ref,
|
||||||
|
watchEffect,
|
||||||
|
defineComponent,
|
||||||
|
type PropType,
|
||||||
|
type InjectionKey,
|
||||||
|
} 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,
|
||||||
} from '../utils';
|
} from '../utils';
|
||||||
|
import { getElementTranslateY, findIndexOfEnabledOption } from './utils';
|
||||||
|
|
||||||
// Composables
|
// Composables
|
||||||
import { useParent } from '@vant/use';
|
import { useParent } from '@vant/use';
|
||||||
@ -20,42 +23,36 @@ import { useTouch } from '../composables/use-touch';
|
|||||||
import { useExpose } from '../composables/use-expose';
|
import { useExpose } from '../composables/use-expose';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { PickerOption, PickerColumnProvide } from './types';
|
import type {
|
||||||
|
PickerOption,
|
||||||
|
PickerFieldNames,
|
||||||
|
PickerColumnProvide,
|
||||||
|
} from './types';
|
||||||
|
|
||||||
const DEFAULT_DURATION = 200;
|
const DEFAULT_DURATION = 200;
|
||||||
|
|
||||||
// 惯性滑动思路:
|
// 惯性滑动思路:
|
||||||
// 在手指离开屏幕时,如果和上一次 move 时的间隔小于 `MOMENTUM_LIMIT_TIME` 且 move
|
// 在手指离开屏幕时,如果和上一次 move 时的间隔小于 `MOMENTUM_TIME` 且 move
|
||||||
// 距离大于 `MOMENTUM_LIMIT_DISTANCE` 时,执行惯性滑动
|
// 距离大于 `MOMENTUM_DISTANCE` 时,执行惯性滑动
|
||||||
const MOMENTUM_LIMIT_TIME = 300;
|
const MOMENTUM_TIME = 300;
|
||||||
const MOMENTUM_LIMIT_DISTANCE = 15;
|
const MOMENTUM_DISTANCE = 15;
|
||||||
|
|
||||||
const [name, bem] = createNamespace('picker-column');
|
const [name, bem] = createNamespace('picker-column');
|
||||||
|
|
||||||
function getElementTranslateY(element: Element) {
|
|
||||||
const { transform } = window.getComputedStyle(element);
|
|
||||||
const translateY = transform.slice(7, transform.length - 1).split(', ')[5];
|
|
||||||
return Number(translateY);
|
|
||||||
}
|
|
||||||
|
|
||||||
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: {
|
||||||
textKey: makeRequiredProp(String),
|
value: numericProp,
|
||||||
|
fields: makeRequiredProp(Object as PropType<Required<PickerFieldNames>>),
|
||||||
|
options: makeArrayProp<PickerOption>(),
|
||||||
readonly: Boolean,
|
readonly: Boolean,
|
||||||
allowHtml: Boolean,
|
allowHtml: Boolean,
|
||||||
className: unknownProp,
|
optionHeight: makeRequiredProp(Number),
|
||||||
itemHeight: makeRequiredProp(Number),
|
|
||||||
defaultIndex: makeNumberProp(0),
|
|
||||||
swipeDuration: makeRequiredProp(numericProp),
|
swipeDuration: makeRequiredProp(numericProp),
|
||||||
initialOptions: makeArrayProp<PickerOption>(),
|
visibleOptionNum: makeRequiredProp(numericProp),
|
||||||
visibleItemCount: makeRequiredProp(numericProp),
|
|
||||||
},
|
},
|
||||||
|
|
||||||
emits: ['change'],
|
emits: ['change'],
|
||||||
@ -68,61 +65,34 @@ export default defineComponent({
|
|||||||
let transitionEndTrigger: null | (() => void);
|
let transitionEndTrigger: null | (() => void);
|
||||||
|
|
||||||
const wrapper = ref<HTMLElement>();
|
const wrapper = ref<HTMLElement>();
|
||||||
|
const currentOffset = ref(0);
|
||||||
const state = reactive({
|
const currentDuration = ref(0);
|
||||||
index: props.defaultIndex,
|
|
||||||
offset: 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.optionHeight * (+props.visibleOptionNum - 1)) / 2;
|
||||||
|
|
||||||
const adjustIndex = (index: number) => {
|
const updateValueByIndex = (index: number) => {
|
||||||
index = clamp(index, 0, count());
|
const enabledIndex = findIndexOfEnabledOption(props.options, index);
|
||||||
|
const offset = -enabledIndex * props.optionHeight;
|
||||||
|
|
||||||
for (let i = index; i < count(); i++) {
|
|
||||||
if (!isOptionDisabled(state.options[i])) return i;
|
|
||||||
}
|
|
||||||
for (let i = index - 1; i >= 0; i--) {
|
|
||||||
if (!isOptionDisabled(state.options[i])) return i;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const setIndex = (index: number, emitChange?: boolean) => {
|
|
||||||
index = adjustIndex(index) || 0;
|
|
||||||
|
|
||||||
const offset = -index * props.itemHeight;
|
|
||||||
const trigger = () => {
|
const trigger = () => {
|
||||||
if (index !== state.index) {
|
const value = props.options[enabledIndex][props.fields.value];
|
||||||
state.index = index;
|
if (value !== props.value) {
|
||||||
|
emit('change', value);
|
||||||
if (emitChange) {
|
|
||||||
emit('change', index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// trigger the change event after transitionend when moving
|
// trigger the change event after transitionend when moving
|
||||||
if (moving && offset !== state.offset) {
|
if (moving && offset !== currentOffset.value) {
|
||||||
transitionEndTrigger = trigger;
|
transitionEndTrigger = trigger;
|
||||||
} else {
|
} else {
|
||||||
trigger();
|
trigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
state.offset = offset;
|
currentOffset.value = 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) => {
|
||||||
@ -131,34 +101,28 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
transitionEndTrigger = null;
|
transitionEndTrigger = null;
|
||||||
state.duration = DEFAULT_DURATION;
|
currentDuration.value = 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) =>
|
||||||
clamp(Math.round(-offset / props.itemHeight), 0, count() - 1);
|
clamp(Math.round(-offset / props.optionHeight), 0, count() - 1);
|
||||||
|
|
||||||
const momentum = (distance: number, duration: number) => {
|
const momentum = (distance: number, duration: number) => {
|
||||||
const speed = Math.abs(distance / duration);
|
const speed = Math.abs(distance / duration);
|
||||||
|
|
||||||
distance = state.offset + (speed / 0.003) * (distance < 0 ? -1 : 1);
|
distance =
|
||||||
|
currentOffset.value + (speed / 0.003) * (distance < 0 ? -1 : 1);
|
||||||
|
|
||||||
const index = getIndexByOffset(distance);
|
const index = getIndexByOffset(distance);
|
||||||
|
|
||||||
state.duration = +props.swipeDuration;
|
currentDuration.value = +props.swipeDuration;
|
||||||
setIndex(index, true);
|
updateValueByIndex(index);
|
||||||
};
|
};
|
||||||
|
|
||||||
const stopMomentum = () => {
|
const stopMomentum = () => {
|
||||||
moving = false;
|
moving = false;
|
||||||
state.duration = 0;
|
currentDuration.value = 0;
|
||||||
|
|
||||||
if (transitionEndTrigger) {
|
if (transitionEndTrigger) {
|
||||||
transitionEndTrigger();
|
transitionEndTrigger();
|
||||||
@ -175,13 +139,11 @@ export default defineComponent({
|
|||||||
|
|
||||||
if (moving) {
|
if (moving) {
|
||||||
const translateY = getElementTranslateY(wrapper.value!);
|
const translateY = getElementTranslateY(wrapper.value!);
|
||||||
state.offset = Math.min(0, translateY - baseOffset());
|
currentOffset.value = Math.min(0, translateY - baseOffset());
|
||||||
startOffset = state.offset;
|
|
||||||
} else {
|
|
||||||
startOffset = state.offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state.duration = 0;
|
currentDuration.value = 0;
|
||||||
|
startOffset = currentOffset.value;
|
||||||
touchStartTime = Date.now();
|
touchStartTime = Date.now();
|
||||||
momentumOffset = startOffset;
|
momentumOffset = startOffset;
|
||||||
transitionEndTrigger = null;
|
transitionEndTrigger = null;
|
||||||
@ -199,16 +161,16 @@ export default defineComponent({
|
|||||||
preventDefault(event, true);
|
preventDefault(event, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.offset = clamp(
|
currentOffset.value = clamp(
|
||||||
startOffset + touch.deltaY.value,
|
startOffset + touch.deltaY.value,
|
||||||
-(count() * props.itemHeight),
|
-(count() * props.optionHeight),
|
||||||
props.itemHeight
|
props.optionHeight
|
||||||
);
|
);
|
||||||
|
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
if (now - touchStartTime > MOMENTUM_LIMIT_TIME) {
|
if (now - touchStartTime > MOMENTUM_TIME) {
|
||||||
touchStartTime = now;
|
touchStartTime = now;
|
||||||
momentumOffset = state.offset;
|
momentumOffset = currentOffset.value;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -217,23 +179,22 @@ export default defineComponent({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const distance = state.offset - momentumOffset;
|
const distance = currentOffset.value - momentumOffset;
|
||||||
const duration = Date.now() - touchStartTime;
|
const duration = Date.now() - touchStartTime;
|
||||||
const allowMomentum =
|
const startMomentum =
|
||||||
duration < MOMENTUM_LIMIT_TIME &&
|
duration < MOMENTUM_TIME && Math.abs(distance) > MOMENTUM_DISTANCE;
|
||||||
Math.abs(distance) > MOMENTUM_LIMIT_DISTANCE;
|
|
||||||
|
|
||||||
if (allowMomentum) {
|
if (startMomentum) {
|
||||||
momentum(distance, duration);
|
momentum(distance, duration);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const index = getIndexByOffset(state.offset);
|
const index = getIndexByOffset(currentOffset.value);
|
||||||
state.duration = DEFAULT_DURATION;
|
currentDuration.value = 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);
|
||||||
@ -241,21 +202,24 @@ export default defineComponent({
|
|||||||
|
|
||||||
const renderOptions = () => {
|
const renderOptions = () => {
|
||||||
const optionStyle = {
|
const optionStyle = {
|
||||||
height: `${props.itemHeight}px`,
|
height: `${props.optionHeight}px`,
|
||||||
};
|
};
|
||||||
|
|
||||||
return state.options.map((option, index: number) => {
|
return props.options.map((option, index) => {
|
||||||
const text = getOptionText(option);
|
const text = option[props.fields.text];
|
||||||
const disabled = isOptionDisabled(option);
|
const { disabled } = option;
|
||||||
|
const value: string | number = option[props.fields.value];
|
||||||
const data = {
|
const data = {
|
||||||
role: 'button',
|
role: 'button',
|
||||||
style: optionStyle,
|
style: optionStyle,
|
||||||
tabindex: disabled ? -1 : 0,
|
tabindex: disabled ? -1 : 0,
|
||||||
class: bem('item', {
|
class: [
|
||||||
disabled,
|
bem('item', {
|
||||||
selected: index === state.index,
|
disabled,
|
||||||
}),
|
selected: value === props.value,
|
||||||
|
}),
|
||||||
|
option.className,
|
||||||
|
],
|
||||||
onClick: () => onClickItem(index),
|
onClick: () => onClickItem(index),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -272,39 +236,21 @@ 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,
|
watchEffect(() => {
|
||||||
getValue,
|
const index = props.options.findIndex(
|
||||||
setValue,
|
(option) => option[props.fields.value] === props.value
|
||||||
setOptions,
|
);
|
||||||
stopMomentum,
|
const enabledIndex = findIndexOfEnabledOption(props.options, index);
|
||||||
|
const offset = -enabledIndex * props.optionHeight;
|
||||||
|
currentOffset.value = offset;
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(() => props.initialOptions, setOptions);
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.defaultIndex,
|
|
||||||
(value) => setIndex(value)
|
|
||||||
);
|
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<div
|
<div
|
||||||
class={[bem(), props.className]}
|
class={bem()}
|
||||||
onTouchstart={onTouchStart}
|
onTouchstart={onTouchStart}
|
||||||
onTouchmove={onTouchMove}
|
onTouchmove={onTouchMove}
|
||||||
onTouchend={onTouchEnd}
|
onTouchend={onTouchEnd}
|
||||||
@ -313,9 +259,11 @@ export default defineComponent({
|
|||||||
<ul
|
<ul
|
||||||
ref={wrapper}
|
ref={wrapper}
|
||||||
style={{
|
style={{
|
||||||
transform: `translate3d(0, ${state.offset + baseOffset()}px, 0)`,
|
transform: `translate3d(0, ${
|
||||||
transitionDuration: `${state.duration}ms`,
|
currentOffset.value + baseOffset()
|
||||||
transitionProperty: state.duration ? 'all' : 'none',
|
}px, 0)`,
|
||||||
|
transitionDuration: `${currentDuration.value}ms`,
|
||||||
|
transitionProperty: currentDuration.value ? 'all' : 'none',
|
||||||
}}
|
}}
|
||||||
class={bem('wrapper')}
|
class={bem('wrapper')}
|
||||||
onTransitionend={stopMomentum}
|
onTransitionend={stopMomentum}
|
||||||
|
@ -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 = ({ selectedValues }) => {
|
||||||
|
Toast(`Value: ${selectedValues.join(',')}`);
|
||||||
};
|
};
|
||||||
const onChange = (value, index) => {
|
const onChange = ({ selectedValues }) => {
|
||||||
Toast(`Value: ${value}, Index: ${index}`);
|
Toast(`Value: ${selectedValues.join(',')}`);
|
||||||
};
|
};
|
||||||
const onCancel = () => Toast('Cancel');
|
const onCancel = () => Toast('Cancel');
|
||||||
|
|
||||||
@ -55,161 +60,6 @@ export default {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### Default Index
|
|
||||||
|
|
||||||
```html
|
|
||||||
<van-picker title="Title" :columns="columns" :default-index="2" />
|
|
||||||
```
|
|
||||||
|
|
||||||
### Multiple Columns
|
|
||||||
|
|
||||||
```html
|
|
||||||
<van-picker title="Title" :columns="columns" />
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
export default {
|
|
||||||
setup() {
|
|
||||||
const columns = [
|
|
||||||
{
|
|
||||||
values: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
|
|
||||||
defaultIndex: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
values: ['Morning', 'Afternoon', 'Evening'],
|
|
||||||
defaultIndex: 1,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return { columns };
|
|
||||||
},
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Cascade
|
|
||||||
|
|
||||||
```html
|
|
||||||
<van-picker title="Title" :columns="columns" />
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
export default {
|
|
||||||
setup() {
|
|
||||||
const columns = [
|
|
||||||
{
|
|
||||||
text: 'Zhejiang',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
text: 'Hangzhou',
|
|
||||||
children: [{ text: 'Xihu' }, { text: 'Yuhang' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: 'Wenzhou',
|
|
||||||
children: [{ text: 'Lucheng' }, { text: 'Ouhai' }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: 'Fujian',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
text: 'Fuzhou',
|
|
||||||
children: [{ text: 'Gulou' }, { text: 'Taijiang' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: 'Xiamen',
|
|
||||||
children: [{ text: 'Siming' }, { text: 'Haicang' }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return { columns };
|
|
||||||
},
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Disable option
|
|
||||||
|
|
||||||
```html
|
|
||||||
<van-picker :columns="columns" />
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
export default {
|
|
||||||
setup() {
|
|
||||||
const columns = [
|
|
||||||
{ text: 'Delaware', disabled: true },
|
|
||||||
{ text: 'Florida' },
|
|
||||||
{ text: 'Georqia' },
|
|
||||||
];
|
|
||||||
|
|
||||||
return { columns };
|
|
||||||
},
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Set Column Values
|
|
||||||
|
|
||||||
```html
|
|
||||||
<van-picker ref="picker" title="Title" :columns="columns" @change="onChange" />
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
import { ref } from 'vue';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
setup() {
|
|
||||||
const picker = ref(null);
|
|
||||||
|
|
||||||
const states = {
|
|
||||||
Group1: ['Delaware', 'Florida', 'Georqia', 'Indiana', 'Maine'],
|
|
||||||
Group2: ['Alabama', 'Kansas', 'Louisiana', 'Texas'],
|
|
||||||
};
|
|
||||||
const columns = [
|
|
||||||
{ values: Object.keys(states) },
|
|
||||||
{ values: states.Group1 },
|
|
||||||
];
|
|
||||||
|
|
||||||
const onChange = (values) => {
|
|
||||||
picker.value.setColumnValues(1, states[values[0]]);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
picker,
|
|
||||||
columns,
|
|
||||||
onChange,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Loading
|
|
||||||
|
|
||||||
When Picker columns data is acquired asynchronously, use `loading` prop to show loading prompt.
|
|
||||||
|
|
||||||
```html
|
|
||||||
<van-picker title="Title" :columns="columns" :loading="loading" />
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
import { ref } from 'vue';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
setup() {
|
|
||||||
const columns = ref([]);
|
|
||||||
const loading = ref(true);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
columns.value = ['Option'];
|
|
||||||
loading.value = false;
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
return { columns, loading };
|
|
||||||
},
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### With Popup
|
### With Popup
|
||||||
|
|
||||||
```html
|
```html
|
||||||
@ -236,13 +86,19 @@ import { ref } from 'vue';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
setup() {
|
setup() {
|
||||||
const columns = ['Delaware', 'Florida', 'Georqia', 'Indiana', 'Maine'];
|
const columns = [
|
||||||
|
{ text: 'Delaware', value: 'Delaware' },
|
||||||
|
{ text: 'Florida', value: 'Florida' },
|
||||||
|
{ text: 'Georqia', value: 'Georqia' },
|
||||||
|
{ text: 'Indiana', value: 'Indiana' },
|
||||||
|
{ text: 'Maine', value: 'Maine' },
|
||||||
|
];
|
||||||
const result = ref('');
|
const result = ref('');
|
||||||
const showPicker = ref(false);
|
const showPicker = ref(false);
|
||||||
|
|
||||||
const onConfirm = (value) => {
|
const onConfirm = ({ selectedOptions }) => {
|
||||||
result.value = value;
|
|
||||||
showPicker.value = false;
|
showPicker.value = false;
|
||||||
|
fieldValue.value = selectedOptions[0].text;
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -255,6 +111,141 @@ export default {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Multiple Columns
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-picker title="Title" :columns="columns" />
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const columns = [
|
||||||
|
[
|
||||||
|
{ 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' },
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
return { columns };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cascade
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-picker title="Title" :columns="columns" />
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
text: 'Zhejiang',
|
||||||
|
value: 'Zhejiang',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: 'Hangzhou',
|
||||||
|
value: 'Hangzhou',
|
||||||
|
children: [
|
||||||
|
{ text: 'Xihu', value: 'Xihu' },
|
||||||
|
{ text: 'Yuhang', value: 'Yuhang' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Wenzhou',
|
||||||
|
value: 'Wenzhou',
|
||||||
|
children: [
|
||||||
|
{ text: 'Lucheng', value: 'Lucheng' },
|
||||||
|
{ text: 'Ouhai', value: 'Ouhai' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Fujian',
|
||||||
|
value: 'Fujian',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: 'Fuzhou',
|
||||||
|
value: 'Fuzhou',
|
||||||
|
children: [
|
||||||
|
{ text: 'Gulou', value: 'Gulou' },
|
||||||
|
{ text: 'Taijiang', value: 'Taijiang' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Xiamen',
|
||||||
|
value: 'Xiamen',
|
||||||
|
children: [
|
||||||
|
{ text: 'Siming', value: 'Siming' },
|
||||||
|
{ text: 'Haicang', value: 'Haicang' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return { columns };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Disable option
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-picker :columns="columns" />
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const columns = [
|
||||||
|
{ text: 'Delaware', value: 'Delaware', disabled: true },
|
||||||
|
{ text: 'Florida', value: 'Florida' },
|
||||||
|
{ text: 'Georqia', value: 'Georqia' },
|
||||||
|
];
|
||||||
|
return { columns };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Loading
|
||||||
|
|
||||||
|
When Picker columns data is acquired asynchronously, use `loading` prop to show loading prompt.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-picker title="Title" :columns="columns" :loading="loading" />
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const columns = ref([]);
|
||||||
|
const loading = ref(true);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
columns.value = [{ text: 'Option', value: 'option' }];
|
||||||
|
loading.value = false;
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
return { columns, loading };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
### Custom Columns Field
|
### Custom Columns Field
|
||||||
|
|
||||||
```html
|
```html
|
||||||
@ -299,6 +290,7 @@ export default {
|
|||||||
|
|
||||||
const customFieldName = {
|
const customFieldName = {
|
||||||
text: 'cityName',
|
text: 'cityName',
|
||||||
|
value: 'cityName',
|
||||||
children: 'cities',
|
children: 'cities',
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -316,8 +308,8 @@ export default {
|
|||||||
|
|
||||||
| Attribute | Description | Type | Default |
|
| Attribute | Description | Type | Default |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| columns | Columns data | _Column[]_ | `[]` |
|
| columns | Columns data | _PickerOption[] \| PickerOption[][]_ | `[]` |
|
||||||
| columns-field-names | custom columns field | _object_ | `{ text: 'text', values: 'values', children: 'children' }` |
|
| columns-field-names | custom columns field | _object_ | `{ text: 'text', value: 'value', children: 'children' }` |
|
||||||
| title | Toolbar title | _string_ | - |
|
| title | Toolbar title | _string_ | - |
|
||||||
| confirm-button-text | Text of confirm button | _string_ | `Confirm` |
|
| confirm-button-text | Text of confirm button | _string_ | `Confirm` |
|
||||||
| cancel-button-text | Text of cancel button | _string_ | `Cancel` |
|
| cancel-button-text | Text of cancel button | _string_ | `Cancel` |
|
||||||
@ -325,59 +317,47 @@ export default {
|
|||||||
| loading | Whether to show loading prompt | _boolean_ | `false` |
|
| loading | Whether to show loading prompt | _boolean_ | `false` |
|
||||||
| show-toolbar | Whether to show toolbar | _boolean_ | `true` |
|
| show-toolbar | Whether to show toolbar | _boolean_ | `true` |
|
||||||
| allow-html | Whether to allow HTML in option text | _boolean_ | `false` |
|
| allow-html | Whether to allow HTML in option text | _boolean_ | `false` |
|
||||||
| default-index | Default value index of single column picker | _number \| string_ | `0` |
|
| option-height | Option height, supports `px` `vw` `vh` `rem` unit, default `px` | _number \| string_ | `44` |
|
||||||
| item-height | Option height, supports `px` `vw` `vh` `rem` unit, default `px` | _number \| string_ | `44` |
|
| visible-option-num | Count of visible columns | _number \| string_ | `6` |
|
||||||
| visible-item-count | Count of visible columns | _number \| string_ | `6` |
|
|
||||||
| swipe-duration | Duration of the momentum animation,unit `ms` | _number \| string_ | `1000` |
|
| swipe-duration | Duration of the momentum animation,unit `ms` | _number \| string_ | `1000` |
|
||||||
|
|
||||||
### Events
|
### Events
|
||||||
|
|
||||||
Picker events will pass different parameters according to the columns are single or multiple
|
|
||||||
|
|
||||||
| Event | Description | Arguments |
|
| Event | Description | Arguments |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| confirm | Emitted when click confirm button | Single column:current value,current index<br>Multiple columns:current values,current indexes |
|
| confirm | Emitted when the confirm button is clicked | _{ selectedValues, selectedOptions }_ |
|
||||||
| cancel | Emitted when click cancel button | Single column:current value,current index<br>Multiple columns:current values,current indexes |
|
| cancel | Emitted when the cancel button is clicked | _{ selectedValues, selectedOptions }_ |
|
||||||
| change | Emitted when current option changed | Single column:Picker instance, current value,current index<br>Multiple columns:Picker instance, current values,column index |
|
| change | Emitted when current option is changed | _{ selectedValues, selectedOptions, columnIndex }_ |
|
||||||
|
|
||||||
### Slots
|
### Slots
|
||||||
|
|
||||||
| Name | Description | SlotProps |
|
| Name | Description | SlotProps |
|
||||||
| --------------- | ---------------------------- | -------------------------- |
|
| --------------- | ---------------------------- | ---------------------- |
|
||||||
| toolbar `3.1.2` | Custom toolbar content | - |
|
| toolbar `3.1.2` | Custom toolbar content | - |
|
||||||
| title | Custom title | - |
|
| title | Custom title | - |
|
||||||
| confirm | Custom confirm button text | - |
|
| confirm | Custom confirm button text | - |
|
||||||
| cancel | Custom cancel button text | - |
|
| cancel | Custom cancel button text | - |
|
||||||
| option | Custom option content | _option: string \| object_ |
|
| option | Custom option content | _option: PickerOption_ |
|
||||||
| columns-top | Custom content above columns | - |
|
| columns-top | Custom content above columns | - |
|
||||||
| columns-bottom | Custom content below columns | - |
|
| columns-bottom | Custom content below columns | - |
|
||||||
|
|
||||||
### Data Structure of Column
|
### Data Structure of PickerOption
|
||||||
|
|
||||||
| Key | Description | Type |
|
| Key | Description | Type |
|
||||||
| ------------ | ------------------------- | --------------------------- |
|
| --------- | ------------------------- | --------------------------- |
|
||||||
| values | Value of column | _Array<string \| number>_ |
|
| text | Text | _string \| number_ |
|
||||||
| defaultIndex | Default value index | _number_ |
|
| value | Value of option | _string \| number_ |
|
||||||
| className | ClassName for this column | _string \| Array \| object_ |
|
| disabled | Whether to disable option | _boolean_ |
|
||||||
| children | Cascade children | _Column_ |
|
| children | Cascade children options | _PickerOption[]_ |
|
||||||
|
| className | ClassName for this option | _string \| Array \| object_ |
|
||||||
|
|
||||||
### Methods
|
### Methods
|
||||||
|
|
||||||
Use [ref](https://v3.vuejs.org/guide/component-template-refs.html) to get Picker instance and call instance methods.
|
Use [ref](https://v3.vuejs.org/guide/component-template-refs.html) to get Picker instance and call instance methods.
|
||||||
|
|
||||||
| Name | Description | Attribute | Return value |
|
| Name | Description | Attribute | Return value |
|
||||||
| --- | --- | --- | --- |
|
| ------- | ------------------------------------- | --------- | ------------ |
|
||||||
| getValues | Get current values of all columns | - | values |
|
| confirm | Stop scrolling and emit confirm event | - | - |
|
||||||
| setValues | Set current values of all columns | values | - |
|
|
||||||
| getIndexes | Get current indexes of all columns | - | indexes |
|
|
||||||
| setIndexes | Set current indexes of all columns | indexes | - |
|
|
||||||
| getColumnValue | Get current value of the column | columnIndex | value |
|
|
||||||
| setColumnValue | Set current value of the column | columnIndex, value | - |
|
|
||||||
| getColumnIndex | Get current index of the column | columnIndex | optionIndex |
|
|
||||||
| setColumnIndex | Set current index of the column | columnIndex, optionIndex | - |
|
|
||||||
| getColumnValues | Get columns data of the column | columnIndex | values |
|
|
||||||
| setColumnValues | Set columns data of the column | columnIndex, values | - |
|
|
||||||
| confirm | Stop scrolling and emit confirm event | - | - |
|
|
||||||
|
|
||||||
### Types
|
### Types
|
||||||
|
|
||||||
@ -390,9 +370,10 @@ import type {
|
|||||||
PickerOption,
|
PickerOption,
|
||||||
PickerInstance,
|
PickerInstance,
|
||||||
PickerFieldNames,
|
PickerFieldNames,
|
||||||
PickerObjectColumn,
|
|
||||||
PickerObjectOption,
|
|
||||||
PickerToolbarPosition,
|
PickerToolbarPosition,
|
||||||
|
PickerCancelEventParams,
|
||||||
|
PickerChangeEventParams,
|
||||||
|
PickerConfirmEventParams,
|
||||||
} from 'vant';
|
} from 'vant';
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
### 介绍
|
### 介绍
|
||||||
|
|
||||||
提供多个选项集合供用户选择,支持单列选择和多列级联,通常与[弹出层](#/zh-CN/popup)组件配合使用。
|
提供多个选项集合供用户选择,支持单列选择、多列选择和级联选择,通常与[弹出层](#/zh-CN/popup)组件配合使用。
|
||||||
|
|
||||||
### 引入
|
### 引入
|
||||||
|
|
||||||
@ -43,13 +43,18 @@ 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' },
|
||||||
|
];
|
||||||
|
const onConfirm = ({ selectedValues }) => {
|
||||||
|
Toast(`当前值: ${selectedValues.join(',')}`);
|
||||||
};
|
};
|
||||||
const onChange = (value, index) => {
|
const onChange = ({ selectedValues }) => {
|
||||||
Toast(`当前值: ${value}, 当前索引: ${index}`);
|
Toast(`当前值: ${selectedValues.join(',')}`);
|
||||||
};
|
};
|
||||||
const onCancel = () => Toast('取消');
|
const onCancel = () => Toast('取消');
|
||||||
|
|
||||||
@ -63,175 +68,6 @@ export default {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### 默认选中项
|
|
||||||
|
|
||||||
单列选择时,可以通过 `default-index` 属性设置初始选中项的索引。
|
|
||||||
|
|
||||||
```html
|
|
||||||
<van-picker title="标题" :columns="columns" :default-index="2" />
|
|
||||||
```
|
|
||||||
|
|
||||||
### 多列选择
|
|
||||||
|
|
||||||
`columns` 属性可以通过对象数组的形式配置多列选择,对象中可以配置选项数据、初始选中项等,详细格式见[下方表格](#/zh-CN/picker#column-shu-ju-jie-gou)。
|
|
||||||
|
|
||||||
```html
|
|
||||||
<van-picker title="标题" :columns="columns" />
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
export default {
|
|
||||||
setup() {
|
|
||||||
const columns = [
|
|
||||||
// 第一列
|
|
||||||
{
|
|
||||||
values: ['周一', '周二', '周三', '周四', '周五'],
|
|
||||||
defaultIndex: 2,
|
|
||||||
},
|
|
||||||
// 第二列
|
|
||||||
{
|
|
||||||
values: ['上午', '下午', '晚上'],
|
|
||||||
defaultIndex: 1,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return { columns };
|
|
||||||
},
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### 级联选择
|
|
||||||
|
|
||||||
使用 `columns` 的 `children` 字段可以实现选项级联的效果。如果级联层级较多,推荐使用 [Cascader 级联选项组件](#/zh-CN/cascader)。
|
|
||||||
|
|
||||||
```html
|
|
||||||
<van-picker title="标题" :columns="columns" />
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
export default {
|
|
||||||
setup() {
|
|
||||||
const columns = [
|
|
||||||
{
|
|
||||||
text: '浙江',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
text: '杭州',
|
|
||||||
children: [{ text: '西湖区' }, { text: '余杭区' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: '温州',
|
|
||||||
children: [{ text: '鹿城区' }, { text: '瓯海区' }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: '福建',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
text: '福州',
|
|
||||||
children: [{ text: '鼓楼区' }, { text: '台江区' }],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: '厦门',
|
|
||||||
children: [{ text: '思明区' }, { text: '海沧区' }],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return { columns };
|
|
||||||
},
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
> 级联选择的数据嵌套深度需要保持一致,如果部分选项没有子选项,可以使用空字符串进行占位。
|
|
||||||
|
|
||||||
### 禁用选项
|
|
||||||
|
|
||||||
选项可以为对象结构,通过设置 `disabled` 来禁用该选项。
|
|
||||||
|
|
||||||
```html
|
|
||||||
<van-picker :columns="columns" />
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
export default {
|
|
||||||
setup() {
|
|
||||||
const columns = [
|
|
||||||
{ text: '杭州', disabled: true },
|
|
||||||
{ text: '宁波' },
|
|
||||||
{ text: '温州' },
|
|
||||||
];
|
|
||||||
|
|
||||||
return { columns };
|
|
||||||
},
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### 动态设置选项
|
|
||||||
|
|
||||||
通过 Picker 上的实例方法可以更灵活地控制选择器,比如使用 `setColumnValues` 方法实现多列联动。
|
|
||||||
|
|
||||||
```html
|
|
||||||
<van-picker ref="picker" :columns="columns" @change="onChange" />
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
import { ref } from 'vue';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
setup() {
|
|
||||||
const picker = ref(null);
|
|
||||||
|
|
||||||
const cities = {
|
|
||||||
浙江: ['杭州', '宁波', '温州', '嘉兴', '湖州'],
|
|
||||||
福建: ['福州', '厦门', '莆田', '三明', '泉州'],
|
|
||||||
};
|
|
||||||
const columns = [
|
|
||||||
{ values: Object.keys(cities) },
|
|
||||||
{ values: cities['浙江'] },
|
|
||||||
];
|
|
||||||
|
|
||||||
const onChange = (values) => {
|
|
||||||
picker.value.setColumnValues(1, cities[values[0]]);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
picker,
|
|
||||||
columns,
|
|
||||||
onChange,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### 加载状态
|
|
||||||
|
|
||||||
若选择器数据是异步获取的,可以通过 `loading` 属性显示加载提示。
|
|
||||||
|
|
||||||
```html
|
|
||||||
<van-picker :columns="columns" :loading="loading" />
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
import { ref } from 'vue';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
setup() {
|
|
||||||
const columns = ref([]);
|
|
||||||
const loading = ref(true);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
columns.value = ['选项'];
|
|
||||||
loading.value = false;
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
return { columns, loading };
|
|
||||||
},
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### 搭配弹出层使用
|
### 搭配弹出层使用
|
||||||
|
|
||||||
在实际场景中,Picker 通常作为用于辅助表单填写,可以搭配 Popup 和 Field 实现该效果。
|
在实际场景中,Picker 通常作为用于辅助表单填写,可以搭配 Popup 和 Field 实现该效果。
|
||||||
@ -259,13 +95,19 @@ import { ref } from 'vue';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
setup() {
|
setup() {
|
||||||
const columns = ['杭州', '宁波', '温州', '绍兴', '湖州', '嘉兴', '金华'];
|
const columns = [
|
||||||
|
{ text: '杭州', value: 'Hangzhou' },
|
||||||
|
{ text: '宁波', value: 'Ningbo' },
|
||||||
|
{ text: '温州', value: 'Wenzhou' },
|
||||||
|
{ text: '绍兴', value: 'Shaoxing' },
|
||||||
|
{ text: '湖州', value: 'Huzhou' },
|
||||||
|
];
|
||||||
const result = ref('');
|
const result = ref('');
|
||||||
const showPicker = ref(false);
|
const showPicker = ref(false);
|
||||||
|
|
||||||
const onConfirm = (value) => {
|
const onConfirm = ({ selectedOptions }) => {
|
||||||
result.value = value;
|
|
||||||
showPicker.value = false;
|
showPicker.value = false;
|
||||||
|
fieldValue.value = selectedOptions[0].text;
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -278,6 +120,151 @@ export default {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 多列选择
|
||||||
|
|
||||||
|
`columns` 属性可以通过二维数组的形式配置多列选择。
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-picker title="标题" :columns="columns" />
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const columns = [
|
||||||
|
// 第一列
|
||||||
|
[
|
||||||
|
{ text: '周一', value: 'Monday' },
|
||||||
|
{ text: '周二', value: 'Tuesday' },
|
||||||
|
{ text: '周三', value: 'Wednesday' },
|
||||||
|
{ text: '周四', value: 'Thursday' },
|
||||||
|
{ text: '周五', value: 'Friday' },
|
||||||
|
],
|
||||||
|
// 第二列
|
||||||
|
[
|
||||||
|
{ text: '上午', value: 'Morning' },
|
||||||
|
{ text: '下午', value: 'Afternoon' },
|
||||||
|
{ text: '晚上', value: 'Evening' },
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
return { columns };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 级联选择
|
||||||
|
|
||||||
|
使用 `columns` 的 `children` 字段可以实现选项级联的效果。如果级联层级较多,推荐使用 [Cascader 级联选项组件](#/zh-CN/cascader)。
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-picker title="标题" :columns="columns" />
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
text: '浙江',
|
||||||
|
value: 'Zhejiang',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: '杭州',
|
||||||
|
value: 'Hangzhou',
|
||||||
|
children: [
|
||||||
|
{ text: '西湖区', value: 'Xihu' },
|
||||||
|
{ text: '余杭区', value: 'Yuhang' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '温州',
|
||||||
|
value: 'Wenzhou',
|
||||||
|
children: [
|
||||||
|
{ text: '鹿城区', value: 'Lucheng' },
|
||||||
|
{ text: '瓯海区', value: 'Ouhai' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '福建',
|
||||||
|
value: 'Fujian',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
text: '福州',
|
||||||
|
value: 'Fuzhou',
|
||||||
|
children: [
|
||||||
|
{ text: '鼓楼区', value: 'Gulou' },
|
||||||
|
{ text: '台江区', value: 'Taijiang' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '厦门',
|
||||||
|
value: 'Xiamen',
|
||||||
|
children: [
|
||||||
|
{ text: '思明区', value: 'Siming' },
|
||||||
|
{ text: '海沧区', value: 'Haicang' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return { columns };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
> 级联选择的数据嵌套深度需要保持一致,如果部分选项没有子选项,可以使用空字符串进行占位。
|
||||||
|
|
||||||
|
### 禁用选项
|
||||||
|
|
||||||
|
选项可以为对象结构,通过设置 `disabled` 来禁用该选项。
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-picker :columns="columns" />
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const columns = [
|
||||||
|
{ text: '杭州', value: 'Hangzhou', disabled: true },
|
||||||
|
{ text: '宁波', value: 'Ningbo' },
|
||||||
|
{ text: '温州', value: 'Wenzhou' },
|
||||||
|
];
|
||||||
|
return { columns };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 加载状态
|
||||||
|
|
||||||
|
若选择器数据是异步获取的,可以通过 `loading` 属性显示加载提示。
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-picker :columns="columns" :loading="loading" />
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const columns = ref([]);
|
||||||
|
const loading = ref(true);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
columns.value = [{ text: '选项', value: 'option' }];
|
||||||
|
loading.value = false;
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
return { columns, loading };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
### 自定义 Columns 的结构
|
### 自定义 Columns 的结构
|
||||||
|
|
||||||
```html
|
```html
|
||||||
@ -322,6 +309,7 @@ export default {
|
|||||||
|
|
||||||
const customFieldName = {
|
const customFieldName = {
|
||||||
text: 'cityName',
|
text: 'cityName',
|
||||||
|
value: 'cityName',
|
||||||
children: 'cities',
|
children: 'cities',
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -339,8 +327,8 @@ export default {
|
|||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 |
|
| 参数 | 说明 | 类型 | 默认值 |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| columns | 对象数组,配置每一列显示的数据 | _Column[]_ | `[]` |
|
| columns | 对象数组,配置每一列显示的数据 | _PickerOption[] \| PickerOption[][]_ | `[]` |
|
||||||
| columns-field-names | 自定义 `columns` 结构中的字段 | _object_ | `{ text: 'text', values: 'values', children: 'children' }` |
|
| columns-field-names | 自定义 `columns` 结构中的字段 | _object_ | `{ text: 'text', value: 'value', children: 'children' }` |
|
||||||
| title | 顶部栏标题 | _string_ | - |
|
| title | 顶部栏标题 | _string_ | - |
|
||||||
| confirm-button-text | 确认按钮文字 | _string_ | `确认` |
|
| confirm-button-text | 确认按钮文字 | _string_ | `确认` |
|
||||||
| cancel-button-text | 取消按钮文字 | _string_ | `取消` |
|
| cancel-button-text | 取消按钮文字 | _string_ | `取消` |
|
||||||
@ -348,61 +336,47 @@ export default {
|
|||||||
| loading | 是否显示加载状态 | _boolean_ | `false` |
|
| loading | 是否显示加载状态 | _boolean_ | `false` |
|
||||||
| show-toolbar | 是否显示顶部栏 | _boolean_ | `true` |
|
| show-toolbar | 是否显示顶部栏 | _boolean_ | `true` |
|
||||||
| allow-html | 是否允许选项内容中渲染 HTML | _boolean_ | `false` |
|
| allow-html | 是否允许选项内容中渲染 HTML | _boolean_ | `false` |
|
||||||
| default-index | 单列选择时,默认选中项的索引 | _number \| string_ | `0` |
|
| option-height | 选项高度,支持 `px` `vw` `vh` `rem` 单位,默认 `px` | _number \| string_ | `44` |
|
||||||
| item-height | 选项高度,支持 `px` `vw` `vh` `rem` 单位,默认 `px` | _number \| string_ | `44` |
|
| visible-option-num | 可见的选项个数 | _number \| string_ | `6` |
|
||||||
| visible-item-count | 可见的选项个数 | _number \| string_ | `6` |
|
|
||||||
| swipe-duration | 快速滑动时惯性滚动的时长,单位 `ms` | _number \| string_ | `1000` |
|
| swipe-duration | 快速滑动时惯性滚动的时长,单位 `ms` | _number \| string_ | `1000` |
|
||||||
|
|
||||||
### Events
|
### Events
|
||||||
|
|
||||||
当选择器有多列时,事件回调参数会返回数组。
|
|
||||||
|
|
||||||
| 事件名 | 说明 | 回调参数 |
|
| 事件名 | 说明 | 回调参数 |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| confirm | 点击完成按钮时触发 | 单列:选中值,选中值对应的索引<br>多列:所有列选中值,所有列选中值对应的索引 |
|
| confirm | 点击完成按钮时触发 | _{ selectedValues, selectedOptions }_ |
|
||||||
| cancel | 点击取消按钮时触发 | 单列:选中值,选中值对应的索引<br>多列:所有列选中值,所有列选中值对应的索引 |
|
| cancel | 点击取消按钮时触发 | _{ selectedValues, selectedOptions }_ |
|
||||||
| change | 选项改变时触发 | 单列:选中值,选中值对应的索引<br>多列:所有列选中值,当前列对应的索引 |
|
| change | 选项改变时触发 | _{ selectedValues, selectedOptions, columnIndex }_ |
|
||||||
|
|
||||||
### Slots
|
### Slots
|
||||||
|
|
||||||
| 名称 | 说明 | 参数 |
|
| 名称 | 说明 | 参数 |
|
||||||
| ---------------- | ---------------------- | -------------------------- |
|
| ---------------- | ---------------------- | ---------------------- |
|
||||||
| toolbar `v3.1.2` | 自定义整个顶部栏的内容 | - |
|
| toolbar `v3.1.2` | 自定义整个顶部栏的内容 | - |
|
||||||
| title | 自定义标题内容 | - |
|
| title | 自定义标题内容 | - |
|
||||||
| confirm | 自定义确认按钮内容 | - |
|
| confirm | 自定义确认按钮内容 | - |
|
||||||
| cancel | 自定义取消按钮内容 | - |
|
| cancel | 自定义取消按钮内容 | - |
|
||||||
| option | 自定义选项内容 | _option: string \| object_ |
|
| option | 自定义选项内容 | _option: PickerOption_ |
|
||||||
| columns-top | 自定义选项上方内容 | - |
|
| columns-top | 自定义选项上方内容 | - |
|
||||||
| columns-bottom | 自定义选项下方内容 | - |
|
| columns-bottom | 自定义选项下方内容 | - |
|
||||||
|
|
||||||
### Column 数据结构
|
### PickerOption 数据结构
|
||||||
|
|
||||||
当传入多列数据时,`columns` 为一个对象数组,数组中的每一个对象配置每一列,每一列有以下 `key`:
|
| 键名 | 说明 | 类型 |
|
||||||
|
| --------- | ------------ | --------------------------- |
|
||||||
| 键名 | 说明 | 类型 |
|
| text | 选项文字内容 | _string \| number_ |
|
||||||
| ------------ | -------------------------- | --------------------------- |
|
| value | 选项对应的值 | _string \| number_ |
|
||||||
| values | 列中对应的备选值 | _Array<string \| number>_ |
|
| disabled | 是否禁用选项 | _boolean_ |
|
||||||
| defaultIndex | 初始选中项的索引,默认为 0 | _number_ |
|
| children | 级联选项 | _PickerOption[]_ |
|
||||||
| className | 为对应列添加额外的类名 | _string \| Array \| object_ |
|
| className | 选项额外类名 | _string \| Array \| object_ |
|
||||||
| children | 级联选项 | _Column_ |
|
|
||||||
|
|
||||||
### 方法
|
### 方法
|
||||||
|
|
||||||
通过 ref 可以获取到 Picker 实例并调用实例方法,详见[组件实例方法](#/zh-CN/advanced-usage#zu-jian-shi-li-fang-fa)。
|
通过 ref 可以获取到 Picker 实例并调用实例方法,详见[组件实例方法](#/zh-CN/advanced-usage#zu-jian-shi-li-fang-fa)。
|
||||||
|
|
||||||
| 方法名 | 说明 | 参数 | 返回值 |
|
| 方法名 | 说明 | 参数 | 返回值 |
|
||||||
| --- | --- | --- | --- |
|
| ------- | --------------------------------- | ---- | ------ |
|
||||||
| getValues | 获取所有列选中的值 | - | values |
|
| confirm | 停止惯性滚动并触发 `confirm` 事件 | - | - |
|
||||||
| setValues | 设置所有列选中的值 | values | - |
|
|
||||||
| getIndexes | 获取所有列选中值对应的索引 | - | indexes |
|
|
||||||
| setIndexes | 设置所有列选中值对应的索引 | indexes | - |
|
|
||||||
| getColumnValue | 获取对应列选中的值 | columnIndex | value |
|
|
||||||
| setColumnValue | 设置对应列选中的值 | columnIndex, value | - |
|
|
||||||
| getColumnIndex | 获取对应列选中项的索引 | columnIndex | optionIndex |
|
|
||||||
| setColumnIndex | 设置对应列选中项的索引 | columnIndex, optionIndex | - |
|
|
||||||
| getColumnValues | 获取对应列中所有选项 | columnIndex | values |
|
|
||||||
| setColumnValues | 设置对应列中所有选项 | columnIndex, values | - |
|
|
||||||
| confirm | 停止惯性滚动并触发 confirm 事件 | - | - |
|
|
||||||
|
|
||||||
### 类型定义
|
### 类型定义
|
||||||
|
|
||||||
@ -415,9 +389,10 @@ import type {
|
|||||||
PickerOption,
|
PickerOption,
|
||||||
PickerInstance,
|
PickerInstance,
|
||||||
PickerFieldNames,
|
PickerFieldNames,
|
||||||
PickerObjectColumn,
|
|
||||||
PickerObjectOption,
|
|
||||||
PickerToolbarPosition,
|
PickerToolbarPosition,
|
||||||
|
PickerCancelEventParams,
|
||||||
|
PickerChangeEventParams,
|
||||||
|
PickerConfirmEventParams,
|
||||||
} from 'vant';
|
} from 'vant';
|
||||||
```
|
```
|
||||||
|
|
||||||
|
59
packages/vant/src/picker/demo/WithPopup.vue
Normal file
59
packages/vant/src/picker/demo/WithPopup.vue
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import VanPicker from '..';
|
||||||
|
import VanField from '../../field';
|
||||||
|
import VanPopup from '../../popup';
|
||||||
|
import { basicColumns } from './data';
|
||||||
|
import { useTranslate } from '../../../docs/site/use-translate';
|
||||||
|
import type { PickerConfirmEventParams } from '../types';
|
||||||
|
|
||||||
|
const t = useTranslate({
|
||||||
|
'zh-CN': {
|
||||||
|
city: '城市',
|
||||||
|
withPopup: '搭配弹出层使用',
|
||||||
|
chooseCity: '选择城市',
|
||||||
|
basicColumns: basicColumns['zh-CN'],
|
||||||
|
},
|
||||||
|
'en-US': {
|
||||||
|
city: 'City',
|
||||||
|
withPopup: 'With Popup',
|
||||||
|
chooseCity: 'Choose City',
|
||||||
|
basicColumns: basicColumns['en-US'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const showPicker = ref(false);
|
||||||
|
const fieldValue = ref('');
|
||||||
|
|
||||||
|
const onClickField = () => {
|
||||||
|
showPicker.value = true;
|
||||||
|
};
|
||||||
|
const onCancel = () => {
|
||||||
|
showPicker.value = false;
|
||||||
|
};
|
||||||
|
const onConfirm = ({ selectedOptions }: PickerConfirmEventParams) => {
|
||||||
|
showPicker.value = false;
|
||||||
|
fieldValue.value = selectedOptions[0].text as string;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<demo-block card :title="t('withPopup')">
|
||||||
|
<van-field
|
||||||
|
v-model="fieldValue"
|
||||||
|
is-link
|
||||||
|
readonly
|
||||||
|
:label="t('city')"
|
||||||
|
:placeholder="t('chooseCity')"
|
||||||
|
@click="onClickField"
|
||||||
|
/>
|
||||||
|
<van-popup v-model:show="showPicker" round position="bottom">
|
||||||
|
<van-picker
|
||||||
|
:title="t('title')"
|
||||||
|
:columns="t('basicColumns')"
|
||||||
|
@cancel="onCancel"
|
||||||
|
@confirm="onConfirm"
|
||||||
|
/>
|
||||||
|
</van-popup>
|
||||||
|
</demo-block>
|
||||||
|
</template>
|
@ -1,23 +1,48 @@
|
|||||||
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: ['上午', '下午', '晚上'],
|
|
||||||
defaultIndex: 1,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
'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 +50,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,34 +96,52 @@ 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' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const cascadeColumnsCustomKey = {
|
export const customKeyColumns = {
|
||||||
'zh-CN': [
|
'zh-CN': [
|
||||||
{
|
{
|
||||||
cityName: '浙江',
|
cityName: '浙江',
|
||||||
@ -138,3 +199,16 @@ export const cascadeColumnsCustomKey = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const disabledColumns = {
|
||||||
|
'zh-CN': [
|
||||||
|
{ text: '杭州', value: 'Hangzhou', disabled: true },
|
||||||
|
{ text: '宁波', value: 'Ningbo' },
|
||||||
|
{ text: '温州', value: 'Wenzhou' },
|
||||||
|
],
|
||||||
|
'en-US': [
|
||||||
|
{ text: 'Delaware', value: 'Delaware', disabled: true },
|
||||||
|
{ text: 'Florida', value: 'Florida' },
|
||||||
|
{ text: 'Georqia', value: 'Georqia' },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
@ -1,146 +1,79 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import VanPicker from '..';
|
import WithPopup from './WithPopup.vue';
|
||||||
import VanField from '../../field';
|
import VanPicker, {
|
||||||
import VanPopup from '../../popup';
|
PickerChangeEventParams,
|
||||||
import { ref, computed } from 'vue';
|
PickerConfirmEventParams,
|
||||||
import { dateColumns, cascadeColumns, cascadeColumnsCustomKey } from './data';
|
} from '..';
|
||||||
import { useTranslate } from '../../../docs/site/use-translate';
|
import {
|
||||||
|
dateColumns,
|
||||||
|
basicColumns,
|
||||||
|
cascadeColumns,
|
||||||
|
disabledColumns,
|
||||||
|
customKeyColumns,
|
||||||
|
} from './data';
|
||||||
import { Toast } from '../../toast';
|
import { Toast } from '../../toast';
|
||||||
|
import { useTranslate } from '../../../docs/site/use-translate';
|
||||||
|
|
||||||
const t = useTranslate({
|
const t = useTranslate({
|
||||||
'zh-CN': {
|
'zh-CN': {
|
||||||
city: '城市',
|
|
||||||
cascade: '级联选择',
|
cascade: '级联选择',
|
||||||
withPopup: '搭配弹出层使用',
|
|
||||||
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'],
|
||||||
|
disabledColumns: disabledColumns['zh-CN'],
|
||||||
multipleColumns: '多列选择',
|
multipleColumns: '多列选择',
|
||||||
setColumnValues: '动态设置选项',
|
|
||||||
customChildrenKey: '自定义 Columns 结构',
|
customChildrenKey: '自定义 Columns 结构',
|
||||||
customChildrenColumns: cascadeColumnsCustomKey['zh-CN'],
|
customChildrenColumns: customKeyColumns['zh-CN'],
|
||||||
textColumns: [
|
toastContent: (value: string) => `当前值:${value}`,
|
||||||
'杭州',
|
|
||||||
'宁波',
|
|
||||||
'温州',
|
|
||||||
'绍兴',
|
|
||||||
'湖州',
|
|
||||||
'嘉兴',
|
|
||||||
'金华',
|
|
||||||
'衢州',
|
|
||||||
],
|
|
||||||
disabledColumns: [
|
|
||||||
{ text: '杭州', disabled: true },
|
|
||||||
{ text: '宁波' },
|
|
||||||
{ text: '温州' },
|
|
||||||
],
|
|
||||||
column3: {
|
|
||||||
浙江: ['杭州', '宁波', '温州', '嘉兴', '湖州'],
|
|
||||||
福建: ['福州', '厦门', '莆田', '三明', '泉州'],
|
|
||||||
},
|
|
||||||
toastContent: (value: string, index: number) =>
|
|
||||||
`当前值:${value}, 当前索引:${index}`,
|
|
||||||
},
|
},
|
||||||
'en-US': {
|
'en-US': {
|
||||||
city: 'City',
|
|
||||||
cascade: 'Cascade',
|
cascade: 'Cascade',
|
||||||
withPopup: 'With Popup',
|
|
||||||
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'],
|
||||||
|
disabledColumns: disabledColumns['en-US'],
|
||||||
multipleColumns: 'Multiple Columns',
|
multipleColumns: 'Multiple Columns',
|
||||||
setColumnValues: 'Set Column Values',
|
|
||||||
customChildrenKey: 'Custom Columns Fields',
|
customChildrenKey: 'Custom Columns Fields',
|
||||||
customChildrenColumns: cascadeColumnsCustomKey['en-US'],
|
customChildrenColumns: customKeyColumns['en-US'],
|
||||||
textColumns: ['Delaware', 'Florida', 'Georqia', 'Indiana', 'Maine'],
|
|
||||||
disabledColumns: [
|
|
||||||
{ text: 'Delaware', disabled: true },
|
|
||||||
{ text: 'Florida' },
|
|
||||||
{ text: 'Georqia' },
|
|
||||||
],
|
|
||||||
column3: {
|
|
||||||
Group1: ['Delaware', 'Florida', 'Georqia', 'Indiana', 'Maine'],
|
|
||||||
Group2: ['Alabama', 'Kansas', 'Louisiana', 'Texas'],
|
|
||||||
},
|
|
||||||
toastContent: (value: string, index: number) =>
|
toastContent: (value: string, index: number) =>
|
||||||
`Value: ${value}, Index:${index}`,
|
`Value: ${value}, Index:${index}`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const picker = ref();
|
const customFieldName = {
|
||||||
const showPicker = ref(false);
|
|
||||||
const fieldValue = ref('');
|
|
||||||
const customFieldName = ref({
|
|
||||||
text: 'cityName',
|
text: 'cityName',
|
||||||
|
value: 'cityName',
|
||||||
children: 'cities',
|
children: 'cities',
|
||||||
});
|
|
||||||
|
|
||||||
const columns = computed(() => {
|
|
||||||
const column = t('column3');
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
values: Object.keys(column),
|
|
||||||
className: 'column1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
values: column[Object.keys(column)[0]],
|
|
||||||
className: 'column2',
|
|
||||||
defaultIndex: 2,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
});
|
|
||||||
|
|
||||||
const onChange1 = (value: string, index: number) => {
|
|
||||||
Toast(t('toastContent', value, index));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onChange2 = (values: string[]) => {
|
const onChange1 = ({ selectedValues }: PickerChangeEventParams) => {
|
||||||
picker.value.setColumnValues(1, t('column3')[values[0]]);
|
Toast(t('toastContent', selectedValues.join(',')));
|
||||||
};
|
};
|
||||||
|
|
||||||
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'));
|
||||||
|
|
||||||
const onCancel2 = () => {
|
|
||||||
showPicker.value = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onClickField = () => {
|
|
||||||
showPicker.value = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const onConfirm2 = (value: string) => {
|
|
||||||
showPicker.value = false;
|
|
||||||
fieldValue.value = value;
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<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"
|
@change="onChange1"
|
||||||
|
@confirm="onConfirm"
|
||||||
/>
|
/>
|
||||||
</demo-block>
|
</demo-block>
|
||||||
|
|
||||||
<demo-block card :title="t('defaultIndex')">
|
<WithPopup />
|
||||||
<van-picker
|
|
||||||
:title="t('title')"
|
|
||||||
:columns="t('textColumns')"
|
|
||||||
:default-index="2"
|
|
||||||
@change="onChange1"
|
|
||||||
/>
|
|
||||||
</demo-block>
|
|
||||||
|
|
||||||
<demo-block card :title="t('multipleColumns')">
|
<demo-block card :title="t('multipleColumns')">
|
||||||
<van-picker
|
<van-picker
|
||||||
@ -159,37 +92,10 @@ const onConfirm2 = (value: string) => {
|
|||||||
<van-picker :title="t('title')" :columns="t('disabledColumns')" />
|
<van-picker :title="t('title')" :columns="t('disabledColumns')" />
|
||||||
</demo-block>
|
</demo-block>
|
||||||
|
|
||||||
<demo-block card :title="t('setColumnValues')">
|
|
||||||
<van-picker
|
|
||||||
ref="picker"
|
|
||||||
:title="t('title')"
|
|
||||||
:columns="columns"
|
|
||||||
@change="onChange2"
|
|
||||||
/>
|
|
||||||
</demo-block>
|
|
||||||
|
|
||||||
<demo-block card :title="t('loadingStatus')">
|
<demo-block card :title="t('loadingStatus')">
|
||||||
<van-picker loading :title="t('title')" :columns="columns" />
|
<van-picker loading :title="t('title')" />
|
||||||
</demo-block>
|
</demo-block>
|
||||||
|
|
||||||
<demo-block card :title="t('withPopup')">
|
|
||||||
<van-field
|
|
||||||
v-model="fieldValue"
|
|
||||||
is-link
|
|
||||||
readonly
|
|
||||||
:label="t('city')"
|
|
||||||
:placeholder="t('chooseCity')"
|
|
||||||
@click="onClickField"
|
|
||||||
/>
|
|
||||||
<van-popup v-model:show="showPicker" round position="bottom">
|
|
||||||
<van-picker
|
|
||||||
:title="t('title')"
|
|
||||||
:columns="t('textColumns')"
|
|
||||||
@cancel="onCancel2"
|
|
||||||
@confirm="onConfirm2"
|
|
||||||
/>
|
|
||||||
</van-popup>
|
|
||||||
</demo-block>
|
|
||||||
<demo-block card :title="t('customChildrenKey')">
|
<demo-block card :title="t('customChildrenKey')">
|
||||||
<van-picker
|
<van-picker
|
||||||
:title="t('title')"
|
:title="t('title')"
|
||||||
|
@ -9,9 +9,10 @@ export type {
|
|||||||
PickerOption,
|
PickerOption,
|
||||||
PickerInstance,
|
PickerInstance,
|
||||||
PickerFieldNames,
|
PickerFieldNames,
|
||||||
PickerObjectColumn,
|
|
||||||
PickerObjectOption,
|
|
||||||
PickerToolbarPosition,
|
PickerToolbarPosition,
|
||||||
|
PickerCancelEventParams,
|
||||||
|
PickerChangeEventParams,
|
||||||
|
PickerConfirmEventParams,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
declare module 'vue' {
|
declare module 'vue' {
|
||||||
|
@ -84,86 +84,35 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="van-picker">
|
<div class="van-cell van-cell--clickable van-field"
|
||||||
<div class="van-picker__toolbar">
|
role="button"
|
||||||
<button type="button"
|
tabindex="0"
|
||||||
class="van-picker__cancel van-haptics-feedback"
|
>
|
||||||
|
<div class="van-cell__title van-field__label">
|
||||||
|
<label id="van-field-label"
|
||||||
|
for="van-field-input"
|
||||||
>
|
>
|
||||||
Cancel
|
City
|
||||||
</button>
|
</label>
|
||||||
<div class="van-picker__title van-ellipsis">
|
|
||||||
Title
|
|
||||||
</div>
|
|
||||||
<button type="button"
|
|
||||||
class="van-picker__confirm van-haptics-feedback"
|
|
||||||
>
|
|
||||||
Confirm
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="van-picker__columns"
|
<div class="van-cell__value van-field__value">
|
||||||
style="height: 264px;"
|
<div class="van-field__body">
|
||||||
>
|
<input type="text"
|
||||||
<div class="van-picker-column">
|
id="van-field-input"
|
||||||
<ul style="transform: translate3d(0, 22px, 0); transition-duration: 0ms; transition-property: none;"
|
class="van-field__control"
|
||||||
class="van-picker-column__wrapper"
|
readonly
|
||||||
|
placeholder="Choose City"
|
||||||
|
aria-labelledby="van-field-label"
|
||||||
>
|
>
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
Delaware
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
Florida
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item van-picker-column__item--selected"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
Georqia
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
Indiana
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
Maine
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="van-picker__mask"
|
|
||||||
style="background-size: 100% 110px;"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="van-hairline-unset--top-bottom van-picker__frame"
|
|
||||||
style="height: 44px;"
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<i class="van-badge__wrapper van-icon van-icon-arrow van-cell__right-icon">
|
||||||
|
</i>
|
||||||
</div>
|
</div>
|
||||||
|
<transition-stub>
|
||||||
|
</transition-stub>
|
||||||
|
<transition-stub>
|
||||||
|
</transition-stub>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="van-picker">
|
<div class="van-picker">
|
||||||
@ -186,13 +135,13 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
style="height: 264px;"
|
style="height: 264px;"
|
||||||
>
|
>
|
||||||
<div class="van-picker-column">
|
<div class="van-picker-column">
|
||||||
<ul style="transform: translate3d(0, 22px, 0); transition-duration: 0ms; transition-property: none;"
|
<ul style="transform: translate3d(0, 110px, 0); transition-duration: 0ms; transition-property: none;"
|
||||||
class="van-picker-column__wrapper"
|
class="van-picker-column__wrapper"
|
||||||
>
|
>
|
||||||
<li role="button"
|
<li role="button"
|
||||||
style="height: 44px;"
|
style="height: 44px;"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
class="van-picker-column__item"
|
class="van-picker-column__item van-picker-column__item--selected"
|
||||||
>
|
>
|
||||||
<div class="van-ellipsis">
|
<div class="van-ellipsis">
|
||||||
Monday
|
Monday
|
||||||
@ -210,7 +159,7 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
<li role="button"
|
<li role="button"
|
||||||
style="height: 44px;"
|
style="height: 44px;"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
class="van-picker-column__item van-picker-column__item--selected"
|
class="van-picker-column__item"
|
||||||
>
|
>
|
||||||
<div class="van-ellipsis">
|
<div class="van-ellipsis">
|
||||||
Wednesday
|
Wednesday
|
||||||
@ -237,13 +186,13 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="van-picker-column">
|
<div class="van-picker-column">
|
||||||
<ul style="transform: translate3d(0, 66px, 0); transition-duration: 0ms; transition-property: none;"
|
<ul style="transform: translate3d(0, 110px, 0); transition-duration: 0ms; transition-property: none;"
|
||||||
class="van-picker-column__wrapper"
|
class="van-picker-column__wrapper"
|
||||||
>
|
>
|
||||||
<li role="button"
|
<li role="button"
|
||||||
style="height: 44px;"
|
style="height: 44px;"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
class="van-picker-column__item"
|
class="van-picker-column__item van-picker-column__item--selected"
|
||||||
>
|
>
|
||||||
<div class="van-ellipsis">
|
<div class="van-ellipsis">
|
||||||
Morning
|
Morning
|
||||||
@ -252,7 +201,7 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
<li role="button"
|
<li role="button"
|
||||||
style="height: 44px;"
|
style="height: 44px;"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
class="van-picker-column__item van-picker-column__item--selected"
|
class="van-picker-column__item"
|
||||||
>
|
>
|
||||||
<div class="van-ellipsis">
|
<div class="van-ellipsis">
|
||||||
Afternoon
|
Afternoon
|
||||||
@ -447,112 +396,6 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<div class="van-picker">
|
|
||||||
<div class="van-picker__toolbar">
|
|
||||||
<button type="button"
|
|
||||||
class="van-picker__cancel van-haptics-feedback"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
<div class="van-picker__title van-ellipsis">
|
|
||||||
Title
|
|
||||||
</div>
|
|
||||||
<button type="button"
|
|
||||||
class="van-picker__confirm van-haptics-feedback"
|
|
||||||
>
|
|
||||||
Confirm
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="van-picker__columns"
|
|
||||||
style="height: 264px;"
|
|
||||||
>
|
|
||||||
<div class="van-picker-column column1">
|
|
||||||
<ul style="transform: translate3d(0, 110px, 0); transition-duration: 0ms; transition-property: none;"
|
|
||||||
class="van-picker-column__wrapper"
|
|
||||||
>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item van-picker-column__item--selected"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
Group1
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
Group2
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="van-picker-column column2">
|
|
||||||
<ul style="transform: translate3d(0, 22px, 0); transition-duration: 0ms; transition-property: none;"
|
|
||||||
class="van-picker-column__wrapper"
|
|
||||||
>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
Delaware
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
Florida
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item van-picker-column__item--selected"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
Georqia
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
Indiana
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
Maine
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="van-picker__mask"
|
|
||||||
style="background-size: 100% 110px;"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="van-hairline-unset--top-bottom van-picker__frame"
|
|
||||||
style="height: 44px;"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<div class="van-picker">
|
<div class="van-picker">
|
||||||
<div class="van-picker__toolbar">
|
<div class="van-picker__toolbar">
|
||||||
@ -587,123 +430,15 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
<div class="van-picker__columns"
|
<div class="van-picker__columns"
|
||||||
style="height: 264px;"
|
style="height: 264px;"
|
||||||
>
|
>
|
||||||
<div class="van-picker-column column1">
|
<div class="van-picker-column">
|
||||||
<ul style="transform: translate3d(0, 110px, 0); transition-duration: 0ms; transition-property: none;"
|
<ul style="transform: translate3d(0, 110px, 0); transition-duration: 0ms; transition-property: none;"
|
||||||
class="van-picker-column__wrapper"
|
class="van-picker-column__wrapper"
|
||||||
>
|
>
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item van-picker-column__item--selected"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
Group1
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
Group2
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="van-picker-column column2">
|
|
||||||
<ul style="transform: translate3d(0, 22px, 0); transition-duration: 0ms; transition-property: none;"
|
|
||||||
class="van-picker-column__wrapper"
|
|
||||||
>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
Delaware
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
Florida
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item van-picker-column__item--selected"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
Georqia
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
Indiana
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
Maine
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="van-picker__mask"
|
|
||||||
style="background-size: 100% 110px;"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="van-hairline-unset--top-bottom van-picker__frame"
|
|
||||||
style="height: 44px;"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<div class="van-cell van-cell--clickable van-field"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
<div class="van-cell__title van-field__label">
|
|
||||||
<label id="van-field-label"
|
|
||||||
for="van-field-input"
|
|
||||||
>
|
|
||||||
City
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="van-cell__value van-field__value">
|
|
||||||
<div class="van-field__body">
|
|
||||||
<input type="text"
|
|
||||||
id="van-field-input"
|
|
||||||
class="van-field__control"
|
|
||||||
readonly
|
|
||||||
placeholder="Choose City"
|
|
||||||
aria-labelledby="van-field-label"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<i class="van-badge__wrapper van-icon van-icon-arrow van-cell__right-icon">
|
|
||||||
</i>
|
|
||||||
</div>
|
|
||||||
<transition-stub>
|
|
||||||
</transition-stub>
|
|
||||||
<transition-stub>
|
|
||||||
</transition-stub>
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<div class="van-picker">
|
<div class="van-picker">
|
||||||
<div class="van-picker__toolbar">
|
<div class="van-picker__toolbar">
|
||||||
|
@ -1,179 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`column watch default index 1`] = `
|
exports[`should not allow to render html text 1`] = `
|
||||||
<div class="van-picker-column">
|
|
||||||
<ul style="transform: translate3d(0, 50px, 0); transition-duration: 0ms; transition-property: none;"
|
|
||||||
class="van-picker-column__wrapper"
|
|
||||||
>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 50px;"
|
|
||||||
tabindex="-1"
|
|
||||||
class="van-picker-column__item van-picker-column__item--disabled"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
1
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 50px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item van-picker-column__item--selected"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
1990
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 50px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
1991
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 50px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
1992
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 50px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
1993
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 50px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
1994
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 50px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
1995
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`column watch default index 2`] = `
|
|
||||||
<div class="van-picker-column">
|
|
||||||
<ul style="transform: translate3d(0, 0px, 0); transition-duration: 0ms; transition-property: none;"
|
|
||||||
class="van-picker-column__wrapper"
|
|
||||||
>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 50px;"
|
|
||||||
tabindex="-1"
|
|
||||||
class="van-picker-column__item van-picker-column__item--disabled"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
1
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 50px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
1990
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 50px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item van-picker-column__item--selected"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
1991
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 50px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
1992
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 50px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
1993
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 50px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
1994
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 50px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
1995
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`columns-top、columns-bottom prop 1`] = `
|
|
||||||
<div class="van-picker">
|
|
||||||
<div class="van-picker__toolbar">
|
|
||||||
<button type="button"
|
|
||||||
class="van-picker__cancel van-haptics-feedback"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
<button type="button"
|
|
||||||
class="van-picker__confirm van-haptics-feedback"
|
|
||||||
>
|
|
||||||
Confirm
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
Custom Columns Top
|
|
||||||
<div class="van-picker__columns"
|
|
||||||
style="height: 264px;"
|
|
||||||
>
|
|
||||||
<div class="van-picker-column">
|
|
||||||
<ul style="transform: translate3d(0, 110px, 0); transition-duration: 0ms; transition-property: none;"
|
|
||||||
class="van-picker-column__wrapper"
|
|
||||||
>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
Custom Columns Bottom
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`not allow html 1`] = `
|
|
||||||
<div class="van-picker">
|
<div class="van-picker">
|
||||||
<div class="van-picker__toolbar">
|
<div class="van-picker__toolbar">
|
||||||
<button type="button"
|
<button type="button"
|
||||||
@ -217,235 +44,7 @@ exports[`not allow html 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`render option slot with object columns 1`] = `
|
exports[`should render bottom toolbar when toolbar-position is bottom 1`] = `
|
||||||
<div class="van-picker">
|
|
||||||
<div class="van-picker__toolbar">
|
|
||||||
<button type="button"
|
|
||||||
class="van-picker__cancel van-haptics-feedback"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
<button type="button"
|
|
||||||
class="van-picker__confirm van-haptics-feedback"
|
|
||||||
>
|
|
||||||
Confirm
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="van-picker__columns"
|
|
||||||
style="height: 264px;"
|
|
||||||
>
|
|
||||||
<div class="van-picker-column">
|
|
||||||
<ul style="transform: translate3d(0, 110px, 0); transition-duration: 0ms; transition-property: none;"
|
|
||||||
class="van-picker-column__wrapper"
|
|
||||||
>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item van-picker-column__item--selected"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
foo
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
bar
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="van-picker__mask"
|
|
||||||
style="background-size: 100% 110px;"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="van-hairline-unset--top-bottom van-picker__frame"
|
|
||||||
style="height: 44px;"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`render option slot with simple columns 1`] = `
|
|
||||||
<div class="van-picker">
|
|
||||||
<div class="van-picker__toolbar">
|
|
||||||
<button type="button"
|
|
||||||
class="van-picker__cancel van-haptics-feedback"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
<button type="button"
|
|
||||||
class="van-picker__confirm van-haptics-feedback"
|
|
||||||
>
|
|
||||||
Confirm
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="van-picker__columns"
|
|
||||||
style="height: 264px;"
|
|
||||||
>
|
|
||||||
<div class="van-picker-column">
|
|
||||||
<ul style="transform: translate3d(0, 110px, 0); transition-duration: 0ms; transition-property: none;"
|
|
||||||
class="van-picker-column__wrapper"
|
|
||||||
>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item van-picker-column__item--selected"
|
|
||||||
>
|
|
||||||
foo
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 44px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
bar
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="van-picker__mask"
|
|
||||||
style="background-size: 100% 110px;"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="van-hairline-unset--top-bottom van-picker__frame"
|
|
||||||
style="height: 44px;"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`set rem item-height 1`] = `
|
|
||||||
<div class="van-picker">
|
|
||||||
<div class="van-picker__toolbar">
|
|
||||||
<button type="button"
|
|
||||||
class="van-picker__cancel van-haptics-feedback"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
<button type="button"
|
|
||||||
class="van-picker__confirm van-haptics-feedback"
|
|
||||||
>
|
|
||||||
Confirm
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="van-picker__columns"
|
|
||||||
style="height: 960px;"
|
|
||||||
>
|
|
||||||
<div class="van-picker-column">
|
|
||||||
<ul style="transform: translate3d(0, 400px, 0); transition-duration: 0ms; transition-property: none;"
|
|
||||||
class="van-picker-column__wrapper"
|
|
||||||
>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 160px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item van-picker-column__item--selected"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
1990
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li role="button"
|
|
||||||
style="height: 160px;"
|
|
||||||
tabindex="0"
|
|
||||||
class="van-picker-column__item"
|
|
||||||
>
|
|
||||||
<div class="van-ellipsis">
|
|
||||||
1991
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="van-picker__mask"
|
|
||||||
style="background-size: 100% 400px;"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="van-hairline-unset--top-bottom van-picker__frame"
|
|
||||||
style="height: 160px;"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`should render confirm/cancel slot correctly 1`] = `
|
|
||||||
<div class="van-picker">
|
|
||||||
<div class="van-picker__toolbar">
|
|
||||||
<button type="button"
|
|
||||||
class="van-picker__cancel van-haptics-feedback"
|
|
||||||
>
|
|
||||||
Custom Cancel
|
|
||||||
</button>
|
|
||||||
<button type="button"
|
|
||||||
class="van-picker__confirm van-haptics-feedback"
|
|
||||||
>
|
|
||||||
Custom Confirm
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="van-picker__columns"
|
|
||||||
style="height: 264px;"
|
|
||||||
>
|
|
||||||
<div class="van-picker-column">
|
|
||||||
<ul style="transform: translate3d(0, 110px, 0); transition-duration: 0ms; transition-property: none;"
|
|
||||||
class="van-picker-column__wrapper"
|
|
||||||
>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`should render title slot correctly 1`] = `
|
|
||||||
<div class="van-picker">
|
|
||||||
<div class="van-picker__toolbar">
|
|
||||||
<button type="button"
|
|
||||||
class="van-picker__cancel van-haptics-feedback"
|
|
||||||
>
|
|
||||||
Cancel
|
|
||||||
</button>
|
|
||||||
Custom title
|
|
||||||
<button type="button"
|
|
||||||
class="van-picker__confirm van-haptics-feedback"
|
|
||||||
>
|
|
||||||
Confirm
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="van-picker__columns"
|
|
||||||
style="height: 264px;"
|
|
||||||
>
|
|
||||||
<div class="van-picker-column">
|
|
||||||
<ul style="transform: translate3d(0, 110px, 0); transition-duration: 0ms; transition-property: none;"
|
|
||||||
class="van-picker-column__wrapper"
|
|
||||||
>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`should render toolbar slot correctly 1`] = `
|
|
||||||
<div class="van-picker">
|
|
||||||
<div class="van-picker__toolbar">
|
|
||||||
Custom toolbar
|
|
||||||
</div>
|
|
||||||
<div class="van-picker__columns"
|
|
||||||
style="height: 264px;"
|
|
||||||
>
|
|
||||||
<div class="van-picker-column">
|
|
||||||
<ul style="transform: translate3d(0, 110px, 0); transition-duration: 0ms; transition-property: none;"
|
|
||||||
class="van-picker-column__wrapper"
|
|
||||||
>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`toolbar-position prop 1`] = `
|
|
||||||
<div class="van-picker">
|
<div class="van-picker">
|
||||||
<div class="van-picker__columns"
|
<div class="van-picker__columns"
|
||||||
style="height: 264px;"
|
style="height: 264px;"
|
||||||
|
152
packages/vant/src/picker/test/__snapshots__/slots.spec.ts.snap
Normal file
152
packages/vant/src/picker/test/__snapshots__/slots.spec.ts.snap
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`should render columns-top、columns-bottom slots correctly 1`] = `
|
||||||
|
<div class="van-picker">
|
||||||
|
<div class="van-picker__toolbar">
|
||||||
|
<button type="button"
|
||||||
|
class="van-picker__cancel van-haptics-feedback"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button type="button"
|
||||||
|
class="van-picker__confirm van-haptics-feedback"
|
||||||
|
>
|
||||||
|
Confirm
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
Custom Columns Top
|
||||||
|
<div class="van-picker__columns"
|
||||||
|
style="height: 264px;"
|
||||||
|
>
|
||||||
|
<div class="van-picker-column">
|
||||||
|
<ul style="transform: translate3d(0, 110px, 0); transition-duration: 0ms; transition-property: none;"
|
||||||
|
class="van-picker-column__wrapper"
|
||||||
|
>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
Custom Columns Bottom
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`should render confirm/cancel slot correctly 1`] = `
|
||||||
|
<div class="van-picker">
|
||||||
|
<div class="van-picker__toolbar">
|
||||||
|
<button type="button"
|
||||||
|
class="van-picker__cancel van-haptics-feedback"
|
||||||
|
>
|
||||||
|
Custom Cancel
|
||||||
|
</button>
|
||||||
|
<button type="button"
|
||||||
|
class="van-picker__confirm van-haptics-feedback"
|
||||||
|
>
|
||||||
|
Custom Confirm
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="van-picker__columns"
|
||||||
|
style="height: 264px;"
|
||||||
|
>
|
||||||
|
<div class="van-picker-column">
|
||||||
|
<ul style="transform: translate3d(0, 110px, 0); transition-duration: 0ms; transition-property: none;"
|
||||||
|
class="van-picker-column__wrapper"
|
||||||
|
>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`should render option slot correctly 1`] = `
|
||||||
|
<div class="van-picker">
|
||||||
|
<div class="van-picker__toolbar">
|
||||||
|
<button type="button"
|
||||||
|
class="van-picker__cancel van-haptics-feedback"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button type="button"
|
||||||
|
class="van-picker__confirm van-haptics-feedback"
|
||||||
|
>
|
||||||
|
Confirm
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="van-picker__columns"
|
||||||
|
style="height: 264px;"
|
||||||
|
>
|
||||||
|
<div class="van-picker-column">
|
||||||
|
<ul style="transform: translate3d(0, 110px, 0); transition-duration: 0ms; transition-property: none;"
|
||||||
|
class="van-picker-column__wrapper"
|
||||||
|
>
|
||||||
|
<li role="button"
|
||||||
|
style="height: 44px;"
|
||||||
|
tabindex="0"
|
||||||
|
class="van-picker-column__item van-picker-column__item--selected"
|
||||||
|
>
|
||||||
|
Custom 1990
|
||||||
|
</li>
|
||||||
|
<li role="button"
|
||||||
|
style="height: 44px;"
|
||||||
|
tabindex="0"
|
||||||
|
class="van-picker-column__item"
|
||||||
|
>
|
||||||
|
Custom 1991
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="van-picker__mask"
|
||||||
|
style="background-size: 100% 110px;"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="van-hairline-unset--top-bottom van-picker__frame"
|
||||||
|
style="height: 44px;"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`should render title slot correctly 1`] = `
|
||||||
|
<div class="van-picker">
|
||||||
|
<div class="van-picker__toolbar">
|
||||||
|
<button type="button"
|
||||||
|
class="van-picker__cancel van-haptics-feedback"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
Custom title
|
||||||
|
<button type="button"
|
||||||
|
class="van-picker__confirm van-haptics-feedback"
|
||||||
|
>
|
||||||
|
Confirm
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="van-picker__columns"
|
||||||
|
style="height: 264px;"
|
||||||
|
>
|
||||||
|
<div class="van-picker-column">
|
||||||
|
<ul style="transform: translate3d(0, 110px, 0); transition-duration: 0ms; transition-property: none;"
|
||||||
|
class="van-picker-column__wrapper"
|
||||||
|
>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`should render toolbar slot correctly 1`] = `
|
||||||
|
<div class="van-picker">
|
||||||
|
<div class="van-picker__toolbar">
|
||||||
|
Custom toolbar
|
||||||
|
</div>
|
||||||
|
<div class="van-picker__columns"
|
||||||
|
style="height: 264px;"
|
||||||
|
>
|
||||||
|
<div class="van-picker-column">
|
||||||
|
<ul style="transform: translate3d(0, 110px, 0); transition-duration: 0ms; transition-property: none;"
|
||||||
|
class="van-picker-column__wrapper"
|
||||||
|
>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
@ -1,20 +1,16 @@
|
|||||||
import { later, mount, triggerDrag } from '../../../test';
|
import { later, mount, triggerDrag } from '../../../test';
|
||||||
import { Picker } from '..';
|
import { Picker } from '..';
|
||||||
import PickerColumn from '../PickerColumn';
|
|
||||||
|
|
||||||
const simpleColumn = ['1990', '1991', '1992', '1993', '1994', '1995'];
|
const simpleColumn = [
|
||||||
const columns = [
|
{ text: '1990', value: '1990' },
|
||||||
{
|
{ text: '1991', value: '1991' },
|
||||||
values: ['vip', 'normal'],
|
{ text: '1992', value: '1992' },
|
||||||
className: 'column1',
|
{ text: '1993', value: '1993' },
|
||||||
},
|
{ text: '1994', value: '1994' },
|
||||||
{
|
{ text: '1995', value: '1995' },
|
||||||
values: simpleColumn,
|
|
||||||
className: 'column2',
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
test('simple columns confirm & cancel event', () => {
|
test('should emit confirm event after clicking the confirm button', () => {
|
||||||
const wrapper = mount(Picker, {
|
const wrapper = mount(Picker, {
|
||||||
props: {
|
props: {
|
||||||
showToolbar: true,
|
showToolbar: true,
|
||||||
@ -23,89 +19,32 @@ test('simple columns confirm & cancel event', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
wrapper.find('.van-picker__confirm').trigger('click');
|
wrapper.find('.van-picker__confirm').trigger('click');
|
||||||
wrapper.find('.van-picker__cancel').trigger('click');
|
expect(wrapper.emitted('confirm')![0]).toEqual([
|
||||||
expect(wrapper.emitted('confirm')![0]).toEqual(['1990', 0]);
|
{
|
||||||
expect(wrapper.emitted('cancel')![0]).toEqual(['1990', 0]);
|
selectedOptions: [{ text: '1990', value: '1990' }],
|
||||||
wrapper.unmount();
|
selectedValues: ['1990'],
|
||||||
});
|
|
||||||
|
|
||||||
test('multiple columns confirm & cancel event', () => {
|
|
||||||
const wrapper = mount(Picker, {
|
|
||||||
props: {
|
|
||||||
showToolbar: true,
|
|
||||||
columns,
|
|
||||||
},
|
},
|
||||||
});
|
|
||||||
|
|
||||||
wrapper.find('.van-picker__confirm').trigger('click');
|
|
||||||
wrapper.find('.van-picker__cancel').trigger('click');
|
|
||||||
|
|
||||||
const params = [
|
|
||||||
['vip', '1990'],
|
|
||||||
[0, 0],
|
|
||||||
];
|
|
||||||
|
|
||||||
expect(wrapper.emitted('confirm')![0]).toEqual(params);
|
|
||||||
expect(wrapper.emitted('cancel')![0]).toEqual(params);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('set picker values', () => {
|
|
||||||
const wrapper = mount(Picker, {
|
|
||||||
props: {
|
|
||||||
columns,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const vm = wrapper.vm as Record<string, any>;
|
|
||||||
|
|
||||||
expect(vm.getColumnValues(-1)).toEqual(undefined);
|
|
||||||
expect(vm.getColumnValues(1)).toHaveLength(6);
|
|
||||||
expect(vm.getColumnValue(1)).toEqual('1990');
|
|
||||||
|
|
||||||
vm.setColumnValue(0, 'normal');
|
|
||||||
expect(vm.getColumnValue(0)).toEqual('normal');
|
|
||||||
|
|
||||||
vm.setColumnIndex(0, 0);
|
|
||||||
expect(vm.getColumnValue(0)).toEqual('vip');
|
|
||||||
|
|
||||||
vm.setColumnValue(1, '1991');
|
|
||||||
expect(vm.getColumnValue(1)).toEqual('1991');
|
|
||||||
|
|
||||||
vm.setColumnValues(0, ['vip', 'normal', 'other']);
|
|
||||||
expect(vm.getColumnValues(0)).toHaveLength(3);
|
|
||||||
expect(vm.getValues()).toHaveLength(2);
|
|
||||||
|
|
||||||
vm.setColumnValues(-1, []);
|
|
||||||
expect(vm.getValues()).toHaveLength(2);
|
|
||||||
|
|
||||||
vm.setValues(['vip', '1992']);
|
|
||||||
expect(vm.getColumnIndex(1)).toEqual(2);
|
|
||||||
expect(vm.getColumnIndex(2)).toEqual(undefined);
|
|
||||||
expect(vm.getIndexes(2)).toEqual([0, 2]);
|
|
||||||
|
|
||||||
vm.setIndexes([1, 4]);
|
|
||||||
expect(vm.getColumnValue(1)).toEqual('1994');
|
|
||||||
expect(vm.getColumnValue(2)).toEqual(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('drag columns', () => {
|
|
||||||
const wrapper = mount(Picker, {
|
|
||||||
props: {
|
|
||||||
columns,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
triggerDrag(wrapper.find('.van-picker-column'), 0, -100);
|
|
||||||
wrapper.find('.van-picker-column ul').trigger('transitionend');
|
|
||||||
|
|
||||||
// 由于在极短的时间(大约几毫秒)移动 `100px`,因此再计算惯性滚动的距离时,
|
|
||||||
// 会得到一个很大的值,导致会滚动到且选中列表的最后一项
|
|
||||||
expect(wrapper.emitted<[Array<string>, number]>('change')![0][0]).toEqual([
|
|
||||||
'normal',
|
|
||||||
'1990',
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('drag simple columns', () => {
|
test('should emit cancel event after clicking the cancel button', () => {
|
||||||
|
const wrapper = mount(Picker, {
|
||||||
|
props: {
|
||||||
|
showToolbar: true,
|
||||||
|
columns: simpleColumn,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
wrapper.find('.van-picker__cancel').trigger('click');
|
||||||
|
expect(wrapper.emitted('cancel')![0]).toEqual([
|
||||||
|
{
|
||||||
|
selectedOptions: [{ text: '1990', value: '1990' }],
|
||||||
|
selectedValues: ['1990'],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should emit change event after draging the column', () => {
|
||||||
const wrapper = mount(Picker, {
|
const wrapper = mount(Picker, {
|
||||||
props: {
|
props: {
|
||||||
columns: simpleColumn,
|
columns: simpleColumn,
|
||||||
@ -115,121 +54,21 @@ test('drag simple columns', () => {
|
|||||||
triggerDrag(wrapper.find('.van-picker-column'), 0, -100);
|
triggerDrag(wrapper.find('.van-picker-column'), 0, -100);
|
||||||
wrapper.find('.van-picker-column ul').trigger('transitionend');
|
wrapper.find('.van-picker-column ul').trigger('transitionend');
|
||||||
|
|
||||||
// 由于在极短的时间(大约几毫秒)移动 `100px`,因此再计算惯性滚动的距离时,
|
expect(wrapper.emitted('change')).toEqual([
|
||||||
// 会得到一个很大的值,导致会滚动到且选中列表的最后一项
|
[
|
||||||
expect(wrapper.emitted<[string, number]>('change')![0][0]).toEqual('1995');
|
{
|
||||||
|
columnIndex: 0,
|
||||||
|
selectedOptions: [{ text: '1995', value: '1995' }],
|
||||||
|
selectedValues: ['1995'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('column watch default index', async () => {
|
test('should emit change event when after clicking a option', async () => {
|
||||||
const disabled = { disabled: true, text: 1 };
|
|
||||||
const wrapper = mount(PickerColumn, {
|
|
||||||
props: {
|
|
||||||
initialOptions: [disabled, ...simpleColumn],
|
|
||||||
textKey: 'text',
|
|
||||||
itemHeight: 50,
|
|
||||||
visibleItemCount: 5,
|
|
||||||
swipeDuration: 1000,
|
|
||||||
},
|
|
||||||
} as any);
|
|
||||||
|
|
||||||
await later();
|
|
||||||
expect(wrapper.html()).toMatchSnapshot();
|
|
||||||
|
|
||||||
await wrapper.setProps({
|
|
||||||
defaultIndex: 2,
|
|
||||||
});
|
|
||||||
expect(wrapper.html()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should render title slot correctly', () => {
|
|
||||||
const wrapper = mount(Picker, {
|
|
||||||
slots: {
|
|
||||||
title: () => 'Custom title',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(wrapper.html()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should render toolbar slot correctly', () => {
|
|
||||||
const wrapper = mount(Picker, {
|
|
||||||
slots: {
|
|
||||||
toolbar: () => 'Custom toolbar',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
expect(wrapper.html()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('should render confirm/cancel slot correctly', () => {
|
|
||||||
const wrapper = mount(Picker, {
|
|
||||||
slots: {
|
|
||||||
confirm: () => 'Custom Confirm',
|
|
||||||
cancel: () => 'Custom Cancel',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(wrapper.html()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('render option slot with simple columns', () => {
|
|
||||||
const wrapper = mount(Picker, {
|
|
||||||
props: {
|
|
||||||
columns: ['foo', 'bar'],
|
|
||||||
showToolbar: true,
|
|
||||||
},
|
|
||||||
slots: {
|
|
||||||
option: (item) => item,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(wrapper.html()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('render option slot with object columns', () => {
|
|
||||||
const wrapper = mount(Picker, {
|
|
||||||
props: {
|
|
||||||
columns: [{ text: 'foo' }, { text: 'bar' }],
|
|
||||||
showToolbar: true,
|
|
||||||
},
|
|
||||||
slots: {
|
|
||||||
options: (item) => item,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(wrapper.html()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('simulation finger swipe again before transitionend', () => {
|
|
||||||
// mock getComputedStyle
|
|
||||||
// see: https://github.com/jsdom/jsdom/issues/2588
|
|
||||||
const originGetComputedStyle = window.getComputedStyle;
|
|
||||||
window.getComputedStyle = (ele) => {
|
|
||||||
const style = originGetComputedStyle(ele);
|
|
||||||
|
|
||||||
return {
|
|
||||||
...style,
|
|
||||||
transform: 'matrix(1, 0, 0, 1, 0, -5)',
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const wrapper = mount(Picker, {
|
|
||||||
props: {
|
|
||||||
columns: simpleColumn,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
triggerDrag(wrapper.find('.van-picker-column'), 0, -5);
|
|
||||||
triggerDrag(wrapper.find('.van-picker-column'), -5, -100);
|
|
||||||
wrapper.find('.van-picker-column ul').trigger('transitionend');
|
|
||||||
expect(wrapper.emitted<[string, number]>('change')![0][0]).toEqual('1995');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('click column item', () => {
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ text: '杭州' },
|
{ text: 'A', value: 'A' },
|
||||||
{ text: '宁波' },
|
{ text: 'B', value: 'B' },
|
||||||
{ text: '温州', disabled: true },
|
|
||||||
{ text: '嘉兴', disabled: true },
|
|
||||||
];
|
];
|
||||||
const wrapper = mount(Picker, {
|
const wrapper = mount(Picker, {
|
||||||
props: {
|
props: {
|
||||||
@ -237,13 +76,50 @@ test('click column item', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
wrapper.findAll('.van-picker-column__item')[3].trigger('click');
|
await wrapper.findAll('.van-picker-column__item')[1].trigger('click');
|
||||||
expect(wrapper.emitted<[string, number]>('change')![0][0]).toEqual(
|
expect(wrapper.emitted('change')).toEqual([
|
||||||
columns[1]
|
[
|
||||||
);
|
{
|
||||||
|
columnIndex: 0,
|
||||||
|
selectedOptions: [{ text: 'B', value: 'B' }],
|
||||||
|
selectedValues: ['B'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('toolbar-position prop', () => {
|
test('should not emit change event if modelValue is not changed', async () => {
|
||||||
|
const columns = [
|
||||||
|
{ text: 'A', value: 'A' },
|
||||||
|
{ text: 'B', value: 'B' },
|
||||||
|
];
|
||||||
|
const wrapper = mount(Picker, {
|
||||||
|
props: {
|
||||||
|
modelValue: ['B'],
|
||||||
|
columns,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await wrapper.findAll('.van-picker-column__item')[1].trigger('click');
|
||||||
|
expect(wrapper.emitted('change')).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not emit change event when after clicking a disabled option', async () => {
|
||||||
|
const columns = [
|
||||||
|
{ text: 'A', value: 'A' },
|
||||||
|
{ text: 'B', value: 'B', disabled: true },
|
||||||
|
];
|
||||||
|
const wrapper = mount(Picker, {
|
||||||
|
props: {
|
||||||
|
columns,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await wrapper.findAll('.van-picker-column__item')[1].trigger('click');
|
||||||
|
expect(wrapper.emitted<[string, number]>('change')).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should render bottom toolbar when toolbar-position is bottom', () => {
|
||||||
const wrapper = mount(Picker, {
|
const wrapper = mount(Picker, {
|
||||||
props: {
|
props: {
|
||||||
showToolbar: true,
|
showToolbar: true,
|
||||||
@ -254,66 +130,67 @@ test('toolbar-position prop', () => {
|
|||||||
expect(wrapper.html()).toMatchSnapshot();
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('not allow html', () => {
|
test('should not allow to render html text', () => {
|
||||||
const wrapper = mount(Picker, {
|
const wrapper = mount(Picker, {
|
||||||
props: {
|
props: {
|
||||||
allowHtml: false,
|
allowHtml: false,
|
||||||
columns: ['<div>option</div>'],
|
columns: [{ text: '<div>option</div>' }],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.html()).toMatchSnapshot();
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('columns-top、columns-bottom prop', () => {
|
test('should allow to update columns props dynamically', async () => {
|
||||||
const wrapper = mount(Picker, {
|
const wrapper = mount(Picker, {
|
||||||
props: {
|
props: {
|
||||||
showToolbar: true,
|
modelValue: ['2'],
|
||||||
},
|
columns: [
|
||||||
slots: {
|
{ text: '1', value: '1' },
|
||||||
'columns-top': () => 'Custom Columns Top',
|
{ text: '2', value: '2' },
|
||||||
'columns-bottom': () => 'Custom Columns Bottom',
|
],
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(wrapper.html()).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('watch columns change', async () => {
|
|
||||||
const wrapper = mount(Picker, {
|
|
||||||
props: {
|
|
||||||
showToolbar: true,
|
|
||||||
columns: ['1', '2'],
|
|
||||||
defaultIndex: 1,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await wrapper.setProps({
|
await wrapper.setProps({
|
||||||
columns: ['2', '3'],
|
columns: [
|
||||||
|
{ text: '2', value: '2' },
|
||||||
|
{ text: '3', value: '3' },
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
wrapper.find('.van-picker__confirm').trigger('click');
|
wrapper.find('.van-picker__confirm').trigger('click');
|
||||||
expect(wrapper.emitted<[string, number]>('confirm')![0]).toEqual(['3', 1]);
|
expect(wrapper.emitted<[string, number]>('confirm')![0]).toEqual([
|
||||||
|
{ selectedOptions: [{ text: '2', value: '2' }], selectedValues: ['2'] },
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not reset index when columns unchanged', async () => {
|
test('should not reset index when columns unchanged', async () => {
|
||||||
const wrapper = mount(Picker, {
|
const wrapper = mount(Picker, {
|
||||||
props: {
|
props: {
|
||||||
|
modelValue: ['2'],
|
||||||
showToolbar: true,
|
showToolbar: true,
|
||||||
columns: ['1', '2'],
|
columns: [
|
||||||
|
{ text: '1', value: '1' },
|
||||||
|
{ text: '2', value: '2' },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
(wrapper.vm as Record<string, any>).setIndexes([1]);
|
|
||||||
await wrapper.setProps({
|
await wrapper.setProps({
|
||||||
columns: ['1', '2'],
|
columns: [
|
||||||
|
{ text: '1', value: '1' },
|
||||||
|
{ text: '2', value: '2' },
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
wrapper.find('.van-picker__confirm').trigger('click');
|
await wrapper.find('.van-picker__confirm').trigger('click');
|
||||||
expect(wrapper.emitted<[string, number]>('confirm')![0]).toEqual(['2', 1]);
|
expect(wrapper.emitted<[string, number]>('confirm')![0]).toEqual([
|
||||||
|
{ selectedOptions: [{ text: '2', value: '2' }], selectedValues: ['2'] },
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('set rem item-height', async () => {
|
test('should allow to set rem option height', async () => {
|
||||||
const originGetComputedStyle = window.getComputedStyle;
|
const originGetComputedStyle = window.getComputedStyle;
|
||||||
|
|
||||||
window.getComputedStyle = () => ({ fontSize: '16px' } as CSSStyleDeclaration);
|
window.getComputedStyle = () => ({ fontSize: '16px' } as CSSStyleDeclaration);
|
||||||
@ -321,27 +198,29 @@ test('set rem item-height', async () => {
|
|||||||
const wrapper = mount(Picker, {
|
const wrapper = mount(Picker, {
|
||||||
props: {
|
props: {
|
||||||
columns: simpleColumn.slice(0, 2),
|
columns: simpleColumn.slice(0, 2),
|
||||||
itemHeight: '10rem',
|
optionHeight: '10rem',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await later();
|
await later();
|
||||||
expect(wrapper.html()).toMatchSnapshot();
|
expect(wrapper.find('.van-picker-column__item').style.height).toEqual(
|
||||||
|
'160px'
|
||||||
|
);
|
||||||
|
|
||||||
window.getComputedStyle = originGetComputedStyle;
|
window.getComputedStyle = originGetComputedStyle;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('readonly prop', () => {
|
test('should not allow to change option when using readonly prop', async () => {
|
||||||
const wrapper = mount(Picker, {
|
const wrapper = mount(Picker, {
|
||||||
props: {
|
props: {
|
||||||
columns,
|
columns: simpleColumn,
|
||||||
readonly: true,
|
readonly: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
triggerDrag(wrapper.find('.van-picker-column'), 0, -100);
|
triggerDrag(wrapper.find('.van-picker-column'), 0, -100);
|
||||||
wrapper.find('.van-picker-column ul').trigger('transitionend');
|
await wrapper.find('.van-picker-column ul').trigger('transitionend');
|
||||||
wrapper.findAll('.van-picker-column__item')[3].trigger('click');
|
await wrapper.findAll('.van-picker-column__item')[3].trigger('click');
|
||||||
|
|
||||||
expect(wrapper.emitted('change')).toBeFalsy();
|
expect(wrapper.emitted('change')).toBeFalsy();
|
||||||
});
|
});
|
||||||
@ -349,7 +228,7 @@ test('readonly prop', () => {
|
|||||||
test('should not render mask and frame when options is empty', async () => {
|
test('should not render mask and frame when options is empty', async () => {
|
||||||
const wrapper = mount(Picker, {
|
const wrapper = mount(Picker, {
|
||||||
props: {
|
props: {
|
||||||
columns: [{ values: [] }],
|
columns: [[], []],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
expect(wrapper.find('.van-picker__mask').exists()).toBeFalsy();
|
expect(wrapper.find('.van-picker__mask').exists()).toBeFalsy();
|
||||||
|
64
packages/vant/src/picker/test/slots.spec.ts
Normal file
64
packages/vant/src/picker/test/slots.spec.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import { mount } from '../../../test';
|
||||||
|
import { Picker, PickerOption } from '..';
|
||||||
|
|
||||||
|
const simpleColumn = [
|
||||||
|
{ text: '1990', value: '1990' },
|
||||||
|
{ text: '1991', value: '1991' },
|
||||||
|
];
|
||||||
|
|
||||||
|
test('should render title slot correctly', () => {
|
||||||
|
const wrapper = mount(Picker, {
|
||||||
|
slots: {
|
||||||
|
title: () => 'Custom title',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should render toolbar slot correctly', () => {
|
||||||
|
const wrapper = mount(Picker, {
|
||||||
|
slots: {
|
||||||
|
toolbar: () => 'Custom toolbar',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should render confirm/cancel slot correctly', () => {
|
||||||
|
const wrapper = mount(Picker, {
|
||||||
|
slots: {
|
||||||
|
confirm: () => 'Custom Confirm',
|
||||||
|
cancel: () => 'Custom Cancel',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should render option slot correctly', () => {
|
||||||
|
const wrapper = mount(Picker, {
|
||||||
|
props: {
|
||||||
|
columns: simpleColumn,
|
||||||
|
},
|
||||||
|
slots: {
|
||||||
|
option: (option: PickerOption) => `Custom ${option.text}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should render columns-top、columns-bottom slots correctly', () => {
|
||||||
|
const wrapper = mount(Picker, {
|
||||||
|
props: {
|
||||||
|
showToolbar: true,
|
||||||
|
},
|
||||||
|
slots: {
|
||||||
|
'columns-top': () => 'Custom Columns Top',
|
||||||
|
'columns-bottom': () => 'Custom Columns Bottom',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.html()).toMatchSnapshot();
|
||||||
|
});
|
@ -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;
|
||||||
|
};
|
||||||
|
110
packages/vant/src/picker/utils.ts
Normal file
110
packages/vant/src/picker/utils.ts
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
import { isDef, clamp, extend } from '../utils';
|
||||||
|
import type { Ref } from 'vue';
|
||||||
|
import type { PickerOption, PickerColumn, PickerFieldNames } from './types';
|
||||||
|
|
||||||
|
export function getFirstEnabledOption(options: PickerOption[]) {
|
||||||
|
return options.find((option) => !option.disabled) || options[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getColumnsType(
|
||||||
|
columns: PickerColumn | PickerColumn[],
|
||||||
|
fields: Required<PickerFieldNames>
|
||||||
|
) {
|
||||||
|
const firstColumn = columns[0];
|
||||||
|
if (firstColumn) {
|
||||||
|
if (Array.isArray(firstColumn)) {
|
||||||
|
return 'multiple';
|
||||||
|
}
|
||||||
|
if (fields.children in firstColumn) {
|
||||||
|
return 'cascade';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 'default';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findIndexOfEnabledOption(
|
||||||
|
options: PickerOption[],
|
||||||
|
index: number
|
||||||
|
) {
|
||||||
|
index = clamp(index, 0, options.length);
|
||||||
|
|
||||||
|
for (let i = index; i < options.length; i++) {
|
||||||
|
if (!options[i].disabled) return i;
|
||||||
|
}
|
||||||
|
for (let i = index - 1; i >= 0; i--) {
|
||||||
|
if (!options[i].disabled) return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findOptionByValue(
|
||||||
|
options: PickerOption[],
|
||||||
|
value: number | string,
|
||||||
|
fields: Required<PickerFieldNames>
|
||||||
|
) {
|
||||||
|
const index = options.findIndex((option) => option[fields.value] === value);
|
||||||
|
const enabledIndex = findIndexOfEnabledOption(options, index);
|
||||||
|
return options[enabledIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatCascadeColumns(
|
||||||
|
columns: PickerColumn | PickerColumn[],
|
||||||
|
fields: Required<PickerFieldNames>,
|
||||||
|
selectedValues: Ref<Array<number | string>>
|
||||||
|
) {
|
||||||
|
const formatted: PickerColumn[] = [];
|
||||||
|
|
||||||
|
let cursor: PickerOption | undefined = {
|
||||||
|
[fields.children]: columns,
|
||||||
|
};
|
||||||
|
let columnIndex = 0;
|
||||||
|
|
||||||
|
while (cursor && cursor[fields.children]) {
|
||||||
|
const options: PickerOption[] = cursor[fields.children];
|
||||||
|
const value = selectedValues.value[columnIndex];
|
||||||
|
|
||||||
|
cursor = isDef(value)
|
||||||
|
? findOptionByValue(options, value, fields)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (!cursor && options.length) {
|
||||||
|
const firstValue = getFirstEnabledOption(options)[fields.value];
|
||||||
|
cursor = findOptionByValue(options, firstValue, fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
columnIndex++;
|
||||||
|
formatted.push(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatted;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getElementTranslateY(element: Element) {
|
||||||
|
const { transform } = window.getComputedStyle(element);
|
||||||
|
const translateY = transform.slice(7, transform.length - 1).split(', ')[5];
|
||||||
|
return Number(translateY);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isValuesEqual(
|
||||||
|
valuesA: Array<string | number>,
|
||||||
|
valuesB: Array<string | number>
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
valuesA.length === valuesB.length &&
|
||||||
|
valuesA.every((value, index) => value === valuesB[index])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assignDefaultFields(
|
||||||
|
fields: PickerFieldNames | undefined
|
||||||
|
): Required<PickerFieldNames> {
|
||||||
|
return extend(
|
||||||
|
{
|
||||||
|
text: 'text',
|
||||||
|
value: 'value',
|
||||||
|
children: 'children',
|
||||||
|
},
|
||||||
|
fields
|
||||||
|
);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user