React 组件封装之 Select 选择框
一、Select 选择框
组件说明:
选择选项时出现弹框选择。
效果展示:
点击选项时出现下拉选择弹框。
二、使用案例
import {Select} from 'share';
import React from 'react';
export default class Example extends React.Component {
constructor(props) {
super(props);
}
render(){
return <Select
options={this.state.typeList}
babel="分类"
onChange={this.changeType.bind(this)}
/>
}
}
三、API 使用指南
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
options | 选项数组 | Array | [] |
babel | 选项标题 | string | 无 |
onChange | 选中某一行的点击事件 | void | 无 |
四、源代码
index.js
import React from 'react';
import right from '../images/select/right.png';
import select from '../images/select/select.png';
import './index.css';
import close from '../images/select/close.png';
import {defaultProps} from './defaultProps';
export default class Select extends React.Component {
static defaultProps = defaultProps;
constructor(props) {
super(props);
this.state = {
isShow: false,
active:(props.activeOne && props.activeOne.type-1)||0,
value:'',
id:'',
bottomHeight:250,
}
}
componentWillReceiveProps({options,onChange}){
const isContainedInNumbers = options.some(number => number.id === this.state.id);
if (isContainedInNumbers) {
return;
}
this.state.value = this.props.activeOne && this.props.activeOne.name||options[0].name;//默认显示第一个类别
this.state.id = this.props.activeOne && this.props.activeOne.type||options[0].id;//默认显示第一个类别id
// 由于更新父组件state,导致父组件重新render,
// 而React在render时,不管子组件属性是否改变,都会调用componentWillReceiveProps,
// 因此会导致componentWillReceiveProps死循环
// 不过没关系,前面加上了终止条件
onChange(options[0]);
}
showBox(str) {
this.setState({
isShow: !this.state.isShow
},()=>{
if(str == "setHeight"){
this.setHeight(this)
}
})
}
setHeight(that){
var height = this.refs && this.refs.box.offsetHeight;
if(height>=this.state.bottomHeight){
console.log(that.refs.box);
that.refs.box.style.height = this.state.bottomHeight+"px";
that.refs.box.style.overflow = "scroll";
}
}
closeBox(){
this.setState({
isShow: false
})
}
change(item,index){
const {onChange}=this.props;
onChange(item);
this.setState({
value:item.name,
active:index
})
}
render() {
const {prefixCls,options, babel} =this.props;
return (
<div className={prefixCls}>
<div>{babel}</div>
<div className={prefixCls+'-wrap'} onClick={() => this.showBox("setHeight")}>
<div>{this.state.value}</div>
<img src={right} alt="" className={prefixCls+'-arrow'}/>
</div>
{this.state.isShow ?
<div className={prefixCls+'-modal'}>
<div className={prefixCls+'-content'} ref="box" onClick={()=>this.showBox()}>
<div className={prefixCls+'-height'}>
<div className={prefixCls+'-item'}>
<div className={prefixCls+'-item-left'}>
<img className={prefixCls+'-item-icon'} src={select} alt="" onClick={()=>this.closeBox()}/>
<span className="cm-ml-10 cm-c-main">请选择分类</span>
</div>
<img className={prefixCls+'-item-icon'} src={close} alt="" onClick={()=>this.closeBox()}/></div>
</div>
{options.map((item,index) => {
console.log(item);
return <div key={index} className={this.state.active == index? prefixCls+'-label-active':prefixCls+'-label'} onClick={()=>this.change(item,index)}>{item.name}</div>
})}
</div></div> : null}
</div>
)
}
}
index.less
@import '../default';
@prefixCls: s-select;
/* 默认搜索bar */
.@{prefixCls} {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
.@{prefixCls}-wrap{
display: flex;
align-items: center;
.@{prefixCls}-arrow{
width:@size-20
}
}
.@{prefixCls}-modal{
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 9999;
text-align: center;
background: rgba(50,50,50,0.5);
.@{prefixCls}-content{
position: absolute;
left: 0;
right: 0;
bottom: 0;
z-index: 9999;
text-align: center;
background: #ffffff;
.@{prefixCls}-height{
height: @size-40;
.@{prefixCls}-item{
color: @c-main;
display: flex;
align-items: center;
justify-content: space-between;
position: fixed;
left: 0;
right: 0;
background: #ffffff;
height: @size-40;
line-height: @size-40;
.@{prefixCls}-item-left{
display: flex;
align-items: center;
margin-left: @size-10;
}
}
.@{prefixCls}-item-icon{
width: @size-20;
margin-right: @size-10;
}
}
.@{prefixCls}-label{
height: @size-40;
line-height: @size-40;
color: @c-999;
border-top:1px solid @border-c-base;
}
.@{prefixCls}-label-active{
height: @size-40;
line-height: @size-40;
color: @c-main;
border-top:1px solid @border-c-base;
}
}
}
}
defaultProps.js
function noop() {}
export const defaultProps = {
prefixCls: 's-select',
options:[],
babel:"",
onChange:noop
};