From ad6f3433764044e8cada8ccb32000bfe844ee6a3 Mon Sep 17 00:00:00 2001 From: tangjinzhou <415800467@qq.com> Date: Thu, 2 Jul 2020 00:24:44 +0800 Subject: [PATCH] feat: update autocomplete --- components/_util/props-util.js | 3 + components/auto-complete/InputElement.jsx | 106 ++++++++++++---------- components/auto-complete/index.jsx | 84 +++++++++-------- components/vc-select/util.js | 3 +- examples/index.js | 2 + 5 files changed, 104 insertions(+), 94 deletions(-) diff --git a/components/_util/props-util.js b/components/_util/props-util.js index 930f8a3de..98314f755 100644 --- a/components/_util/props-util.js +++ b/components/_util/props-util.js @@ -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; diff --git a/components/auto-complete/InputElement.jsx b/components/auto-complete/InputElement.jsx index 131b3bf0a..fa3ac0abd 100644 --- a/components/auto-complete/InputElement.jsx +++ b/components/auto-complete/InputElement.jsx @@ -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; diff --git a/components/auto-complete/index.jsx b/components/auto-complete/index.jsx index 0d5d93814..b7cc47f2a 100644 --- a/components/auto-complete/index.jsx +++ b/components/auto-complete/index.jsx @@ -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; // 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] : ; return {element}; }, 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 ; }, }; /* 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; diff --git a/components/vc-select/util.js b/components/vc-select/util.js index 80f06b0f9..94d771e71 100644 --- a/components/vc-select/util.js +++ b/components/vc-select/util.js @@ -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; } diff --git a/examples/index.js b/examples/index.js index 077500338..fa856fc9d 100644 --- a/examples/index.js +++ b/examples/index.js @@ -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');