feat: select add fieldNames

feat-css-var
tangjinzhou 2022-03-06 16:59:49 +08:00
parent 72e5afab9f
commit 741ec4c835
8 changed files with 125 additions and 21 deletions

View File

@ -1,17 +1,17 @@
import type { App, Plugin, ExtractPropTypes, PropType } from 'vue'; import type { App, Plugin, ExtractPropTypes, PropType, HTMLAttributes } from 'vue';
import { provide, defineComponent, ref, watch, computed, toRef } from 'vue'; import { provide, defineComponent, ref, watch, computed, toRef } from 'vue';
import PropTypes, { withUndefined } from '../_util/vue-types'; import PropTypes from '../_util/vue-types';
import type { SpinProps } from '../spin';
import Spin from '../spin'; import Spin from '../spin';
import type { PaginationConfig } from '../pagination'; import type { PaginationConfig } from '../pagination';
import Pagination, { paginationConfig } from '../pagination'; import Pagination from '../pagination';
import { Row } from '../grid'; import { Row } from '../grid';
import Item from './Item'; import Item from './Item';
import { flattenChildren } from '../_util/props-util'; import { flattenChildren } from '../_util/props-util';
import initDefaultProps from '../_util/props-util/initDefaultProps'; import initDefaultProps from '../_util/props-util/initDefaultProps';
import type { Key } from '../_util/type'; import type { Key } from '../_util/type';
import { tuple } from '../_util/type';
import ItemMeta from './ItemMeta'; import ItemMeta from './ItemMeta';
import useConfigInject from '../_util/hooks/useConfigInject'; import useConfigInject from '../_util/hooks/useConfigInject';
import useBreakpoint from '../_util/hooks/useBreakpoint'; import useBreakpoint from '../_util/hooks/useBreakpoint';
@ -36,41 +36,41 @@ export interface ListGridType {
xxxl?: ColumnCount; xxxl?: ColumnCount;
} }
export const ListSize = tuple('small', 'default', 'large'); export type ListSize = 'small' | 'default' | 'large';
export type ListItemLayout = 'horizontal' | 'vertical'; export type ListItemLayout = 'horizontal' | 'vertical';
export const listProps = { export const listProps = () => ({
bordered: PropTypes.looseBool, bordered: PropTypes.looseBool,
dataSource: PropTypes.array, dataSource: PropTypes.array,
extra: PropTypes.any, extra: PropTypes.any,
grid: { type: Object as PropType<ListGridType>, default: undefined }, grid: { type: Object as PropType<ListGridType>, default: undefined },
itemLayout: PropTypes.oneOf(tuple('horizontal', 'vertical')), itemLayout: String as PropType<ListItemLayout>,
loading: withUndefined(PropTypes.oneOfType([PropTypes.looseBool, PropTypes.object])), loading: {
type: [Boolean, Object] as PropType<boolean | (SpinProps & HTMLAttributes)>,
default: undefined as boolean | (SpinProps & HTMLAttributes),
},
loadMore: PropTypes.any, loadMore: PropTypes.any,
pagination: withUndefined( pagination: {
PropTypes.oneOfType([ type: [Boolean, Object] as PropType<false | PaginationConfig>,
PropTypes.shape<PaginationConfig>(paginationConfig()).loose, default: undefined as false | PaginationConfig,
PropTypes.looseBool, },
]), prefixCls: String,
),
prefixCls: PropTypes.string,
rowKey: [String, Number, Function] as PropType<Key | ((item: any) => Key)>, rowKey: [String, Number, Function] as PropType<Key | ((item: any) => Key)>,
renderItem: PropTypes.any, renderItem: PropTypes.any,
size: PropTypes.oneOf(ListSize), size: String as PropType<ListSize>,
split: PropTypes.looseBool, split: PropTypes.looseBool,
header: PropTypes.any, header: PropTypes.any,
footer: PropTypes.any, footer: PropTypes.any,
locale: { locale: {
type: Object as PropType<ListLocale>, type: Object as PropType<ListLocale>,
}, },
}; });
export interface ListLocale { export interface ListLocale {
emptyText: any; emptyText: any;
} }
export type ListProps = Partial<ExtractPropTypes<typeof listProps>>; export type ListProps = Partial<ExtractPropTypes<ReturnType<typeof listProps>>>;
import { ListContextKey } from './contextKey'; import { ListContextKey } from './contextKey';
import type { RenderEmptyHandler } from '../config-provider/renderEmpty'; import type { RenderEmptyHandler } from '../config-provider/renderEmpty';
@ -78,7 +78,7 @@ import type { RenderEmptyHandler } from '../config-provider/renderEmpty';
const List = defineComponent({ const List = defineComponent({
name: 'AList', name: 'AList',
Item, Item,
props: initDefaultProps(listProps, { props: initDefaultProps(listProps(), {
dataSource: [], dataSource: [],
bordered: false, bordered: false,
split: true, split: true,

View File

@ -153,6 +153,17 @@ exports[`renders ./components/select/demo/custom-dropdown-menu.vue correctly 1`]
</div> </div>
`; `;
exports[`renders ./components/select/demo/field-names.vue correctly 1`] = `
<div style="width: 120px;" class="ant-select ant-select-single ant-select-show-arrow">
<!---->
<!---->
<div class="ant-select-selector"><span class="ant-select-selection-search"><input id="rc_select_TEST_OR_SSR" autocomplete="off" class="ant-select-selection-search-input" style="opacity: 0;" role="combobox" aria-haspopup="listbox" aria-owns="rc_select_TEST_OR_SSR_list" aria-autocomplete="list" aria-controls="rc_select_TEST_OR_SSR_list" aria-activedescendant="rc_select_TEST_OR_SSR_list_0" readonly="" unselectable="on" type="search"></span><span class="ant-select-selection-item" title="Lucy">Lucy</span>
<!---->
</div><span class="ant-select-arrow" style="user-select: none;" unselectable="on" aria-hidden="true"><span role="img" aria-label="down" class="anticon anticon-down ant-select-suffix"><svg focusable="false" class="" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"></path></svg></span></span>
<!---->
</div>
`;
exports[`renders ./components/select/demo/hide-selected.vue correctly 1`] = ` exports[`renders ./components/select/demo/hide-selected.vue correctly 1`] = `
<div style="width: 100%;" class="ant-select ant-select-multiple ant-select-show-search"> <div style="width: 100%;" class="ant-select ant-select-multiple ant-select-show-search">
<!----> <!---->

View File

@ -0,0 +1,81 @@
<docs>
---
order: 0
title:
zh-CN: 自定义 labelvalueoptions 字段
en-US: Custom `label` `value` `options` field
---
## zh-CN
方便数据结构转换
仅支持 options 传递不支持 a-select-option 构造节点
## en-US
Easy data structure conversion.
Only options passing is supported, a-select-option construction node is not supported.
</docs>
<template>
<a-select
ref="select"
v-model:value="value"
style="width: 120px"
:options="options"
:field-names="{ label: 'name', value: 'id', options: 'children' }"
@focus="focus"
@change="handleChange"
></a-select>
</template>
<script lang="ts">
import type { SelectProps } from 'ant-design-vue';
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const options = ref<SelectProps['options']>([
{
id: 'jack',
name: 'Jack',
children: [
{
id: 'small jack',
name: 'samll Jack',
},
],
},
{
id: 'lucy',
name: 'Lucy',
},
{
id: 'disabled',
name: 'Disabled',
disabled: true,
},
{
id: 'yiminghe',
name: 'Yiminghe',
},
]);
const focus = () => {
console.log('focus');
};
const handleChange = (value: string) => {
console.log(`selected ${value}`);
};
return {
focus,
handleChange,
value: ref('lucy'),
options,
};
},
});
</script>

View File

@ -17,6 +17,7 @@
<CustomDropdownMenu /> <CustomDropdownMenu />
<OptionLabelProp /> <OptionLabelProp />
<BigData /> <BigData />
<fieldNamesVue />
</demo-sort> </demo-sort>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -37,6 +38,7 @@ import CustomDropdownMenu from './custom-dropdown-menu.vue';
import OptionLabelProp from './option-label-prop.vue'; import OptionLabelProp from './option-label-prop.vue';
import BigData from './big-data.vue'; import BigData from './big-data.vue';
import Responsive from './responsive.vue'; import Responsive from './responsive.vue';
import fieldNamesVue from './field-names.vue';
import CN from '../index.zh-CN.md'; import CN from '../index.zh-CN.md';
import US from '../index.en-US.md'; import US from '../index.en-US.md';
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
@ -44,6 +46,7 @@ export default defineComponent({
CN, CN,
US, US,
components: { components: {
fieldNamesVue,
Basic, Basic,
Size, Size,
Tags, Tags,

View File

@ -35,6 +35,7 @@ Select component to select value from options.
| dropdownRender | Customize dropdown content | ({menuNode: VNode, props}) => VNode \| v-slot | - | | | dropdownRender | Customize dropdown content | ({menuNode: VNode, props}) => VNode \| v-slot | - | |
| dropdownStyle | style of dropdown menu | object | - | | | dropdownStyle | style of dropdown menu | object | - | |
| dropdownMenuStyle | additional style applied to dropdown menu | object | - | | | dropdownMenuStyle | additional style applied to dropdown menu | object | - | |
| fieldNames | Customize node label, value, options field name | object | { label: `label`, value: `value`, options: `options` } | 3.0 |
| filterOption | If true, filter options by input, if function, filter options against it. The function will receive two arguments, `inputValue` and `option`, if the function returns `true`, the option will be included in the filtered set; Otherwise, it will be excluded. | boolean or function(inputValue, option) | true | | | filterOption | If true, filter options by input, if function, filter options against it. The function will receive two arguments, `inputValue` and `option`, if the function returns `true`, the option will be included in the filtered set; Otherwise, it will be excluded. | boolean or function(inputValue, option) | true | |
| firstActiveValue | Value of action option by default | string\|string\[] | - | | | firstActiveValue | Value of action option by default | string\|string\[] | - | |
| getPopupContainer | Parent Node which the selector should be rendered to. Default to `body`. When position issues happen, try to modify it into scrollable content and position it relative. | function(triggerNode) | () => document.body | | | getPopupContainer | Parent Node which the selector should be rendered to. Default to `body`. When position issues happen, try to modify it into scrollable content and position it relative. | function(triggerNode) | () => document.body | |

View File

@ -27,7 +27,13 @@ export interface LabeledValue {
export type SelectValue = RawValue | RawValue[] | LabeledValue | LabeledValue[] | undefined; export type SelectValue = RawValue | RawValue[] | LabeledValue | LabeledValue[] | undefined;
export const selectProps = () => ({ export const selectProps = () => ({
...omit(vcSelectProps<SelectValue>(), ['inputIcon', 'mode', 'getInputElement', 'backfill']), ...omit(vcSelectProps<SelectValue>(), [
'inputIcon',
'mode',
'getInputElement',
'getRawInputElement',
'backfill',
]),
value: { value: {
type: [Array, Object, String, Number] as PropType<SelectValue>, type: [Array, Object, String, Number] as PropType<SelectValue>,
}, },

View File

@ -36,6 +36,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/_0XzgOis7/Select.svg
| dropdownRender | 自定义下拉框内容 | ({menuNode: VNode, props}) => VNode \| v-slot | - | | | dropdownRender | 自定义下拉框内容 | ({menuNode: VNode, props}) => VNode \| v-slot | - | |
| dropdownStyle | 下拉菜单的 style 属性 | object | - | | | dropdownStyle | 下拉菜单的 style 属性 | object | - | |
| dropdownMenuStyle | dropdown 菜单自定义样式 | object | - | | | dropdownMenuStyle | dropdown 菜单自定义样式 | object | - | |
| fieldNames | 自定义节点 label、value、options 的字段 | object | { label: `label`, value: `value`, options: `options` } | 3.0 |
| filterOption | 是否根据输入项进行筛选。当其为一个函数时,会接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 `true`,反之则返回 `false`。 | boolean or function(inputValue, option) | true | | | filterOption | 是否根据输入项进行筛选。当其为一个函数时,会接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 `true`,反之则返回 `false`。 | boolean or function(inputValue, option) | true | |
| firstActiveValue | 默认高亮的选项 | string\|string\[] | - | | | firstActiveValue | 默认高亮的选项 | string\|string\[] | - | |
| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。 | Function(triggerNode) | () => document.body | | | getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。 | Function(triggerNode) | () => document.body | |

View File

@ -193,6 +193,7 @@
"prettier": "^2.2.0", "prettier": "^2.2.0",
"pretty-quick": "^3.0.0", "pretty-quick": "^3.0.0",
"prismjs": "^1.23.0", "prismjs": "^1.23.0",
"qs": "^6.10.3",
"query-string": "^7.0.1", "query-string": "^7.0.1",
"querystring": "^0.2.0", "querystring": "^0.2.0",
"raw-loader": "^4.0.2", "raw-loader": "^4.0.2",