add select demo

pull/9/head
tangjinzhou 2018-02-12 18:10:51 +08:00
parent 6ee21bcfd3
commit fcb3f8c5f0
12 changed files with 389 additions and 45 deletions

View File

@ -22,7 +22,7 @@ const getSlotOptions = (ele) => {
if (ele.$vnode) { if (ele.$vnode) {
componentOptions = ele.$vnode.componentOptions componentOptions = ele.$vnode.componentOptions
} }
return componentOptions.Ctor.options return componentOptions ? componentOptions.Ctor.options || {} : {}
} }
const getOptionProps = (instance) => { const getOptionProps = (instance) => {
const { $options = {}, $props = {}} = instance const { $options = {}, $props = {}} = instance
@ -43,8 +43,17 @@ const getPropsData = (ele) => {
if (ele.$vnode) { if (ele.$vnode) {
componentOptions = ele.$vnode.componentOptions componentOptions = ele.$vnode.componentOptions
} }
return componentOptions && componentOptions.propsData return componentOptions ? componentOptions.propsData || {} : {}
} }
const getAttrs = (ele) => {
let data = ele.data
if (ele.$vnode) {
data = ele.$vnode.data
}
return data ? data.attrs || {} : {}
}
const getKey = (ele) => { const getKey = (ele) => {
let key = ele.key let key = ele.key
if (ele.$vnode) { if (ele.$vnode) {
@ -52,5 +61,15 @@ const getKey = (ele) => {
} }
return key return key
} }
export { hasProp, filterProps, getOptionProps, getComponentFromProp, getSlotOptions, slotHasProp, getPropsData, getKey } export {
hasProp,
filterProps,
getOptionProps,
getComponentFromProp,
getSlotOptions,
slotHasProp,
getPropsData,
getKey,
getAttrs,
}
export default hasProp export default hasProp

View File

@ -128,7 +128,7 @@ export function getPropsData (ele) {
return ele.componentOptions && ele.componentOptions.propsData return ele.componentOptions && ele.componentOptions.propsData
} }
export function getValueByProp (ele, prop) { export function getValueByProp (ele, prop) {
return ele.componentOptions && ele.componentOptions.propsData[prop] return ele.componentOptions && ele.componentOptions.propsData && ele.componentOptions.propsData[prop]
} }
export function getEvents (child) { export function getEvents (child) {

View File

@ -1,5 +1,9 @@
<script> <script>
import PropTypes from '../_util/vue-types'
export default { export default {
props: {
label: PropTypes.any,
},
isSelectOptGroup: true, isSelectOptGroup: true,
} }
</script> </script>

View File

@ -8,6 +8,7 @@ export default {
PropTypes.number, PropTypes.number,
]), ]),
disabled: PropTypes.bool, disabled: PropTypes.bool,
title: PropTypes.string,
}, },
isSelectOption: true, isSelectOption: true,
} }

View File

@ -113,25 +113,32 @@ export default {
}) })
}, },
watch: { watch: {
'$props': { // '$props': {
handler: function (nextProps) { // handler: function (nextProps) {
if (hasProp(this, 'value')) { // if (hasProp(this, 'value')) {
const { combobox, $slots } = this // console.log('nextProps', nextProps)
let value = toArray(this.value) // const { combobox, $slots } = this
value = this.addLabelToValue(value) // let value = toArray(this.value)
value = this.addTitleToValue($slots.default, value) // value = this.addLabelToValue(value)
this.setState({ // value = this.addTitleToValue($slots.default, value)
sValue: value, // this.setState({
}) // sValue: value,
if (combobox) { // })
this.setState({ // if (combobox) {
inputValue: value.length // this.setState({
? this.getLabelFromProps(value[0].key) // inputValue: value.length
: '', // ? this.getLabelFromProps(value[0].key)
}) // : '',
} // })
} // }
}, // }
// },
// },
value (val) {
this.updateState()
},
combobox () {
this.updateState()
}, },
}, },
updated () { updated () {
@ -148,10 +155,6 @@ export default {
} }
}) })
}, },
beforeUpdate () {
// console.log('beforeUpdate')
// this.adjustOpenState()
},
beforeDestroy () { beforeDestroy () {
this.clearFocusTime() this.clearFocusTime()
this.clearBlurTime() this.clearBlurTime()
@ -163,6 +166,22 @@ export default {
} }
}, },
methods: { methods: {
updateState () {
const { combobox, $slots } = this
let value = toArray(this.value)
value = this.addLabelToValue(value)
value = this.addTitleToValue($slots.default, value)
this.setState({
sValue: value,
})
if (combobox) {
this.setState({
inputValue: value.length
? this.getLabelFromProps(value[0].key)
: '',
})
}
},
onInputChange (event) { onInputChange (event) {
const { tokenSeparators } = this const { tokenSeparators } = this
const val = event.target.value const val = event.target.value
@ -437,7 +456,7 @@ export default {
}, },
onChoiceAnimationLeave () { onChoiceAnimationLeave () {
this.$refs.selectTriggerRef.triggerRef.forcePopupAlign() this.$refs.selectTriggerRef.$refs.triggerRef.forcePopupAlign()
}, },
getOptionsFromChildren (value, children = [], options = []) { getOptionsFromChildren (value, children = [], options = []) {
let values = value let values = value
@ -535,6 +554,7 @@ export default {
}, },
getLabelFromOption (child) { getLabelFromOption (child) {
console.log(child, this.optionLabelProp)
return getPropValue(child, this.optionLabelProp) return getPropValue(child, this.optionLabelProp)
}, },
@ -635,14 +655,12 @@ export default {
if (options.length) { if (options.length) {
const firstOption = findFirstMenuItem(options) const firstOption = findFirstMenuItem(options)
if (firstOption) { if (firstOption) {
console.log('pre', this.sValue)
sValue = [ sValue = [
{ {
key: firstOption.key, key: firstOption.key,
label: this.getLabelFromOption(firstOption), label: this.getLabelFromOption(firstOption),
}, },
] ]
console.log('new', this.sValue, sValue)
this.fireChange(sValue) this.fireChange(sValue)
} }
} }
@ -833,6 +851,8 @@ export default {
this.clearFocusTime() this.clearFocusTime()
} }
this.focusTimer = setTimeout(() => { this.focusTimer = setTimeout(() => {
this._focused = true
this.updateFocusClassName()
this.__emit('focus') this.__emit('focus')
}, 10) }, 10)
}, },
@ -911,7 +931,7 @@ export default {
return return
} }
if (getSlotOptions(child).isSelectOptGroup) { if (getSlotOptions(child).isSelectOptGroup) {
nextValues = this.addTitleToValue(child.$slots.default, nextValues) nextValues = this.addTitleToValue(child.componentOptions.children, nextValues)
} else { } else {
const value = getValuePropValue(child) const value = getValuePropValue(child)
const valueIndex = keys.indexOf(value) const valueIndex = keys.indexOf(value)
@ -961,7 +981,7 @@ export default {
this.__emit('select', labelInValue ? value : value.key, this.getSingleOptionByValueKey(value.key)) this.__emit('select', labelInValue ? value : value.key, this.getSingleOptionByValueKey(value.key))
}, },
fireChange (value) { fireChange (value) {
if (hasProp(this, 'value')) { if (!hasProp(this, 'value')) {
this.setState({ this.setState({
sValue: value, sValue: value,
}) })
@ -975,7 +995,7 @@ export default {
isChildDisabled (key) { isChildDisabled (key) {
return this.$slots.default.some(child => { return this.$slots.default.some(child => {
const childValue = getValuePropValue(child) const childValue = getValuePropValue(child)
return childValue === key && getValue(child, 'title') return childValue === key && getValue(child, 'disabled')
}) })
}, },
@ -1304,6 +1324,7 @@ export default {
} }
if (isMultipleOrTags(props)) { if (isMultipleOrTags(props)) {
selectedValueNodes = limitedCountValue.map(singleValue => { selectedValueNodes = limitedCountValue.map(singleValue => {
console.log('singleValue', singleValue)
let content = singleValue.label let content = singleValue.label
const title = singleValue.title || content const title = singleValue.title || content
if ( if (
@ -1353,29 +1374,25 @@ export default {
if (isMultipleOrTags(props) && choiceTransitionName) { if (isMultipleOrTags(props) && choiceTransitionName) {
const transitionProps = getTransitionProps(choiceTransitionName, { const transitionProps = getTransitionProps(choiceTransitionName, {
tag: 'ul', tag: 'ul',
// beforeEnter: this.onChoiceAnimationLeave, afterLeave: this.onChoiceAnimationLeave,
}) })
innerNode = ( innerNode = (
<transition-group <transition-group
// onLeave={this.onChoiceAnimationLeave}
// component='ul'
// transitionName={choiceTransitionName}
{...transitionProps} {...transitionProps}
onClick={this.muitipleContainerClick}
> >
{selectedValueNodes} {selectedValueNodes}
</transition-group> </transition-group>
) )
} else { } else {
innerNode = ( innerNode = (
<ul onClick={this.muitipleContainerClick}> <ul>
{selectedValueNodes} {selectedValueNodes}
</ul> </ul>
) )
} }
} }
return ( return (
<div class={className} ref='topCtrlRef'> <div class={className} ref='topCtrlRef' onClick={this.muitipleContainerClick}>
{this.getPlaceholderElement()} {this.getPlaceholderElement()}
{innerNode} {innerNode}
</div> </div>
@ -1426,17 +1443,18 @@ export default {
e.stopPropagation() e.stopPropagation()
this.clearBlurTime() this.clearBlurTime()
if (!this.disabled) { if (!this.disabled) {
const input = this.getInputDOMNode()
if (this._focused && this.openStatus) { if (this._focused && this.openStatus) {
this._focused = false this._focused = false
this.setOpenState(false, false) this.setOpenState(false, false)
this.getInputDOMNode().blur() input && input.blur()
} else { } else {
// this._focused = true // this._focused = true
// this.updateFocusClassName() // this.updateFocusClassName()
// this.timeoutFocus() // this.timeoutFocus()
this._focused = true this._focused = true
this.setOpenState(true, true) this.setOpenState(true, true)
this.getInputDOMNode().focus() input && input.focus()
} }
} }
}, },

View File

@ -0,0 +1,56 @@
<script>
import Select, { Option } from '../index'
import '../assets/index.less'
import { fetch } from './tbFetchSuggest'
export default {
data () {
return {
data: [],
value: [],
}
},
methods: {
onChange (value) {
console.log('onChange ', value)
this.value = value
},
onSelect (value) {
console.log('select ', value)
},
fetchData (value) {
fetch(value, (data) => {
this.data = data
})
},
},
render () {
const data = this.data
const options = data.map((d) => {
return <Option key={d.value}><i>{d.text}</i></Option>
})
return (<div>
<h2>multiple suggest</h2>
<div>
<Select
style={{ width: '500px' }}
labelInValue
optionLabelProp='children'
value={this.value}
onChange={this.onChange}
tags
placeholder='placeholder'
notFoundContent=''
onSearch={this.fetchData}
onSelect={this.onSelect}
filterOption={false}
>
{options}
</Select>
</div>
</div>)
},
}
</script>

View File

@ -0,0 +1,58 @@
<script>
import Select, { Option } from '../index'
import '../assets/index.less'
import { fetch } from './tbFetchSuggest'
export default {
data () {
return {
data: [],
value: ['b11'],
}
},
methods: {
onChange (value) {
console.log('onChange ', value)
this.value = value
},
onSelect (value) {
console.log('select ', value)
},
fetchData (value) {
fetch(value, (data) => {
this.data = data
})
},
},
render () {
const children = []
for (let i = 10; i < 36; i++) {
// 11 => readonly selected item
children.push(<Option disabled={i === 11} key={i.toString(36) + i}>中文{i}</Option>)
}
const dropdownMenuStyle = {
maxHeight: '200px',
}
return (<div>
<h2>multiple readonly default selected item</h2>
<div>
<Select
multiple
value={this.value}
animation='slide-up'
choiceTransitionName='rc-select-selection__choice-zoom'
dropdownMenuStyle={dropdownMenuStyle}
style={{ width: '500px' }}
optionFilterProp='children'
optionLabelProp='children'
placeholder='please select'
onChange={this.onChange}
>
{children}
</Select>
</div>
</div>)
},
}
</script>

View File

@ -0,0 +1,74 @@
<script>
import Select, { Option } from '../index'
import '../assets/index.less'
export default {
data () {
return {
useAnim: 0,
value: ['a10'],
}
},
methods: {
onChange (value, options) {
console.log('onChange', value, options)
this.value = value
},
onSelect (...args) {
console.log('select ', args)
},
onDeselect (...args) {
console.log('deselect ', args)
},
useAnimation (e) {
this.useAnim = e.target.checked
},
},
render () {
const children = []
for (let i = 10; i < 36; i++) {
children.push(
<Option key={i.toString(36) + i} disabled={i === 10} title={`中文${i}`}>
中文{i}
</Option>
)
}
const dropdownMenuStyle = {
maxHeight: '200px',
}
return (<div>
<h2>multiple selectscroll the menu</h2>
<p>
<label>
anim
<input checked={this.useAnim} type='checkbox' onChange={this.useAnimation} />
</label>
</p>
<div style={{ width: '300px' }}>
<Select
value={this.value}
animation={this.useAnim ? 'slide-up' : null}
choiceTransitionName='rc-select-selection__choice-zoom'
dropdownMenuStyle={dropdownMenuStyle}
style={{ width: '500px' }}
multiple
allowClear
optionFilterProp='children'
optionLabelProp='children'
onSelect={this.onSelect}
onDeselect={this.onDeselect}
placeholder='please select'
onChange={this.onChange}
onFocus={() => console.log('focus')}
tokenSeparators={[' ', ',']}
>
{children}
</Select>
</div>
</div>)
},
}
</script>

View File

@ -0,0 +1,43 @@
<script>
import Select, { Option, OptGroup } from '../index'
import '../assets/index.less'
export default {
methods: {
onChange (value, options) {
console.log(`selected ${value}`)
},
},
render () {
return (<div>
<h2>Select OptGroup</h2>
<div style={{ width: '300px' }}>
<Select
placeholder='placeholder'
defaultValue='lucy'
showSearch={false}
style={{ width: '500px' }}
onChange={this.onChange}
>
<OptGroup label='manager'>
<Option value='jack'>
<b
style={{
color: 'red',
}}
>
jack
</b>
</Option>
<Option value='lucy'>lucy</Option>
</OptGroup>
<OptGroup label='engineer'>
<Option value='yiminghe'>yiminghe</Option>
</OptGroup>
</Select>
</div>
</div>)
},
}
</script>

View File

@ -0,0 +1,31 @@
<script>
import Select, { Option } from '../index'
import '../assets/index.less'
export default {
methods: {
onChange (value, options) {
console.log(`selected ${value}`)
},
},
render () {
return (<div>
<h2>Select optionFilterProp</h2>
<div style={{ width: '300px' }}>
<Select
defaultValue='张三'
style={{ width: '500px' }}
placeholder='placeholder'
optionFilterProp='desc'
onChange={this.onChange}
>
<Option value='张三' desc='张三 zhang san'>ddd</Option>
<Option value='李四' desc='李四 li si'>李四</Option>
<Option value='王五' desc='王五 wang wu'>王五</Option>
</Select>
</div>
</div>)
},
}
</script>

View File

@ -0,0 +1,30 @@
<script>
import Select, { Option } from '../index'
import '../assets/index.less'
export default {
methods: {
onChange (value, options) {
console.log(`selected ${value}`)
},
},
render () {
const cases = {
0: { name: 'Case 1' },
1: { name: 'Case 2' },
2: { name: 'Case 3' },
}
return (<div>
<h2>Select optionLabelProp</h2>
<Select style={{ width: '500px' }} optionLabelProp='children' multiple allowClear>
{
Object.keys(cases).map(key => (
<Option key={key} value={key}>{cases[key].name}</Option>
))
}
</Select>
</div>)
},
}
</script>

View File

@ -1,4 +1,4 @@
import { getPropsData, getSlotOptions, getKey } from '../_util/props-util' import { getPropsData, getSlotOptions, getKey, getAttrs } from '../_util/props-util'
export function getValuePropValue (child) { export function getValuePropValue (child) {
const props = getPropsData(child) const props = getPropsData(child)
if ('value' in props) { if ('value' in props) {
@ -26,7 +26,12 @@ export function getPropValue (child, prop) {
return child.componentOptions.children return child.componentOptions.children
} }
} }
return getPropsData(child)[prop] const data = getPropsData(child)
if (prop in data) {
return data[prop]
} else {
return getAttrs(child)[prop]
}
} }
export function isMultiple (props) { export function isMultiple (props) {
@ -150,7 +155,12 @@ export function defaultFilterFn (input, child) {
if (props.disabled) { if (props.disabled) {
return false return false
} }
const value = String(getPropValue(child, this.optionFilterProp)) let value = getPropValue(child, this.optionFilterProp)
if (value.length && value[0].text) {
value = value[0].text
} else {
value = String(value)
}
return ( return (
value.toLowerCase().indexOf(input.toLowerCase()) > -1 value.toLowerCase().indexOf(input.toLowerCase()) > -1
) )