mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
feat(Picker): custom columns children key (#7791)
This commit is contained in:
parent
680c93d103
commit
5d75aabaae
@ -258,6 +258,63 @@ export default {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Custom Columns Field
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-picker
|
||||||
|
:title="Title"
|
||||||
|
:columns="columns"
|
||||||
|
:columns-field-names="customFieldName"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { reactive } from 'vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
cityName: 'Zhejiang',
|
||||||
|
cities: [
|
||||||
|
{
|
||||||
|
cityName: 'Hangzhou',
|
||||||
|
cities: [{ cityName: 'Xihu' }, { cityName: 'Yuhang' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cityName: 'Wenzhou',
|
||||||
|
cities: [{ cityName: 'Lucheng' }, { cityName: 'Ouhai' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cityName: 'Fujian',
|
||||||
|
cities: [
|
||||||
|
{
|
||||||
|
cityName: 'Fuzhou',
|
||||||
|
cities: [{ cityName: 'Gulou' }, { cityName: 'Taijiang' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cityName: 'Xiamen',
|
||||||
|
cities: [{ cityName: 'Siming' }, { cityName: 'Haicang' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const customFieldName = {
|
||||||
|
text: 'cityName',
|
||||||
|
children: 'cities',
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
columns,
|
||||||
|
customFieldName,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
### Props
|
### Props
|
||||||
@ -265,6 +322,7 @@ export default {
|
|||||||
| Attribute | Description | Type | Default |
|
| Attribute | Description | Type | Default |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| columns | Columns data | _Column[]_ | `[]` |
|
| columns | Columns data | _Column[]_ | `[]` |
|
||||||
|
| columns-field-names | custom columns field | _object_ | `{ text: 'text', values: 'values', 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` |
|
||||||
|
@ -281,6 +281,63 @@ export default {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 自定义 Columns 的结构
|
||||||
|
|
||||||
|
```html
|
||||||
|
<van-picker
|
||||||
|
:title="标题"
|
||||||
|
:columns="columns"
|
||||||
|
:columns-field-names="customFieldName"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { reactive } from 'vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
setup() {
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
cityName: '浙江',
|
||||||
|
cities: [
|
||||||
|
{
|
||||||
|
cityName: '杭州',
|
||||||
|
cities: [{ cityName: '西湖区' }, { cityName: '余杭区' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cityName: '温州',
|
||||||
|
cities: [{ cityName: '鹿城区' }, { cityName: '瓯海区' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cityName: '福建',
|
||||||
|
cities: [
|
||||||
|
{
|
||||||
|
cityName: '福州',
|
||||||
|
cities: [{ cityName: '鼓楼区' }, { cityName: '台江区' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cityName: '厦门',
|
||||||
|
cities: [{ cityName: '思明区' }, { cityName: '海沧区' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const customFieldName = {
|
||||||
|
text: 'cityName',
|
||||||
|
children: 'cities',
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
columns,
|
||||||
|
customFieldName,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
### Props
|
### Props
|
||||||
@ -288,6 +345,7 @@ export default {
|
|||||||
| 参数 | 说明 | 类型 | 默认值 |
|
| 参数 | 说明 | 类型 | 默认值 |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| columns | 对象数组,配置每一列显示的数据 | _Column[]_ | `[]` |
|
| columns | 对象数组,配置每一列显示的数据 | _Column[]_ | `[]` |
|
||||||
|
| columns-field-names | 自定义`columns`结构中的字段 | _object_ | `{ text: 'text', values: 'values', children: 'children' }` |
|
||||||
| title | 顶部栏标题 | _string_ | - |
|
| title | 顶部栏标题 | _string_ | - |
|
||||||
| confirm-button-text | 确认按钮文字 | _string_ | `确认` |
|
| confirm-button-text | 确认按钮文字 | _string_ | `确认` |
|
||||||
| cancel-button-text | 取消按钮文字 | _string_ | `取消` |
|
| cancel-button-text | 取消按钮文字 | _string_ | `取消` |
|
||||||
|
@ -79,3 +79,62 @@ export const cascadeColumns = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const cascadeColumnsCustomKey = {
|
||||||
|
'zh-CN': [
|
||||||
|
{
|
||||||
|
cityName: '浙江',
|
||||||
|
cities: [
|
||||||
|
{
|
||||||
|
cityName: '杭州',
|
||||||
|
cities: [{ cityName: '西湖区' }, { cityName: '余杭区' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cityName: '温州',
|
||||||
|
cities: [{ cityName: '鹿城区' }, { cityName: '瓯海区' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cityName: '福建',
|
||||||
|
cities: [
|
||||||
|
{
|
||||||
|
cityName: '福州',
|
||||||
|
cities: [{ cityName: '鼓楼区' }, { cityName: '台江区' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cityName: '厦门',
|
||||||
|
cities: [{ cityName: '思明区' }, { cityName: '海沧区' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'en-US': [
|
||||||
|
{
|
||||||
|
cityName: 'Zhejiang',
|
||||||
|
cities: [
|
||||||
|
{
|
||||||
|
cityName: 'Hangzhou',
|
||||||
|
cities: [{ cityName: 'Xihu' }, { cityName: 'Yuhang' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cityName: 'Wenzhou',
|
||||||
|
cities: [{ cityName: 'Lucheng' }, { cityName: 'Ouhai' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cityName: 'Fujian',
|
||||||
|
cities: [
|
||||||
|
{
|
||||||
|
cityName: 'Fuzhou',
|
||||||
|
cities: [{ cityName: 'Gulou' }, { cityName: 'Taijiang' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cityName: 'Xiamen',
|
||||||
|
cities: [{ cityName: 'Siming' }, { cityName: 'Haicang' }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
@ -64,11 +64,18 @@
|
|||||||
/>
|
/>
|
||||||
</van-popup>
|
</van-popup>
|
||||||
</demo-block>
|
</demo-block>
|
||||||
|
<demo-block card :title="t('customChildrenKey')">
|
||||||
|
<van-picker
|
||||||
|
:title="t('title')"
|
||||||
|
:columns="t('customChildrenColumns')"
|
||||||
|
:columns-field-names="customFieldName"
|
||||||
|
/>
|
||||||
|
</demo-block>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { ref, computed, reactive, toRefs } from 'vue';
|
import { ref, computed, reactive, toRefs } from 'vue';
|
||||||
import { dateColumns, cascadeColumns } from './data';
|
import { dateColumns, cascadeColumns, cascadeColumnsCustomKey } from './data';
|
||||||
import { useTranslate } from '@demo/use-translate';
|
import { useTranslate } from '@demo/use-translate';
|
||||||
import Toast from '../../toast';
|
import Toast from '../../toast';
|
||||||
|
|
||||||
@ -85,6 +92,8 @@ const i18n = {
|
|||||||
cascadeColumns: cascadeColumns['zh-CN'],
|
cascadeColumns: cascadeColumns['zh-CN'],
|
||||||
multipleColumns: '多列选择',
|
multipleColumns: '多列选择',
|
||||||
setColumnValues: '动态设置选项',
|
setColumnValues: '动态设置选项',
|
||||||
|
customChildrenKey: '自定义Columns字段',
|
||||||
|
customChildrenColumns: cascadeColumnsCustomKey['zh-CN'],
|
||||||
textColumns: [
|
textColumns: [
|
||||||
'杭州',
|
'杭州',
|
||||||
'宁波',
|
'宁波',
|
||||||
@ -118,6 +127,8 @@ const i18n = {
|
|||||||
cascadeColumns: cascadeColumns['en-US'],
|
cascadeColumns: cascadeColumns['en-US'],
|
||||||
multipleColumns: 'Multiple Columns',
|
multipleColumns: 'Multiple Columns',
|
||||||
setColumnValues: 'Set Column Values',
|
setColumnValues: 'Set Column Values',
|
||||||
|
customChildrenKey: 'Custom Columns Fields',
|
||||||
|
customChildrenColumns: cascadeColumnsCustomKey['en-US'],
|
||||||
textColumns: ['Delaware', 'Florida', 'Georqia', 'Indiana', 'Maine'],
|
textColumns: ['Delaware', 'Florida', 'Georqia', 'Indiana', 'Maine'],
|
||||||
disabledColumns: [
|
disabledColumns: [
|
||||||
{ text: 'Delaware', disabled: true },
|
{ text: 'Delaware', disabled: true },
|
||||||
@ -139,6 +150,10 @@ export default {
|
|||||||
const state = reactive({
|
const state = reactive({
|
||||||
showPicker: false,
|
showPicker: false,
|
||||||
fieldValue: '',
|
fieldValue: '',
|
||||||
|
customFieldName: {
|
||||||
|
text: 'cityName',
|
||||||
|
children: 'cities',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const columns = computed(() => {
|
const columns = computed(() => {
|
||||||
|
@ -22,6 +22,7 @@ export default createComponent({
|
|||||||
type: Array,
|
type: Array,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
|
columnsFieldNames: Object,
|
||||||
defaultIndex: {
|
defaultIndex: {
|
||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
default: 0,
|
default: 0,
|
||||||
@ -40,6 +41,12 @@ export default createComponent({
|
|||||||
|
|
||||||
setup(props, { emit, slots }) {
|
setup(props, { emit, slots }) {
|
||||||
const formattedColumns = ref([]);
|
const formattedColumns = ref([]);
|
||||||
|
const { text, values: valuesKey, children: childKey } = {
|
||||||
|
text: props.valueKey, // 向下兼容
|
||||||
|
values: 'values',
|
||||||
|
children: 'children',
|
||||||
|
...(props.columnsFieldNames || {}),
|
||||||
|
};
|
||||||
|
|
||||||
const { children, linkChildren } = useChildren(PICKER_KEY);
|
const { children, linkChildren } = useChildren(PICKER_KEY);
|
||||||
|
|
||||||
@ -51,10 +58,10 @@ export default createComponent({
|
|||||||
const { columns } = props;
|
const { columns } = props;
|
||||||
const firstColumn = columns[0] || {};
|
const firstColumn = columns[0] || {};
|
||||||
|
|
||||||
if (firstColumn.children) {
|
if (firstColumn[childKey]) {
|
||||||
return 'cascade';
|
return 'cascade';
|
||||||
}
|
}
|
||||||
if (firstColumn.values) {
|
if (firstColumn[valuesKey]) {
|
||||||
return 'object';
|
return 'object';
|
||||||
}
|
}
|
||||||
return 'text';
|
return 'text';
|
||||||
@ -63,10 +70,10 @@ export default createComponent({
|
|||||||
const formatCascade = () => {
|
const formatCascade = () => {
|
||||||
const formatted = [];
|
const formatted = [];
|
||||||
|
|
||||||
let cursor = { children: props.columns };
|
let cursor = { [childKey]: props.columns };
|
||||||
|
|
||||||
while (cursor && cursor.children) {
|
while (cursor && cursor[childKey]) {
|
||||||
const { children } = cursor;
|
const children = cursor[childKey];
|
||||||
let defaultIndex = cursor.defaultIndex ?? +props.defaultIndex;
|
let defaultIndex = cursor.defaultIndex ?? +props.defaultIndex;
|
||||||
|
|
||||||
while (children[defaultIndex] && children[defaultIndex].disabled) {
|
while (children[defaultIndex] && children[defaultIndex].disabled) {
|
||||||
@ -79,7 +86,7 @@ export default createComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
formatted.push({
|
formatted.push({
|
||||||
values: cursor.children,
|
[valuesKey]: cursor[childKey],
|
||||||
className: cursor.className,
|
className: cursor.className,
|
||||||
defaultIndex,
|
defaultIndex,
|
||||||
});
|
});
|
||||||
@ -94,7 +101,7 @@ export default createComponent({
|
|||||||
const { columns } = props;
|
const { columns } = props;
|
||||||
|
|
||||||
if (dataType.value === 'text') {
|
if (dataType.value === 'text') {
|
||||||
formattedColumns.value = [{ values: columns }];
|
formattedColumns.value = [{ [valuesKey]: columns }];
|
||||||
} else if (dataType.value === 'cascade') {
|
} else if (dataType.value === 'cascade') {
|
||||||
formatCascade();
|
formatCascade();
|
||||||
} else {
|
} else {
|
||||||
@ -114,17 +121,17 @@ export default createComponent({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onCascadeChange = (columnIndex) => {
|
const onCascadeChange = (columnIndex) => {
|
||||||
let cursor = { children: props.columns };
|
let cursor = { [childKey]: props.columns };
|
||||||
const indexes = getIndexes();
|
const indexes = getIndexes();
|
||||||
|
|
||||||
for (let i = 0; i <= columnIndex; i++) {
|
for (let i = 0; i <= columnIndex; i++) {
|
||||||
cursor = cursor.children[indexes[i]];
|
cursor = cursor[childKey][indexes[i]];
|
||||||
}
|
}
|
||||||
|
|
||||||
while (cursor && cursor.children) {
|
while (cursor && cursor[childKey]) {
|
||||||
columnIndex++;
|
columnIndex++;
|
||||||
setColumnValues(columnIndex, cursor.children);
|
setColumnValues(columnIndex, cursor[childKey]);
|
||||||
cursor = cursor.children[cursor.defaultIndex || 0];
|
cursor = cursor[childKey][cursor.defaultIndex || 0];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -258,14 +265,14 @@ export default createComponent({
|
|||||||
<PickerColumn
|
<PickerColumn
|
||||||
v-slots={{ option: slots.option }}
|
v-slots={{ option: slots.option }}
|
||||||
readonly={props.readonly}
|
readonly={props.readonly}
|
||||||
valueKey={props.valueKey}
|
valueKey={text}
|
||||||
allowHtml={props.allowHtml}
|
allowHtml={props.allowHtml}
|
||||||
className={item.className}
|
className={item.className}
|
||||||
itemHeight={itemHeight.value}
|
itemHeight={itemHeight.value}
|
||||||
defaultIndex={item.defaultIndex ?? +props.defaultIndex}
|
defaultIndex={item.defaultIndex ?? +props.defaultIndex}
|
||||||
swipeDuration={props.swipeDuration}
|
swipeDuration={props.swipeDuration}
|
||||||
visibleItemCount={props.visibleItemCount}
|
visibleItemCount={props.visibleItemCount}
|
||||||
initialOptions={item.values}
|
initialOptions={item[valuesKey]}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
onChange(columnIndex);
|
onChange(columnIndex);
|
||||||
}}
|
}}
|
||||||
|
@ -698,4 +698,107 @@ exports[`should render demo and match snapshot 1`] = `
|
|||||||
<transition-stub>
|
<transition-stub>
|
||||||
</transition-stub>
|
</transition-stub>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="van-picker">
|
||||||
|
<div class="van-picker__toolbar">
|
||||||
|
<button type="button"
|
||||||
|
class="van-picker__cancel"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<div class="van-picker__title van-ellipsis">
|
||||||
|
Title
|
||||||
|
</div>
|
||||||
|
<button type="button"
|
||||||
|
class="van-picker__confirm"
|
||||||
|
>
|
||||||
|
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">
|
||||||
|
Zhejiang
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li role="button"
|
||||||
|
style="height: 44px;"
|
||||||
|
tabindex="0"
|
||||||
|
class="van-picker-column__item"
|
||||||
|
>
|
||||||
|
<div class="van-ellipsis">
|
||||||
|
Fujian
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<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">
|
||||||
|
Hangzhou
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li role="button"
|
||||||
|
style="height: 44px;"
|
||||||
|
tabindex="0"
|
||||||
|
class="van-picker-column__item"
|
||||||
|
>
|
||||||
|
<div class="van-ellipsis">
|
||||||
|
Wenzhou
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<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">
|
||||||
|
Xihu
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li role="button"
|
||||||
|
style="height: 44px;"
|
||||||
|
tabindex="0"
|
||||||
|
class="van-picker-column__item"
|
||||||
|
>
|
||||||
|
<div class="van-ellipsis">
|
||||||
|
Yuhang
|
||||||
|
</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>
|
||||||
`;
|
`;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user