Skip to content

Commit 7eeee69

Browse files
committed
perf: flatten children
1 parent dd68c0d commit 7eeee69

File tree

4 files changed

+80
-28
lines changed

4 files changed

+80
-28
lines changed

components/_util/props-util.js

+44-10
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,39 @@ const getSlots = ele => {
6767
});
6868
return { ...slots, ...getScopedSlots(ele) };
6969
};
70+
71+
const flattenChildren = (children = [], filterEmpty = true) => {
72+
const temp = Array.isArray(children) ? children : [children];
73+
const res = [];
74+
temp.forEach(child => {
75+
if (Array.isArray(child)) {
76+
res.push(...flattenChildren(child, filterEmpty));
77+
} else if (child && child.type === Fragment) {
78+
res.push(...flattenChildren(child.children, filterEmpty));
79+
} else if (child && isVNode(child)) {
80+
if (filterEmpty && !isEmptyElement(child)) {
81+
res.push(child);
82+
} else if (!filterEmpty) {
83+
res.push(child);
84+
}
85+
}
86+
});
87+
return res;
88+
};
89+
7090
const getSlot = (self, name = 'default', options = {}) => {
71-
let res = self.$slots[name] && self.$slots[name](options);
72-
while (res && res.length === 1 && (res[0].type === Fragment || Array.isArray(res[0]))) {
73-
res = res[0].children || res[0];
91+
if (isVNode(self)) {
92+
if (self.type === Fragment) {
93+
return name === 'default' ? flattenChildren(self.children) : [];
94+
} else if (self.children && self.children[name]) {
95+
return flattenChildren(self.children[name](options));
96+
} else {
97+
return [];
98+
}
99+
} else {
100+
let res = self.$slots[name] && self.$slots[name](options);
101+
return flattenChildren(res);
74102
}
75-
return res && res.__v_isVNode ? [res] : res;
76103
};
77104

78105
const getAllChildren = ele => {
@@ -128,26 +155,32 @@ const getOptionProps = instance => {
128155
return res;
129156
};
130157
const getComponent = (instance, prop = 'default', options = instance, execute = true) => {
158+
let com = undefined;
131159
if (instance.$) {
132160
const temp = instance[prop];
133161
if (temp !== undefined) {
134162
return typeof temp === 'function' && execute ? temp(options) : temp;
135163
} else {
136-
let com = instance.$slots[prop];
164+
com = instance.$slots[prop];
137165
com = execute && com ? com(options) : com;
138-
return Array.isArray(com) && com.length === 1 ? com[0] : com;
139166
}
140167
} else if (isVNode(instance)) {
141168
const temp = instance.props && instance.props[prop];
142-
if (temp !== undefined && temp !== null) {
169+
if (temp !== undefined && instance.props !== null) {
143170
return typeof temp === 'function' && execute ? temp(options) : temp;
171+
} else if (instance.type === Fragment) {
172+
com = instance.children;
144173
} else if (instance.children && instance.children[prop]) {
145-
let com = instance.children[prop];
174+
com = instance.children[prop];
146175
com = execute && com ? com(options) : com;
147-
return Array.isArray(com) && com.length === 1 ? com[0] : com;
148176
}
149177
}
150-
return undefined;
178+
if (Array.isArray(com)) {
179+
com = flattenChildren(com);
180+
com = com.length === 1 ? com[0] : com;
181+
com = com.length === 0 ? undefined : com;
182+
}
183+
return com;
151184
};
152185
const getComponentFromProp = (instance, prop, options = instance, execute = true) => {
153186
if (instance.$createElement) {
@@ -381,5 +414,6 @@ export {
381414
getAllProps,
382415
getAllChildren,
383416
findDOMNode,
417+
flattenChildren,
384418
};
385419
export default hasProp;

components/vc-select/DropdownMenu.jsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import scrollIntoView from 'dom-scroll-into-view';
55
import { getSelectKeys, preventDefaultEvent, saveRef } from './util';
66
import { cloneElement } from '../_util/vnode';
77
import BaseMixin from '../_util/BaseMixin';
8-
import { findDOMNode } from '../_util/props-util';
8+
import { findDOMNode, getSlot } from '../_util/props-util';
99

1010
export default {
1111
name: 'DropdownMenu',
@@ -152,7 +152,7 @@ export default {
152152

153153
clonedMenuItems = menuItems.map(item => {
154154
if (item.type.isMenuItemGroup) {
155-
const children = (item.children?.default() || []).map(clone);
155+
const children = getSlot(item).map(clone);
156156
const newItem = cloneElement(item);
157157
newItem.children = { ...item.children, default: () => children };
158158
return newItem;

components/vc-select/Select.jsx

+31-13
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
getComponent,
1515
getEvents,
1616
getOptionProps,
17+
getSlot,
1718
} from '../_util/props-util';
1819
import getTransitionProps from '../_util/getTransitionProps';
1920
import { cloneElement } from '../_util/vnode';
@@ -223,11 +224,11 @@ const Select = {
223224
},
224225
getOptionsFromChildren(children = [], options = []) {
225226
children.forEach(child => {
226-
if (!child.data || child.data.slot !== undefined) {
227+
if (!child) {
227228
return;
228229
}
229230
if (child.type?.isSelectOptGroup) {
230-
this.getOptionsFromChildren(child.children?.default(), options);
231+
this.getOptionsFromChildren(getSlot(child), options);
231232
} else {
232233
options.push(child);
233234
}
@@ -782,7 +783,7 @@ const Select = {
782783
const props = this.$props;
783784
const { _inputValue: inputValue, _mirrorInputValue } = this.$data;
784785
const attrs = this.$attrs;
785-
const defaultInput = <input id={attrs.id} autoComplete="off" />;
786+
const defaultInput = <input {...(attrs.id !== undefined ? {id: attrs.id}: {})} autoComplete="off"/>;
786787

787788
const inputElement = props.getInputElement ? props.getInputElement() : defaultInput;
788789
const inputCls = classnames(inputElement.class, {
@@ -795,7 +796,6 @@ const Select = {
795796
<div class={`${props.prefixCls}-search__field__wrap`} onClick={this.inputClick}>
796797
{cloneElement(inputElement, {
797798
disabled: props.disabled,
798-
value: inputValue,
799799
...(inputElement.props || {}),
800800
disabled: props.disabled,
801801
value: inputValue,
@@ -881,6 +881,21 @@ const Select = {
881881
if (fireSearch) {
882882
this.$emit('search', inputValue);
883883
}
884+
} else {
885+
// TODO
886+
// https://github.com/vuejs/vue-next/issues/1471
887+
this.setState(
888+
{
889+
_inputValue: `${inputValue} `,
890+
},
891+
);
892+
this.$nextTick(()=>{
893+
this.setState(
894+
{
895+
_inputValue: inputValue,
896+
},
897+
);
898+
});
884899
}
885900
},
886901
getValueByInput(str) {
@@ -1200,7 +1215,7 @@ const Select = {
12001215
const childValueSub = getValuePropValue(subChild) || subChild.key;
12011216
return (
12021217
<MenuItem key={childValueSub} value={childValueSub} {...subChild.props}>
1203-
{...(subChild.children?.default())}
1218+
{...getSlot(subChild)}
12041219
</MenuItem>
12051220
);
12061221
});
@@ -1247,7 +1262,7 @@ const Select = {
12471262
style: UNSELECTABLE_STYLE,
12481263
class: child?.class,
12491264
};
1250-
const menuItem = <MenuItem {...p}>{child.children?.default()}</MenuItem>;
1265+
const menuItem = <MenuItem {...p}>{getSlot(child)}</MenuItem>;
12511266
sel.push(menuItem);
12521267
menuItems.push(menuItem);
12531268
}
@@ -1503,14 +1518,17 @@ const Select = {
15031518
}
15041519
}
15051520
},
1506-
selectionRefFocus(e) {
1507-
if (this._focused || this.disabled || isMultipleOrTagsOrCombobox(this.$props)) {
1508-
e.preventDefault();
1509-
return;
1521+
selectionRefFocus() {
1522+
if (this.getInputDOMNode() && this.getInputDOMNode()) {
1523+
this.getInputDOMNode().focus();
15101524
}
1511-
this._focused = true;
1512-
this.updateFocusClassName();
1513-
this.$emit('focus');
1525+
// if (this._focused || this.disabled || isMultipleOrTagsOrCombobox(this.$props)) {
1526+
// e.preventDefault();
1527+
// return;
1528+
// }
1529+
// this._focused = true;
1530+
// this.updateFocusClassName();
1531+
// this.$emit('focus');
15141532
},
15151533
selectionRefBlur(e) {
15161534
if (isMultipleOrTagsOrCombobox(this.$props)) {

components/vc-select/util.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { getPropsData, getComponent } from '../_util/props-util';
1+
import { getPropsData, getComponent, getSlot } from '../_util/props-util';
22
import { cloneElement } from '../_util/vnode';
33
import { isVNode, Text } from 'vue';
44

@@ -115,7 +115,7 @@ export function getSelectKeys(menuItems = [], value) {
115115
let selectedKeys = [];
116116
menuItems.forEach(item => {
117117
if (item.type?.isMenuItemGroup) {
118-
selectedKeys = selectedKeys.concat(getSelectKeys(item.children?.default(), value));
118+
selectedKeys = selectedKeys.concat(getSelectKeys(getSlot(item), value));
119119
} else {
120120
const itemValue = getValuePropValue(item);
121121
const itemKey = item.key;
@@ -141,7 +141,7 @@ export function findFirstMenuItem(children) {
141141
const child = children[i];
142142
const props = getPropsData(child);
143143
if (child.type?.isMenuItemGroup) {
144-
const found = findFirstMenuItem(child.children?.default());
144+
const found = findFirstMenuItem(getSlot(child));
145145
if (found) {
146146
return found;
147147
}

0 commit comments

Comments
 (0)