首页 > 开发 > JS > 正文

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

2024-05-06 16:49:30
字体:
来源:转载
供稿:网友

之前一直用的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;}@observerexport 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"));

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持VeVb武林网。


注:相关教程知识阅读请移步到JavaScript/Ajax教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表