@@ -635,11 +635,38 @@ class PromptAssistant {
635635 widget . _eventCleanupFunctions = widget . _eventCleanupFunctions || [ ] ;
636636 widget . _eventCleanupFunctions . push ( removeBlurListener ) ;
637637
638- // 添加输入事件监听,实时更新撤销/重做按钮状态
638+ // 添加输入事件监听,实时更新撤销/重做按钮状态和位置调整
639639 const removeInputListener = EventManager . addDOMListener ( inputWidget . inputEl , 'input' , ( ) => {
640640 UIToolkit . updateUndoRedoButtonState ( widget , HistoryCacheService ) ;
641+ // 检测滚动条状态并调整位置
642+ this . _adjustPositionForScrollbar ( widget , inputWidget . inputEl ) ;
641643 } ) ;
642644 widget . _eventCleanupFunctions . push ( removeInputListener ) ;
645+
646+ // 添加ResizeObserver监听输入框尺寸变化
647+ if ( window . ResizeObserver ) {
648+ const resizeObserver = new ResizeObserver ( ( ) => {
649+ // 延迟执行,确保浏览器完成布局更新
650+ setTimeout ( ( ) => {
651+ this . _adjustPositionForScrollbar ( widget , inputWidget . inputEl ) ;
652+ } , 10 ) ;
653+ } ) ;
654+
655+ resizeObserver . observe ( inputWidget . inputEl ) ;
656+
657+ // 添加清理函数
658+ widget . _eventCleanupFunctions . push ( ( ) => {
659+ resizeObserver . disconnect ( ) ;
660+ } ) ;
661+ } else {
662+ // 降级方案:监听window resize事件
663+ const removeResizeListener = EventManager . addDOMListener ( window , 'resize' ,
664+ EventManager . debounce ( ( ) => {
665+ this . _adjustPositionForScrollbar ( widget , inputWidget . inputEl ) ;
666+ } , 100 )
667+ ) ;
668+ widget . _eventCleanupFunctions . push ( removeResizeListener ) ;
669+ }
643670 }
644671
645672 return widget ;
@@ -705,6 +732,11 @@ class PromptAssistant {
705732 this . _setupUIEventHandling ( widget , inputEl , containerDiv ) ;
706733 this . _setupUIPosition ( widget , inputEl , containerDiv , canvasContainerRect ) ;
707734
735+ // 初始滚动条检测和位置调整
736+ setTimeout ( ( ) => {
737+ this . _adjustPositionForScrollbar ( widget , inputEl ) ;
738+ } , 100 ) ; // 延迟执行,确保DOM完全渲染
739+
708740 // 默认隐藏状态
709741 containerDiv . style . display = 'none' ;
710742
@@ -1967,6 +1999,65 @@ class PromptAssistant {
19671999 return button ;
19682000 }
19692001
2002+ /**
2003+ * 检测输入框是否有滚动条
2004+ * @param {HTMLElement } inputEl - 输入框元素
2005+ * @returns {boolean } 是否有垂直滚动条
2006+ */
2007+ _detectScrollbar ( inputEl ) {
2008+ if ( ! inputEl || inputEl . tagName !== 'TEXTAREA' ) {
2009+ return false ;
2010+ }
2011+
2012+ try {
2013+ // 检查垂直滚动条:scrollHeight > clientHeight
2014+ const hasVerticalScrollbar = inputEl . scrollHeight > inputEl . clientHeight ;
2015+ logger . debug ( `[滚动条检测] 输入框滚动状态 | scrollHeight: ${ inputEl . scrollHeight } | clientHeight: ${ inputEl . clientHeight } | 有滚动条: ${ hasVerticalScrollbar } ` ) ;
2016+ return hasVerticalScrollbar ;
2017+ } catch ( error ) {
2018+ logger . error ( `[滚动条检测] 检测失败 | 错误: ${ error . message } ` ) ;
2019+ return false ;
2020+ }
2021+ }
2022+
2023+ /**
2024+ * 根据滚动条状态调整小助手位置
2025+ * @param {Object } widget - 小助手实例
2026+ * @param {HTMLElement } inputEl - 输入框元素
2027+ */
2028+ _adjustPositionForScrollbar ( widget , inputEl ) {
2029+ if ( ! widget ?. element || ! inputEl ) return ;
2030+
2031+ const hasScrollbar = this . _detectScrollbar ( inputEl ) ;
2032+ const containerDiv = widget . element ;
2033+
2034+ // 检查当前定位模式
2035+ const isStandardMode = containerDiv . style . position !== 'fixed' ;
2036+
2037+ if ( isStandardMode ) {
2038+ // ---标准定位模式调整---
2039+ const rightOffset = hasScrollbar ? '16px' : '4px' ; // 有滚动条时向左偏移10px
2040+ containerDiv . style . right = rightOffset ;
2041+ logger . debug ( `[位置调整] 标准方案 | 有滚动条: ${ hasScrollbar } | 右偏移: ${ rightOffset } ` ) ;
2042+ } else {
2043+ // ---兼容定位模式调整---
2044+ // 需要重新计算位置,因为固定定位使用的是left属性
2045+ const inputRect = inputEl . getBoundingClientRect ( ) ;
2046+ const offsetRight = hasScrollbar ? 18 : 6 ; // 有滚动条时增加10px偏移
2047+
2048+ // 临时隐藏以获取正确尺寸
2049+ containerDiv . style . visibility = 'hidden' ;
2050+ void containerDiv . offsetWidth ;
2051+
2052+ // 计算新位置
2053+ const newLeft = inputRect . right - containerDiv . offsetWidth - offsetRight ;
2054+ containerDiv . style . left = `${ newLeft } px` ;
2055+ containerDiv . style . visibility = 'visible' ;
2056+
2057+ logger . debug ( `[位置调整] 兼容方案 | 有滚动条: ${ hasScrollbar } | 左偏移: ${ newLeft } px` ) ;
2058+ }
2059+ }
2060+
19702061 /**
19712062 * 设置UI位置
19722063 * 使用绝对定位方式
@@ -2116,8 +2207,9 @@ class PromptAssistant {
21162207 // 强制回流以获取正确尺寸
21172208 void containerDiv . offsetWidth ;
21182209
2119- // 现在设置位置 - 放置在输入框右下角
2120- const offsetRight = 6 ; // 右侧偏移
2210+ // 现在设置位置 - 放置在输入框右下角,考虑滚动条状态
2211+ const hasScrollbar = inputEl . tagName === 'TEXTAREA' && inputEl . scrollHeight > inputEl . clientHeight ;
2212+ const offsetRight = hasScrollbar ? 16 : 6 ; // 有滚动条时增加10px偏移
21212213 const offsetBottom = 4 ;
21222214
21232215 containerDiv . style . left = `${ inputRect . right - containerDiv . offsetWidth - offsetRight } px` ;
0 commit comments