曹睿
2025-04-22 03426aefbf891aa1fe3064d4301d17d5de869114
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// [z-paging]聊天记录模式模块
import u from '.././z-paging-utils'
 
export default {
    props: {
        // 使用聊天记录模式,默认为否
        useChatRecordMode: {
            type: Boolean,
            default: u.gc('useChatRecordMode', false)
        },
        // 使用聊天记录模式时滚动到顶部后,列表垂直移动偏移距离。默认0rpx。单位px(暂时无效)
        chatRecordMoreOffset: {
            type: [Number, String],
            default: u.gc('chatRecordMoreOffset', '0rpx')
        },
        // 使用聊天记录模式时是否自动隐藏键盘:在用户触摸列表时候自动隐藏键盘,默认为是
        autoHideKeyboardWhenChat: {
            type: Boolean,
            default: u.gc('autoHideKeyboardWhenChat', true)
        },
        // 使用聊天记录模式中键盘弹出时是否自动调整slot="bottom"高度,默认为是
        autoAdjustPositionWhenChat: {
            type: Boolean,
            default: u.gc('autoAdjustPositionWhenChat', true)
        },
        // 使用聊天记录模式中键盘弹出时占位高度偏移距离。默认0rpx。单位px
        chatAdjustPositionOffset: {
            type: [Number, String],
            default: u.gc('chatAdjustPositionOffset', '0rpx')
        },
        // 使用聊天记录模式中键盘弹出时是否自动滚动到底部,默认为否
        autoToBottomWhenChat: {
            type: Boolean,
            default: u.gc('autoToBottomWhenChat', false)
        },
        // 使用聊天记录模式中reload时是否显示chatLoading,默认为否
        showChatLoadingWhenReload: {
            type: Boolean,
            default: u.gc('showChatLoadingWhenReload', false)
        },
        // 在聊天记录模式中滑动到顶部状态为默认状态时,以加载中的状态展示,默认为是。若设置为否,则默认会显示【点击加载更多】,然后才会显示loading
        chatLoadingMoreDefaultAsLoading: {
            type: Boolean,
            default: u.gc('chatLoadingMoreDefaultAsLoading', true)
        },
    },
    data() {
        return {
            // 键盘高度
            keyboardHeight: 0,
            // 键盘高度是否未改变,此时占位高度变化不需要动画效果
            isKeyboardHeightChanged: false,
        }
    },
    computed: {
        finalChatRecordMoreOffset() {
            return u.convertToPx(this.chatRecordMoreOffset);
        },
        finalChatAdjustPositionOffset() {
            return u.convertToPx(this.chatAdjustPositionOffset);
        },
        // 聊天记录模式旋转180度style
        chatRecordRotateStyle() {
            let cellStyle;
            // 在vue中,直接将列表倒置,因此在vue的cell中,也直接写style="transform: scaleY(-1)"转回来即可。
            // #ifndef APP-NVUE
            cellStyle = this.useChatRecordMode ? { transform: 'scaleY(-1)' } : {};
            // #endif
            
            // 在nvue中,需要考虑数据量不满一页的情况,因为nvue中的list无法通过flex-end修改不满一页的起始位置,会导致不满一页时列表数据从底部开始,因此需要特别判断
            // 当数据不满一屏的时候,不进行列表倒置
            // #ifdef APP-NVUE
            cellStyle = this.useChatRecordMode ? { transform: this.isFirstPageAndNoMore ? 'scaleY(1)' : 'scaleY(-1)' } : {};
            // #endif
            
            this.$emit('update:cellStyle', cellStyle);
            this.$emit('cellStyleChange', cellStyle);
            
            // 在聊天记录模式中,如果列表没有倒置并且当前是第一页,则需要自动滚动到最底部
            this.$nextTick(() => {
                if (this.isFirstPage && this.isChatRecordModeAndNotInversion) {
                    this.$nextTick(() => {
                        // 这里多次触发滚动到底部是为了避免在某些情况下,即使是在nextTick但是cell未渲染完毕导致滚动到底部位置不正确的问题
                        this._scrollToBottom(false);
                        u.delay(() => {
                            this._scrollToBottom(false);
                            u.delay(() => {
                                this._scrollToBottom(false);
                            }, 50)
                        }, 50)
                    })
                }
            })
            return cellStyle;
        },
        // 是否是聊天记录列表并且有配置transform
        isChatRecordModeHasTransform() {
            return this.useChatRecordMode && this.chatRecordRotateStyle && this.chatRecordRotateStyle.transform;
        },
        // 是否是聊天记录列表并且列表未倒置
        isChatRecordModeAndNotInversion() {
            return this.isChatRecordModeHasTransform && this.chatRecordRotateStyle.transform === 'scaleY(1)';
        },
        // 是否是聊天记录列表并且列表倒置
        isChatRecordModeAndInversion() {
            return this.isChatRecordModeHasTransform && this.chatRecordRotateStyle.transform === 'scaleY(-1)';
        },
        // 最终的聊天记录模式中底部安全区域的高度,如果开启了底部安全区域并且键盘未弹出,则添加底部区域高度
        chatRecordModeSafeAreaBottom() {
            return this.safeAreaInsetBottom && !this.keyboardHeight ? this.safeAreaBottom : 0;
        }
    },
    mounted() {
        // 监听键盘高度变化(H5、百度小程序、抖音小程序、飞书小程序不支持)
        // #ifndef H5 || MP-BAIDU || MP-TOUTIAO
        if (this.useChatRecordMode) {
            uni.onKeyboardHeightChange(this._handleKeyboardHeightChange);
        }
        // #endif
    },
    methods: {
        // 添加聊天记录
        addChatRecordData(data, toBottom = true, toBottomWithAnimate = true) {
            if (!this.useChatRecordMode) return;
            this.isTotalChangeFromAddData = true;
            this.addDataFromTop(data, toBottom, toBottomWithAnimate);
        },
        // 手动触发滚动到顶部加载更多,聊天记录模式时有效
        doChatRecordLoadMore() {
            this.useChatRecordMode && this._onLoadingMore('click');
        },
        // 处理键盘高度变化
        _handleKeyboardHeightChange(res) {
            this.$emit('keyboardHeightChange', res);
            if (this.autoAdjustPositionWhenChat) {
                this.isKeyboardHeightChanged = true;
                this.keyboardHeight = res.height > 0 ? res.height + this.finalChatAdjustPositionOffset : res.height;
            }
            if (this.autoToBottomWhenChat && this.keyboardHeight > 0) {
                u.delay(() => {
                    this.scrollToBottom(false);
                    u.delay(() => {
                        this.scrollToBottom(false);
                    })
                })
            } 
        }
    }
}