文章目录
前言
js
[Vue warn]: Unhandled error during execution of scheduler flush. This is likely a Vue internals bug. Please open an issue at https://github.com/vuejs/core .
at <BaseTransition appear=false persisted=false mode=undefined ... >
at <Transition name="uni-fade" onClose=fn >
at <Toast title="上传成功" icon="success" duration=1500 ...
Vue 警告 ,提示在 Vue 调度过程中有未处理的错误,而且错误发生在 BaseTransition 组件中,这与 uni.showToast 的显示/隐藏动画过渡相关。
这个问题的核心原因 是:Toast 组件在动画过渡期间被提前销毁或重复调用,导致 Vue 的过渡组件内部状态异常。
具体原因分析
-
Vue 过渡动画的生命周期问题
uni.showToast内部使用了 Vue 的Transition组件来实现淡入淡出动画- 在动画执行期间(通常是 300-500ms),如果组件被强制移除或重复创建,会导致 Transition 组件内部状态混乱
- 这时 Vue 会抛出 "Unhandled error during execution of scheduler flush" 警告
-
常见的触发场景
javascript// 场景1:快速连续调用(最常见) function handleUpload() { uni.showToast({ title: '上传中...', icon: 'loading' }); // 上传完成后立即显示成功 upload().then(() => { uni.showToast({ title: '上传成功', icon: 'success' }); // 此时前一个toast的过渡动画可能还在进行 }); } // 场景2:在Vue生命周期钩子中不恰当地调用 onBeforeUnmount() { // 组件即将销毁时调用toast uni.showToast({ title: '保存成功' }); // 危险! } // 场景3:与页面路由切换冲突 uni.redirectTo({ url: '/pages/new' }); uni.showToast({ title: '跳转中' }); // 页面切换可能导致toast组件被意外销毁
解决方案
方案1:添加延迟防止快速连续调用(推荐)
javascript
async function safeShowToast(options) {
// 先关闭可能存在的toast
uni.hideToast();
// 添加微小延迟,确保前一个toast完全销毁
await new Promise(resolve => setTimeout(resolve, 50));
// 显示新的toast
uni.showToast(options);
}
// 使用
safeShowToast({
title: '上传成功',
icon: 'success',
duration: 1500
});
方案2:防抖处理频繁调用
javascript
let toastTimer = null;
function debouncedToast(options) {
if (toastTimer) {
clearTimeout(toastTimer);
uni.hideToast();
}
toastTimer = setTimeout(() => {
uni.showToast(options);
toastTimer = null;
}, 100);
}
方案3:确保在合适的生命周期调用
javascript
export default {
data() {
return {
isMounted: true
};
},
mounted() {
this.isMounted = true;
},
beforeUnmount() {
this.isMounted = false;
uni.hideToast(); // 组件销毁前清理toast
},
methods: {
safeToast(options) {
if (!this.isMounted) return;
uni.showToast(options);
}
}
};
方案4:检查并修复特定场景
javascript
// 修复上传示例
async function handleUpload() {
// 先隐藏可能的loading
uni.hideLoading();
// 显示上传中toast
uni.showToast({
title: '上传中...',
icon: 'loading',
duration: 10000 // 设置较长duration,手动控制关闭
});
try {
await upload();
// 先关闭上传中toast
uni.hideToast();
// 短暂延迟后显示成功
setTimeout(() => {
uni.showToast({
title: '上传成功',
icon: 'success',
duration: 1500
});
}, 100);
} catch (error) {
uni.hideToast();
// 错误处理...
}
}
针对你的具体错误信息
错误信息中显示:
js
at <Toast title="上传成功" icon="success" duration=1500 ...
这表明是显示"上传成功"的 Toast 时出现了问题。很可能是在某个上传逻辑中,有快速连续调用 toast 的情况。
临时排查方案
-
在 main.js 或 App.vue 中添加全局错误捕获
javascript// 在App.vue的onLaunch中 onLaunch() { // 捕获Vue警告和错误 Vue.config.errorHandler = (err, vm, info) => { console.error('[Vue错误]', err, info); // 可以选择不显示某些警告 if (err.message && err.message.includes('BaseTransition')) { console.warn('Toast过渡动画错误,已忽略'); return; // 阻止错误继续传播 } }; } -
使用 try-catch 包装
javascriptfunction showToastSafely(options) { try { uni.showToast(options); } catch (err) { console.warn('Toast显示失败,尝试重新显示', err); setTimeout(() => { uni.showToast(options); }, 100); } }
总结建议
- 优先使用方案1(添加延迟),这是最简单且最有效的解决方案
- 检查业务逻辑 ,避免在以下情况调用 toast:
- 页面路由切换时
- 组件销毁生命周期中
- 快速连续的操作中
- 如果使用了 async/await,确保在异步操作之间有适当的延迟或状态检查