feat(Picker): custom columns children key (#7791)

This commit is contained in:
晓晓晓晓晓丶vv 2020-12-29 19:53:12 +08:00 committed by GitHub
parent 680c93d103
commit 5d75aabaae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 315 additions and 15 deletions

View File

@ -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` |

View File

@ -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_ | `取消` |

View File

@ -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' }],
},
],
},
],
};

View File

@ -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(() => {

View File

@ -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);
}}

View File

@ -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>
`;