如何定制一个下拉框

写在前面的话

h5为我们提供了select标签, 如果只是为了基本需求, 使用原生的就好, 然而作为一个有追求的咸鱼, 如何能够忍受原生那丑陋的UI呢, 因此我决定自己定制一个下拉框.

注: 使用原生select, 可以使用appearance:none;清除默认的箭头样式
复制代码

开始定制

本文的写作环境为react 16.3.2 , css方面使用了stylus预编译器, 请一一对照, 废话不多说, 直接上代码.

// Select.js
//本示例使用了CSS3 @keyframes和animation  , ie要到10才支持, 请注意兼容性

import React, { Component } from 'react'
import arrowImg from '../images/arrow.png'  //本地资源的一张图片



export default class Select extends Component {
	constructor(props){
		super(props)
		this.state = {
			select: '',  //选中的值
			isOption: false,  //是否展示下拉菜单
			options: this.props.valueArr|| [] //下拉菜单中的数组
		}
		// 绑定this
		this.selectShow = this.selectShow.bind(this)
		this.selectHiden = this.selectHiden.bind(this)
		this.selectValue = this.selectValue.bind(this)
}
        //显示下拉菜单
	selectShow(){
		this.setState({ isOption: true })
		}
        //隐藏下拉菜单
	selectHiden(){
		this.setState({ isOption: false })
	}
        //选择option
	selectValue(e){
		let { id } = e.currentTarget.dataset
		let { options } = this.state 
		this.setState({ select: options[id], isOption: false }, this.props.cb&&this.props.cb(options[id]))
		// cb为父级传入的函数, 简单示例
		// <Select cb={ value=> console.log(value)  } />
	}

	render(){
		let { select, isOption, options } = this.state
		select = select? select : options[0] 
		return (
			<div className='select-container' >
				<div className={!isOption?'select-value': 'select-value-select'} onClick={ this.selectShow } >
					{select}<img alt='箭头' src={arrowImg} className={isOption?'select-arrow' : 'select-arrow-show'} />
				</div>
				<div className={isOption ? 'select-moadl':''}  onClick={ this.selectHiden } ></div>
				<div className={isOption?'select-option-position': 'select-none'} >
					<div className={isOption? 'select-option-container' : ''} >
					{
						options.map((item, index) =>
							<div className='select-option' key={ index } data-id={ index } onClick={ this.selectValue } >{item}</div>)
					}
					</div>
				</div>
			</div>
			)
	}
}
复制代码
//select.styl   
.select-container
	width 200px
	display  inline-block
	text-align center



.select-value
	border-radius 5px
	border 1px solid rgba(0,0,0,0.3)
	position relative
	line-height 1
	padding 5px 0
	
.select-value:hover
	border 1px solid #40a9ff
	
.select-value-select
	border-radius 5px
	border 1px solid #40a9ff
	position relative
	line-height 1
	padding 5px 0
	
.select-arrow
	position absolute
	right 10px
	width 20px 
	height 20px
	animation rotateArrow 1s
	animation-fill-mode forwards

.select-arrow-show
	position absolute
	right 10px
	width 20px 
	height 20px
	animation rotateArrowShow 1s
	animation-fill-mode forwards


@keyframes rotateArrow {
	from { transform:rotate(0deg); }
	to { transform: rotate(180deg) }
}

@keyframes rotateArrowShow{
	from { transform: rotate(180deg) }
	to { transform: rotate(0deg) }
}

.select-moadl
	position absolute
	top 0
	left 0 
	right 0
	bottom 0
	z-index 10
	// background red
	
	
.select-option-position
	position relative
	
.select-option-container
	position absolute
	z-index 11
	background rgba(0,0,0,0.15)
	width 200px
	
.select-option:hover
	background #40a9ff
	color white
	
.select-none
	display none
复制代码

项目使用

import React from 'react'
import Select from './Select'

let valueArr = [2017,2018,2019]
const App = () => (
    <div>
        <Select cb= { value => console.log(value) } valueArr={ valueArr } />
    </div>
)
复制代码

这样, 自作版的下拉框就实现了, 样式如下图

关于下拉框的补充说明

因为本组件使用了自有生命周期来管理内部状态, 因此当你在项目中传入的valueArr在渲染之前就已经有值, 那么一切好说, 但是在正常使用过程中, valueArr 很可能还没有值, 就已经开始渲染了, 导致之后有值, 但是传进去也无效了, 因此需要告诉它, 记得更新数据, 加入react的生命周期

//react 16.3
statice getDerivedStateFromProps(nextProps, preProps){
    if(nextProps.valueArr.length){
        return { options: nextProps.valueArr }
    }
    else return nextProps
}

//react 16.3 之前的
componentWillReceiveProps(nextProps){
    if(nextProps.valueArr.length){
        this.setState({options: nextProps.valueArr } )
    }
}
复制代码

这样就能解决异步传输问题了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值