Files

276 lines
6.1 KiB
Vue
Raw Permalink Normal View History

2026-02-10 08:05:03 +08:00
<template>
<view>
<TMessageItem
v-for="(item) in messageList"
:key="item.id"
:ref="item.id"
@close-btn-click="handleClose($event, { tagId: item.id })"
@link-click="handleLinkClick($event, { tagId: item.id })"
@duration-end="handleDurationEnd($event, { tagId: item.id })"
>
<template #icon>
<slot
name="icon"
/>
</template>
<template #content>
<slot
name="content"
/>
</template>
<slot />
<template #link>
<slot
name="link"
/>
</template>
<template #close-btn>
<slot
name="close-btn"
/>
</template>
</TMessageItem>
</view>
</template>
<script>
import TMessageItem from '../message-item/message-item.vue';
import { uniComponent } from '../common/src/index';
import { prefix } from '../common/config';
import { MessageType } from './message.interface';
import props from './props';
import { unitConvert } from '../common/utils';
const SHOW_DURATION = 400;
const name = `${prefix}-message`;
export default uniComponent({
name,
options: {
styleIsolation: 'shared',
},
components: {
TMessageItem,
},
props: {
...props,
},
data() {
return {
prefix,
classPrefix: name,
messageList: [],
instances: [],
index: 0,
};
},
watch: {
visible: {
handler(value) {
if (value) {
const data = Object.keys(props).reduce((acc, key) => ({
...acc,
[key]: this[key],
}), {});
this.setMessage(data, this.theme);
} else {
this.messageList = [];
}
},
immediate: true,
},
},
pageLifetimes: {
show() {
this.hideAll();
},
},
mounted() {
},
methods: {
/**
* 设置消息信息
* @param msg
* @param theme
*/
setMessage(msg, theme = MessageType.info) {
let id = `${name}_${this.index}`;
if (msg.single) {
// 不能与外层的 ref 相同,否则抖音小程序报错
id = `${name}_inner`;
}
const gap = unitConvert(msg.gap || this.gap);
const msgObj = {
...msg,
theme,
id,
gap,
};
const instanceIndex = this.instances.findIndex(x => x.id === id);
if (instanceIndex < 0) {
this.addMessage(msgObj);
} else {
// 更新消息
const instance = this.instances[instanceIndex];
const offsetHeight = this.getOffsetHeight(instanceIndex);
instance.resetData(() => {
Object.keys(msgObj).forEach((key) => {
instance[key] = msgObj[key];
});
setTimeout(() => {
instance.show.call(instance, offsetHeight);
});
instance.onHide = () => {
this.close(id);
};
});
}
},
/**
* 新增消息
* @param msgObj
*/
addMessage(msgObj) {
const list = [...this.messageList, { id: msgObj.id }];
this.messageList = list;
setTimeout(() => {
const offsetHeight = this.getOffsetHeight();
const instance = this.showMessageItem(msgObj, msgObj.id, offsetHeight);
if (this.instances) {
this.instances.push(instance);
this.index += 1;
}
}, 33);
},
/**
* 获取消息显示top偏移距离
* @param index
* @returns
*/
getOffsetHeight(index = -1) {
let offsetHeight = 0;
let len = index;
if (len === -1 || len > this.instances.length) {
len = this.instances.length;
}
for (let i = 0; i < len; i += 1) {
const instance = this.instances[i];
offsetHeight += instance.height + instance.gap;
}
return offsetHeight;
},
/**
* 新增消息显示
* @param options
* @param id
* @param offsetHeight
* @returns
*/
showMessageItem(options, id, offsetHeight) {
let instance = this.$refs[`${id}`];
if (Array.isArray(instance)) {
instance = instance[0];
}
if (instance) {
instance.resetData(() => {
Object.keys(options).forEach((key) => {
instance[key] = options[key];
});
setTimeout(() => {
instance.show.call(instance, offsetHeight);
});
instance.onHide = () => {
this.close(id);
};
});
return instance;
}
console.error('未找到组件,请确认 selector && context 是否正确');
},
close(id) {
setTimeout(() => {
this.removeMsg(id);
}, SHOW_DURATION);
this.removeInstance(id);
},
/**
* 移除指定消息id为空则删除全部消息
* @param id
*/
hide(id) {
if (!id) {
this.hideAll();
}
const instance = this.instances.find(x => x.id === id);
if (instance) {
instance.hide();
}
},
/**
* 移除全部消息
*/
hideAll() {
// 消息移除后也会移除instance下标不用增加直至全部删除
for (let i = 0; i < this.instances.length;) {
const instance = this.instances[i];
instance.hide();
}
},
/**
* 移除message实例
*/
removeInstance(id) {
const index = this.instances.findIndex(x => x.id === id);
if (index < 0) return;
const instance = this.instances[index];
const removedHeight = instance.height;
this.instances.splice(index, 1);
for (let i = index; i < this.instances.length; i += 1) {
const instance = this.instances[i];
instance.wrapTop = instance.wrapTop - removedHeight - instance.gap;
}
},
/**
* 移除页面元素
* @param id
*/
removeMsg(id) {
this.messageList = this.messageList.filter(item => item.id !== id);
// #ifdef VUE2
this.$set(this, 'messageList', this.messageList);
// #endif
},
handleClose(e) {
this.$emit('close-btn-click', { e });
},
handleLinkClick(e) {
this.$emit('link-click', { e });
},
handleDurationEnd(e) {
this.$emit('duration-end', { e });
},
},
});
</script>
<style scoped>
</style>