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
|
||||
|
||||
### Props
|
||||
@ -265,6 +322,7 @@ export default {
|
||||
| Attribute | Description | Type | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| columns | Columns data | _Column[]_ | `[]` |
|
||||
| columns-field-names | custom columns field | _object_ | `{ text: 'text', values: 'values', children: 'children' }` |
|
||||
| title | Toolbar title | _string_ | - |
|
||||
| confirm-button-text | Text of confirm button | _string_ | `Confirm` |
|
||||
| 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
|
||||
|
||||
### Props
|
||||
@ -288,6 +345,7 @@ export default {
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| columns | 对象数组,配置每一列显示的数据 | _Column[]_ | `[]` |
|
||||
| columns-field-names | 自定义`columns`结构中的字段 | _object_ | `{ text: 'text', values: 'values', children: 'children' }` |
|
||||
| title | 顶部栏标题 | _string_ | - |
|
||||
| confirm-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>
|
||||
</demo-block>
|
||||
<demo-block card :title="t('customChildrenKey')">
|
||||
<van-picker
|
||||
:title="t('title')"
|
||||
:columns="t('customChildrenColumns')"
|
||||
:columns-field-names="customFieldName"
|
||||
/>
|
||||
</demo-block>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
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 Toast from '../../toast';
|
||||
|
||||
@ -85,6 +92,8 @@ const i18n = {
|
||||
cascadeColumns: cascadeColumns['zh-CN'],
|
||||
multipleColumns: '多列选择',
|
||||
setColumnValues: '动态设置选项',
|
||||
customChildrenKey: '自定义Columns字段',
|
||||
customChildrenColumns: cascadeColumnsCustomKey['zh-CN'],
|
||||
textColumns: [
|
||||
'杭州',
|
||||
'宁波',
|
||||
@ -118,6 +127,8 @@ const i18n = {
|
||||
cascadeColumns: cascadeColumns['en-US'],
|
||||
multipleColumns: 'Multiple Columns',
|
||||
setColumnValues: 'Set Column Values',
|
||||
customChildrenKey: 'Custom Columns Fields',
|
||||
customChildrenColumns: cascadeColumnsCustomKey['en-US'],
|
||||
textColumns: ['Delaware', 'Florida', 'Georqia', 'Indiana', 'Maine'],
|
||||
disabledColumns: [
|
||||
{ text: 'Delaware', disabled: true },
|
||||
@ -139,6 +150,10 @@ export default {
|
||||
const state = reactive({
|
||||
showPicker: false,
|
||||
fieldValue: '',
|
||||
customFieldName: {
|
||||
text: 'cityName',
|
||||
children: 'cities',
|
||||
},
|
||||
});
|
||||
|
||||
const columns = computed(() => {
|
||||
|
@ -22,6 +22,7 @@ export default createComponent({
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
columnsFieldNames: Object,
|
||||
defaultIndex: {
|
||||
type: [Number, String],
|
||||
default: 0,
|
||||
@ -40,6 +41,12 @@ export default createComponent({
|
||||
|
||||
setup(props, { emit, slots }) {
|
||||
const formattedColumns = ref([]);
|
||||
const { text, values: valuesKey, children: childKey } = {
|
||||
text: props.valueKey, // 向下兼容
|
||||
values: 'values',
|
||||
children: 'children',
|
||||
...(props.columnsFieldNames || {}),
|
||||
};
|
||||
|
||||
const { children, linkChildren } = useChildren(PICKER_KEY);
|
||||
|
||||
@ -51,10 +58,10 @@ export default createComponent({
|
||||
const { columns } = props;
|
||||
const firstColumn = columns[0] || {};
|
||||
|
||||
if (firstColumn.children) {
|
||||
if (firstColumn[childKey]) {
|
||||
return 'cascade';
|
||||
}
|
||||
if (firstColumn.values) {
|
||||
if (firstColumn[valuesKey]) {
|
||||
return 'object';
|
||||
}
|
||||
return 'text';
|
||||
@ -63,10 +70,10 @@ export default createComponent({
|
||||
const formatCascade = () => {
|
||||
const formatted = [];
|
||||
|
||||
let cursor = { children: props.columns };
|
||||
let cursor = { [childKey]: props.columns };
|
||||
|
||||
while (cursor && cursor.children) {
|
||||
const { children } = cursor;
|
||||
while (cursor && cursor[childKey]) {
|
||||
const children = cursor[childKey];
|
||||
let defaultIndex = cursor.defaultIndex ?? +props.defaultIndex;
|
||||
|
||||
while (children[defaultIndex] && children[defaultIndex].disabled) {
|
||||
@ -79,7 +86,7 @@ export default createComponent({
|
||||
}
|
||||
|
||||
formatted.push({
|
||||
values: cursor.children,
|
||||
[valuesKey]: cursor[childKey],
|
||||
className: cursor.className,
|
||||
defaultIndex,
|
||||
});
|
||||
@ -94,7 +101,7 @@ export default createComponent({
|
||||
const { columns } = props;
|
||||
|
||||
if (dataType.value === 'text') {
|
||||
formattedColumns.value = [{ values: columns }];
|
||||
formattedColumns.value = [{ [valuesKey]: columns }];
|
||||
} else if (dataType.value === 'cascade') {
|
||||
formatCascade();
|
||||
} else {
|
||||
@ -114,17 +121,17 @@ export default createComponent({
|
||||
};
|
||||
|
||||
const onCascadeChange = (columnIndex) => {
|
||||
let cursor = { children: props.columns };
|
||||
let cursor = { [childKey]: props.columns };
|
||||
const indexes = getIndexes();
|
||||
|
||||
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++;
|
||||
setColumnValues(columnIndex, cursor.children);
|
||||
cursor = cursor.children[cursor.defaultIndex || 0];
|
||||
setColumnValues(columnIndex, cursor[childKey]);
|
||||
cursor = cursor[childKey][cursor.defaultIndex || 0];
|
||||
}
|
||||
};
|
||||
|
||||
@ -258,14 +265,14 @@ export default createComponent({
|
||||
<PickerColumn
|
||||
v-slots={{ option: slots.option }}
|
||||
readonly={props.readonly}
|
||||
valueKey={props.valueKey}
|
||||
valueKey={text}
|
||||
allowHtml={props.allowHtml}
|
||||
className={item.className}
|
||||
itemHeight={itemHeight.value}
|
||||
defaultIndex={item.defaultIndex ?? +props.defaultIndex}
|
||||
swipeDuration={props.swipeDuration}
|
||||
visibleItemCount={props.visibleItemCount}
|
||||
initialOptions={item.values}
|
||||
initialOptions={item[valuesKey]}
|
||||
onChange={() => {
|
||||
onChange(columnIndex);
|
||||
}}
|
||||
|
@ -698,4 +698,107 @@ exports[`should render demo and match snapshot 1`] = `
|
||||
<transition-stub>
|
||||
</transition-stub>
|
||||
</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