feat: select
							parent
							
								
									5a0bb6d50e
								
							
						
					
					
						commit
						106b82ca67
					
				|  | @ -95,7 +95,7 @@ const getSlotOptions = ele => { | |||
| }; | ||||
| const findDOMNode = instance => { | ||||
|   let node = instance.$el; | ||||
|   while (!node.tagName) { | ||||
|   while (node && !node.tagName) { | ||||
|     node = node.nextSibling; | ||||
|   } | ||||
|   return node; | ||||
|  | @ -200,7 +200,8 @@ const getAllProps = ele => { | |||
|   return props; | ||||
| }; | ||||
| 
 | ||||
| const getPropsData = vnode => { | ||||
| const getPropsData = ins => { | ||||
|   const vnode = ins.$ ? ins.$ : ins; | ||||
|   const res = {}; | ||||
|   const originProps = vnode.props || {}; | ||||
|   const props = {}; | ||||
|  |  | |||
|  | @ -107,10 +107,6 @@ const Select = { | |||
|     choiceTransitionName: PropTypes.string.def('zoom'), | ||||
|   }, | ||||
|   propTypes: SelectPropTypes, | ||||
|   // model: { | ||||
|   //   prop: 'value', | ||||
|   //   event: 'change', | ||||
|   // }, | ||||
|   setup() { | ||||
|     return { | ||||
|       configProvider: inject('configProvider', ConfigConsumerProps), | ||||
|  |  | |||
|  | @ -154,7 +154,9 @@ const Menu = { | |||
| 
 | ||||
|   render() { | ||||
|     const props = { ...getOptionProps(this), ...this.$attrs }; | ||||
|     props.class += ` ${props.prefixCls}-root`; | ||||
|     props.class = props.class | ||||
|       ? `${props.class} ${props.prefixCls}-root` | ||||
|       : `${props.prefixCls}-root`; | ||||
|     const subPopupMenuProps = { | ||||
|       ...props, | ||||
|       itemIcon: getComponent(this, 'itemIcon', props), | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ import scrollIntoView from 'dom-scroll-into-view'; | |||
| import { getSelectKeys, preventDefaultEvent, saveRef } from './util'; | ||||
| import { cloneElement } from '../_util/vnode'; | ||||
| import BaseMixin from '../_util/BaseMixin'; | ||||
| import { getSlotOptions, findDOMNode } from '../_util/props-util'; | ||||
| import { findDOMNode } from '../_util/props-util'; | ||||
| 
 | ||||
| export default { | ||||
|   name: 'DropdownMenu', | ||||
|  | @ -151,10 +151,11 @@ export default { | |||
|           }; | ||||
| 
 | ||||
|           clonedMenuItems = menuItems.map(item => { | ||||
|             debugger; | ||||
|             if (getSlotOptions(item).isMenuItemGroup) { | ||||
|               const children = item.componentOptions.children.map(clone); | ||||
|               return cloneElement(item, { children }); | ||||
|             if (item.type.isMenuItemGroup) { | ||||
|               const children = (item.children?.default() || []).map(clone); | ||||
|               const newItem = cloneElement(item); | ||||
|               newItem.children = { ...item.children, default: () => children }; | ||||
|               return newItem; | ||||
|             } | ||||
|             return clone(item); | ||||
|           }); | ||||
|  | @ -182,9 +183,8 @@ export default { | |||
|             {...menuProps} | ||||
|             selectedKeys={selectedKeys} | ||||
|             prefixCls={`${prefixCls}-menu`} | ||||
|           > | ||||
|             {clonedMenuItems} | ||||
|           </Menu> | ||||
|             children={clonedMenuItems} | ||||
|           ></Menu> | ||||
|         ); | ||||
|       } | ||||
|       return null; | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| import {TransitionGroup} from 'vue'; | ||||
| import KeyCode from '../_util/KeyCode'; | ||||
| import PropTypes from '../_util/vue-types'; | ||||
| import classnames from 'classnames'; | ||||
|  | @ -8,13 +9,10 @@ import Option from './Option'; | |||
| import OptGroup from './OptGroup'; | ||||
| import { | ||||
|   hasProp, | ||||
|   getSlotOptions, | ||||
|   getPropsData, | ||||
|   getValueByProp as getValue, | ||||
|   getComponent, | ||||
|   getEvents, | ||||
|   getClass, | ||||
|   getAttrs, | ||||
|   getOptionProps, | ||||
| } from '../_util/props-util'; | ||||
| import getTransitionProps from '../_util/getTransitionProps'; | ||||
|  | @ -106,10 +104,6 @@ const Select = { | |||
|     // onDeselect: noop, | ||||
|     // onInputKeydown: noop, | ||||
|   }, | ||||
|   // model: { | ||||
|   //   prop: 'value', | ||||
|   //   event: 'change', | ||||
|   // }, | ||||
|   created() { | ||||
|     this.saveInputRef = saveRef(this, 'inputRef'); | ||||
|     this.saveInputMirrorRef = saveRef(this, 'inputMirrorRef'); | ||||
|  | @ -175,7 +169,7 @@ const Select = { | |||
|     __propsSymbol__() { | ||||
|       Object.assign(this.$data, this.getDerivedState(getOptionProps(this), this.$data)); | ||||
|     }, | ||||
|     '$data._inputValue'(val) { | ||||
|     _inputValue(val) { | ||||
|       this.$data._mirrorInputValue = val; | ||||
|     }, | ||||
|   }, | ||||
|  | @ -232,8 +226,8 @@ const Select = { | |||
|         if (!child.data || child.data.slot !== undefined) { | ||||
|           return; | ||||
|         } | ||||
|         if (getSlotOptions(child).isSelectOptGroup) { | ||||
|           this.getOptionsFromChildren(child.componentOptions.children, options); | ||||
|         if (child.type?.isSelectOptGroup) { | ||||
|           this.getOptionsFromChildren(child.children?.default(), options); | ||||
|         } else { | ||||
|           options.push(child); | ||||
|         } | ||||
|  | @ -787,32 +781,31 @@ const Select = { | |||
|     _getInputElement() { | ||||
|       const props = this.$props; | ||||
|       const { _inputValue: inputValue, _mirrorInputValue } = this.$data; | ||||
|       const attrs = getAttrs(this); | ||||
|       const attrs = this.$attrs; | ||||
|       const defaultInput = <input id={attrs.id} autoComplete="off" />; | ||||
| 
 | ||||
|       const inputElement = props.getInputElement ? props.getInputElement() : defaultInput; | ||||
|       const inputCls = classnames(getClass(inputElement), { | ||||
|       const inputCls = classnames(inputElement.class, { | ||||
|         [`${props.prefixCls}-search__field`]: true, | ||||
|       }); | ||||
|       const inputEvents = getEvents(inputElement); | ||||
|       // https://github.com/ant-design/ant-design/issues/4992#issuecomment-281542159 | ||||
|       // Add space to the end of the inputValue as the width measurement tolerance | ||||
|       inputElement.data = inputElement.data || {}; | ||||
|       return ( | ||||
|         <div class={`${props.prefixCls}-search__field__wrap`} onClick={this.inputClick}> | ||||
|           {cloneElement(inputElement, { | ||||
|             disabled: props.disabled, | ||||
|             value: inputValue, | ||||
|             ...(inputElement.data.attrs || {}), | ||||
|             ...(inputElement.props || {}), | ||||
|             disabled: props.disabled, | ||||
|             value: inputValue, | ||||
|             class: inputCls, | ||||
|             ref: this.saveInputRef, | ||||
|             directives: [ | ||||
|               { | ||||
|                 name: 'ant-input', | ||||
|               }, | ||||
|             ], | ||||
|             // directives: [ | ||||
|             //   { | ||||
|             //     name: 'ant-input', | ||||
|             //   }, | ||||
|             // ], | ||||
|             onInput: this.onInputChange, | ||||
|             onKeydown: chaining( | ||||
|               this.onInputKeydown, | ||||
|  | @ -1099,6 +1092,7 @@ const Select = { | |||
|       const vls = this.getVLForOnChange(value); | ||||
|       const options = this.getOptionsBySingleValue(value); | ||||
|       this._valueOptions = options; | ||||
|       this.$emit('update:value', vls); | ||||
|       this.$emit('change', vls, isMultipleOrTags(this.$props) ? options : options[0]); | ||||
|     }, | ||||
| 
 | ||||
|  | @ -1186,16 +1180,11 @@ const Select = { | |||
|       const { _inputValue: inputValue } = this.$data; | ||||
|       const tags = props.tags; | ||||
|       children.forEach(child => { | ||||
|         const type = child.type; | ||||
|         warning( | ||||
|           typeof type === 'object' && type.isSelectOption, | ||||
|           'the children of `Select` should be `Select.Option` or `Select.OptGroup`, ' + | ||||
|             `instead of \`${getSlotOptions(child).name || getSlotOptions(child)}\`.`, | ||||
|         ); | ||||
|         if (typeof type !== 'object' || !type.isSelectOption) { | ||||
|         if (!child) { | ||||
|           return; | ||||
|         } | ||||
|         if (type.isSelectOptGroup) { | ||||
|         const type = child.type; | ||||
|         if (type?.isSelectOptGroup) { | ||||
|           let label = getComponent(child, 'label'); | ||||
|           let key = child.key; | ||||
|           if (!key && typeof label === 'string') { | ||||
|  | @ -1211,14 +1200,14 @@ const Select = { | |||
|               const childValueSub = getValuePropValue(subChild) || subChild.key; | ||||
|               return ( | ||||
|                 <MenuItem key={childValueSub} value={childValueSub} {...subChild.props}> | ||||
|                   {subChild.children?.default()} | ||||
|                   {...(subChild.children?.default())} | ||||
|                 </MenuItem> | ||||
|               ); | ||||
|             }); | ||||
| 
 | ||||
|             sel.push( | ||||
|               <MenuItemGroup key={key} title={label} class={child.props?.class}> | ||||
|                 {innerItems} | ||||
|                 {...innerItems} | ||||
|               </MenuItemGroup>, | ||||
|             ); | ||||
| 
 | ||||
|  | @ -1232,7 +1221,7 @@ const Select = { | |||
|             if (innerItems.length) { | ||||
|               sel.push( | ||||
|                 <MenuItemGroup key={key} title={label} {...child.props}> | ||||
|                   {innerItems} | ||||
|                   {...innerItems} | ||||
|                 </MenuItemGroup>, | ||||
|               ); | ||||
|             } | ||||
|  | @ -1240,6 +1229,10 @@ const Select = { | |||
| 
 | ||||
|           return; | ||||
|         } | ||||
|         warning( | ||||
|           typeof type === 'object' && type.isSelectOption, | ||||
|           'the children of `Select` should be `Select.Option` or `Select.OptGroup`, ', | ||||
|         ); | ||||
| 
 | ||||
|         const childValue = getValuePropValue(child); | ||||
| 
 | ||||
|  | @ -1416,10 +1409,10 @@ const Select = { | |||
|         if (isMultipleOrTags(props) && choiceTransitionName) { | ||||
|           const transitionProps = getTransitionProps(choiceTransitionName, { | ||||
|             tag: 'ul', | ||||
|             afterLeave: this.onChoiceAnimationLeave, | ||||
|             onAfterLeave: this.onChoiceAnimationLeave, | ||||
|           }); | ||||
|           innerNode = ( | ||||
|             <transition-group {...transitionProps}>{selectedValueNodes}</transition-group> | ||||
|             <TransitionGroup {...transitionProps}>{selectedValueNodes}</TransitionGroup> | ||||
|           ); | ||||
|         } else { | ||||
|           innerNode = <ul>{selectedValueNodes}</ul>; | ||||
|  |  | |||
|  | @ -1,11 +1,9 @@ | |||
| // based on vc-select 9.2.2
 | ||||
| import ProxySelect, { Select } from './Select'; | ||||
| import Select from './Select'; | ||||
| import Option from './Option'; | ||||
| import { SelectPropTypes } from './PropTypes'; | ||||
| import OptGroup from './OptGroup'; | ||||
| Select.Option = Option; | ||||
| Select.OptGroup = OptGroup; | ||||
| ProxySelect.Option = Option; | ||||
| ProxySelect.OptGroup = OptGroup; | ||||
| export { Select, Option, OptGroup, SelectPropTypes }; | ||||
| export default ProxySelect; | ||||
| export default Select; | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| import { getPropsData, getSlotOptions, getKey, getComponent } from '../_util/props-util'; | ||||
| import { getPropsData, getComponent } from '../_util/props-util'; | ||||
| import { cloneElement } from '../_util/vnode'; | ||||
| import { isVNode, Text } from 'vue'; | ||||
| 
 | ||||
| export function toTitle(title) { | ||||
|   if (typeof title === 'string') { | ||||
|  | @ -15,8 +16,8 @@ export function getValuePropValue(child) { | |||
|   if ('value' in props) { | ||||
|     return props.value; | ||||
|   } | ||||
|   if (getKey(child) !== undefined) { | ||||
|     return getKey(child); | ||||
|   if (child.key !== undefined) { | ||||
|     return child.key; | ||||
|   } | ||||
|   if (typeof child.type === 'object' && child.type.isSelectOptGroup) { | ||||
|     const label = getComponent(child, 'label'); | ||||
|  | @ -32,20 +33,14 @@ export function getPropValue(child, prop) { | |||
|     return getValuePropValue(child); | ||||
|   } | ||||
|   if (prop === 'children') { | ||||
|     const newChild = child.$slots | ||||
|       ? cloneElement(child.$slots.default) | ||||
|       : cloneElement(child.componentOptions.children); | ||||
|     if (newChild.length === 1 && !newChild[0].tag) { | ||||
|       return newChild[0].text; | ||||
|     const newChild = cloneElement(getComponent(child)); | ||||
|     if (isVNode(newChild) && newChild.type === Text) { | ||||
|       return newChild.children; | ||||
|     } | ||||
|     return newChild; | ||||
|   } | ||||
|   const data = getPropsData(child); | ||||
|   if (prop in data) { | ||||
|     return data[prop]; | ||||
|   } else { | ||||
|     return child.props && child.props[prop]; | ||||
|   } | ||||
|   const props = getPropsData(child); | ||||
|   return props[prop]; | ||||
| } | ||||
| 
 | ||||
| export function isMultiple(props) { | ||||
|  | @ -113,14 +108,14 @@ export function getLabelFromPropsValue(value, key) { | |||
|   return label; | ||||
| } | ||||
| 
 | ||||
| export function getSelectKeys(menuItems, value) { | ||||
| export function getSelectKeys(menuItems = [], value) { | ||||
|   if (value === null || value === undefined) { | ||||
|     return []; | ||||
|   } | ||||
|   let selectedKeys = []; | ||||
|   menuItems.forEach(item => { | ||||
|     if (getSlotOptions(item).isMenuItemGroup) { | ||||
|       selectedKeys = selectedKeys.concat(getSelectKeys(item.componentOptions.children, value)); | ||||
|     if (item.type?.isMenuItemGroup) { | ||||
|       selectedKeys = selectedKeys.concat(getSelectKeys(item.children?.default(), value)); | ||||
|     } else { | ||||
|       const itemValue = getValuePropValue(item); | ||||
|       const itemKey = item.key; | ||||
|  | @ -145,8 +140,8 @@ export function findFirstMenuItem(children) { | |||
|   for (let i = 0; i < children.length; i++) { | ||||
|     const child = children[i]; | ||||
|     const props = getPropsData(child); | ||||
|     if (getSlotOptions(child).isMenuItemGroup) { | ||||
|       const found = findFirstMenuItem(child.componentOptions.children); | ||||
|     if (child.type?.isMenuItemGroup) { | ||||
|       const found = findFirstMenuItem(child.children?.default()); | ||||
|       if (found) { | ||||
|         return found; | ||||
|       } | ||||
|  |  | |||
|  | @ -5,7 +5,8 @@ import PopupInner from './PopupInner'; | |||
| import LazyRenderBox from './LazyRenderBox'; | ||||
| import animate from '../_util/css-animation'; | ||||
| import BaseMixin from '../_util/BaseMixin'; | ||||
| import { getListeners, splitAttrs } from '../_util/props-util'; | ||||
| import { saveRef } from './utils'; | ||||
| import { getListeners, splitAttrs, findDOMNode } from '../_util/props-util'; | ||||
| 
 | ||||
| export default { | ||||
|   name: 'VCTriggerPopup', | ||||
|  | @ -36,6 +37,8 @@ export default { | |||
|   data() { | ||||
|     this.domEl = null; | ||||
|     this.currentAlignClassName = undefined; | ||||
|     this.savePopupRef = saveRef.bind(this, 'popupInstance'); | ||||
|     this.saveAlignRef = saveRef.bind(this, 'alignInstance'); | ||||
|     return { | ||||
|       // Used for stretch | ||||
|       stretchChecked: false, | ||||
|  | @ -62,13 +65,13 @@ export default { | |||
|       this.setStretchSize(); | ||||
|     }); | ||||
|   }, | ||||
|   beforeUnmount() { | ||||
|     if (this.$el.parentNode) { | ||||
|       this.$el.parentNode.removeChild(this.$el); | ||||
|     } else if (this.$el.remove) { | ||||
|       this.$el.remove(); | ||||
|     } | ||||
|   }, | ||||
|   // beforeUnmount() { | ||||
|   //   if (this.$el.parentNode) { | ||||
|   //     this.$el.parentNode.removeChild(this.$el); | ||||
|   //   } else if (this.$el.remove) { | ||||
|   //     this.$el.remove(); | ||||
|   //   } | ||||
|   // }, | ||||
|   methods: { | ||||
|     onAlign(popupDomNode, align) { | ||||
|       const props = this.$props; | ||||
|  | @ -111,7 +114,7 @@ export default { | |||
|     }, | ||||
| 
 | ||||
|     getPopupDomNode() { | ||||
|       return this.$refs.popupInstance ? this.$refs.popupInstance.$el : null; | ||||
|       return findDOMNode(this.popupInstance); | ||||
|     }, | ||||
| 
 | ||||
|     getTargetElement() { | ||||
|  | @ -158,6 +161,7 @@ export default { | |||
|       } ${currentAlignClassName}`; | ||||
|     }, | ||||
|     getPopupElement() { | ||||
|       const { savePopupRef } = this; | ||||
|       const { $props: props, $attrs, $slots, getTransitionName } = this; | ||||
|       const { stretchChecked, targetHeight, targetWidth } = this.$data; | ||||
|       const { style = {} } = $attrs; | ||||
|  | @ -197,8 +201,8 @@ export default { | |||
|         if (!stretchChecked) { | ||||
|           // sizeStyle.visibility = 'hidden' | ||||
|           setTimeout(() => { | ||||
|             if (this.$refs.alignInstance) { | ||||
|               this.$refs.alignInstance.forceAlign(); | ||||
|             if (this.alignInstance) { | ||||
|               this.alignInstance.forceAlign(); | ||||
|             } | ||||
|           }, 0); | ||||
|         } | ||||
|  | @ -209,7 +213,7 @@ export default { | |||
|         // hiddenClassName, | ||||
|         class: className, | ||||
|         ...onEvents, | ||||
|         ref: 'popupInstance', | ||||
|         ref: savePopupRef, | ||||
|         style: { ...sizeStyle, ...popupStyle, ...style, ...this.getZIndexStyle() }, | ||||
|       }; | ||||
|       let transitionProps = { | ||||
|  | @ -221,13 +225,13 @@ export default { | |||
|       const transitionEvent = { | ||||
|         onBeforeEnter: () => { | ||||
|           // el.style.display = el.__vOriginalDisplay | ||||
|           // this.$refs.alignInstance.forceAlign(); | ||||
|           // this.alignInstance.forceAlign(); | ||||
|         }, | ||||
|         onEnter: (el, done) => { | ||||
|           // render 后 vue 会移除通过animate动态添加的 class导致动画闪动,延迟两帧添加动画class,可以进一步定位或者重写 transition 组件 | ||||
|           this.$nextTick(() => { | ||||
|             if (this.$refs.alignInstance) { | ||||
|               this.$refs.alignInstance.$nextTick(() => { | ||||
|             if (this.alignInstance) { | ||||
|               this.alignInstance.$nextTick(() => { | ||||
|                 this.domEl = el; | ||||
|                 animate(el, `${transitionName}-enter`, done); | ||||
|               }); | ||||
|  | @ -258,7 +262,7 @@ export default { | |||
|               <Align | ||||
|                 target={this.getAlignTarget()} | ||||
|                 key="popup" | ||||
|                 ref="alignInstance" | ||||
|                 ref={this.saveAlignRef} | ||||
|                 monitorWindowResize | ||||
|                 align={align} | ||||
|                 onAlign={this.onAlign} | ||||
|  | @ -275,7 +279,7 @@ export default { | |||
|             v-show={visible} | ||||
|             target={this.getAlignTarget()} | ||||
|             key="popup" | ||||
|             ref="alignInstance" | ||||
|             ref={this.saveAlignRef} | ||||
|             monitorWindowResize | ||||
|             disabled={!visible} | ||||
|             align={align} | ||||
|  |  | |||
|  | @ -318,7 +318,7 @@ export default { | |||
|         return; | ||||
|       } | ||||
|       const target = event.target; | ||||
|       const root = this.$el; | ||||
|       const root = findDOMNode(this); | ||||
|       if (!contains(root, target) && !this.hasPopupMouseDown) { | ||||
|         this.close(); | ||||
|       } | ||||
|  | @ -417,11 +417,7 @@ export default { | |||
|         ...mouseProps, | ||||
|         ref: this.savePopup, | ||||
|       }; | ||||
|       return ( | ||||
|         <Popup ref="popup" {...popupProps}> | ||||
|           {getComponent(self, 'popup')} | ||||
|         </Popup> | ||||
|       ); | ||||
|       return <Popup {...popupProps}>{getComponent(self, 'popup')}</Popup>; | ||||
|     }, | ||||
| 
 | ||||
|     getContainer() { | ||||
|  | @ -434,7 +430,7 @@ export default { | |||
|       popupContainer.style.left = '0'; | ||||
|       popupContainer.style.width = '100%'; | ||||
|       const mountNode = props.getPopupContainer | ||||
|         ? props.getPopupContainer(this.$el, dialogContext) | ||||
|         ? props.getPopupContainer(findDOMNode(this), dialogContext) | ||||
|         : props.getDocument().body; | ||||
|       mountNode.appendChild(popupContainer); | ||||
|       this.popupContainer = popupContainer; | ||||
|  |  | |||
|  | @ -25,3 +25,7 @@ export function getAlignPopupClassName(builtinPlacements, prefixCls, align, isAl | |||
|   return ''; | ||||
| } | ||||
| export function noop() {} | ||||
| 
 | ||||
| export function saveRef(name, component) { | ||||
|   this[name] = component; | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 tanjinzhou
						tanjinzhou