From c44c425a670188c5ce034343d589c9033e482ef8 Mon Sep 17 00:00:00 2001 From: tangjinzhou <415800467@qq.com> Date: Sun, 11 Feb 2018 18:04:31 +0800 Subject: [PATCH] fix select --- components/vc-select/Select.vue | 107 +++++++++++++------- components/vc-select/demo/email.vue | 46 +++++++++ components/vc-select/demo/force-suggest.vue | 64 ++++++++++++ components/vc-select/demo/tbFetchSuggest.js | 35 +++++++ components/vc-select/util.js | 9 +- examples/routes.js | 2 +- package.json | 2 + 7 files changed, 225 insertions(+), 40 deletions(-) create mode 100644 components/vc-select/demo/email.vue create mode 100644 components/vc-select/demo/force-suggest.vue create mode 100644 components/vc-select/demo/tbFetchSuggest.js diff --git a/components/vc-select/Select.vue b/components/vc-select/Select.vue index 8118cd3d6..f6824cc31 100644 --- a/components/vc-select/Select.vue +++ b/components/vc-select/Select.vue @@ -9,7 +9,6 @@ import { hasProp, getSlotOptions } from '../_util/props-util' import getTransitionProps from '../_util/getTransitionProps' import { cloneElement, getClass, getPropsData, getValueByProp as getValue, getEvents } from '../_util/vnode' import BaseMixin from '../_util/BaseMixin' - import { getPropValue, getValuePropValue, @@ -62,7 +61,7 @@ export default { dropdownMenuStyle: PropTypes.object.def({}), optionFilterProp: SelectPropTypes.optionFilterProp.def('value'), optionLabelProp: SelectPropTypes.optionLabelProp.def('value'), - notFoundContent: PropTypes.string.def('Not Found'), + notFoundContent: PropTypes.any.def('Not Found'), backfill: PropTypes.bool.def(false), showAction: SelectPropTypes.showAction.def(['click']), combobox: PropTypes.bool.def(false), @@ -83,7 +82,7 @@ export default { sValue = toArray(defaultValue) } sValue = this.addLabelToValue(sValue) - sValue = this.addTitleToValue($slots, sValue) + sValue = this.addTitleToValue($slots.default, sValue) let inputValue = '' if (combobox) { inputValue = sValue.length @@ -115,7 +114,7 @@ export default { const { combobox, $slots } = this let value = toArray(this.value) value = this.addLabelToValue(value) - value = this.addTitleToValue($slots, value) + value = this.addTitleToValue($slots.default, value) this.setState({ sValue: value, }) @@ -127,9 +126,7 @@ export default { }) } } - // this.adjustOpenState() }, - deep: true, }, }, updated () { @@ -413,7 +410,7 @@ export default { if (sValue.length) { this.fireChange([]) } - // this.setOpenState(false, true) + this.setOpenState(false, true) if (inputValue) { this.setInputValue('') } @@ -555,21 +552,51 @@ export default { }, inputBlur (e) { this.clearBlurTime() + if (this.disabled) { + return + } this.blurTimer = setTimeout(() => { - if (!this.disabled) { - this._focused = false - this.setOpenState(false, false) + this._focused = false + this.updateFocusClassName() + const props = this.$props + let { sValue } = this + const { inputValue } = this + if ( + isSingleMode(props) && + props.showSearch && + inputValue && + props.defaultActiveFirstOption + ) { + const options = this._options || [] + if (options.length) { + const firstOption = findFirstMenuItem(options) + if (firstOption) { + sValue = [ + { + key: firstOption.key, + label: this.getLabelFromOption(firstOption), + }, + ] + this.fireChange(sValue) + } + } + } else if (isMultipleOrTags(props) && inputValue) { + this.inputValue = this.getInputDOMNode().value = '' } + this.__emit('blur', this.getVLForOnChange(sValue)) + this.setOpenState(false) }, 10) }, inputFocus (e) { this.clearBlurTime() + this.clearFocusTime() + this.timeoutFocus() }, _getInputElement () { const props = this.$props const inputElement = props.getInputElement ? props.getInputElement() - : + : const inputCls = classnames(getClass(inputElement), { [`${props.prefixCls}-search__field`]: true, }) @@ -638,9 +665,9 @@ export default { return this.$refs.selectTriggerRef.getInnerMenu() }, - setOpenState (open, needFocus, forceSet) { + setOpenState (open, needFocus) { const { $props: props, openStatus } = this - if (!forceSet && openStatus === open) { + if (openStatus === open) { this.maybeFocus(open, needFocus) return } @@ -785,6 +812,7 @@ export default { this._focused = true } } else { + console.log(activeElement) if (activeElement !== this.$refs.selectionRef) { this.$refs.selectionRef.focus() this._focused = true @@ -810,15 +838,15 @@ export default { return value }, - addTitleToValue ($slots, values) { + addTitleToValue (children = [], values) { let nextValues = values const keys = values.map(v => v.key) - $slots.default.forEach(child => { + children.forEach(child => { if (!child) { return } if (getSlotOptions(child).isSelectOptGroup) { - nextValues = this.addTitleToValue(child.$slots, nextValues) + nextValues = this.addTitleToValue(child.$slots.default, nextValues) } else { const value = getValuePropValue(child) const valueIndex = keys.indexOf(value) @@ -1048,7 +1076,7 @@ export default { return options }, - renderFilterOptionsFromChildren (children, childrenKeys, menuItems) { + renderFilterOptionsFromChildren (children = [], childrenKeys, menuItems) { const sel = [] const props = this.$props const { inputValue } = this @@ -1320,11 +1348,14 @@ export default { if (!this.disabled) { if (this._focused && this.openStatus) { this._focused = false - this.setOpenState(false, false, true) + this.setOpenState(false, false) this.getInputDOMNode().blur() } else { + // this._focused = true + // this.updateFocusClassName() + // this.timeoutFocus() this._focused = true - this.setOpenState(true, true, true) + this.setOpenState(true, true) this.getInputDOMNode().focus() } } @@ -1338,12 +1369,25 @@ export default { const { disabled, prefixCls, inputValue, sValue, $listeners } = this const { mouseenter = noop, mouseleave = noop, popupScroll = noop } = $listeners const ctrlNode = this.renderTopControlNode(openStatus) - let extraSelectionProps = {} + const selectionProps = { + props: {}, + attrs: { + role: 'combobox', + 'aria-autocomplete': 'list', + 'aria-haspopup': 'true', + 'aria-expanded': openStatus.toString(), + }, + on: { + click: this.selectionRefClick, + }, + class: `${prefixCls}-selection ${prefixCls}-selection--${multiple ? 'multiple' : 'single'}`, + ref: 'selectionRef', + key: 'selection', + + } if (!isMultipleOrTagsOrCombobox(props)) { - extraSelectionProps = { - onKeyDown: this.onKeyDown, - tabIndex: props.disabled ? -1 : 0, - } + selectionProps.on.keydown = this.onKeyDown + selectionProps.attrs.tabIndex = props.disabled ? -1 : 0 } const rootCls = { [prefixCls]: 1, @@ -1389,22 +1433,9 @@ export default { ref='rootRef' // onBlur={this.onOuterBlur} // onFocus={this.onOuterFocus} - // onClick={this.rootRefClick} class={classnames(rootCls)} - // tabindex='-1' > -
+
{ctrlNode} {this.renderClear()} {multiple || !props.showArrow ? null : ( diff --git a/components/vc-select/demo/email.vue b/components/vc-select/demo/email.vue new file mode 100644 index 000000000..714b539db --- /dev/null +++ b/components/vc-select/demo/email.vue @@ -0,0 +1,46 @@ + diff --git a/components/vc-select/demo/force-suggest.vue b/components/vc-select/demo/force-suggest.vue new file mode 100644 index 000000000..f0c63e071 --- /dev/null +++ b/components/vc-select/demo/force-suggest.vue @@ -0,0 +1,64 @@ + diff --git a/components/vc-select/demo/tbFetchSuggest.js b/components/vc-select/demo/tbFetchSuggest.js new file mode 100644 index 000000000..c6c3e64f7 --- /dev/null +++ b/components/vc-select/demo/tbFetchSuggest.js @@ -0,0 +1,35 @@ + +import jsonp from 'jsonp' +import querystring from 'querystring' +let timeout +let currentValue + +export function fetch (value, callback) { + if (timeout) { + clearTimeout(timeout) + timeout = null + } + currentValue = value + + function fake () { + const str = querystring.encode({ + code: 'utf-8', + q: value, + }) + jsonp(`http://suggest.taobao.com/sug?${str}`, (err, d) => { // eslint-disable-line + if (currentValue === value) { + const result = d.result + const data = [] + result.forEach((r) => { + data.push({ + value: r[0], + text: r[0], + }) + }) + callback(data) + } + }) + } + + timeout = setTimeout(fake, 300) +} diff --git a/components/vc-select/util.js b/components/vc-select/util.js index 2fac37b0f..d6b8f1a61 100644 --- a/components/vc-select/util.js +++ b/components/vc-select/util.js @@ -19,7 +19,14 @@ export function getPropValue (child, prop) { if (prop === 'value') { return getValuePropValue(child) } - return child.props[prop] + if (prop === 'children') { + if (child.$slots) { + return child.$slots.default + } else { + return child.componentOptions.children + } + } + return getPropsData(child)[prop] } export function isMultiple (props) { diff --git a/examples/routes.js b/examples/routes.js index 74145911d..5e4a0d694 100644 --- a/examples/routes.js +++ b/examples/routes.js @@ -3,7 +3,7 @@ const AsyncComp = () => { const hashs = window.location.hash.split('/') const d = hashs[hashs.length - 1] return { - component: import(`../components/spin/demo/index.vue`), + component: import(`../components/vc-select/demo/${d}.vue`), } } export default [ diff --git a/package.json b/package.json index 0cfcdd748..f6aeca1e0 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "highlight.js": "^9.12.0", "html-webpack-plugin": "^2.30.1", "istanbul-instrumenter-loader": "^3.0.0", + "jsonp": "^0.2.1", "karma": "^1.4.1", "karma-coverage": "^1.1.1", "karma-coverage-istanbul-reporter": "^1.3.0", @@ -67,6 +68,7 @@ "marked": "^0.3.7", "mocha": "^3.2.0", "pre-commit": "^1.2.2", + "querystring": "^0.2.0", "selenium-server": "^3.0.1", "semver": "^5.3.0", "sinon": "^4.0.2",