fix select

pull/9/head
tangjinzhou 2018-02-11 18:04:31 +08:00
parent 832d13eb0c
commit c44c425a67
7 changed files with 225 additions and 40 deletions

View File

@ -9,7 +9,6 @@ import { hasProp, getSlotOptions } from '../_util/props-util'
import getTransitionProps from '../_util/getTransitionProps' import getTransitionProps from '../_util/getTransitionProps'
import { cloneElement, getClass, getPropsData, getValueByProp as getValue, getEvents } from '../_util/vnode' import { cloneElement, getClass, getPropsData, getValueByProp as getValue, getEvents } from '../_util/vnode'
import BaseMixin from '../_util/BaseMixin' import BaseMixin from '../_util/BaseMixin'
import { import {
getPropValue, getPropValue,
getValuePropValue, getValuePropValue,
@ -62,7 +61,7 @@ export default {
dropdownMenuStyle: PropTypes.object.def({}), dropdownMenuStyle: PropTypes.object.def({}),
optionFilterProp: SelectPropTypes.optionFilterProp.def('value'), optionFilterProp: SelectPropTypes.optionFilterProp.def('value'),
optionLabelProp: SelectPropTypes.optionLabelProp.def('value'), optionLabelProp: SelectPropTypes.optionLabelProp.def('value'),
notFoundContent: PropTypes.string.def('Not Found'), notFoundContent: PropTypes.any.def('Not Found'),
backfill: PropTypes.bool.def(false), backfill: PropTypes.bool.def(false),
showAction: SelectPropTypes.showAction.def(['click']), showAction: SelectPropTypes.showAction.def(['click']),
combobox: PropTypes.bool.def(false), combobox: PropTypes.bool.def(false),
@ -83,7 +82,7 @@ export default {
sValue = toArray(defaultValue) sValue = toArray(defaultValue)
} }
sValue = this.addLabelToValue(sValue) sValue = this.addLabelToValue(sValue)
sValue = this.addTitleToValue($slots, sValue) sValue = this.addTitleToValue($slots.default, sValue)
let inputValue = '' let inputValue = ''
if (combobox) { if (combobox) {
inputValue = sValue.length inputValue = sValue.length
@ -115,7 +114,7 @@ export default {
const { combobox, $slots } = this const { combobox, $slots } = this
let value = toArray(this.value) let value = toArray(this.value)
value = this.addLabelToValue(value) value = this.addLabelToValue(value)
value = this.addTitleToValue($slots, value) value = this.addTitleToValue($slots.default, value)
this.setState({ this.setState({
sValue: value, sValue: value,
}) })
@ -127,9 +126,7 @@ export default {
}) })
} }
} }
// this.adjustOpenState()
}, },
deep: true,
}, },
}, },
updated () { updated () {
@ -413,7 +410,7 @@ export default {
if (sValue.length) { if (sValue.length) {
this.fireChange([]) this.fireChange([])
} }
// this.setOpenState(false, true) this.setOpenState(false, true)
if (inputValue) { if (inputValue) {
this.setInputValue('') this.setInputValue('')
} }
@ -555,21 +552,51 @@ export default {
}, },
inputBlur (e) { inputBlur (e) {
this.clearBlurTime() this.clearBlurTime()
if (this.disabled) {
return
}
this.blurTimer = setTimeout(() => { this.blurTimer = setTimeout(() => {
if (!this.disabled) { this._focused = false
this._focused = false this.updateFocusClassName()
this.setOpenState(false, false) 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) }, 10)
}, },
inputFocus (e) { inputFocus (e) {
this.clearBlurTime() this.clearBlurTime()
this.clearFocusTime()
this.timeoutFocus()
}, },
_getInputElement () { _getInputElement () {
const props = this.$props const props = this.$props
const inputElement = props.getInputElement const inputElement = props.getInputElement
? props.getInputElement() ? props.getInputElement()
: <input id={props.id} autoComplete='off' value='1111'/> : <input id={props.id} autoComplete='off'/>
const inputCls = classnames(getClass(inputElement), { const inputCls = classnames(getClass(inputElement), {
[`${props.prefixCls}-search__field`]: true, [`${props.prefixCls}-search__field`]: true,
}) })
@ -638,9 +665,9 @@ export default {
return this.$refs.selectTriggerRef.getInnerMenu() return this.$refs.selectTriggerRef.getInnerMenu()
}, },
setOpenState (open, needFocus, forceSet) { setOpenState (open, needFocus) {
const { $props: props, openStatus } = this const { $props: props, openStatus } = this
if (!forceSet && openStatus === open) { if (openStatus === open) {
this.maybeFocus(open, needFocus) this.maybeFocus(open, needFocus)
return return
} }
@ -785,6 +812,7 @@ export default {
this._focused = true this._focused = true
} }
} else { } else {
console.log(activeElement)
if (activeElement !== this.$refs.selectionRef) { if (activeElement !== this.$refs.selectionRef) {
this.$refs.selectionRef.focus() this.$refs.selectionRef.focus()
this._focused = true this._focused = true
@ -810,15 +838,15 @@ export default {
return value return value
}, },
addTitleToValue ($slots, values) { addTitleToValue (children = [], values) {
let nextValues = values let nextValues = values
const keys = values.map(v => v.key) const keys = values.map(v => v.key)
$slots.default.forEach(child => { children.forEach(child => {
if (!child) { if (!child) {
return return
} }
if (getSlotOptions(child).isSelectOptGroup) { if (getSlotOptions(child).isSelectOptGroup) {
nextValues = this.addTitleToValue(child.$slots, nextValues) nextValues = this.addTitleToValue(child.$slots.default, nextValues)
} else { } else {
const value = getValuePropValue(child) const value = getValuePropValue(child)
const valueIndex = keys.indexOf(value) const valueIndex = keys.indexOf(value)
@ -1048,7 +1076,7 @@ export default {
return options return options
}, },
renderFilterOptionsFromChildren (children, childrenKeys, menuItems) { renderFilterOptionsFromChildren (children = [], childrenKeys, menuItems) {
const sel = [] const sel = []
const props = this.$props const props = this.$props
const { inputValue } = this const { inputValue } = this
@ -1320,11 +1348,14 @@ export default {
if (!this.disabled) { if (!this.disabled) {
if (this._focused && this.openStatus) { if (this._focused && this.openStatus) {
this._focused = false this._focused = false
this.setOpenState(false, false, true) this.setOpenState(false, false)
this.getInputDOMNode().blur() this.getInputDOMNode().blur()
} else { } else {
// this._focused = true
// this.updateFocusClassName()
// this.timeoutFocus()
this._focused = true this._focused = true
this.setOpenState(true, true, true) this.setOpenState(true, true)
this.getInputDOMNode().focus() this.getInputDOMNode().focus()
} }
} }
@ -1338,12 +1369,25 @@ export default {
const { disabled, prefixCls, inputValue, sValue, $listeners } = this const { disabled, prefixCls, inputValue, sValue, $listeners } = this
const { mouseenter = noop, mouseleave = noop, popupScroll = noop } = $listeners const { mouseenter = noop, mouseleave = noop, popupScroll = noop } = $listeners
const ctrlNode = this.renderTopControlNode(openStatus) 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)) { if (!isMultipleOrTagsOrCombobox(props)) {
extraSelectionProps = { selectionProps.on.keydown = this.onKeyDown
onKeyDown: this.onKeyDown, selectionProps.attrs.tabIndex = props.disabled ? -1 : 0
tabIndex: props.disabled ? -1 : 0,
}
} }
const rootCls = { const rootCls = {
[prefixCls]: 1, [prefixCls]: 1,
@ -1389,22 +1433,9 @@ export default {
ref='rootRef' ref='rootRef'
// onBlur={this.onOuterBlur} // onBlur={this.onOuterBlur}
// onFocus={this.onOuterFocus} // onFocus={this.onOuterFocus}
// onClick={this.rootRefClick}
class={classnames(rootCls)} class={classnames(rootCls)}
// tabindex='-1'
> >
<div <div {...selectionProps}>
ref='selectionRef'
key='selection'
class={`${prefixCls}-selection
${prefixCls}-selection--${multiple ? 'multiple' : 'single'}`}
role='combobox'
aria-autocomplete='list'
aria-haspopup='true'
aria-expanded={openStatus}
{...extraSelectionProps}
onClick={this.selectionRefClick}
>
{ctrlNode} {ctrlNode}
{this.renderClear()} {this.renderClear()}
{multiple || !props.showArrow ? null : ( {multiple || !props.showArrow ? null : (

View File

@ -0,0 +1,46 @@
<script>
import Select, { Option } from '../index'
import '../assets/index.less'
export default {
data () {
return {
disabled: false,
options: [],
}
},
methods: {
onChange (value) {
console.log('onChange', value)
let options = []
if (value) {
if (value.indexOf('@') >= 0) {
options = <Option key={value}>{value}</Option>
} else {
options = ['gmail.com', 'yahoo.com', 'outlook.com'].map((domain) => {
const email = `${value}@${domain}`
return <Option key={email}>{email}</Option>
})
}
}
this.options = options
},
onSelect (v) {
console.log('onSelect', v)
},
},
render () {
return (<Select
combobox
notFoundContent={false}
style='width: 200px'
onChange={this.onChange}
onSelect={this.onSelect}
placeholder='请输入账户名'
>
{this.options}
</Select>)
},
}
</script>

View File

@ -0,0 +1,64 @@
<script>
import Select, { Option } from '../index'
import { fetch } from './tbFetchSuggest'
import '../assets/index.less'
export default {
data () {
return {
disabled: false,
data: [],
value: undefined,
}
},
methods: {
onChange (value) {
console.log('select ', value)
// value.label = value.key
this.value = value
},
fetchData (value) {
if (value) {
fetch(value, (data) => {
this.data = data
})
} else {
this.data = []
}
},
toggleDisabled () {
this.disabled = !this.disabled
},
},
render () {
const data = this.data
const options = data.map((d) => {
return <Option key={d.value}><i>{d.text}</i></Option>
})
return (<div>
<h2>force suggest</h2>
<p>
<button onClick={this.toggleDisabled}>toggle disabled</button>
</p>
<div>
<Select
labelInValue
onSearch={this.fetchData}
disabled={this.disabled}
value={this.value}
optionLabelProp='children'
placeholder='placeholder'
defaultActiveFirstOption
style={{ width: '500px' }}
onChange={this.onChange}
filterOption={false}
>
{options}
</Select>
</div>
</div>)
},
}
</script>

View File

@ -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)
}

View File

@ -19,7 +19,14 @@ export function getPropValue (child, prop) {
if (prop === 'value') { if (prop === 'value') {
return getValuePropValue(child) 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) { export function isMultiple (props) {

View File

@ -3,7 +3,7 @@ const AsyncComp = () => {
const hashs = window.location.hash.split('/') const hashs = window.location.hash.split('/')
const d = hashs[hashs.length - 1] const d = hashs[hashs.length - 1]
return { return {
component: import(`../components/spin/demo/index.vue`), component: import(`../components/vc-select/demo/${d}.vue`),
} }
} }
export default [ export default [

View File

@ -51,6 +51,7 @@
"highlight.js": "^9.12.0", "highlight.js": "^9.12.0",
"html-webpack-plugin": "^2.30.1", "html-webpack-plugin": "^2.30.1",
"istanbul-instrumenter-loader": "^3.0.0", "istanbul-instrumenter-loader": "^3.0.0",
"jsonp": "^0.2.1",
"karma": "^1.4.1", "karma": "^1.4.1",
"karma-coverage": "^1.1.1", "karma-coverage": "^1.1.1",
"karma-coverage-istanbul-reporter": "^1.3.0", "karma-coverage-istanbul-reporter": "^1.3.0",
@ -67,6 +68,7 @@
"marked": "^0.3.7", "marked": "^0.3.7",
"mocha": "^3.2.0", "mocha": "^3.2.0",
"pre-commit": "^1.2.2", "pre-commit": "^1.2.2",
"querystring": "^0.2.0",
"selenium-server": "^3.0.1", "selenium-server": "^3.0.1",
"semver": "^5.3.0", "semver": "^5.3.0",
"sinon": "^4.0.2", "sinon": "^4.0.2",