ColPicker
Use multi-column picker for cascading selection, providing better interaction experience. The multi-column picker supports unlimited level selection.
Note
Multi-column picker is commonly used for selecting provinces, cities, and districts. We use Vant's China province, city, and district data as the data source. You can install the @vant/area-data npm package to import it:
# via npm
npm i @vant/area-data
# via yarn
yarn add @vant/area-data
# via pnpm
pnpm add @vant/area-data
# via Bun
bun add @vant/area-data
To facilitate developers using @vant/area-data
for development and debugging, we have encapsulated useColPickerData
. You can directly use useColPickerData
to get the data source.
useColPickerData
wrapper based on @vant/area-data
// You can place this code in src/hooks/useColPickerData.ts in your project
import { useCascaderAreaData } from '@vant/area-data'
export type CascaderOption = {
text: string
value: string
children?: CascaderOption[]
}
/**
* Use '@vant/area-data' as data source to construct ColPicker component data
* @returns
*/
export function useColPickerData() {
// '@vant/area-data' data source
const colPickerData: CascaderOption[] = useCascaderAreaData()
// Find child nodes by code, return all nodes if no code provided
function findChildrenByCode(data: CascaderOption[], code?: string): CascaderOption[] | null {
if (!code) {
return data
}
for (const item of data) {
if (item.value === code) {
return item.children || null
}
if (item.children) {
const childrenResult = findChildrenByCode(item.children, code)
if (childrenResult) {
return childrenResult
}
}
}
return null
}
return { colPickerData, findChildrenByCode }
}
Basic Usage
label
sets the left text content;
columns
sets the data source, which is a two-dimensional array. Each column is a one-dimensional array, and each option includes value
(option value) and label
(option name).
v-model
sets the selected value, which is an array;
You can also listen to the change
event to get the selected value. The event
is an object containing two properties: value
(selected value array) and selectedItems
(selected item object array).
Pass in the column-change
property, which is of type function
and receives an options object parameter. The structure of options is as follows:
Parameter | Type | Description | Version |
---|---|---|---|
selectedItem | object | Currently selected item in the column, data structure is consistent with the options in columns | - |
index | number | Current column index | - |
rowIndex | number | Current column selected item index | - |
resolve | function | Receives the option array for the next column | - |
finish | function | End picker selection, if cannot close normally like data fetch failure, execute finish(false) | - |
<wd-col-picker label="Select Address" v-model="value" :columns="area" :column-change="columnChange" @confirm="handleConfirm"></wd-col-picker>
// useColPickerData can be referenced from the introduction at the top of this section
// Adjust the import path according to your actual situation, don't just copy and paste
import { useColPickerData } from '@/hooks/useColPickerData'
const { colPickerData, findChildrenByCode } = useColPickerData()
const value = ref<string[]>([])
const area = ref<any[]>([
colPickerData.map((item) => {
return {
value: item.value,
label: item.text
}
})
])
const columnChange = ({ selectedItem, resolve, finish }) => {
const areaData = findChildrenByCode(colPickerData, selectedItem.value)
if (areaData && areaData.length) {
resolve(
areaData.map((item) => {
return {
value: item.value,
label: item.text
}
})
)
} else {
finish()
}
}
function handleConfirm({ value }) {
console.log(value)
}
Asynchronous Loading
Generally, column-change is an asynchronous data fetching operation. When column-change is triggered, the component will have a default loading state, which is closed after the data responds.
If the asynchronous data request fails, call finish(false)
.
<wd-col-picker label="Select Address" v-model="value" :columns="area" :column-change="columnChange" @confirm="handleConfirm"></wd-col-picker>
// useColPickerData can be referenced from the introduction at the top of this section
// Adjust the import path according to your actual situation, don't just copy and paste
import { useColPickerData } from '@/hooks/useColPickerData'
const { colPickerData, findChildrenByCode } = useColPickerData()
const value = ref<string[]>([])
const area = ref<any[]>([
colPickerData.map((item) => {
return {
value: item.value,
label: item.text
}
})
])
const columnChange = ({ selectedItem, resolve, finish }) => {
// Simulate asynchronous request
setTimeout(() => {
// Simulate request failure
if (Math.random() > 0.7) {
finish(false)
toast.error('Data request failed, please try again')
return
}
// Why use selectedItem.value as code? Because when constructing area, we put the identifier in the value field, similarly you can change it to other fields as long as they correspond to area's fields
const areaData = findChildrenByCode(colPickerData, selectedItem.value)
if (areaData && areaData.length) {
resolve(
areaData.map((item) => {
return {
value: item.value,
label: item.text
}
})
)
} else {
// When there are no more items, complete the operation
finish()
}
}, 300)
}
function handleConfirm({ value }) {
console.log(value)
}
Initial Options
There are two ways to set initial options:
- When setting initial options, the length of the
columns
array should match the length of thevalue
array, and each value invalue
must be found incolumns
.
<wd-col-picker label="Select Address" v-model="value" :columns="area" :column-change="columnChange"></wd-col-picker>
// useColPickerData can be referenced from the introduction at the top of this section
// Adjust the import path according to your actual situation, don't just copy and paste
import { useColPickerData } from '@/hooks/useColPickerData'
const { colPickerData, findChildrenByCode } = useColPickerData()
const value = ref<string[]>(['110000', '110100', '110101'])
const area = ref<any[]>([
colPickerData.map((item) => {
return {
value: item.value,
label: item.text
}
}),
findChildrenByCode(colPickerData, '110000')!.map((item) => {
return {
value: item.value,
label: item.text
}
}),
findChildrenByCode(colPickerData, '110100')!.map((item) => {
return {
value: item.value,
label: item.text
}
})
])
const columnChange = ({ selectedItem, resolve, finish, index }) => {
const areaData = findChildrenByCode(colPickerData, selectedItem.value)
if (areaData && areaData.length) {
resolve(
areaData.map((item) => {
return {
value: item.value,
label: item.text
}
})
)
} else {
finish()
}
}
- Use the
auto-complete
attribute. Whenauto-complete
istrue
, the component will automatically trigger thecolumn-change
event to complete the data.
<wd-col-picker label="Select Address" v-model="value" :columns="area" :column-change="columnChange" auto-complete></wd-col-picker>
// useColPickerData can be referenced from the introduction at the top of this section
// Adjust the import path according to your actual situation, don't just copy and paste
import { useColPickerData } from '@/hooks/useColPickerData'
const { colPickerData, findChildrenByCode } = useColPickerData()
const value = ref<string[]>(['110000', '110100', '110101'])
const area = ref<any[]>([
colPickerData.map((item) => {
return {
value: item.value,
label: item.text
}
})
])
const columnChange = ({ selectedItem, resolve, finish }) => {
const areaData = findChildrenByCode(colPickerData, selectedItem.value)
if (areaData && areaData.length) {
resolve(
areaData.map((item) => {
return {
value: item.value,
label: item.text
}
})
)
} else {
finish()
}
}
Disabled
Set disabled
to disable the picker.
<wd-col-picker label="Select Address" v-model="value" :columns="area" :column-change="columnChange" disabled></wd-col-picker>
Readonly
Set readonly
to make the picker readonly.
<wd-col-picker label="Select Address" v-model="value" :columns="area" :column-change="columnChange" readonly></wd-col-picker>
Disabled Options
Set the disabled
property in option data to disable specific options.
<wd-col-picker label="Select Address" v-model="value" :columns="area" :column-change="columnChange"></wd-col-picker>
const area = ref<any[]>([
[
{ value: '1', label: 'Beijing', disabled: true },
{ value: '2', label: 'Shanghai' },
{ value: '3', label: 'Shenzhen' }
]
])
const columnChange = ({ selectedItem, resolve, finish }) => {
if (selectedItem.value === '1') {
resolve([
{ value: '11', label: 'Dongcheng District' },
{ value: '12', label: 'Xicheng District' }
])
} else if (selectedItem.value === '2') {
resolve([
{ value: '21', label: 'Huangpu District' },
{ value: '22', label: 'Xuhui District' }
])
} else {
finish()
}
}
Option Tips
Set the tip
property in option data to show tips for options.
<wd-col-picker label="Select Address" v-model="value" :columns="area" :column-change="columnChange"></wd-col-picker>
const area = ref<any[]>([
[
{ value: '1', label: 'Beijing', tip: 'Capital' },
{ value: '2', label: 'Shanghai', tip: 'Municipality' },
{ value: '3', label: 'Shenzhen', tip: 'Special Economic Zone' }
]
])
const columnChange = ({ selectedItem, resolve, finish }) => {
if (selectedItem.value === '1') {
resolve([
{ value: '11', label: 'Dongcheng District' },
{ value: '12', label: 'Xicheng District' }
])
} else if (selectedItem.value === '2') {
resolve([
{ value: '21', label: 'Huangpu District' },
{ value: '22', label: 'Xuhui District' }
])
} else {
finish()
}
}
Display Format
Set display-format
to customize the display text.
<wd-col-picker label="Select Address" v-model="value" :columns="area" :column-change="columnChange" :display-format="displayFormat"></wd-col-picker>
const displayFormat = (items) => {
return items.map((item) => item.label).join(' > ')
}
Set Title
Set title
to customize the popup title.
<wd-col-picker label="Select Address" v-model="value" :columns="area" :column-change="columnChange" title="Select Region"></wd-col-picker>
Before Confirm
Set before-confirm
to validate before confirming.
<wd-col-picker label="Select Address" v-model="value" :columns="area" :column-change="columnChange" :before-confirm="beforeConfirm"></wd-col-picker>
const beforeConfirm = (value, resolve) => {
if (value.length < 3) {
toast.error('Please select a complete address')
resolve(false)
} else {
resolve(true)
}
}
Error State
Set error
to show error state.
<wd-col-picker label="Select Address" v-model="value" :columns="area" :column-change="columnChange" error></wd-col-picker>
Required Style
Set required
to show required asterisk.
<wd-col-picker label="Select Address" v-model="value" :columns="area" :column-change="columnChange" required></wd-col-picker>
Required Marker Position
Set marker-side
to control the position of the required marker.
<wd-col-picker label="Select Address" v-model="value" :columns="area" :column-change="columnChange" required marker-side="after"></wd-col-picker>
Picker Size
Set size
to change picker size.
<wd-col-picker label="Select Address" v-model="value" :columns="area" :column-change="columnChange" size="large"></wd-col-picker>
Right Align Value
Set align-right
to right-align the picker value.
<wd-col-picker label="Select Address" v-model="value" :columns="area" :column-change="columnChange" align-right></wd-col-picker>
Custom Picker
Use slots to customize the picker display.
<wd-col-picker v-model="value" :columns="area" :column-change="columnChange" use-default-slot>
<wd-cell title="Select Address" :value="value.length ? displayFormat(selectedItems) : 'Please select'" is-link></wd-cell>
</wd-col-picker>
const selectedItems = ref([])
const displayFormat = (items) => {
return items.map((item) => item.label).join(' > ')
}
const handleConfirm = ({ selectedItems: items }) => {
selectedItems.value = items
}
Attributes
Attribute | Description | Type | Options | Default | Version |
---|---|---|---|---|---|
v-model | Selected value | array | - | - | - |
columns | Picker data, 2D array | array | - | - | - |
value-key | Key for the value property in option objects | string | - | value | - |
label-key | Key for the label property in option objects | string | - | label | - |
tip-key | Key for the tip property in option objects | string | - | tip | - |
title | Popup title | string | - | - | - |
label | Left-side text label | string | - | - | - |
placeholder | Placeholder text | string | - | Select | - |
disabled | Disabled state | boolean | - | false | - |
readonly | Readonly state | boolean | - | false | - |
display-format | Custom display text formatting function (returns a string) | function | - | - | - |
column-change | Function to handle column changes, receives current column's selected item, column index, selected item index, next column data handler resolve, and finish selection function | function | - | - | - |
size | Picker size | string | large | - | - |
label-width | Left-side label width | string | - | 33% | - |
error | Error state (displays value in red) | boolean | - | false | - |
required | Whether to display the required asterisk | boolean | - | false | - |
marker-side | Position of the required marker | string | before / after | before | 1.12.0 |
align-right | Right-align the picker value | boolean | - | false | - |
before-confirm | Validation function before confirming, receives (value, resolve) parameters, continue execution through resolve, resolve accepts 1 boolean parameter | function | - | - | - |
loading-color | Loading icon color | string | - | #4D80F0 | - |
use-default-slot | Set this option when using default slot | boolean | - | false | - |
use-label-slot | Set this option when using label slot | boolean | - | false | - |
close-on-click-modal | Whether to close when clicking modal | boolean | - | true | - |
auto-complete | Automatically trigger column-change event to complete data, triggers column-change when columns is empty array or columns array length is less than value array length | boolean | - | false | - |
z-index | Popup z-index | number | - | 15 | - |
safe-area-inset-bottom | Whether to enable bottom safe area adaptation for popup panel (iPhone X type models) | boolean | - | true | - |
ellipsis | Whether to hide overflow | boolean | - | false | - |
prop | Form field model property name, required when using form validation | string | - | - | - |
rules | Form validation rules, used with wd-form component | FormItemRule [] | - | [] | - |
lineWidth | Bottom line width in pixels | number | - | - | 1.3.7 |
lineHeight | Bottom line height in pixels | number | - | - | 1.3.7 |
root-portal | Whether to detach from the page, used to solve various fixed positioning issues | boolean | - | false | 1.11.0 |
FormItemRule Data Structure
Key | Description | Type |
---|---|---|
required | Whether it's a required field | boolean |
message | Error message | string |
validator | Validation through function, can return a Promise for async validation | (value, rule) => boolean | Promise |
pattern | Validation through regular expression, regex mismatch indicates validation failure | RegExp |
Option Data Structure
Key | Description | Type | Required | Version |
---|---|---|---|---|
value | Option value | string | Yes | - |
label | Option name | string | Yes | - |
tip | Option tip | string | No | - |
disabled | Disable option | boolean | No | - |
Events
Event Name | Description | Parameters | Version |
---|---|---|---|
confirm | Triggered when the last column option is selected | { value(option value array), selectedItems(option array) } | - |
close | Triggered when close button or overlay is clicked | - | - |
Methods
Method Name | Description | Parameters | Version |
---|---|---|---|
open | Open picker popup | - | - |
close | Close picker popup | - | - |
Slots
Name | Description | Version |
---|---|---|
default | Custom display | - |
label | Left slot | - |
External Style Classes
Class Name | Description | Version |
---|---|---|
custom-class | Root node style | - |
custom-label-class | Label external custom style | - |
custom-value-class | Value external custom style | - |