11import type { Placement , Strategy , OffsetOptions , RootBoundary , Boundary , ReferenceElement } from '@floating-ui/dom'
22import { computePosition , autoUpdate , flip , offset , shift , arrow , hide , limitShift } from '@floating-ui/dom'
33
4- import { hooks } from '@opentiny/vue-common'
5-
6- const { reactive, watch, markRaw, onBeforeUnmount } = hooks
7-
84interface IFloatOption {
95 reference : null | ReferenceElement
106 popper : null | HTMLElement
@@ -330,7 +326,7 @@ const emit = (state: IFloatOption, eventName: string, params?: any) => {
330326}
331327
332328/** 快速构建虚拟元素的辅助方法, 适于右键菜单,区域选择, 跟随光标等场景 */
333- const virtualEl = ( x : number , y : number , w : number = 0 , h : number = 0 ) => ( {
329+ const virtualEl = ( x : number , y : number , w = 0 , h = 0 ) => ( {
334330 getBoundingClientRect ( ) {
335331 return {
336332 width : 0 ,
@@ -346,66 +342,68 @@ const virtualEl = (x: number, y: number, w: number = 0, h: number = 0) => ({
346342} )
347343
348344/** 响应式的弹出层管理函数,适用于场景: tooltip, poppover, select, 右键菜单, floatbar, notify, 或 canvas上跟随鼠标等 */
349- export const useFloating = ( option : Partial < IFloatOption > = { } ) => {
350- const state = reactive ( option ) as IFloatOption
345+ export const useFloating =
346+ ( { reactive, watch, markRaw, onBeforeUnmount } ) =>
347+ ( option : Partial < IFloatOption > = { } ) => {
348+ const state = reactive ( option ) as IFloatOption
351349
352- let cleanup : null | ( ( ) => void ) = null
350+ let cleanup : null | ( ( ) => void ) = null
353351
354- // 0、标准化state
355- Object . keys ( defaultOption ) . forEach ( ( key ) => {
356- if ( ! Object . prototype . hasOwnProperty . call ( state , key ) ) {
357- state [ key ] = defaultOption [ key ]
358- }
359- } )
360- state . _last = markRaw ( { } ) as any
361- state . _events = markRaw ( { show : [ ] , hide : [ ] , update : [ ] } )
362-
363- const watchState = ( ) => {
364- // 1、引用和弹窗同时存在
365- if ( state . popper && state . reference ) {
366- // 1.1 当前需要显示, 可能是show变化了,也可能是其它任意值变化了, 都需要重新的一次update
367- if ( state . show ) {
368- appendPopper ( state )
369- if ( state . autoUpdate ) {
352+ // 0、标准化state
353+ Object . keys ( defaultOption ) . forEach ( ( key ) => {
354+ if ( ! Object . prototype . hasOwnProperty . call ( state , key ) ) {
355+ state [ key ] = defaultOption [ key ]
356+ }
357+ } )
358+ state . _last = markRaw ( { } ) as any
359+ state . _events = markRaw ( { show : [ ] , hide : [ ] , update : [ ] } )
360+
361+ const watchState = ( ) => {
362+ // 1、引用和弹窗同时存在
363+ if ( state . popper && state . reference ) {
364+ // 1.1 当前需要显示, 可能是show变化了,也可能是其它任意值变化了, 都需要重新的一次update
365+ if ( state . show ) {
366+ appendPopper ( state )
367+ if ( state . autoUpdate ) {
368+ cleanup && cleanup ( )
369+ cleanup = autoUpdatePopper ( state )
370+ } else {
371+ updatePopper ( state )
372+ }
373+ }
374+ // 1.2 当前不需要显示
375+ else {
370376 cleanup && cleanup ( )
371- cleanup = autoUpdatePopper ( state )
372- } else {
373- updatePopper ( state )
377+ closePopper ( state )
374378 }
375379 }
376- // 1.2 当前不需要显示
380+ // 2、引用和弹窗不全。 可能前一次是全的,所以要释放一下
377381 else {
378382 cleanup && cleanup ( )
379383 closePopper ( state )
380384 }
381- }
382- // 2、引用和弹窗不全。 可能前一次是全的,所以要释放一下
383- else {
384- cleanup && cleanup ( )
385- closePopper ( state )
386- }
387385
388- state . _last . popper = state . popper
389- state . _last . reference = state . reference
390- state . _last . show = ( state . show && state . popper && state . reference ) as boolean // 真实的是否show变量
391- state . _last . appendToBody = state . appendToBody
392- state . _last . timestamp = new Date ( ) . getTime ( )
393- }
386+ state . _last . popper = state . popper
387+ state . _last . reference = state . reference
388+ state . _last . show = ( state . show && state . popper && state . reference ) as boolean // 真实的是否show变量
389+ state . _last . appendToBody = state . appendToBody
390+ state . _last . timestamp = new Date ( ) . getTime ( )
391+ }
394392
395- watch ( state , watchState , { immediate : true } )
393+ watch ( state , watchState , { immediate : true } )
396394
397- const on = ( eventName , cb ) => state . _events [ eventName ] . push ( cb )
398- const off = ( eventName , cb ) => ( state . _events [ eventName ] = state . _events [ eventName ] . filter ( ( i ) => i !== cb ) )
395+ const on = ( eventName , cb ) => state . _events [ eventName ] . push ( cb )
396+ const off = ( eventName , cb ) => ( state . _events [ eventName ] = state . _events [ eventName ] . filter ( ( i ) => i !== cb ) )
399397
400- // 3、组件卸载前,移除元素
401- onBeforeUnmount ( ( ) => {
402- cleanup && cleanup ( )
403- closePopper ( state )
404- } )
398+ // 3、组件卸载前,移除元素
399+ onBeforeUnmount ( ( ) => {
400+ cleanup && cleanup ( )
401+ closePopper ( state )
402+ } )
405403
406- // 4、返回state 及辅助方法
407- // 正常修改state去触发更新,但如果某些业务想在state不变时,仍想执行一次更新, 则使用forceUpdate即可
408- // 比如select 懒加载: popper, show都不变, 但popper 的大小变化了,可以forceUpdate一下。
409- // 【autoUpdate 理论上会监听 popper的resize的, 这层考虑可能是多余。】
410- return { state, on, off, virtualEl, forceUpdate : watchState }
411- }
404+ // 4、返回state 及辅助方法
405+ // 正常修改state去触发更新,但如果某些业务想在state不变时,仍想执行一次更新, 则使用forceUpdate即可
406+ // 比如select 懒加载: popper, show都不变, 但popper 的大小变化了,可以forceUpdate一下。
407+ // 【autoUpdate 理论上会监听 popper的resize的, 这层考虑可能是多余。】
408+ return { state, on, off, virtualEl, forceUpdate : watchState }
409+ }
0 commit comments