pref: 优化消息列表

This commit is contained in:
Pang 2024-01-12 11:09:44 +08:00
parent 36735ace50
commit 976b9690d2
3 changed files with 73 additions and 101 deletions

View File

@ -68,7 +68,7 @@
"vue-resize-observer": "^2.0.16", "vue-resize-observer": "^2.0.16",
"vue-router": "^3.6.5", "vue-router": "^3.6.5",
"vue-template-compiler": "~2.6.14", "vue-template-compiler": "~2.6.14",
"vue-virtual-scroll-list-hi": "^2.3.5-7", "vue-virtual-scroll-list-hi": "^2.3.5-8",
"vuedraggable": "^2.24.3", "vuedraggable": "^2.24.3",
"vuex": "^3.6.2" "vuex": "^3.6.2"
}, },

View File

@ -153,7 +153,7 @@
</p> </p>
</div> </div>
<div class="dialog-top-message-btn"> <div class="dialog-top-message-btn">
<Loading v-if="topPosLoad" type="pure"/> <Loading v-if="topPosLoad > 0" type="pure"/>
<i v-else class="taskfont">&#xee15;</i> <i v-else class="taskfont">&#xee15;</i>
<i class="taskfont" @click.stop="onCancelTop(topMsg)">&#xe6e5;</i> <i class="taskfont" @click.stop="onCancelTop(topMsg)">&#xe6e5;</i>
</div> </div>
@ -188,7 +188,6 @@
@scroll="onScroll" @scroll="onScroll"
@range="onRange" @range="onRange"
@totop="onPrevPage" @totop="onPrevPage"
@resized="onItemRendered"
@on-mention="onMention" @on-mention="onMention"
@on-longpress="onLongpress" @on-longpress="onLongpress"
@ -623,7 +622,6 @@ import UserAvatarTip from "../../../components/UserAvatar/tip.vue";
import DialogGroupWordChain from "./DialogGroupWordChain"; import DialogGroupWordChain from "./DialogGroupWordChain";
import DialogGroupVote from "./DialogGroupVote"; import DialogGroupVote from "./DialogGroupVote";
export default { export default {
name: "DialogWrapper", name: "DialogWrapper",
components: { components: {
@ -665,11 +663,15 @@ export default {
data() { data() {
return { return {
keeps: 25, keeps: 25,
loadIng: 0,
msgItem: DialogItem, msgItem: DialogItem,
msgText: '', msgText: '',
msgNew: 0, msgNew: 0, //
msgType: '', msgType: '', //
loadIng: 0, msgActivity: false, //
msgPrepared: false, //
focusLazy: false, focusLazy: false,
focusTimer: null, focusTimer: null,
@ -725,11 +727,8 @@ export default {
recordState: '', recordState: '',
wrapperStart: null, wrapperStart: null,
scrollOffset: 0,
scrollTail: 0, scrollTail: 0,
scrollOffset: 0,
preventMoreLoad: false,
preventToBottom: false,
replyListShow: false, replyListShow: false,
replyListId: 0, replyListId: 0,
@ -757,6 +756,7 @@ export default {
scrollAction: 0, scrollAction: 0,
scrollTmp: 0, scrollTmp: 0,
scrollIng: 0, scrollIng: 0,
scrollGroup: null,
approveDetails: {id: 0}, approveDetails: {id: 0},
approveDetailsShow: false, approveDetailsShow: false,
@ -765,15 +765,12 @@ export default {
observers: [], observers: [],
unreadOne: 0, // id unreadOne: 0, // id
topPosLoad: false, // topPosLoad: 0, //
positionLoad: 0, // positionLoad: 0, //
positionShow: false, // positionShow: false, //
renderMsgNum: 0, // preventMoreLoad: false, //
renderMsgSizes: new Map(), //
msgActivityStatus: false, //
listPreparedStatus: false, //
selectedTextStatus: false, // selectedTextStatus: false, //
scrollToBottomAndRefresh: false, // scrollToBottomRefresh: false, //
androidKeyboardVisible: false, // Android androidKeyboardVisible: false, // Android
} }
}, },
@ -1132,9 +1129,13 @@ export default {
return 1024000 return 1024000
}, },
readEnabled({msgActivityStatus, listPreparedStatus}) { readEnabled({msgActivity, msgPrepared}) {
return msgActivityStatus === 0 && listPreparedStatus return msgActivity === 0 && msgPrepared
}, },
stickToBottom({windowActive, scrollTail}) {
return windowActive && scrollTail <= 0
}
}, },
watch: { watch: {
@ -1156,39 +1157,28 @@ export default {
}, },
immediate: true immediate: true
}, },
dialogId: { dialogId: {
handler(dialog_id, old_id) { handler(dialog_id, old_id) {
this.scrollInit()
if (dialog_id) { if (dialog_id) {
this.msgNew = 0 this.msgNew = 0
this.msgType = '' this.msgType = ''
this.unreadOne = 0 this.unreadOne = 0
this.scrollTail = 0
this.scrollOffset = 0
this.searchShow = false this.searchShow = false
this.positionShow = false this.positionShow = false
this.listPreparedStatus = false this.msgPrepared = false
this.scrollToBottomAndRefresh = false this.scrollToBottomRefresh = false
this.renderMsgNum = Math.min(this.keeps, Math.max(this.allMsgList.length, 1))
this.renderMsgSizes.clear()
this.allMsgs = this.allMsgList this.allMsgs = this.allMsgList
// //
const tmpMsgA = this.allMsgList.map(({id, msg, emoji}) => {
return {id, msg, emoji}
})
this.getMsgs({ this.getMsgs({
dialog_id, dialog_id,
msg_id: this.msgId, msg_id: this.msgId,
msg_type: this.msgType, msg_type: this.msgType,
save_before: _ => this.onMarkOffset(false)
}).then(_ => { }).then(_ => {
this.openId = dialog_id this.openId = dialog_id
this.listPreparedStatus = true this.msgPrepared = true
//
const tmpMsgB = this.allMsgList.map(({id, msg, emoji}) => {
return {id, msg, emoji}
})
if (JSON.stringify(tmpMsgA) != JSON.stringify(tmpMsgB)) {
this.renderMsgNum = Math.min(this.keeps, Math.max(this.allMsgList.length, 1))
}
// //
setTimeout(_ => { setTimeout(_ => {
this.onSearchMsgId() this.onSearchMsgId()
@ -1238,6 +1228,16 @@ export default {
this.observers.push({key: 'scroller', observer: scrollerObserver}) this.observers.push({key: 'scroller', observer: scrollerObserver})
} }
} }
if (this.$refs.scroller) {
this.scrollGroup = this.$refs.scroller.$el.querySelector('[role="group"]')
if (this.scrollGroup) {
if (!this.observers.find(({key}) => key === 'scrollGroup')) {
const groupObserver = new ResizeObserver(this.onResizeEvent)
groupObserver.observe(this.scrollGroup);
this.observers.push({key: 'scrollGroup', observer: groupObserver})
}
}
}
}) })
}, },
immediate: true immediate: true
@ -1322,7 +1322,7 @@ export default {
const lastMsg = this.allMsgs[this.allMsgs.length - 1] const lastMsg = this.allMsgs[this.allMsgs.length - 1]
const lastEl = $A(this.$refs.scroller.$el).find(`[data-id="${lastMsg.id}"]`) const lastEl = $A(this.$refs.scroller.$el).find(`[data-id="${lastMsg.id}"]`)
if (lastEl.length === 0) { if (lastEl.length === 0) {
this.scrollToBottomAndRefresh = true this.scrollToBottomRefresh = true
return; return;
} }
// //
@ -1333,7 +1333,6 @@ export default {
if (JSON.stringify(newList) == JSON.stringify(oldList)) { if (JSON.stringify(newList) == JSON.stringify(oldList)) {
return; return;
} }
const {tail} = this.scrollInfo();
if ($A.isIos() && newList.length !== oldList.length) { if ($A.isIos() && newList.length !== oldList.length) {
// iOS // iOS
const scrollEl = this.$refs.scroller.$el const scrollEl = this.$refs.scroller.$el
@ -1346,12 +1345,16 @@ export default {
this.allMsgs = newList; this.allMsgs = newList;
} }
// //
if (!this.windowActive || (tail > 55 && oldList.length > 0)) { if (!this.stickToBottom) {
const lastId = oldList[oldList.length - 1]?.id || 0 const oldId = oldList.length > 0 ? oldList[oldList.length - 1].id : 0
const tmpList = newList.filter(item => item.id && item.id > lastId && item.userid != this.userId && !item.read_at) this.msgNew += newList.filter(item => item.id && item.id > oldId && item.userid != this.userId && !item.read_at).length
this.msgNew += tmpList.length }
} else { },
!this.preventToBottom && this.onToBottom()
'allMsgs.length' () {
if (this.stickToBottom) {
this.onToBottom()
} }
}, },
@ -1597,8 +1600,7 @@ export default {
item.msg.text = data.text item.msg.text = data.text
} }
this.$nextTick(_ => { this.$nextTick(_ => {
const {tail: newTail} = this.scrollInfo() if (tail <= 10 && tail != this.scrollInfo().tail) {
if (tail <= 10 && newTail != tail) {
this.operatePreventScroll++ this.operatePreventScroll++
this.$refs.scroller.scrollToBottom() this.$refs.scroller.scrollToBottom()
setTimeout(_ => this.operatePreventScroll--, 50) setTimeout(_ => this.operatePreventScroll--, 50)
@ -1703,7 +1705,6 @@ export default {
delay: 600 delay: 600
}) })
} }
this.preventToBottom = true;
this.getMsgs({ this.getMsgs({
dialog_id: this.dialogId, dialog_id: this.dialogId,
msg_id: this.msgId, msg_id: this.msgId,
@ -1719,7 +1720,6 @@ export default {
if (msg_id > 0) { if (msg_id > 0) {
this.$store.dispatch("cancelLoad", `msg-${msg_id}`) this.$store.dispatch("cancelLoad", `msg-${msg_id}`)
} }
this.preventToBottom = false;
}) })
} }
}) })
@ -2072,6 +2072,8 @@ export default {
entries.some(({target, contentRect}) => { entries.some(({target, contentRect}) => {
if (target === this.$refs.msgs) { if (target === this.$refs.msgs) {
this.onMsgsResize(contentRect) this.onMsgsResize(contentRect)
} else if (target === this.scrollGroup) {
this.onScrollGroupResize(contentRect)
} }
}) })
}, },
@ -2091,6 +2093,18 @@ export default {
this.__msgs_height = height; this.__msgs_height = height;
}, },
onScrollGroupResize({height}) {
const {offset, tail} = this.scrollInfo()
if (this.stickToBottom) {
this.onToBottom()
} else if (tail > 0
&& typeof this.__scroll_group_data !== "undefined"
&& offset - this.__scroll_group_data.offset + tail === height - this.__scroll_group_data.height) {
this.onToBottom()
}
this.__scroll_group_data = {height, offset, tail}
},
onActive() { onActive() {
this.$emit("on-active"); this.$emit("on-active");
}, },
@ -2131,33 +2145,6 @@ export default {
} }
}, },
onMarkOffset(recovery = false) {
const scroller = this.$refs.scroller
if (!scroller) {
return false
}
if (recovery) {
if (this.__mark_offset === undefined) {
return false
}
this.onToOffset(scroller.getScrollSize() - scroller.getClientSize() - this.__mark_offset)
this.__mark_offset = undefined
} else {
this.__mark_offset = scroller.getScrollSize() - scroller.getClientSize() - scroller.getOffset()
}
return true
},
scrollInit() {
const scroller = this.$refs.scroller;
if (scroller && this.allMsgs.length > 0) {
scroller.virtual.destroy()
this.allMsgs = []
scroller.scrollToOffset(0)
scroller.installVirtual()
}
},
scrollInfo() { scrollInfo() {
const scroller = this.$refs.scroller; const scroller = this.$refs.scroller;
if (scroller) { if (scroller) {
@ -2204,7 +2191,7 @@ export default {
}, },
onReGetMsg() { onReGetMsg() {
this.scrollToBottomAndRefresh = false this.scrollToBottomRefresh = false
this.getMsgs({ this.getMsgs({
dialog_id: this.dialogId, dialog_id: this.dialogId,
msg_id: this.msgId, msg_id: this.msgId,
@ -2240,22 +2227,6 @@ export default {
}).catch(() => {}) }).catch(() => {})
}, },
onItemRendered(id, size) {
const scroller = this.$refs.scroller
if (!scroller) {
return
}
if (this.renderMsgNum > 0 && scroller.getSizes() >= this.renderMsgNum) {
this.renderMsgNum = 0
!this.onMarkOffset(true) && this.onToBottom()
} else if (this.renderMsgSizes.has(id)
&& size > this.renderMsgSizes.get(id)
&& size - this.renderMsgSizes.get(id) === this.scrollInfo().tail) {
this.onToBottom()
}
this.renderMsgSizes.set(id, size)
},
onDialogMenu(cmd) { onDialogMenu(cmd) {
switch (cmd) { switch (cmd) {
case "searchMsg": case "searchMsg":
@ -2527,16 +2498,16 @@ export default {
}, },
onActivity(activity) { onActivity(activity) {
if (this.msgActivityStatus === false) { if (this.msgActivity === false) {
if (activity) { if (activity) {
this.msgActivityStatus = 1 this.msgActivity = 1
} }
return return
} }
if (activity) { if (activity) {
this.msgActivityStatus++ this.msgActivity++
} else { } else {
this.msgActivityStatus-- this.msgActivity--
} }
}, },
@ -2548,9 +2519,9 @@ export default {
const {offset, tail} = this.scrollInfo(); const {offset, tail} = this.scrollInfo();
this.scrollOffset = offset; this.scrollOffset = offset;
this.scrollTail = tail; this.scrollTail = tail;
if (this.scrollTail <= 55) { if (tail <= 10) {
this.msgNew = 0; this.msgNew = 0;
this.scrollToBottomAndRefresh && this.onReGetMsg() this.scrollToBottomRefresh && this.onReGetMsg()
} }
// //
this.scrollAction = event.target.scrollTop; this.scrollAction = event.target.scrollTop;
@ -3433,9 +3404,9 @@ export default {
if (!this.topMsg) { if (!this.topMsg) {
return return
} }
this.topPosLoad = true this.topPosLoad++
this.onPositionId(this.topMsg.id).finally(_ => { this.onPositionId(this.topMsg.id).finally(_ => {
this.topPosLoad = false this.topPosLoad--
}) })
}, },

View File

@ -521,6 +521,7 @@
.dialog-msgs { .dialog-msgs {
flex: 1; flex: 1;
position: relative; position: relative;
overflow: hidden;
} }
.dialog-position { .dialog-position {
@ -557,8 +558,8 @@
.dialog-scroller { .dialog-scroller {
position: absolute; position: absolute;
top: 0;
left: 0; left: 0;
bottom: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
padding: 16px 32px 0; padding: 16px 32px 0;