React_自定义组件_下拉框

avatar
作者
筋斗云
阅读量:10

目录

一、效果图

二、代码

1.直接使用_不和父组件传参

2.作为通用组件使用_和父组件传参


一、效果图

1.未选择任何选项时

2.悬浮效果

3.点击效果

4.选中选项的样式

5.选项太多时效果,(设置最大高度200,根据需要自行更改.popover-box样式的max-height即可)

二、代码

使用技术 react+scss+tsx ,如果你用 react+scss+jsx , 只需要将所有的类型注解(num:number 和 person:string)后面的类型去掉即可。只有函数的参数使用了类型注解,去掉即可。

新建一个文件夹 selecteOption,下面建两个文件 index.tsx,index.scss。

1.直接使用_不和父组件传参

index.tsx:

import './index.scss'; // 使用svg,后期更改图标颜色比较方便,还可以做悬浮变色。记得换成你自己路径下的图片 import { ReactComponent as Up } from '../../assets/images/icon-up.svg'; import { useState, useEffect } from 'react'  function SelectOption() {    // 选项body的滚动条   const [scrollWidth, setScrollWidth] = useState(0)    // 选项弹窗是否显示,为了优化用户体验,控制它的opacity透明度隐藏,为了使选项点击事件能够生效,选项弹窗立即隐藏   const [showOption, setShowOption] = useState(false)   // 选项弹窗是否显示,控制它的div是否存在,(弹窗隐藏后元素存在,点击事件生效)需要将弹窗移除   const [showOptionSetTimeout, setShowOptionSetTimeout] = useState(false)    // 当前选中的选项   const [selectedItem, setSelectedItem] = useState({     id: '',     item: ''   })    //挂载后,计算选项弹窗是否有滚动条,从而改变选项弹窗body宽度   function changeWidth() {     var myElement: any = document.getElementById('mySelecte');     var widthWithBorder = myElement.offsetWidth;     var widthWithoutBorder = myElement.clientWidth;     setScrollWidth(widthWithBorder - widthWithoutBorder);   }   useEffect(() => {     changeWidth();   }, []);    /**    * input元素获得焦点以及失去焦点的事件    */   function showOptionBox() {     setShowOption(true)     setShowOptionSetTimeout(true)   }    /**    * 选择框失去焦点事件的处理逻辑      */   function inputBlur() {     setShowOption(false)     console.log(showOption, "showOption")     setTimeout(() => {       setShowOptionSetTimeout(false)     }, 300);   }    /**    * 用户选中了某个选项    * @param id 区分选项的唯一标志    * @param item 选中的名称    */   function selectedOption(id: number, item: string) {     setSelectedItem({       id: String(id), item     });   }    return (     <div className='so-all-box' >       <input type="button" onBlur={inputBlur} className={showOption ? 'so-box borderB' : 'so-box borderA'} id="mySelecte" onClick={() => { showOptionBox() }}>       </input>       <div className={selectedItem.id === '' ? "lr-selected-manage-around-text textA" : "lr-selected-manage-around-text textB"}>         {selectedItem.id === '' ? '请选择' : selectedItem.item}       </div>        {/* 箭头 */}       <Up className={showOption === true ? 'lr-selected-manage-around-icon-select arrow-down' : 'lr-selected-manage-around-icon-select arrow-up'}></Up>        {/* 选择元素的下拉框*/}       {showOptionSetTimeout ?         <div className={showOption ? 'popover-box popover-box-show' : 'popover-box popover-box-hidden'} id="mySelecte" style={{ width: `calc(100% + ${scrollWidth}px)` }}>           {['牛肉馅饼', '北京烤鸭', '蛋糕', '铁锅炖大鹅', '可乐鸡翅'].map((item, index) => (             <div key={index} className={selectedItem.item === item ? "popover-single popover-single-selected" : "popover-single"} onClick={() => { selectedOption(index, item) }}>{item}</div>           ))}         </div>         : ''}      </div>    ); }  export default SelectOption; 

index.scss

.so-all-box {     width: 360px;     position: relative;      .textA {         color: #A7AAA8;     }      .textB {         color: #1E201F;     }      .lr-selected-manage-around-text {         position: absolute;         top: 6px;         left: 12px;     }      .popover-box-show {         opacity: 1;     }      .popover-box-hidden {         opacity: 0;     }      .popover-box {         padding: 4px 0;         position: absolute;         top: 34px;         left: 0;         z-index: 10;         border-radius: 4px;         background: #FFF;         box-shadow: 0px 4px 15px 0px rgba(0, 0, 0, 0.12);         max-height: 200px; //更改选项卡最大高度         overflow: auto;         width: 100%;          .popover-single {             width: 100%;             height: 32px;             line-height: 32px;             cursor: pointer;             color: #505553;             font-size: 14px;             text-align: left;             padding-left: 10px;             box-sizing: border-box;              &.popover-single-selected {                 background: #E8FAF8;                 color: #00b498;             }              &:hover {                 background: #F2F5F4;             }         }     }      .borderA {         border: 1px solid #E8ECEB;     }      .borderB {         border: 1px solid #00b498;     }      .so-box {         width: 360px;         height: 34px;         line-height: 34px;         font-size: 14px;         padding: 2px 10px 0px 10px;         margin: 0;         border-radius: 6px;         box-sizing: border-box;         position: relative;         cursor: pointer;         background-color: #fff;         outline: none;          &:hover {             border: 1px solid #00b498;         }     }      .lr-selected-manage-around-icon-select {         width: 14px;         height: 14px;         position: absolute;         top: 10px;         right: 12px;         stroke: #A8ABB2;         font-size: 14px;         z-index: 9;     }      .arrow-up {         transform: rotateZ(-90deg); //根据箭头方向,自行调整角度,关闭时状态     }      .arrow-down {         transform: rotateZ(90deg); //根据箭头方向,自行调整角度,选项可出现时状态     }  }

使用方法:

//在父元素中引入 import SelectOption from '../selecteOption'  function Home() {   return (     <div>       <SelectOption></SelectOption>     </div>   ); }  export default Home;  

2.作为通用组件使用_和父组件传参

封装为通用组件使用。scss样式文件和上面的一样。

index.tsx

import './index.scss'; // 使用svg,后期更改图标颜色比较方便,还可以做悬浮变色 import { ReactComponent as Up } from '../../assets/images/icon-up.svg'; import { useState, useEffect } from 'react'  function SelectOption(props: any) {   // 父组件传过来的选项组   let optionList = props.selectList    // 选项body的滚动条   const [scrollWidth, setScrollWidth] = useState(0)    // 选项弹窗是否显示,为了优化用户体验,控制它的opacity透明度隐藏,为了使选项点击事件能够生效,选项弹窗立即隐藏   const [showOption, setShowOption] = useState(false)   // 选项弹窗是否显示,控制它的div是否存在,(弹窗隐藏后元素存在,点击事件生效)需要将弹窗移除   const [showOptionSetTimeout, setShowOptionSetTimeout] = useState(false)    // 当前选中的选项,从父元素获得初始值   const [selectedItem, setSelectedItem] = useState(props.currentOption)    //挂载后,计算选项弹窗是否有滚动条,从而改变选项弹窗body宽度   function changeWidth() {     var myElement: any = document.getElementById('mySelecte');     var widthWithBorder = myElement.offsetWidth;     var widthWithoutBorder = myElement.clientWidth;     setScrollWidth(widthWithBorder - widthWithoutBorder);   }   useEffect(() => {     changeWidth();   }, []);    /**    * input元素获得焦点以及失去焦点的事件    */   function showOptionBox() {     setShowOption(true)     setShowOptionSetTimeout(true)   }    /**    * 选择框失去焦点事件的处理逻辑      */   function inputBlur() {     setShowOption(false)     console.log(showOption, "showOption")     setTimeout(() => {       setShowOptionSetTimeout(false)     }, 300);   }    /**    * 用户选中了某个选项    * @param id 区分选项的唯一标志    * @param item 选中的名称    */   function selectedOption(id: number, item: string) {     setSelectedItem({       id: String(id), item     });     // 将用户点击结果返回给父元素     props.getOption({ id: String(id), item });   }    return (     <div className='so-all-box' >       <input type="button" onBlur={inputBlur} className={showOption ? 'so-box borderB' : 'so-box borderA'} id="mySelecte" onClick={() => { showOptionBox() }}>       </input>       <div className={selectedItem.id === '' ? "lr-selected-manage-around-text textA" : "lr-selected-manage-around-text textB"}>         {selectedItem.id === '' ? '请选择' : selectedItem.item}       </div>        {/* 箭头 */}       <Up className={showOption === true ? 'lr-selected-manage-around-icon-select arrow-down' : 'lr-selected-manage-around-icon-select arrow-up'}></Up>        {/* 选择元素的下拉框*/}       {showOptionSetTimeout ?         <div className={showOption ? 'popover-box popover-box-show' : 'popover-box popover-box-hidden'} id="mySelecte" style={{ width: `calc(100% + ${scrollWidth}px)` }}>           {optionList.map((item: any, index: any) => (             <div key={index} className={selectedItem.item === item ? "popover-single popover-single-selected" : "popover-single"} onClick={() => { selectedOption(index, item) }}>{item}</div>           ))}         </div>         : ''}      </div>    ); }  export default SelectOption; 

父组件调用:

//在父元素中引入 import SelectOption from '../selecteOption'  function Home() {    /**    * 下拉框子元素返回的用户点击的结果    * @param obj 返回的结果,是个对象,id唯一标志+item选中的name    */   function getOptionFromSon(obj: Object) {     console.log(obj)     // 将结果传给后端   }    return (     <div>      <SelectOption selectList={['牛肉馅饼', '北京烤鸭', '蛋糕', '铁锅炖大鹅', '可乐鸡翅']} currentOption={{ id: '1', item: '北京烤鸭' }} getOption={getOptionFromSon}></SelectOption>       </div>   ); }  export default Home; 

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!