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() 方法解决。

  1. e.stopPropagation() 只能阻止合成事件间冒泡,即下层的合成事件,不会冒泡到上层的合成事件。事件本身还都是在 document 上执行。所以最多只能阻止 document 事件不能再冒泡到 window 上。
  2. Event 接口的 stopImmediatePropagation() 方法阻止监听同一事件的其他事件监听器被调用。

在 React 中,一个组件只能绑定一个同类型的事件监听器,当重复定义时,后面的监听器会覆盖之前的。

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

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

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

以上是关于CSS自定义下拉框的主要内容,如果未能解决你的问题,请参考以下文章

easyui中自定义下拉框的使用

WeChat-SmallProgram:自定义select下拉选项框组件

我用css定位了导航,怎么当网页下拉到一定高度的时候变成悬浮的?

自定义SWT控件一之自定义单选下拉框

如何打造Android自定义的下拉列表框控件

Struts2 自定义下拉框标签Tag