11import { PropType , VNodeDirective } from 'vue' ;
2- import {
3- createPopper , Modifier , ModifierArguments , Options as popperOptions ,
4- } from '@popperjs/core' ;
2+ import { createPopper , ModifierArguments , Options as popperOptions } from '@popperjs/core' ;
53import { debounce } from 'lodash-es' ;
64import { on , off , once } from '../utils/dom' ;
75import { renderTNodeJSX , renderContent } from '../utils/render-tnode' ;
@@ -216,6 +214,9 @@ export default mixins(classPrefixMixins, getAttachConfigMixins('popup')).extend(
216214 return ;
217215 }
218216
217+ // 获取内层 overlay 元素的尺寸,用于 flip 计算
218+ const overlayEl = this . $refs . overlay as HTMLElement ;
219+
219220 const modifiers : popperOptions [ 'modifiers' ] = getIEVersion ( ) > 9
220221 ? [ ]
221222 : [
@@ -230,25 +231,49 @@ export default mixins(classPrefixMixins, getAttachConfigMixins('popup')).extend(
230231 } ,
231232 ] ;
232233
233- // 当使用 popperContentElement 时,添加custom modifier来维护样式
234- if ( this . popperContentElement ) {
234+ // 如果没有使用 popperContentElement,则需要修正尺寸和偏移量
235+ // 因为外层 popper 元素的尺寸为 0,需要使用内层 overlay 的尺寸
236+ if ( ! this . popperContentElement && overlayEl ) {
237+ // 在 read 阶段修改 rects.popper 的尺寸
235238 modifiers . push ( {
236- name : 'applyStyles' ,
237- phase : 'write' ,
239+ name : 'popperSize' ,
240+ enabled : true ,
241+ phase : 'read' ,
238242 fn : ( { state } : { state : ModifierArguments < popperOptions > [ 'state' ] } ) => {
239- // 确保样式被应用到指定的元素
240- const styles = state . styles . popper ;
241- if ( styles && popperEl ) {
242- Object . assign ( popperEl . style , styles ) ;
243- }
244- const attributes = state . attributes . popper ;
245- if ( attributes && popperEl ) {
246- Object . keys ( attributes ) . forEach ( ( key ) => {
247- popperEl . setAttribute ( key , String ( attributes [ key ] ) ) ;
248- } ) ;
243+ const overlayRect = overlayEl . getBoundingClientRect ( ) ;
244+ // eslint-disable-next-line no-param-reassign
245+ state . rects . popper . width = overlayRect . width ;
246+ // eslint-disable-next-line no-param-reassign
247+ state . rects . popper . height = overlayRect . height ;
248+ } ,
249+ } as any ) ;
250+
251+ // 在 popperOffsets 之后修正偏移量(因为 popperOffsets 用的是错误的尺寸)
252+ modifiers . push ( {
253+ name : 'fixPopperOffsets' ,
254+ enabled : true ,
255+ phase : 'main' ,
256+ requires : [ 'popperOffsets' ] ,
257+ fn : ( { state } : { state : ModifierArguments < popperOptions > [ 'state' ] } ) => {
258+ const overlayRect = overlayEl . getBoundingClientRect ( ) ;
259+ const { placement, modifiersData } = state ;
260+
261+ if ( modifiersData . popperOffsets ) {
262+ // 根据 placement 修正坐标
263+ if ( placement . startsWith ( 'top' ) ) {
264+ // top 位置需要减去内容高度
265+ // eslint-disable-next-line no-param-reassign
266+ modifiersData . popperOffsets . y -= overlayRect . height ;
267+ }
268+ if ( placement . startsWith ( 'left' ) ) {
269+ // left 位置需要减去内容宽度
270+ // eslint-disable-next-line no-param-reassign
271+ modifiersData . popperOffsets . x -= overlayRect . width ;
272+ }
273+ // bottom/right 位置不需要修正
249274 }
250275 } ,
251- } as unknown as any ) ;
276+ } as any ) ;
252277 }
253278
254279 this . popper = createPopper ( triggerEl , popperEl , {
0 commit comments