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模拟多线程
Feb 07 Javascript
javascript onkeydown,onkeyup,onkeypress,onclick,ondblclick
Feb 04 Javascript
分别用marquee和div+js实现首尾相连循环滚动效果,仅3行代码
Sep 21 Javascript
JS 按钮点击触发(兼容IE、火狐)
Aug 07 Javascript
如何调试异步加载页面里包含的js文件
Oct 30 Javascript
基于javascript bootstrap实现生日日期联动选择
Apr 07 Javascript
jQuery监听文件上传实现进度条效果的方法
Oct 16 Javascript
JavaWeb表单及时验证功能在输入后立即验证(含用户类型,性别,爱好...的验证)
Jun 09 Javascript
jQuery操作cookie的示例代码
Jun 05 jQuery
Flutter 超实用简单菜单弹出框 PopupMenuButton功能
Aug 06 Javascript
JQuery获得内容和属性方法解析
May 30 jQuery
Vue使用Ref跨层级获取组件的步骤
Jan 25 Vue.js
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学习之整理字符串
2011/04/17 PHP
PHP全概率运算函数(优化版) Webgame开发必备
2011/07/04 PHP
深入理解:单一入口、MVC、ORM、CURD、ActiveRecord概念
2013/06/06 PHP
PHP下SSL加密解密、验证、签名方法(很简单)
2020/06/28 PHP
JavaScript 动态将数字金额转化为中文大写金额
2009/05/14 Javascript
Javascript 命名空间模式
2013/11/01 Javascript
js图片预加载示例
2014/04/30 Javascript
javascript实现获取浏览器版本、操作系统类型
2015/01/29 Javascript
微信小程序五星评分效果实现代码
2017/04/06 Javascript
vue中各组件之间传递数据的方法示例
2017/07/27 Javascript
实例解析ES6 Proxy使用场景介绍
2018/01/08 Javascript
JS实现马赛克图片效果完整示例
2019/04/13 Javascript
vue 组件基础知识总结
2021/01/26 Vue.js
[02:41]2015国际邀请赛中国区预选赛观战指南
2015/05/20 DOTA
[00:36]DOTA2上海特级锦标赛 Archon战队宣传片
2016/03/04 DOTA
python使用sorted函数对列表进行排序的方法
2015/04/04 Python
复习Python中的字符串知识点
2015/04/14 Python
在Python中用get()方法获取字典键值的教程
2015/05/21 Python
Django中URLconf和include()的协同工作方法
2015/07/20 Python
Python实现多线程抓取妹子图
2015/08/08 Python
Python2.x与Python3.x的区别
2016/01/14 Python
python下如何查询CS反恐精英的服务器信息
2017/01/17 Python
Python父目录、子目录的相互调用方法
2019/02/16 Python
通过pycharm使用git的步骤(图文详解)
2019/06/13 Python
python 实现字符串下标的输出功能
2020/02/13 Python
Django Admin设置应用程序及模型顺序方法详解
2020/04/01 Python
利用python对mysql表做全局模糊搜索并分页实例
2020/07/12 Python
html5 localStorage本地存储_动力节点Java学院整理
2017/07/06 HTML / CSS
Html5插件教程之添加浏览器放大镜效果的商品橱窗
2016/01/07 HTML / CSS
招商经理岗位职责
2013/11/16 职场文书
《七颗钻石》教学反思
2014/02/28 职场文书
《三袋麦子》教学反思
2014/03/02 职场文书
公务员平时考核实施方案
2014/03/11 职场文书
2014年加油站站长工作总结
2014/12/23 职场文书
英语通知范文
2015/04/22 职场文书
kubernetes集群搭建Zabbix监控平台的详细过程
2022/07/07 Servers