剛出來時候 作這種相似的效果,都是 經過 css hover 效果,把組件 包在父級中,經過父級的 hover 事件,來控制 裏面子級 的顯示與隱藏。css
這樣使用,一: 若是是列表裏面作這個功能,就會出現不少這種組件,明明 一個就能夠作這件事,就很浪費性能react
二: 組件嵌套在業務代碼裏面,很差管理 與複用,維護成本高。antd
添加在body 上這種方式沒本身寫過,後面一直都是 使用 antd 或者其餘組件庫,如今寫了,記錄下思路less
這個效果 須要注意 幾點dom
1. 就是 組件顯示的位置。ide
2. 顯示隱藏之間若是過渡,性能
先辨別下 鼠標移入/移出事件this
mouseenter 鼠標移入目標觸發spa
mouseleave 鼠標移出目標觸發code
mouseover 鼠標移入目標觸發,其子元素也會觸發
mouseout 鼠標移出目標觸發,其子元素也會觸發
因此應該用 mouseenter 和 mouseleave, 來處理事件,
1. 經過 mouseenter 拿到 event 對象,來獲取 元素自身寬高 和 元素距離 文檔頂部的距離,和左邊的距離, 來定位元素顯示的位置。特定的狀況還能夠判斷 距離底部位置,從而適當上移顯示組件,或者監聽 窗口變化 resize 事件來 實時變化顯示組件的位置,不過鼠標移入移出顯示應該不用
// 設置組件顯示的位置 setPosition = () => { const { event } = this.props; let $dom = event.currentTarget; let top = $dom.offsetTop + $dom.clientHeight + 5; let left = $dom.offsetLeft; this.setState({ top, left }) }
2. 就是 顯示與隱藏了,
(1)在經過鼠標移入/移出控制,那麼這個按鈕可能有個 hover 效果,可是 這裏不能用 hover ,由於組件是直接添加到body 根部不 鼠標進入到組件,就沒效果了,這裏應該用事件判斷來控制效果。
(2)在鼠標移入按鈕 能夠展現組件,那麼 離開按鈕以後呢,同上,鼠標在從組件回到按鈕上 ,組件怎麼顯示的問題。
在 鼠標移出按鈕的時候 加一個 定時事件,setTimeout 設置時間 0.2s,在日曆組件的移入事件中加一個 clearTimeout, 在時間到以前 進入日曆組件,那麼組件依舊展現,不然,組件關閉,
在鼠標從組件回到按鈕 也是同樣,設置一個定時器,在 按鈕的移入事件中加一個 判斷 是否有定時器,有的話則表示是從組件回來的,可進行清空,若是判斷沒有,則就從新開始,可直接顯示組件,而且要在相對的時機,置空定時器的變量(時長可根據實際狀況設置,鼠標移動仍是很快的)
import React from 'react'; import moment from 'moment'; import Calendar from "./calendar"; import './index.less'; type P = { } let timer: any = null; class Index extends React.Component<P, any> { str = moment().format('YYYY-MM'); constructor(props: P) { super(props); this.state = { flg: false, // 控制 按鈕的 hover 效果 } } componentDidMount() { } // 日曆顯示 show = (e: any) => { this.setState({ flg: true }) let data = { text: this.str, // 這裏是 給日曆組件傳了2個回調事件,移出/移入 mouseenter: this.calendarMouseEnter, mouseleave: this.calendarMouseLeave, event: e } Calendar.open(data); } // 日曆隱藏 hide = () => { timer = setTimeout(() => { this.setState({ flg: false }) Calendar.remove(''); timer = null; }, 200); } // 按鈕鼠標移入 mouseenter = (e: any) => { e.stopPropagation(); if (timer) { clearTimeout(timer); timer = null; } else { this.show(e); } } // 按鈕鼠標移出 mouseleave = (e: any) => { e.stopPropagation(); const { flg } = this.state if (flg) { this.hide(); } } // 日曆鼠標移入 calendarMouseEnter = (e: any) => { e.stopPropagation(); clearTimeout(timer); timer = null; } // 日曆鼠標移出 calendarMouseLeave = (e: any) => { e.stopPropagation(); this.hide(); } render() { const { flg } = this.state; return ( <div className="oper-calendar"> <span className={flg ? "title hover" : "title"} onMouseEnter={this.mouseenter} onMouseLeave={this.mouseleave}>{this.str}</span> </div> ) } } export default Index;