1. 效果图
1.1 消息靠上接近导航栏,菜单显在消息体下方弹出,箭头向上
1.2 消息体没有贴近上方导航栏,菜单在消息体上方弹出,箭头向下
1.3 长消息,菜单在手指按下的位置弹出,无箭头
2. 代码实现
< view class = " message-box" :id = " ' messageBox' + item.msgUID" >
< view :class = " ['message-popup-box', elementPosition == 'nearTop' ? 'right-up-box' : elementPosition == 'nearBottom' ? 'right-down-box' : '']" :style = " elementPosition == 'overstep' ? computedRightMenuStyle : ''" v-if = " item.messagePopup" >
< view class = " message-operate" >
< view class = " operate-item" v-if = " item.messageType == 'TxtMsg'" @click.stop = " copyMessage(item, index)" >
< image src = " https://img.yiqitogether.com/yyqc/20231221/upload_o261zsurq4k7fugtfa3u2uvihq1ta4uo.png" mode = " aspectFill" alt = " " class = " operate-item-icon" > </ image>
< view class = " operate-item-txt" > 复制</ view>
</ view>
< view class = " operate-item" v-if = " item.messageType == 'TxtMsg' || item.messageType == 'ImgMsg' || item.messageType == 'ReferenceMsg'" @click.stop = " referenceMessage(item, index)" >
< image src = " https://img.yiqitogether.com/yyqc/20231221/upload_60riqndcd93gnl4eiy8gejopf6xm9z48.png" mode = " aspectFill" alt = " " class = " operate-item-icon" > </ image>
< view class = " operate-item-txt" > 回复</ view>
</ view>
< view class = " operate-item" v-if = " isRecall" @click.stop = " recallMessage(item, index)" >
< image src = " https://img.yiqitogether.com/yyqc/20231221/upload_dh3xhatlcjchcbh2blbke9c453sv580k.png" mode = " aspectFill" alt = " " class = " operate-item-icon" > </ image>
< view class = " operate-item-txt" > 撤回</ view>
</ view>
< view class = " operate-item" v-if = " !isRecall" @click.stop = " deleteMessage(item, index)" >
< image src = " http://img.yiqitogether.com/static/images/messageGray/icon_delete_white.png" mode = " aspectFill" alt = " " class = " operate-item-icon" > </ image>
< view class = " operate-item-txt" > 删除</ view>
</ view>
< view class = " operate-item" @click.stop = " multipleChoice(item, index)" >
< image src = " https://img.yiqitogether.com/yyqc/20240222/upload_qegsjb8mwt6tr6nzp2yv7bmn4c03cn4x.png" mode = " aspectFill" alt = " " class = " operate-item-icon" > </ image>
< view class = " operate-item-txt" > 多选</ view>
</ view>
</ view>
</ view>
</ view>
computed : {
computedRightMenuStyle ( ) {
if ( this . elementPosition == 'overstep' ) {
return { top : ` ${ this . elTop} px ` , right : 0 }
}
}
}
handleLongPress ( e, item, index ) {
if ( this . isMultipleChoice) {
return
}
let currClientY = e. changedTouches[ 0 ] . clientY
const query = uni. createSelectorQuery ( ) . in ( this )
query
. select ( ` #messageBox ${ item. msgUID} ` )
. boundingClientRect ( res => {
if ( res. top > 180 ) {
this . elementPosition = 'nearBottom'
} else {
if ( res. height > this . windowSize. height / 2 ) {
if ( currClientY < 200 ) {
this . elTop = - res. top + currClientY
} else {
this . elTop = - res. top + currClientY - 60
}
this . elementPosition = 'overstep'
} else {
this . elementPosition = 'nearTop'
}
}
} )
. exec ( )
this . isRecall = false
if ( this . messageItem) {
this . messageItem. messagePopup = false
}
this . messageItem = item
this . messageList[ index] . messagePopup = true
this . $forceUpdate ( )
let now = + new Date ( )
let recalTime = item. sendDate
let timediff = Math. abs ( now - recalTime) / 1000
if ( timediff <= 120 ) {
this . isRecall = true
} else {
this . isRecall = false
}
}
.message-popup-box {
position : absolute;
z-index : 99;
background : #595a5a;
border-radius : 16rpx;
.message-operate {
display : flex;
box-sizing : border-box;
padding : 16rpx;
.operate-item {
padding : 0 20rpx;
.operate-item-icon {
display : block;
width : 44rpx;
height : 44rpx;
background-size : cover;
}
.operate-item-txt {
font-size : 24rpx;
text-align : center;
color : #ffffff;
margin-top : 4rpx;
}
}
}
}
.right-up-box {
right : 0;
bottom : -78rpx;
}
.right-down-box {
right : 0;
top : -120rpx;
}
.right-up-box:before {
content : '' ;
position : absolute;
bottom : 98%;
right : 120rpx;
border : 16rpx solid transparent;
border-bottom : 16rpx solid #595a5a;
}
.right-down-box::before {
content : '' ;
position : absolute;
top : 98%;
right : 120rpx;
border : 16rpx solid transparent;
border-top : 16rpx solid #595a5a;
}