1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 【CSS】自定义下拉框

【CSS】自定义下拉框

时间:2022-01-01 23:56:55

相关推荐

【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.datathis.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 中,一个组件只能绑定一个同类型的事件监听器,当重复定义时,后面的监听器会覆盖之前的。

事实上nativeEventstopImmediatePropagation只能阻止绑定在document上的事件监听器。而合成事件上的e.nativeEvent.stopImmediatePropagation()能阻止合成事件不会冒泡到document上。

利用e.nativeEvent.stopImmediatePropagation解决的问题:

点击 div 内部,由于不冒泡,会正常执行菜单点击;点击 div 外部,执行 document 上事件,关闭 div;

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。