@@ -161,50 +161,59 @@ export default class Popover extends SuperComponent {
161161 return start + triggerSize / 2 - contentSize / 2 ;
162162 } ,
163163
164- calcPlacement ( placement : string , triggerRect : any , contentRect : any ) {
165- const { isHorizontal, isVertical } = this . getToward ( placement ) ;
166- // 获取内容大小
167- const { width : contentWidth , height : contentHeight } = contentRect ;
168- // 获取所在位置
169- const { left : triggerLeft , top : triggerTop , right : triggerRight , bottom : triggerBottom } = triggerRect ;
170- // 是否能正常放置
171- let canPlace = true ;
172- const { windowWidth, windowHeight } = getWindowInfo ( ) ;
173- let finalPlacement = placement ;
174-
175- if ( isHorizontal ) {
176- if ( placement . startsWith ( 'top' ) ) {
177- canPlace = triggerTop - contentHeight >= 0 ;
178- } else if ( placement . startsWith ( 'bottom' ) ) {
179- canPlace = triggerBottom + contentHeight <= windowHeight ;
180- }
181- } else if ( isVertical ) {
182- if ( placement . startsWith ( 'left' ) ) {
183- canPlace = triggerLeft - contentWidth >= 0 ;
184- } else if ( placement . startsWith ( 'right' ) ) {
185- canPlace = triggerRight + contentWidth <= windowWidth ;
186- }
187- }
188-
189- if ( ! canPlace ) {
190- // 反向
191- if ( isHorizontal ) {
192- finalPlacement = placement . startsWith ( 'top' )
193- ? placement . replace ( 'top' , 'bottom' )
194- : placement . replace ( 'bottom' , 'top' ) ;
195- } else if ( isVertical ) {
196- finalPlacement = placement . startsWith ( 'left' )
197- ? placement . replace ( 'left' , 'right' )
198- : placement . replace ( 'right' , 'left' ) ;
199- }
200- }
201-
202- const basePos = this . calcContentPosition ( finalPlacement , triggerRect , contentRect ) ;
203-
204- return {
205- placement : finalPlacement ,
206- ...basePos ,
207- } ;
164+ calcPlacement ( isFixed : boolean , placement : string , triggerRect : any , contentRect : any ) {
165+ return new Promise < { placement : string ; top : number ; left : number } > ( ( resolve ) => {
166+ // 选取当前组件节点所在的组件实例,以支持 fixed 定位的元素计算位置
167+ const owner = this . selectOwnerComponent ( ) . createSelectorQuery ( ) ;
168+ owner . select ( `.${ name } -wrapper--fixed` ) . boundingClientRect ( ) ;
169+ owner . exec ( ( b ) => {
170+ const [ triggerChildRect ] = b ;
171+ if ( triggerChildRect && isFixed ) {
172+ triggerRect = triggerChildRect ;
173+ }
174+
175+ const { isHorizontal, isVertical } = this . getToward ( placement ) ;
176+ // 获取内容大小
177+ const { width : contentWidth , height : contentHeight } = contentRect ;
178+ // 获取所在位置
179+ const { left : triggerLeft , top : triggerTop , right : triggerRight , bottom : triggerBottom } = triggerRect ;
180+ // 是否能正常放置
181+ let canPlace = true ;
182+ const { windowWidth, windowHeight } = getWindowInfo ( ) ;
183+ let finalPlacement = placement ;
184+
185+ if ( isHorizontal ) {
186+ if ( placement . startsWith ( 'top' ) ) {
187+ canPlace = triggerTop - contentHeight >= 0 ;
188+ } else if ( placement . startsWith ( 'bottom' ) ) {
189+ canPlace = triggerBottom + contentHeight <= windowHeight ;
190+ }
191+ } else if ( isVertical ) {
192+ if ( placement . startsWith ( 'left' ) ) {
193+ canPlace = triggerLeft - contentWidth >= 0 ;
194+ } else if ( placement . startsWith ( 'right' ) ) {
195+ canPlace = triggerRight + contentWidth <= windowWidth ;
196+ }
197+ }
198+
199+ if ( ! canPlace ) {
200+ // 反向
201+ if ( isHorizontal ) {
202+ finalPlacement = placement . startsWith ( 'top' )
203+ ? placement . replace ( 'top' , 'bottom' )
204+ : placement . replace ( 'bottom' , 'top' ) ;
205+ } else if ( isVertical ) {
206+ finalPlacement = placement . startsWith ( 'left' )
207+ ? placement . replace ( 'left' , 'right' )
208+ : placement . replace ( 'right' , 'left' ) ;
209+ }
210+ }
211+
212+ const basePos = this . calcContentPosition ( finalPlacement , triggerRect , contentRect ) ;
213+
214+ resolve ( { placement : finalPlacement , ...basePos } ) ;
215+ } ) ;
216+ } ) ;
208217 } ,
209218
210219 async computePosition ( ) {
@@ -217,18 +226,27 @@ export default class Popover extends SuperComponent {
217226 query . select ( `#${ name } -content` ) . boundingClientRect ( ) ;
218227
219228 query . selectViewport ( ) . scrollOffset ( ) ;
220- query . exec ( ( res ) => {
229+ query . exec ( async ( res ) => {
221230 const [ triggerRect , contentRect , viewportOffset ] = res ;
222231 if ( ! triggerRect || ! contentRect ) return ;
223232
233+ // 如果 fixed 定位,不需要加上滚动偏移量
234+ const isFixed = this . properties . fixed ;
224235 // 最终放置位置
225- const { placement : finalPlacement , ...basePos } = this . calcPlacement ( _placement , triggerRect , contentRect ) ;
226- // TODO 优化:滚动时可能导致箭头闪烁
236+ const { placement : finalPlacement , ...basePos } = await this . calcPlacement (
237+ isFixed ,
238+ _placement ,
239+ triggerRect ,
240+ contentRect ,
241+ ) ;
242+
243+ // TODO 优化:滚动时切换placement可能导致箭头闪烁
227244 this . setData ( { _placement : finalPlacement } ) ;
228245
229- const { scrollTop = 0 , scrollLeft = 0 } = viewportOffset ;
230- const top = basePos . top + scrollTop ;
231- const left = basePos . left + scrollLeft ;
246+ const { scrollTop = 0 , scrollLeft = 0 } = viewportOffset || { } ;
247+
248+ const top = isFixed ? basePos . top : basePos . top + scrollTop ;
249+ const left = isFixed ? basePos . left : basePos . left + scrollLeft ;
232250
233251 const style = `top:${ Math . max ( top , 0 ) } px;left:${ Math . max ( left , 0 ) } px;` ;
234252 const arrowStyle = this . calcArrowStyle ( _placement , triggerRect , contentRect ) ;
0 commit comments