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

View File

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

View File

@ -33,7 +33,8 @@ export function getPropValue(child, prop) {
return getValuePropValue(child); return getValuePropValue(child);
} }
if (prop === 'children') { 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) { if (isVNode(newChild) && newChild.type === Text) {
return newChild.children; return newChild.children;
} }

View File

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