CSS自定义下拉框
Posted 嘻嘻的妙妙屋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CSS自定义下拉框相关的知识,希望对你有一定的参考价值。
自定义下拉框
效果
index.tsx
import useState, useEffect from 'react'
import observer from 'mobx-react-lite'
import styles from './index.module.scss'
import recordStore from 'src/store/recordStore'
const DropDownBox: React.FC = props =>
// 查询月份下拉框
const [dropDown, setDropDown] = useState(false) // 默认下拉框为关闭状态
const handleOpen = (e: any) =>
e.stopPropagation() // 禁止事件冒泡
e.nativeEvent.stopImmediatePropagation() // 阻止监听同一事件的其他事件监听器被调用
setDropDown(!dropDown) // 将下拉框设为打开状态
useEffect(() =>
// 点击空白处关闭下拉框
document.body.addEventListener('click', () =>
setDropDown(false)
)
return () =>
document.body.removeEventListener('click', () =>
setDropDown(false)
)
, [])
const selectMonth = (e: any) =>
// console.log(e.currentTarget.getAttribute('data-name'))
setDropDown(!dropDown) // 选择月份后自动关闭下拉框
const month = e.currentTarget.getAttribute('data-name') // 获取下拉选项中的属性值
recordStore.setSelectedMonth(month) // 更新mobx中的month状态值
// 获取最近月份记录
useEffect(() =>
if (recordStore.selectedMonth)
recordStore.getDataList()
, [recordStore.selectedMonth]) // 监听月份值变化, 月份更新则触发获取该月份数据记录的方法
return (
<div className=styles.select>
<ul>
<li>
<div className=styles.head onClick=handleOpen>
<span>recordStore.selectedMonth</span>
<span className=styles.icon_down></span>
</div>
<ul className=dropDown ? styles.option : styles.hide>
recordStore.monthList &&
recordStore.monthList.map((item: string, index: number) => (
<li key=`month_$index` data-name=item className=styles.item onClick=selectMonth>
item
</li>
))
</ul>
</li>
</ul>
</div>
)
export default observer(DropDownBox)
recordStore.ts
import makeAutoObservable, runInAction from 'mobx'
import formatMonth from 'src/utils'
import listMonth from 'src/services/api'
class RecordStore
selectedMonth = '' // 选中月份
monthList: Array<string> = [] // 月份列表
constructor()
makeAutoObservable(this)
// 更改选中月份
async setSelectedMonth(month = '')
runInAction(() =>
this.selectedMonth = month
)
// 获取月份列表
async getMonthList()
const res = await listMonth()
if (res.status === 0)
runInAction(() =>
this.monthList = res.data
this.selectedMonth = res.data.length > 0 && res.data[0]
)
// 获取该月份数据记录
async getDataList()
const res = await helpLog(month: formatMonth(this.selectedMonth))
if (res.status === 0)
runInAction(() =>
this.dataList = res.data
)
export default new RecordStore ()
index.module.scss
.search
display: flex;
line-height: 24px;
ul
margin-left: 8px;
width: 96px;
height: 24px;
border: 1px solid #dcdcdc;
border-radius: 5px;
background: #eeeeee;
font-size: 12px;
cursor: pointer;
li
position: relative;
.head
overflow: hidden;
width: 100%;
height: 24px;
box-sizing: border-box;
line-height: 20px;
padding-left: 15px;
.icon_down
position: absolute;
top: 8px;
right: 16px;
width: 11px;
height: 7px;
background-image: url(../imgs/icon_down.png);
background-size: 100%;
.option
width: 96px;
position: absolute;
top: 23px;
left: -9px;
border: none;
border-radius: 0;
box-sizing: border-box;
z-index: 1;
.item
line-height: 20px;
padding-left: 18px;
background: #eeeeee;
height: 24px;
&:hover
background: #cccccc;
.hide
display: none;
补充
在 React 合成事件中,需要阻止冒泡时,可以使用 e.stopPropagation()
或 e.preventDefault()
方法来解决,另外还可以使用 e.nativeEvent.stopImmediatePropagation()
方法解决。
e.stopPropagation()
只能阻止合成事件间冒泡,即下层的合成事件,不会冒泡到上层的合成事件。事件本身还都是在document
上执行。所以最多只能阻止document
事件不能再冒泡到window
上。Event
接口的stopImmediatePropagation()
方法阻止监听同一事件的其他事件监听器被调用。
在 React 中,一个组件只能绑定一个同类型的事件监听器,当重复定义时,后面的监听器会覆盖之前的。
事实上
nativeEvent
的stopImmediatePropagation
只能阻止绑定在document
上的事件监听器。而合成事件上的e.nativeEvent.stopImmediatePropagation()
能阻止合成事件不会冒泡到document
上。
利用 e.nativeEvent.stopImmediatePropagation
解决的问题:
- 点击 div 内部,由于不冒泡,会正常执行菜单点击;
- 点击 div 外部,执行 document 上事件,关闭 div;
以上是关于CSS自定义下拉框的主要内容,如果未能解决你的问题,请参考以下文章
WeChat-SmallProgram:自定义select下拉选项框组件