@@ -316,10 +316,14 @@ createApp({
316316 v = ( v == null ? '' : String ( v ) ) . replace ( / \s + / g, ' ' ) . trim ( ) ;
317317 return v . length > 80 ? v . slice ( 0 , 77 ) + '…' : v ;
318318 } ,
319- scrollDown ( ) {
319+ scrollDown ( force ) {
320+ // DOM 更新前先判断用户是否贴着底部(此刻还是旧高度):只有本来就在底部(或 force)才自动滚,
321+ // 否则流式中每个 token 都把用户上滚查看历史的位置反复拽回底部(issue #145:思考中滚动条动不了)。
322+ const el = this . $refs . msgList ;
323+ const stick = force || ! el || ( el . scrollHeight - el . scrollTop - el . clientHeight < 80 ) ;
320324 this . $nextTick ( ( ) => {
321- const el = this . $refs . msgList ;
322- if ( el ) el . scrollTop = el . scrollHeight ;
325+ const e = this . $refs . msgList ;
326+ if ( e && stick ) e . scrollTop = e . scrollHeight ;
323327 } ) ;
324328 } ,
325329 onKey ( e ) {
@@ -378,7 +382,15 @@ createApp({
378382 } catch ( _ ) { /* 拉不到就空列表,选择器不显示 */ }
379383 } ,
380384 // syncMention 据输入框当前值 + 光标重算提及态。keyup / input / click 时调用。
381- onInput ( ) { this . mention . hidden = false ; this . syncMention ( ) ; } ,
385+ onInput ( ) { this . mention . hidden = false ; this . syncMention ( ) ; this . autoGrow ( ) ; } ,
386+ // 输入框随内容自适应高度:先归零再按 scrollHeight 设,封顶 200px(与 CSS max-height 一致)。
387+ // 不做的话 textarea 固定 rows="1" 的高度,打多行也不长高(issue #145)。
388+ autoGrow ( ) {
389+ const ta = this . $refs . ta ;
390+ if ( ! ta ) return ;
391+ ta . style . height = 'auto' ;
392+ ta . style . height = Math . min ( ta . scrollHeight , 200 ) + 'px' ;
393+ } ,
382394 syncMention ( ) {
383395 const ta = this . $refs . ta ;
384396 if ( ! ta ) return ;
@@ -426,6 +438,8 @@ createApp({
426438 if ( ! text ) return ;
427439 this . input = '' ;
428440 this . mention . active = false ;
441+ this . $nextTick ( ( ) => this . autoGrow ( ) ) ; // 发送后高度复位回单行
442+ this . scrollDown ( true ) ; // 自己发的消息:强制跟到底部
429443 await fetch ( '/api/input' , {
430444 method : 'POST' ,
431445 headers : { 'Content-Type' : 'application/json' } ,
0 commit comments