feat: update autocomplete

pull/2523/head
tangjinzhou 2020-07-02 00:24:44 +08:00
parent 5e80e8019e
commit ad6f343376
5 changed files with 104 additions and 94 deletions

View File

@ -2,6 +2,7 @@ import isPlainObject from 'lodash/isPlainObject';
import classNames from 'classnames';
import { isVNode, Fragment, Comment, Text } from 'vue';
import { camelize, hyphenate, isOn, resolvePropValue } from './util';
import isValid from './isValid';
// function getType(fn) {
// const match = fn && fn.toString().match(/^\s*function (\w+)/);
// return match ? match[1] : '';
@ -82,6 +83,8 @@ const flattenChildren = (children = [], filterEmpty = true) => {
} else if (!filterEmpty) {
res.push(child);
}
} else if (isValid(child)) {
res.push(child);
}
});
return res;

View File

@ -1,53 +1,59 @@
import PropTypes from '../_util/vue-types';
import { cloneElement } from '../_util/vnode';
import { getOptionProps, getListeners } from '../_util/props-util';
function chaining(...fns) {
return function(...args) {
// eslint-disable-line
// eslint-disable-line
for (let i = 0; i < fns.length; i++) {
if (fns[i] && typeof fns[i] === 'function') {
fns[i].apply(this, args);
}
}
};
}
export default {
name: 'InputElement',
inheritAttrs: false,
props: {
value: PropTypes.any,
disabled: PropTypes.bool,
placeholder: PropTypes.string,
},
render() {
const { $slots = {}, $attrs = {}, placeholder } = this;
const listeners = getListeners(this);
const props = getOptionProps(this);
const value = props.value === undefined ? '' : props.value;
const children = $slots.default[0];
const { componentOptions = {} } = $slots.default[0];
const { listeners: events = {} } = componentOptions;
const newEvent = { ...events };
import { flattenChildren } from '../_util/props-util';
// function chaining(...fns) {
// return function(...args) {
// // eslint-disable-line
// // eslint-disable-line
// for (let i = 0; i < fns.length; i++) {
// if (fns[i] && typeof fns[i] === 'function') {
// fns[i].apply(this, args);
// }
// }
// };
// }
// export default {
// name: 'InputElement',
// inheritAttrs: false,
// props: {
// value: PropTypes.any,
// disabled: PropTypes.bool,
// placeholder: PropTypes.string,
// },
// render() {
// const { $slots = {}, $attrs = {}, placeholder } = this;
// const listeners = getListeners(this);
// const props = getOptionProps(this);
// const value = props.value === undefined ? '' : props.value;
// const children = getSlot(this)[0];
// const { componentOptions = {} } = $slots.default[0];
// const { listeners: events = {} } = componentOptions;
// const newEvent = { ...events };
for (const [eventName, event] of Object.entries(listeners)) {
newEvent[eventName] = chaining(event, events[eventName]);
}
const attrs = { ...$attrs, value };
// https://github.com/vueComponent/ant-design-vue/issues/1761
delete props.placeholder;
if (placeholder) {
props.placeholder = placeholder;
attrs.placeholder = placeholder;
}
return cloneElement(children, {
domProps: {
value,
},
props,
on: newEvent,
attrs,
ref: 'ele',
});
},
// for (const [eventName, event] of Object.entries(listeners)) {
// newEvent[eventName] = chaining(event, events[eventName]);
// }
// const attrs = { ...$attrs, value };
// // https://github.com/vueComponent/ant-design-vue/issues/1761
// delete props.placeholder;
// if (placeholder) {
// props.placeholder = placeholder;
// attrs.placeholder = placeholder;
// }
// return cloneElement(children, {
// domProps: {
// value,
// },
// props,
// on: newEvent,
// attrs,
// ref: 'ele',
// });
// },
// };
const InputElement = (_, { attrs, slots }) => {
const children = flattenChildren(slots.default?.())[0];
return cloneElement(children, { ...attrs });
};
InputElement.inheritAttrs = false;
export default InputElement;

View File

@ -1,17 +1,11 @@
import { inject, provide } from 'vue';
import { Option, OptGroup } from '../vc-select';
import Select, { AbstractSelectProps, SelectValue } from '../select';
import Input from '../input';
import InputElement from './InputElement';
import PropTypes from '../_util/vue-types';
import { ConfigConsumerProps } from '../config-provider';
import {
getComponentFromProp,
getOptionProps,
filterEmpty,
isValidElement,
getListeners,
} from '../_util/props-util';
import Base from '../base';
import { getComponent, getOptionProps, isValidElement, getSlot } from '../_util/props-util';
// const DataSourceItemObject = PropTypes.shape({
// value: String,
@ -26,6 +20,9 @@ import Base from '../base';
// onChange?: React.FormEventHandler<any>;
// value: any;
// }
function isSelectOptionOrSelectOptGroup(child) {
return child && child.type && (child.type.isSelectOption || child.type.isSelectOptGroup);
}
const AutoCompleteProps = {
...AbstractSelectProps(),
@ -41,6 +38,7 @@ const AutoCompleteProps = {
const AutoComplete = {
name: 'AAutoComplete',
inheritAttrs: false,
props: {
...AutoCompleteProps,
prefixCls: PropTypes.string.def('ant-select'),
@ -55,50 +53,53 @@ const AutoComplete = {
},
Option: { ...Option, name: 'AAutoCompleteOption' },
OptGroup: { ...OptGroup, name: 'AAutoCompleteOptGroup' },
model: {
prop: 'value',
event: 'change',
},
inject: {
configProvider: { default: () => ConfigConsumerProps },
},
provide() {
// model: {
// prop: 'value',
// event: 'change',
// },
setup() {
return {
savePopupRef: this.savePopupRef,
configProvider: inject('configProvider', ConfigConsumerProps),
};
},
created() {
provide('savePopupRef', this.savePopupRef);
},
methods: {
savePopupRef(ref) {
this.popupRef = ref;
},
saveSelect(node) {
this.select = node;
},
getInputElement() {
const { $slots, placeholder } = this;
const children = filterEmpty($slots.default);
const { placeholder } = this;
const children = getSlot(this);
const element = children.length ? children[0] : <Input lazy={false} />;
return <InputElement placeholder={placeholder}>{element}</InputElement>;
},
focus() {
if (this.$refs.select) {
this.$refs.select.focus();
if (this.select) {
this.select.focus();
}
},
blur() {
if (this.$refs.select) {
this.$refs.select.blur();
if (this.select) {
this.select.blur();
}
},
},
render() {
const { size, prefixCls: customizePrefixCls, optionLabelProp, dataSource, $slots } = this;
const { size, prefixCls: customizePrefixCls, optionLabelProp, dataSource } = this;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('select', customizePrefixCls);
const { class: className } = this.$attrs;
const cls = {
[className]: !!className,
[`${prefixCls}-lg`]: size === 'large',
[`${prefixCls}-sm`]: size === 'small',
[`${prefixCls}-show-search`]: true,
@ -106,8 +107,8 @@ const AutoComplete = {
};
let options;
const childArray = filterEmpty($slots.dataSource);
if (childArray.length) {
const childArray = getSlot(this, 'dataSource');
if (childArray.length && isSelectOptionOrSelectOptGroup(childArray[0])) {
options = childArray;
} else {
options = dataSource
@ -129,28 +130,25 @@ const AutoComplete = {
: [];
}
const selectProps = {
props: {
...getOptionProps(this),
mode: Select.SECRET_COMBOBOX_MODE_DO_NOT_USE,
optionLabelProp,
getInputElement: this.getInputElement,
notFoundContent: getComponentFromProp(this, 'notFoundContent'),
placeholder: '',
},
...getOptionProps(this),
...this.$attrs,
mode: Select.SECRET_COMBOBOX_MODE_DO_NOT_USE,
optionLabelProp,
getInputElement: this.getInputElement,
notFoundContent: getComponent(this, 'notFoundContent'),
placeholder: '',
class: cls,
ref: 'select',
on: getListeners(this),
ref: this.saveSelect,
};
return <Select {...selectProps}>{options}</Select>;
},
};
/* istanbul ignore next */
AutoComplete.install = function(Vue) {
Vue.use(Base);
Vue.component(AutoComplete.name, AutoComplete);
Vue.component(AutoComplete.Option.name, AutoComplete.Option);
Vue.component(AutoComplete.OptGroup.name, AutoComplete.OptGroup);
AutoComplete.install = function(app) {
app.component(AutoComplete.name, AutoComplete);
app.component(AutoComplete.Option.name, AutoComplete.Option);
app.component(AutoComplete.OptGroup.name, AutoComplete.OptGroup);
};
export default AutoComplete;

View File

@ -33,7 +33,8 @@ export function getPropValue(child, prop) {
return getValuePropValue(child);
}
if (prop === 'children') {
const newChild = cloneElement(getComponent(child));
const temp = getComponent(child);
const newChild = isVNode(temp) ? cloneElement(temp) : temp;
if (isVNode(newChild) && newChild.type === Text) {
return newChild.children;
}

View File

@ -2,6 +2,7 @@ import '@babel/polyfill';
import { createApp } from 'vue';
import App from './App.vue';
import {
AutoComplete,
Radio,
Spin,
Select,
@ -49,4 +50,5 @@ app
.use(Row)
.use(Radio)
.use(InputNumber)
.use(AutoComplete)
.mount('#app');