当前位置: 首页 > news >正文

React_自定义组件_下拉框

目录

一、效果图

二、代码

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;

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 面试题009-Java-MyBatis
  • 【Python】Requests 库使用示例
  • Maven 项目编译提示 unparseable pom 的解决方法
  • 练习:随机点名器5
  • 数据结构与算法基础-学习-37-平衡二叉树(Avl树)之删除节点
  • 各向异性含水层中地下水三维流基本微分方程的推导(二)
  • @Autowired 和 @Resource 区别的补充说明与示例
  • Datadomain存储上的文件大小,linux环境建议使用du -sh --apparent-size或ll -sh来查看
  • 【JAVA入门】Day15 - 接口
  • 实现前端用户密码重置功能(有源码)
  • 【C语言】 —— 预处理详解(下)
  • ubuntu 换源
  • #VERDI# 关于如何查看FSM状态机的方法
  • 【EasyExcel】根据单元格内容自动调整列宽
  • 第九章 面向对象
  • 深入了解以太坊
  • Google 是如何开发 Web 框架的
  • hexo+github搭建个人博客
  • 【译】理解JavaScript:new 关键字
  • Android Studio:GIT提交项目到远程仓库
  • Android 架构优化~MVP 架构改造
  • android图片蒙层
  • Apache Zeppelin在Apache Trafodion上的可视化
  • CSS 三角实现
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • ES6, React, Redux, Webpack写的一个爬 GitHub 的网页
  • github指令
  • HTTP请求重发
  • js数组之filter
  • rc-form之最单纯情况
  • Sublime text 3 3103 注册码
  • Synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReenTrantLock 的对比...
  • Zepto.js源码学习之二
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 简单易用的leetcode开发测试工具(npm)
  • 前端临床手札——文件上传
  • 我这样减少了26.5M Java内存!
  • 回归生活:清理微信公众号
  • 专访Pony.ai 楼天城:自动驾驶已经走过了“从0到1”,“规模”是行业的分水岭| 自动驾驶这十年 ...
  • ​520就是要宠粉,你的心头书我买单
  • ​LeetCode解法汇总2696. 删除子串后的字符串最小长度
  • ​卜东波研究员:高观点下的少儿计算思维
  • ​批处理文件中的errorlevel用法
  • ![CDATA[ ]] 是什么东东
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • ### RabbitMQ五种工作模式:
  • #C++ 智能指针 std::unique_ptr 、std::shared_ptr 和 std::weak_ptr
  • #Linux(权限管理)
  • #LLM入门|Prompt#1.7_文本拓展_Expanding
  • #NOIP 2014#Day.2 T3 解方程
  • #vue3 实现前端下载excel文件模板功能
  • (04)Hive的相关概念——order by 、sort by、distribute by 、cluster by
  • (10)ATF MMU转换表
  • (补)B+树一些思想
  • (二)fiber的基本认识