以下代码是初期写的代码,后来对代码进行优化,解决了初期的bug。完整的选择城市三级联动组件可以参考我的github项目中的代码,这是后期调试成功上传上去的React选择城市三级联动组件
<SelectArea allAreaInfo={allAreaInfo} province={province} city={city} district={district} cancel={this.closeModal} confirm={this.SelectAddress} />
import React,{ Component,PropTypes } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router';
import rest from '../../lib/rest';
const HEIGHT = 36;
export class Picker extends Component {
constructor(props) {
super(props);
this.state = {
selectedIndex: this.props.index
};
this.onScroll = this.onScroll.bind(this);
this.resetPosition = this.resetPosition.bind(this);
}
componentDidMount() {
this.refs.scroller.scrollTop = this.state.selectedIndex * HEIGHT;
this.refs.scroller.addEventListener('touchstart',this.touchStart,false);
this.refs.scroller.addEventListener('touchend',this.touchEnd,false);
this.refs.scroller.addEventListener('mousedown',false);
this.refs.scroller.addEventListener('mouseup',false);
}
touchStart() {
this.isTouchStart = true;
}
touchEnd() {
this.isTouchStart = false;
if (this.timer) clearTimeout(this.timer);
this.timer = setTimeout(this.resetPosition,100);
}
onScroll() {
if (this.timer) clearTimeout(this.timer);
this.timer = setTimeout(this.resetPosition,100);
}
resetPosition() {
let provinceList = [],cityList = [],districtList = [];
const { type = '',allAreaInfo = [],callback = () => { } } = this.props;
if (this.isTouchStart) return;
const top = this.refs.scroller.scrollTop;
const distance = top % HEIGHT;
let target;
if (distance > HEIGHT / 2) {
target = top + HEIGHT - distance;
this.refs.scroller.scrollTop = target;
} else {
target = top - distance;
this.refs.scroller.scrollTop = target;
}
const selectedIndex = target / HEIGHT;
this.setState({
selectedIndex
},() => {
callback(type,selectedIndex);
});
}
render() {
const { list = [] } = this.props;
return (
<div className="ul-area" onScroll={this.onScroll} ref="scroller">
<ul>
<li></li>
{
list.map((item,index) => (
<li key={index} className={`${index === this.state.selectedIndex && 'selected'}`}>{item}</li>
))
}
<li></li>
</ul>
</div>
)
}
}
class SelectArea extends Component {
constructor(props) {
super(props);
this.state = {
provinceList: [],cityList: [],districtList: [],provinceIndex: 0,cityIndex: 0,districtIndex: 0,showPicker: false
};
this.handleSelect = this.handleSelect.bind(this);
}
componentDidMount() {
const { allAreaInfo = [],province = '',city = '',district = '' } = this.props;
let provinceList = [],districtList = [],provinceIndex = 0,cityIndex = 0,districtIndex = 0;
if (province) {
provinceIndex = allAreaInfo.findIndex(item => item.name === province);
cityIndex = allAreaInfo[provinceIndex].city.findIndex(item => item.name === city);
districtIndex = allAreaInfo[provinceIndex].city[cityIndex].area.findIndex(item => item === (district || '其他'));
this.setState({
provinceIndex,cityIndex,districtIndex,showPicker: true
});
}
allAreaInfo.forEach(item => provinceList.push(item.name));
if (allAreaInfo[provinceIndex].city.length) {
allAreaInfo[provinceIndex].city.forEach(item => cityList.push(item.name));
}
this.setState({
provinceList,cityList,districtList: allAreaInfo[provinceIndex].city[cityIndex] && allAreaInfo[provinceIndex].city[cityIndex].area,showPicker: true
});
}
handleSelect(type,index) {
let provinceList = [],districtList = [];
const { provinceIndex,districtIndex } = this.state;
const { allAreaInfo = [] } = this.props;
switch(type) {
case 'province':
allAreaInfo[index].city.forEach(item => cityList.push(item.name));
this.setState({
provinceIndex: index,districtList: allAreaInfo[index].city[0] && allAreaInfo[index].city[0].area
});
break;
case 'city':
this.setState({
cityIndex: index,districtList: allAreaInfo[provinceIndex].city[index] && allAreaInfo[provinceIndex].city[index].area
});
break;
case 'district':
this.setState({
districtIndex: index,districtList: allAreaInfo[provinceIndex].city[cityIndex].area
});
break;
default:
break;
}
}
render() {
const { allAreaInfo = [],cancel = () => {},confirm = () => {} } = this.props;
const { provinceList,districtList,provinceIndex,districtIndex } = this.state;
return (
<div id="select-area">
<div className="col-xs-12 select-area" onClick={e => e.stopPropagation()}>
<div className="row border-bottom-grey">
<div className="col-xs-6" onClick={cancel}>取消</div>
<div className="col-xs-6 text-right font-orange"
onClick={confirm.bind(null,districtIndex)}>确定</div>
</div>
{
this.state.showPicker && (
<div className="row list">
<Picker type="province" allAreaInfo={allAreaInfo} list={provinceList}
index={this.state.provinceIndex} callback={this.handleSelect} />
<Picker type="city" allAreaInfo={allAreaInfo} list={cityList}
index={cityIndex} callback={this.handleSelect} />
<Picker type="district" allAreaInfo={allAreaInfo} list={districtList}
index={districtIndex} callback={this.handleSelect} />
</div>
)
}
</div>
</div>
)
}
}
SelectArea.contextTypes = {
router: PropTypes.object.isrequired
};
SelectArea.propTypes = {
// test: PropTypes.string.isrequired,
};
export default connect(state => (state))(SelectArea);