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 相关文章推荐
通过JS来动态的修改url,实现对url的增删查改
Sep 01 Javascript
jQuery通过控制节点实现仅在前台通过get方法完成参数传递
Feb 02 Javascript
Bootstrap入门书籍之(三)栅格系统
Feb 17 Javascript
Node.js文件操作方法汇总
Mar 22 Javascript
js点击任意区域弹出层消失实现代码
Dec 27 Javascript
jQuery动态产生select option下拉列表
Mar 15 Javascript
js中json对象和字符串的理解及相互转化操作实现方法
Sep 22 Javascript
vuejs项目打包之后的首屏加载优化及打包之后出现的问题
Apr 01 Javascript
在vue中解决提示警告 for循环报错的方法
Sep 28 Javascript
javascript触发模拟鼠标点击事件
Jun 26 Javascript
vue自动添加浏览器兼容前后缀操作
Aug 13 Javascript
使用webpack和rollup打包组件库的方法
Feb 25 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里的JS打印函数
2006/10/09 PHP
php配合jquery实现增删操作具体实例
2013/12/12 PHP
php将数组转换成csv格式文件输出的方法
2015/03/14 PHP
PHP学习笔记(一):基本语法之标记、空白、和注释
2015/04/17 PHP
php无序树实现方法
2015/07/28 PHP
php实现遍历文件夹的方法汇总
2017/03/02 PHP
基于ThinkPHP5框架使用QueryList爬取并存入mysql数据库操作示例
2019/05/25 PHP
基于php解决json_encode中文UNICODE转码问题
2020/11/10 PHP
Javascript 设计模式(二) 闭包
2010/05/26 Javascript
NodeJS的url截取模块url-extract的使用实例
2013/11/18 NodeJs
JQueryiframe页面操作父页面中的元素与方法(实例讲解)
2013/11/19 Javascript
页面加载完毕后滚动条自动滚动一定位置
2014/02/20 Javascript
原生js仿jquery animate动画效果
2016/07/13 Javascript
深入理解jQuery.data() 的实现方式
2016/11/30 Javascript
bootstrap datetimepicker日期插件使用方法
2017/01/13 Javascript
Bootstrap Scrollspy源码学习
2017/03/02 Javascript
jQuery实现的弹幕效果完整实例
2017/09/06 jQuery
webpack中的热刷新与热加载的区别
2018/04/09 Javascript
150行Node.js实现的dns代理工具
2019/08/02 Javascript
详解React的回调渲染模式
2020/09/10 Javascript
深入讲解Python编程中的字符串
2015/10/14 Python
python中zip()方法应用实例分析
2016/04/16 Python
Python基于OpenCV库Adaboost实现人脸识别功能详解
2018/08/25 Python
python tkinter实现界面切换的示例代码
2019/06/14 Python
Python Pandas数据结构简单介绍
2019/07/03 Python
Django自带日志 settings.py文件配置方法
2019/08/30 Python
python实现静态服务器
2019/09/05 Python
python实现把二维列表变为一维列表的方法分析
2019/10/08 Python
python实现图片上添加图片
2019/11/26 Python
利用django创建一个简易的博客网站的示例
2020/09/29 Python
详解Django中异步任务之django-celery
2020/11/05 Python
香港现代设计家具品牌:Ziinlife Furniture
2018/11/13 全球购物
英语师范专业毕业生自荐信
2013/09/21 职场文书
会计系毕业生求职信
2014/05/28 职场文书
2014年党员自我评议(5篇)
2014/09/12 职场文书
查摆问题整改措施
2014/10/24 职场文书