uniapp的message封装
·
这里封装一个比较全面的message和loading,因为loading和message在uniapp中只能存在一个,所以导致经常会出现提示语一闪而过的情况,所以封装一个函数方法,解决问题,同时也让loading不会出现一闪而过的情况
// utils/message.js
/**
* 消息提示管理工具
* 解决 uni-app 中 loading 和 toast 冲突问题
* 支持多 loading 计数、自动关闭、队列管理等
*/
class MessageManager {
constructor() {
this.loadingCount = 0; // 请求计数
this.loadingMap = new Map() // 🔥 记录每一次 showLoading 的调用栈
this.realShowTimer = null; // 真正 showLoading 的定时器
this.minShowTimer = null; // 保证至少显示 1 s 的定时器
this.startTime = 0; // 第一次 showLoading 的时间戳
this.hasShown = false; // 本次是否已经真正出现过 loading
this.toastQueue = [];
this.isShowingToast = false;
this.defaultLoadingText = '加载中...';
this.defaultToastDuration = 3000;
// 🔥 兜底:单例最长 10 s 必须消失
this.maxAlive = 10000
this.maxAliveTimer = null
// #ifdef H5
document.addEventListener('visibilitychange', () => {
if (document.hidden) this.clearAll()
})
// #endif
// #ifndef H5
uni.onAppHide(() => this.clearAll())
// #endif
}
/* 生成唯一 key,用于精准关闭 */
genKey() {
return `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`
}
/**
* 显示加载
* @param {string} title
* @param {boolean} mask
* @returns {string} key 可用于主动 hide
*/
showLoading(title = this.defaultLoadingText, mask = true) {
const key = this.genKey()
if (this.loadingCount === 0) {
this.startTime = Date.now()
this.hasShown = false
this.realShowTimer = setTimeout(() => {
uni.showLoading({
title,
mask
})
this.hasShown = true
this.realShowStart = Date.now()
}, 1000)
// 🔥 兜底定时器
this.maxAliveTimer = setTimeout(() => {
console.error('[MessageManager] loading 存活超过 maxAlive,强制清空', this.loadingMap)
this.clearAll()
}, this.maxAlive)
}
this.loadingCount++
// 🔥 记录调用栈
this.loadingMap.set(key, new Error().stack)
return key
}
/**
* 隐藏 loading
* @param {boolean} force 强制清零
* @param {string} key 如果传了 key,只关闭这一次
*/
hideLoading(force = false, key) {
if (key) {
if (!this.loadingMap.has(key)) return // 已经关过了
this.loadingMap.delete(key)
this.loadingCount = Math.max(0, this.loadingCount - 1)
} else {
if (!force && this.loadingCount > 0) this.loadingCount--
else this.loadingCount = 0
}
if (this.loadingCount === 0) {
clearTimeout(this.realShowTimer)
clearTimeout(this.maxAliveTimer)
if (this.hasShown) {
const alreadyShow = Date.now() - this.realShowStart
const needDelay = Math.max(0, 1000 - alreadyShow)
this.minShowTimer = setTimeout(() => {
uni.hideLoading()
this.checkToastQueue()
}, needDelay)
} else {
uni.hideLoading()
this.checkToastQueue()
}
}
}
/**
* 显示轻提示
* @param {string} title - 提示文字
* @param {object} options - 配置项
* @param {string} options.icon - 图标
* @param {number} options.duration - 持续时间(ms)
* @param {boolean} options.mask - 是否显示透明蒙层
*/
toast(title, options = {}) {
const config = {
title,
icon: options.icon || 'none',
duration: options.duration || this.defaultToastDuration,
mask: options.mask || false
};
// 如果当前有loading显示,先关闭loading并加入队列
if (this.loadingCount > 0) {
this.hideLoading(true);
this.toastQueue.push(config);
return;
}
// 如果当前正在显示toast,加入队列
if (this.isShowingToast) {
this.toastQueue.push(config);
return;
}
this.showToast(config);
}
/**
* 显示toast
* @param {object} config - toast配置
*/
showToast(config) {
this.isShowingToast = true;
uni.showToast({
...config,
complete: () => {
this.isShowingToast = false;
// toast显示完成后检查队列
setTimeout(() => {
this.checkToastQueue();
}, 400); // 增加一点延迟避免快速切换的问题
}
});
}
/**
* 检查并显示队列中的toast
*/
checkToastQueue() {
if (this.toastQueue.length > 0 && !this.isShowingToast && this.loadingCount === 0) {
const nextToast = this.toastQueue.shift();
this.showToast(nextToast);
}
}
/**
* 成功提示
* @param {string} title - 提示文字
* @param {number} duration - 持续时间(ms)
*/
success(title, duration = this.defaultToastDuration) {
this.toast(title, {
icon: 'success',
duration
});
}
/**
* 错误提示
* @param {string} title - 提示文字
* @param {number} duration - 持续时间(ms)
*/
error(title, duration = this.defaultToastDuration) {
this.toast(title, {
icon: 'error',
duration
});
}
/**
* 清空所有提示
*/
clearAll() {
clearTimeout(this.realShowTimer)
clearTimeout(this.minShowTimer)
clearTimeout(this.maxAliveTimer)
this.loadingCount = 0
this.loadingMap.clear()
this.toastQueue = []
this.hasShown = false
uni.hideLoading()
uni.hideToast()
this.isShowingToast = false
}
}
// 导出单例
export default new MessageManager();更多推荐
所有评论(0)