Skip to content

在 UniApp 里封装一个全局 Toast,我学到了什么

提示本文发布于 4 个月前,其中信息可能已经时过境迁...

Toast 提示看起来是一个很小的需求,但在 UniApp 里,要在路由守卫、请求封装这些非组件上下文里统一唤起提示,并没有那么直接。

wot-design-uni 的 Toast 需要在模板中手动放一个 <wd-toast /> 标签,这在组件里用没问题,但如果你在纯 TypeScript 文件里想弹一个提示,就不太行了。

解决问题的思路

核心思路是用 h 函数(Vue 的渲染函数)动态创建 Toast,而不是依赖模板。

typescript
class ToastRenderer {
  private container: HTMLElement | null = null;
  private vnode: VNode | null = null;
  private toastState = ref<ToastOptions>({ show: false });

  constructor() {
    this.init();
  }

  private init() {
    this.container = document.createElement("div");
    this.container.id = "toast-container";
    document.body.appendChild(this.container);

    watch(
      () => this.toastState.value,
      () => this.renderToast(),
      { deep: true, immediate: true }
    );
  }

  // ... 渲染逻辑
}

然后通过一个全局实例暴露出去:

typescript
export const toast = new GlobalToast();

// 在任何地方都能用
toast.success("操作成功!");
toast.error("操作失败,请重试");
toast.loading("加载中...");

几个关键细节

  • 状态管理:用 ref 包裹状态,通过 watch 驱动重新渲染
  • 自动销毁:设置 duration 定时器,超时自动 hide()
  • 遮罩层:需要覆盖背景点击时,通过 cover 参数控制
  • 图标处理:用内联 SVG 模拟 wot-design-uni 的图标风格,避免引入额外资源

这个封装让我更理解 Vue 的渲染机制

以前用 Vue 写组件,都是模板思维——放个标签、传个属性、等它渲染。但这次用 h 函数 + render 手动控制渲染,让我对 Vue 的渲染机制有了更深的理解。

其实 Vue 的模板最终也是编译成 h 函数的,只是框架帮我们做了这层转换。手动控制渲染的时候,你能更清楚地知道"什么时候该渲染、什么时候该销毁"。

封装一个全局 Toast 这件事看起来小,但它涉及了 Vue 渲染机制、状态管理、组件设计等多个方面的知识。把一个"小东西"做好,有时候比做一个大功能更能检验水平。