调整日记评论面板跟随键盘并保留输入草稿

This commit is contained in:
2026-10-11 09:32:45 +08:00
parent 1bafb01741
commit 45c81aeaac
4 changed files with 120 additions and 19 deletions
+44 -10
View File
@@ -12,6 +12,12 @@ Page(withDataCache({
hasMoreComments: true,
showCommentInput: false,
commentText: '',
commentInitialText: '',
commentLength: 0,
commentFocus: false,
commentKeyboardHeight: 0,
commentEditorHeight: 56,
commentSending: false,
replyTo: null,
coverSwiperIndex: 0,
previewImages: [],
@@ -119,28 +125,49 @@ Page(withDataCache({
onPreviewSwiperChange: function(e) { this.setData({ previewIndex: e.detail.current }); },
onCommentTap: function() {
this.setData({ showCommentInput: true, replyTo: null, commentText: '' });
this.openComment(null);
},
onReplyTap: function(e) {
var item = e.currentTarget.dataset.item;
this.setData({
showCommentInput: true,
replyTo: { id: item.id, user_id: item.user_id, nickname: item.nickname },
commentText: ''
});
this.openComment({ id: item.id, user_id: item.user_id, nickname: item.nickname });
},
openComment: function(replyTo) {
var sameTarget = (!replyTo && !this.data.replyTo) ||
(replyTo && this.data.replyTo && replyTo.id === this.data.replyTo.id);
var text = sameTarget ? this.data.commentText : '';
this.setData({ showCommentInput: true, replyTo: replyTo, commentText: text,
commentInitialText: text, commentLength: text.length, commentFocus: true,
commentKeyboardHeight: 0, commentEditorHeight: 56 });
},
onCommentInput: function(e) {
this.setData({ commentText: e.detail.value });
// 不把正文反复写回原生输入框,避免中文输入时光标跳动。
this.data.commentText = e.detail.value || '';
this.setData({ commentLength: this.data.commentText.length });
},
onCommentKeyboardHeight: function(e) {
var height = Math.max(0, Number(e.detail.height) || 0);
if (this.data.showCommentInput) this.setData({ commentKeyboardHeight: height });
},
onCommentLineChange: function(e) {
this.setData({ commentEditorHeight: Math.min(160, Math.max(56, Number(e.detail.height) || 56)) });
},
onCommentBlur: function() {
this.setData({ commentFocus: false });
},
cancelComment: function() {
this.setData({ showCommentInput: false, replyTo: null, commentText: '' });
if (this.data.commentSending) return;
this.setData({ showCommentInput: false, commentFocus: false, commentKeyboardHeight: 0 });
wx.hideKeyboard();
},
onHide: function() {
this.setData({ showCommentInput: false, commentFocus: false, commentKeyboardHeight: 0 });
},
submitComment: async function() {
if (this.data.commentSending) return;
var text = this.data.commentText.trim();
if (!text) { wx.showToast({ title: '请输入评论内容', icon: 'none' }); return; }
this.setData({ commentSending: true });
try {
var params = { diary_id: this.data.diaryId, content: text };
if (this.data.replyTo) {
@@ -166,12 +193,19 @@ Page(withDataCache({
showCommentInput: false,
replyTo: null,
commentText: '',
commentInitialText: '',
commentLength: 0,
commentFocus: false,
commentKeyboardHeight: 0,
'diary.comment_count': (this.data.diary.comment_count || 0) + 1
});
wx.hideKeyboard();
wx.showToast({ title: '评论成功', icon: 'success' });
}
} catch (e) {
wx.showToast({ title: e.error || '评论失败', icon: 'none' });
} finally {
this.setData({ commentSending: false });
}
},
+7 -8
View File
@@ -71,15 +71,14 @@
</view>
</view>
<!-- 评论输入弹窗 -->
<view class="modal-mask" wx:if="{{showCommentInput}}" catchtap="cancelComment">
<view class="modal-box" catchtap="noop">
<view class="modal-top">
<text class="modal-cancel" catchtap="cancelComment">取消</text>
<text class="modal-title">{{replyTo ? '回复 @' + replyTo.nickname : '发表评论'}}</text>
<text class="modal-send" catchtap="submitComment">发送</text>
<!-- 评论面板自行跟随键盘,禁用原生页面上推,避免双重位移。 -->
<view class="comment-compose-mask" wx:if="{{showCommentInput}}" catchtap="cancelComment" catchtouchmove="noop">
<view class="comment-compose {{commentKeyboardHeight > 0 ? 'comment-compose--keyboard' : ''}}" style="bottom:{{commentKeyboardHeight}}px;" catchtap="noop">
<view class="comment-compose-heading"><text>{{replyTo ? '回复 @' + replyTo.nickname : '写下你的留言'}}</text><text class="comment-compose-close" catchtap="cancelComment">收起</text></view>
<view class="comment-compose-field">
<textarea placeholder-class="handwritten-placeholder" class="comment-compose-input" style="height:{{commentEditorHeight}}px;" placeholder="说点什么,让 TA 知道你的心情…" value="{{commentInitialText}}" bindinput="onCommentInput" bindlinechange="onCommentLineChange" bindkeyboardheightchange="onCommentKeyboardHeight" bindblur="onCommentBlur" focus="{{commentFocus}}" fixed="{{true}}" adjust-position="{{false}}" hold-keyboard="{{true}}" show-confirm-bar="{{false}}" cursor-spacing="0" maxlength="500" disabled="{{commentSending}}" />
</view>
<textarea placeholder-class="handwritten-placeholder" class="modal-input" placeholder="说点什么..." value="{{commentText}}" bindinput="onCommentInput" auto-focus maxlength="500" />
<view class="comment-compose-toolbar"><text class="comment-compose-count">{{commentLength}}/500</text><button class="comment-compose-send" catchtap="submitComment" disabled="{{commentLength === 0 || commentSending}}" loading="{{commentSending}}" hover-class="none">发送</button></view>
</view>
</view>
+13 -1
View File
@@ -12,7 +12,19 @@
.comment-box { margin-top:38rpx; }.comment-head { padding-bottom:20rpx; border-bottom:1rpx solid #E9DDD0; }.comment-head-text { color:#352E2A; font-size:28rpx; font-weight:600; }.comment-empty { padding:44rpx 8rpx; text-align:center; font-size:24rpx; line-height:1.7; color:#85776D; }
.comment-item { display:flex; align-items:flex-start; gap:14rpx; padding:24rpx 0; border-bottom:1rpx solid #E9DDD0; }.comment-item:last-child { border:0; }.comment-avatar { width:48rpx; height:48rpx; border-radius:50%; flex-shrink:0; }.comment-body { flex:1; min-width:0; }.comment-top { display:flex; justify-content:space-between; gap:12rpx; flex-wrap:wrap; margin-bottom:12rpx; }.comment-name { font-size:24rpx; color:#352E2A; font-weight:500; }.comment-date { font-size:20rpx; color:#A39386; }.comment-content { display:block; font-size:26rpx; line-height:1.65; color:#65594F; overflow-wrap:break-word; }.comment-at { color:#B74768; }
.bottom-bar { position:fixed; left:0; right:0; bottom:0; z-index:20; background:#FFFDF8; border-top:1rpx solid #E9DDD0; padding:16rpx 44rpx calc(16rpx + env(safe-area-inset-bottom)); height:calc(100rpx + env(safe-area-inset-bottom)); box-sizing:border-box; }.bottom-input { display:flex; align-items:center; gap:14rpx; height:66rpx; border:1rpx solid #E9DDD0; background:#FAF5EE; padding:0 20rpx; border-radius:16rpx; }.bottom-input-icon { width:30rpx; height:30rpx; }.bottom-input-text { color:#85776D; font-size:25rpx; }
.modal-mask { position:fixed; top:0; left:0; right:0; bottom:0; z-index:1200; display:flex; align-items:flex-end; }.modal-box { width:100%; border-radius:24rpx 24rpx 0 0!important; padding:28rpx 32rpx calc(28rpx + env(safe-area-inset-bottom)); }.modal-top { display:flex; align-items:center; justify-content:space-between; gap:16rpx; margin-bottom:24rpx; }.modal-cancel,.modal-send { padding:12rpx 0; font-size:26rpx; color:#85776D; }.modal-send { color:#B74768; }.modal-title { font-size:28rpx; font-weight:500; color:#352E2A; }.modal-input { width:100%; height:200rpx; background:#FAF5EE; border:1rpx solid #E9DDD0; border-radius:16rpx; padding:20rpx; font-size:27rpx; box-sizing:border-box; }
.comment-compose-mask { position:fixed; inset:0; z-index:1200; background:rgba(53,46,42,.24); }
.comment-compose { position:fixed; left:0; right:0; padding:22rpx 28rpx calc(20rpx + env(safe-area-inset-bottom)); box-sizing:border-box; border-radius:28rpx 28rpx 0 0; background:#FFFDF8; }
.comment-compose--keyboard { padding-bottom:16rpx; }
.comment-compose-heading { display:flex; align-items:center; justify-content:space-between; gap:20rpx; margin-bottom:16rpx; font-size:23rpx; line-height:1.5; color:#85776D; }
.comment-compose-heading > text:first-child { flex:1; min-width:0; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }
.comment-compose-close { flex-shrink:0; padding:8rpx 4rpx; color:#B74768; }
.comment-compose-field { background:#FFF0F5; border-radius:22rpx; padding:20rpx 24rpx; }
.comment-compose-input { display:block; width:100%; font-size:28rpx; line-height:1.6; color:#352E2A; }
.comment-compose-toolbar { display:flex; align-items:center; justify-content:space-between; margin-top:14rpx; }
.comment-compose-count { font-size:21rpx; color:#A39386; }
.comment-compose-send { margin:0; min-width:124rpx; height:64rpx; padding:0 28rpx; border-radius:32rpx; background:#F47FA5; color:#FFF; font-size:25rpx; line-height:64rpx; }
.comment-compose-send::after { border:0; }
.comment-compose-send[disabled] { background:#F4E6EB; color:#A39386; }
.preview-mask { position:fixed; top:0; left:0; right:0; bottom:0; z-index:9999; background:rgba(0,0,0,.95); }.preview-swiper { width:100%; height:100%; }.preview-slide { position:relative; }.preview-img { position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); width:100%; display:block; }.preview-num { position:fixed; bottom:calc(44rpx + env(safe-area-inset-bottom)); left:0; right:0; text-align:center; color:#FFFDF8; font-size:25rpx; }.preview-close { position:fixed; top:var(--nav-height,64px); right:24rpx; width:72rpx; height:72rpx; display:flex; align-items:center; justify-content:center; }.preview-close-icon { width:34rpx; height:34rpx; filter:brightness(0) invert(1); }
@media (max-width:350px) { .read-page { padding-left:32rpx; padding-right:32rpx; }.bottom-bar { padding-left:32rpx; padding-right:32rpx; } }