feat: 在留言板组件中添加模态弹窗功能,优化滑动操作和删除确认逻辑

This commit is contained in:
yangzhe 2025-07-31 11:32:11 +08:00
parent 48c94b0905
commit e194091873
2 changed files with 157 additions and 13 deletions

View File

@ -2,16 +2,19 @@
<view class="message-board-component">
<!-- 一个列表一个swipe-action容器更符合官方推荐用法 -->
<view v-for="(item, index) in answerList" :key="item.id">
<uni-swipe-action>
<uni-swipe-action ref="swipeActionRef">
<!-- :right-options="swipeOptions" -->
<uni-swipe-action-item
:disabled="!canSwipe"
:threshold="0.3"
:auto-close="false"
@change="(e) => handleSwipeChange(e, index)"
@change="handleSwipeChange($event, index)"
>
<template #right>
<view class="right-btn-box" @click.stop="handleSwipeClick(item, index, e)">
<template v-slot:right>
<view
class="right-btn-box"
@touchend.stop="handleSwipeClick(item, index)"
>
<image
class="right-btn"
src="/static/common/images/icon_delete.png"
@ -76,7 +79,11 @@
<!-- 回复按钮-老师 -->
<view class="reply-btn-box" v-if="isTeacher">
<button class="reply-btn">
<button
class="reply-btn uni-btn-reset"
:class="{ 'disabled-reply': item.isReply }"
@click.stop="handleReplyClick(item)"
>
<image
class="reply-btn-icon"
src="/static/common/images/icon_reply.png"
@ -104,6 +111,24 @@
</uni-swipe-action-item>
</uni-swipe-action>
</view>
<!-- 模态弹窗 -->
<u-popup
v-model="modalShow"
mode="center"
width="70%"
border-radius="16"
:mask-close-able="false"
>
<view class="custom-modal">
<view class="modal-title">提示</view>
<view class="modal-content">{{ content }}</view>
<view class="modal-footer">
<view class="modal-btn cancel" @click="handleCancel">取消</view>
<view class="modal-btn confirm" @click="handleConfirm">确认</view>
</view>
</view>
</u-popup>
</view>
</template>
@ -134,8 +159,16 @@ export default {
data() {
return {
AvatarDefault, //
currentItem: {}, // item
currentIndex: 0, // item
openedItems: {}, //
isWebMode: false, // web
//
modalShow: false,
content: "确定要撤回该留言吗?",
modalOpenTime: 0,
preventCloseOnce: false, //
};
},
mounted() {
@ -147,9 +180,20 @@ export default {
console.log("isWebMode", this.isWebMode);
},
methods: {
//
handleSwipeChange(e, index) {
// 使Vue
this.$set(this.openedItems, index, e);
// console.log("", this.openedItems);
},
//
handleSwipeClick(item, index, e) {
console.log("按钮点击", item, index, e);
handleSwipeClick(item, index) {
// console.log("swipeClick", item, index);
// console.log("swipeActionRef", this.$refs.swipeActionRef);
this.currentItem = item;
this.currentIndex = index;
this.modalShow = true;
this.modalOpenTime = Date.now(); //
},
// web
@ -157,11 +201,38 @@ export default {
console.log("web模式点击", item);
},
//
handleSwipeChange(isOpened, index) {
// 使Vue
this.$set(this.openedItems, index, isOpened);
console.log("滑动状态", this.openedItems);
//
handleReplyClick(item) {
if (item.isReply) {
return;
}
this.$emit("reply", item);
},
//
handleCancel() {
this.modalShow = false;
},
//
handleConfirm() {
//
if (this.modalOpenTime && Date.now() - this.modalOpenTime < 300) {
console.log("防止误触,请重新点击");
return;
}
//
this.$emit("delete", this.currentItem, (success) => {
//
console.log("callback success", success);
if (success) {
this.$refs.swipeActionRef[this.currentIndex].closeAll();
this.modalShow = false;
}
});
},
},
};
@ -180,6 +251,7 @@ export default {
align-items: center;
justify-content: center;
border-radius: 0 16rpx 16rpx 0;
border: 1px solid #fff; /* 防止初始状态下出现红线 */
margin-bottom: 32rpx;
.right-btn {
width: 32rpx;
@ -302,6 +374,10 @@ export default {
width: 100%;
margin-top: 28rpx;
.uni-btn-reset::after {
border: none !important;
}
.reply-btn {
display: flex;
align-items: center;
@ -320,6 +396,10 @@ export default {
margin-right: 12rpx;
}
}
.disabled-reply {
background: #cccccc;
}
}
}
@ -343,4 +423,51 @@ export default {
height: 32rpx;
margin-right: 8rpx;
}
.custom-modal {
background-color: #fff;
overflow: hidden;
.modal-title {
font-size: 32rpx;
font-weight: 500;
text-align: center;
padding: 30rpx 0;
color: #333;
}
.modal-content {
padding: 30rpx;
font-size: 28rpx;
color: #666;
text-align: center;
min-height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
}
.modal-footer {
display: flex;
border-top: 1px solid #eee;
.modal-btn {
flex: 1;
height: 90rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 30rpx;
&.cancel {
color: #666;
border-right: 1px solid #eee;
}
&.confirm {
color: #4f6aff;
}
}
}
}
</style>

View File

@ -21,8 +21,14 @@
<!-- 内容区域包装器 -->
<view class="content-wrapper">
<!-- 问答列表组件 -->
<message-board :answerList="answerList"></message-board>
<message-board
:answerList="answerList"
@delete="handleDelete"
></message-board>
</view>
<!-- 提示 -->
<u-toast ref="uToast" />
</view>
</template>
@ -91,6 +97,17 @@ export default {
// activeTab
this.activeTab = index === 0 ? "unread" : "replied";
},
handleDelete(item, callback) {
console.log("handleDelete", item);
setTimeout(() => {
this.$refs.uToast.show({
title: "撤回成功",
type: "success",
});
callback(true);
}, 1500);
},
},
};
</script>