react写一个select组件的实现代码


Posted in Javascript onApril 03, 2019

之前一直用的antd的Select组件,但在有些端并不适用,而原生的select样式修改不灵活,遂产生自己写一个组件的想法。观察select组件:

<select onChange={(value) => {this.value=value}}
  <option value='1'>man</option>
  <option value='0'>woman</option>
</select>

可以看出数据都是在option中,有值value和显示出来的数据一一对应。如果我们写一个select组件,那么应该有onChange方法,应该要访问到子元素,而且div是没有value这个属性的,所以option应该也是一个组件,有value属性。下面是我写的组件的用法:

import {MobileSelect, MobileOption} from '../../components/MobileSelect';

 <MobileSelect
  disabled={isDisabled}
  value={data.clarity || ringResponse.clarity || 'Flawless'}
  style={{ width: '132px' }}
  onChange={(v) => this.changeDataValue('clarity', v)}
 >
  {
   (clarity || []).map((item, i) => {
    return (
     <MobileOption key={i + ''} value={item.code}>{item.title}</MobileOption>
    );
   })
  }
 </MobileSelect>

可以看出其和一般的select组件用法差不多。效果如下:

react写一个select组件的实现代码

下面是组件

import {observable} from 'mobx';
import {observer} from 'mobx-react';
import React from 'react';
import {Icon} from 'antd';
import './index.less';

interface IProps {
 disabled?: boolean;
 onChange?: (value) => void;
 value?: string | number;
 style?: React.CSSProperties;
 className?: string;
}
@observer
export class MobileSelect extends React.Component<IProps> {
 @observable showOption = false;   // 是否弹出下拉框
 @observable value: any = '';    // 当前选中的value值
 @observable text: any = '';     // 选中的value值对应的文本
 @observable cell: any;       // 组件的dom节点
 componentDidMount(): void {
  // 获取选择框的ref,当在组件外点击时的时候收起下拉框
  document.addEventListener('click', (e) => {
   if (this.cell && this.cell !== e.target && !this.cell.contains(e.target)) {
    this.showOption = false;
   }
  }, true);
 }
 componentWillReceiveProps(nextProps: Readonly<IProps>, nextContext: any): void {
  // 根据传入的value值,遍历children,找到对应值的展示文本
  if (nextProps.value !== this.props.value || nextProps.children !== this.props.children) {
   React.Children.map(this.props.children, (child, index) => {
    if (nextProps.value === child.props.value) {
     this.text = child.props.children;
    }
   });
  }
 }
 render(): React.ReactNode {
  const {children, value} = this.props;
  console.log(value);
  return (
   <div
    className={'Mobile-Select ' + this.props.className}
    style={this.props.style}
    ref={(node) => this.cell = node}
   >
    <div
     className={'select-wrap'}
     onClick={() => {
      // 禁用不能弹出下拉框
      if (!this.props.disabled) {
       this.showOption = !this.showOption;
      }
     }}
    >
     <Icon type='down' style={this.showOption ? {transform: 'rotate(180deg)'} : {transform: 'rotate(0deg)'}} className={'select-icon'}/>
     {this.text}
    </div>
    <div className={'option-wrap'} style={this.showOption ? {position: 'absolute'} : {display: 'none'}}>
     {
      React.Children.map(children, (child, index) => {
       // 设置选中option和未选中option的样式
       let optionClassName = '';
       if (this.props.value === child.props.value) {
        optionClassName = child.props.className ? child.props.className + ' option-item selected' : 'option-item selected';
       } else {
        optionClassName = child.props.className + ' option-item';
       }
       return (
        <div
         onClick={() => {     // 为了在父组件给子组件添加onClick事件,包裹了一层div
          // 有无onChange事件都能改变值
          if (this.props.value && this.props.onChange) {
           this.props.onChange(child.props.value);
          } else {
           this.text = child.props.children;
           this.value = child.props.value;
          }
          console.log(this.value);
          this.showOption = !this.showOption;
         }}
         style={this.props.style}
         className={optionClassName}
        >{child}</div>
       );
      })
     }
    </div>
   </div>
  );
 }
}
interface OptionProps {
 value?: string | number;
 className?: string;
 style?: React.CSSProperties;
}
export class MobileOption extends React.Component<OptionProps> {
 render(): React.ReactNode {
  const {children} = this.props;
  return (
   <div style={this.props.style}>
    {children}
   </div>
  );
 }
}

下面是组件的样式

.Mobile-Select {
 display: inline-block;
 min-width: 100px;
 margin: 0 6px;
 .select-wrap {
  border: 1px solid #e0c0a2;
  border-radius: 4px;
  padding: 5px 11px;
  display: flex;
  flex-direction: row-reverse;
  justify-content: space-between;
  align-items: center;
  .select-icon {
   transition: .3s;
   float: right;
  }
 }
 .option-wrap {
  box-shadow: 0 0 5px #333;
  z-index: 1000;
  border-radius: 5px;
  .option-item {
   background-color: #fff;
   padding: 2px 11px;
   min-width: 100px;
   &.selected {
    background-color: #fbe6d0;
   }
  }
 }
}

总的来说只实现了select的基本功能。有改进的地方请指点一二。

PS:React Select默认值选中问题

import React from "react";
import { render } from "react-dom";

class App extends React.Component {
 constructor(props) {
  super(props);
  this.state = {
   projects: [],
   value: ""
  };
 }
 componentDidMount() {
  // 模拟ajax调用,成功之后把需要改变的默认值赋值给this.state.value
  setTimeout(() => {
   this.setState({
    projects: [
     { id: 1, name: "花生" },
     { id: 2, name: "苹果" },
     { id: 3, name: "杨桃" }
    ],
    value: 1
   });
  }, 3000);
 }
 handleClick() {
  this.setState({
   projects: [
    { id: 4, name: "水果" },
    { id: 5, name: "西瓜" },
    { id: 6, name: "哈哈哈" }
   ],
   value: 4
  });
 }
 handleChange = e => {
  this.setState({
   value: e.target.value
  });
 };
 render() {
  let projects = this.state.projects;
  return (
   <div>
    <button onClick={this.handleClick.bind(this)}>异步拉取数据</button>
    {/* 这里不用再去判断project的长度是否大于0,在ajax里面做判断就行,如果小于零或者不存在它就是默认值 */}
    <select
     defaultValue=""
     value={this.state.value}
     onChange={this.handleChange}
    >
     {projects.length > 0 &&
      projects.map((item, i) => {
       return (
        <option key={i} value={item.id}>
         {item.name}
        </option>
       );
      })}
    </select>
   </div>
  );
 }
}

render(<App />, document.getElementById("root"));

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery 学习6 操纵元素显示效果的函数
Feb 07 Javascript
jQuery源码分析之Event事件分析
Jun 07 Javascript
文本框文本自动补全效果示例分享
Jan 19 Javascript
a标签的href与onclick事件的区别详解
Nov 12 Javascript
avalonjs实现仿微博的图片拖动特效
May 06 Javascript
JavaScript对表格或元素按文本,数字或日期排序的方法
May 26 Javascript
smartcrop.js智能图片裁剪库
Oct 14 Javascript
jQuery拖动元素并对元素进行重新排序
Dec 30 Javascript
axios全局注册,设置token,以及全局设置url请求网段的方法
Sep 25 Javascript
VUE组件中的 Drawer 抽屉实现代码
Aug 06 Javascript
如何阻止移动端浏览器点击图片浏览
Aug 29 Javascript
微信小程序调用后台service教程详解
Nov 06 Javascript
vue框架下部署上线后刷新报404问题的解决方案(推荐)
Apr 03 #Javascript
JavaScript变速动画函数封装添加任意多个属性
Apr 03 #Javascript
JS中注入eval, Function等系统函数截获动态代码
Apr 03 #Javascript
性能优化篇之Webpack构建速度优化的建议
Apr 03 #Javascript
elementUI多选框反选的实现代码
Apr 03 #Javascript
vue生命周期的探索
Apr 03 #Javascript
用原生 JS 实现 innerHTML 功能实例详解
Apr 03 #Javascript
You might like
PHP取余函数介绍MOD(x,y)与x%y
2014/05/15 PHP
用PHP写的一个冒泡排序法的函数简单实例
2016/05/26 PHP
php禁用函数设置及查看方法详解
2016/07/25 PHP
php 魔术常量详解及实例代码
2016/12/04 PHP
phpStudy2016 配置多个域名期间遇到的问题小结
2017/10/19 PHP
PHP树形结构tree类用法示例
2019/02/01 PHP
jquery的颜色选择插件实例代码
2008/10/02 Javascript
情人节专属 纯js脚本1k大小的3D玫瑰效果
2012/02/11 Javascript
jquery.validate的使用说明介绍
2013/11/12 Javascript
原生JS实现响应式瀑布流布局
2015/04/02 Javascript
深入浅析Extjs中store分组功能的使用方法
2016/04/20 Javascript
AngularJS遍历获取数组元素的方法示例
2017/11/11 Javascript
原生JavaScript实现Ajax异步请求
2017/11/19 Javascript
Vue+ElementUI实现表单动态渲染、可视化配置的方法
2018/03/07 Javascript
jQuery.parseJSON()函数详解
2019/02/28 jQuery
node(koa2) web应用模块介绍详解
2019/03/29 Javascript
layui数据表格 table.render 报错的解决方法
2019/09/29 Javascript
js编写简易的计算器
2020/07/29 Javascript
[02:34]DOTA2英雄基础教程 幽鬼
2014/01/02 DOTA
详解JavaScript编程中的window与window.screen对象
2015/10/26 Python
python使用json序列化datetime类型实例解析
2018/02/11 Python
PYQT5设置textEdit自动滚屏的方法
2019/06/14 Python
flask框架路由常用定义方式总结
2019/07/23 Python
对django中foreignkey的简单使用详解
2019/07/28 Python
python 实现return返回多个值
2019/11/19 Python
使用CSS3美化HTML表单的技巧演示
2016/05/17 HTML / CSS
Ivory Isle Designs美国/加拿大:婚礼和活动文具公司
2018/08/21 全球购物
美国亚洲时尚和美容产品的一站式网上商店:Stylevana
2019/09/05 全球购物
PHP面试题集
2016/12/18 面试题
介绍一下ICMP(Internet Control Message Protocol)Internet控制信息协议
2016/11/26 面试题
社区庆八一活动方案
2014/02/02 职场文书
党员学习中共十八大思想报告
2014/09/12 职场文书
办公室班子四风问题对照检查材料
2014/10/04 职场文书
2015夏季作息时间调整通知
2015/04/24 职场文书
节约用电通知
2015/04/25 职场文书
学生会部长竞选稿
2015/11/19 职场文书