158 lines
3.8 KiB
Vue
158 lines
3.8 KiB
Vue
<script>
|
|
import { hoursTimeFormat } from "utils";
|
|
import contextmenu from "../directives/contextmenu";
|
|
export default {
|
|
name: "LemonMessages",
|
|
components: {},
|
|
props: {
|
|
//是否隐藏消息发送人昵称
|
|
hideName: Boolean,
|
|
//是否隐藏显示消息时间
|
|
hideTime: Boolean,
|
|
reverseUserId: [String, Number],
|
|
timeRange: {
|
|
type: Number,
|
|
default: 1,
|
|
},
|
|
timeFormat: {
|
|
type: Function,
|
|
default(val) {
|
|
return hoursTimeFormat(val);
|
|
},
|
|
},
|
|
messages: {
|
|
type: Array,
|
|
default: () => [],
|
|
},
|
|
},
|
|
data() {
|
|
return {
|
|
_loading: false,
|
|
_loadend: false,
|
|
};
|
|
},
|
|
render() {
|
|
return (
|
|
<div class="lemon-messages" ref="wrap" on-scroll={this._handleScroll}>
|
|
<div
|
|
class={[
|
|
"lemon-messages__load",
|
|
`lemon-messages__load--${this._loadend ? "end" : "ing"}`,
|
|
]}
|
|
>
|
|
{this._loadend ? this._renderLoadEnd() : this._renderLoading()}
|
|
</div>
|
|
{this.messages.map((message, index) => {
|
|
const node = [];
|
|
const tagName = `lemon-message-${message.type}`;
|
|
const prev = this.messages[index - 1];
|
|
if (
|
|
prev &&
|
|
this.msecRange &&
|
|
message.sendTime - prev.sendTime > this.msecRange
|
|
) {
|
|
node.push(
|
|
<lemon-message-event
|
|
attrs={{
|
|
message: {
|
|
id: "__time__",
|
|
type: "event",
|
|
content: hoursTimeFormat(message.sendTime),
|
|
},
|
|
}}
|
|
/>,
|
|
);
|
|
}
|
|
|
|
let attrs;
|
|
if (message.type == "event") {
|
|
attrs = { message: message };
|
|
} else {
|
|
attrs = {
|
|
timeFormat: this.timeFormat,
|
|
message: message,
|
|
reverse: this.reverseUserId == message.fromUser.id,
|
|
hideTime: this.hideTime,
|
|
hideName: this.hideName,
|
|
};
|
|
}
|
|
node.push(<tagName ref="message" refInFor={true} attrs={attrs} />);
|
|
return node;
|
|
})}
|
|
</div>
|
|
);
|
|
},
|
|
computed: {
|
|
msecRange() {
|
|
return this.timeRange * 1000 * 60;
|
|
},
|
|
},
|
|
watch: {},
|
|
methods: {
|
|
_renderLoading() {
|
|
return <i class="lemon-icon-loading lemonani-spin" />;
|
|
},
|
|
_renderLoadEnd() {
|
|
return <span>暂无更多消息</span>;
|
|
},
|
|
loaded() {
|
|
this._loadend = true;
|
|
this.$forceUpdate();
|
|
},
|
|
resetLoadState() {
|
|
this._loading = false;
|
|
this._loadend = false;
|
|
},
|
|
async _handleScroll(e) {
|
|
const { target } = e;
|
|
contextmenu.hide();
|
|
if (
|
|
target.scrollTop == 0 &&
|
|
this._loading == false &&
|
|
this._loadend == false
|
|
) {
|
|
this._loading = true;
|
|
await this.$nextTick();
|
|
const hst = target.scrollHeight;
|
|
|
|
this.$emit("reach-top", async isEnd => {
|
|
await this.$nextTick();
|
|
target.scrollTop = target.scrollHeight - hst;
|
|
this._loading = false;
|
|
this._loadend = !!isEnd;
|
|
});
|
|
}
|
|
},
|
|
async scrollToBottom() {
|
|
await this.$nextTick();
|
|
const { wrap } = this.$refs;
|
|
if (wrap) {
|
|
wrap.scrollTop = wrap.scrollHeight;
|
|
}
|
|
},
|
|
},
|
|
created() {},
|
|
mounted() {},
|
|
};
|
|
</script>
|
|
<style lang="stylus">
|
|
@import '~styles/utils/index'
|
|
+b(lemon-messages)
|
|
height 400px
|
|
overflow-x hidden
|
|
overflow-y auto
|
|
scrollbar-light()
|
|
padding 10px 15px
|
|
+e(time)
|
|
text-align center
|
|
font-size 12px
|
|
+e(load)
|
|
user-select none
|
|
font-size 12px
|
|
text-align center
|
|
color #999
|
|
line-height 30px
|
|
+m(ing)
|
|
font-size 22px
|
|
</style>
|