oopsoh

一个面向 uni-app 的轻量交互工具库,用来优雅处理页面里常见的提示、跳转、确认弹窗、加载态和防重复提交。

GitHub: https://github.com/im76ix/oopsoh
Gitee: https://gitee.com/im76ix/oopsoh

为什么需要 oopsoh

相信经常使用 uni-app 的同学都遇到过这个问题:提交表单成功后,想先给用户一个成功提示,再跳转到下一个页面。

但如果直接这样写:

uni.showToast({
  title: "保存成功",
  duration: 1500,
})

uni.navigateTo({
  url: "/pages/list/index",
})

页面会立刻跳走,提示几乎一闪而过。因为 uni.showToast 是异步展示的,它不会阻塞后面的跳转逻辑。

通常我们会手动加 setTimeout

uni.showToast({
  title: "保存成功",
  duration: 1500,
})

setTimeout(() => {
  uni.navigateTo({
    url: "/pages/list/index",
  })
}, 1500)

可以用,但不够优雅,也很容易在项目里重复出现。

oopsoh 就是为了解决这些页面交互小流程而生。

安装

npm i oopsoh

或:

pnpm add oopsoh

导入方式

oopsoh 同时支持命名空间写法和函数式写法。

推荐写法

import oh from "oopsoh"

oh.success("保存成功")
oh.to("保存成功", "/pages/list/index")

函数式写法

import { toast, confirm, withLoading } from "oopsoh"

toast("hello world")
await confirm("确定删除吗?")
await withLoading("提交中", submit)

兼容旧写法

旧版本的 oh(msg, options, callback) 仍然可以继续使用。

import { oh } from "oopsoh"

oh("保存成功", { ico: "success" }, () => {
  uni.navigateTo({
    url: "/pages/list/index",
  })
})

快速开始

简单提示

oh.toast("hello world")

也可以直接调用 oh,效果等同于 oh.toast

oh("hello world")

函数式写法:

import { toast } from "oopsoh"

toast("hello world")

成功提示

oh.success("保存成功")

等同于:

oh.toast("保存成功", { icon: "success" })

失败提示

oh.error("提交失败")

加载提示

这是基于 uni.showToast 的 loading 图标提示,适合短时间反馈。

oh.loading("加载中")

如果是异步任务的全局加载态,建议使用 oh.withLoading

提示后跳转

navigateTo

跳转到非 tabBar 页面。

oh.to("/pages/detail/index")

提示完成后再跳转:

oh.to("保存成功", "/pages/list/index", {
  icon: "success",
  duration: 1500,
})

传递 uni.navigateTo 原生参数:

oh.to("保存成功", "/pages/list/index", {
  icon: "success",
  route: {
    animationType: "pop-in",
    animationDuration: 300,
  },
})

redirectTo

关闭当前页面并跳转。

oh.redirect("/pages/result/index")

提示完成后再跳转:

oh.redirect("提交成功", "/pages/result/index", {
  icon: "success",
})

reLaunch

关闭所有页面并打开某个页面,常用于登录过期、切换身份、回到首页等场景。

oh.reLaunch("登录已过期", "/pages/login/index", {
  icon: "none",
})

switchTab

跳转到 tabBar 页面。

oh.tab("/pages/home/index")

提示完成后跳转到 tabBar 页面:

oh.tab("发布成功", "/pages/home/index", {
  icon: "success",
})

navigateBack

直接返回上一页:

oh.back()

返回指定层级:

oh.back(2)

提示完成后再返回:

oh.back("保存成功", {
  icon: "success",
  delta: 1,
})

确认弹窗

oh.confirm 基于 uni.showModal 封装,用户点击确认时执行回调并返回 true,取消时返回 false

const ok = await oh.confirm("确定删除这条数据吗?")

if (ok) {
  await deleteItem()
}

也可以把确认后的逻辑直接交给它:

await oh.confirm("确定删除这条数据吗?", async () => {
  await deleteItem()
  oh.success("删除成功")
})

自定义按钮文案:

await oh.confirm(
  "删除后不可恢复,确定继续吗?",
  deleteItem,
  {
    title: "删除确认",
    confirmText: "删除",
    cancelText: "再想想",
    confirmColor: "#e54d42",
  },
)

函数式写法:

import { confirm } from "oopsoh"

await confirm("确定退出登录吗?", logout)

加载态包裹异步任务

oh.withLoading 会自动调用 uni.showLoadinguni.hideLoading。不论任务成功还是失败,都会在结束时关闭 loading。

await oh.withLoading("提交中", async () => {
  await submitForm()
})

获取任务返回值:

const user = await oh.withLoading("加载用户信息", async () => {
  return await getUserInfo()
})

关闭透明蒙层:

await oh.withLoading(
  "加载中",
  loadData,
  {
    mask: false,
  },
)

函数式写法:

import { withLoading } from "oopsoh"

await withLoading("保存中", saveData)

防重复提交

oh.lock 可以给函数加运行锁,防止按钮连点造成重复提交。

const submitOnce = oh.lock(async () => {
  await submitForm()
  oh.success("提交成功")
})

submitOnce()

重复触发时给用户提示:

const submitOnce = oh.lock(submitForm, {
  message: "正在提交,请稍候",
})

任务结束后延迟解锁:

const payOnce = oh.lock(createPayOrder, {
  message: "支付处理中",
  delay: 1000,
})

在 Vue 页面中使用:

<script setup lang="ts">
import oh from "oopsoh"

const submit = oh.lock(async () => {
  await oh.withLoading("提交中", async () => {
    // await api.submit(...)
  })

  oh.to("提交成功", "/pages/list/index", {
    icon: "success",
  })
})
</script>

<template>
  <button @click="submit">提交</button>
</template>

API 总览

oh / toast

oh(msg: string, options?: ToastOptions, callback?: () => void): void
oh.toast(msg: string, options?: ToastOptions, callback?: () => void): void
toast(msg: string, options?: ToastOptions, callback?: () => void): void

显示普通提示。callback 会在提示展示时长结束后执行。

success

oh.success(msg: string, options?: ToastOptions, callback?: () => void): void

显示成功提示,默认 iconsuccess

error

oh.error(msg: string, options?: ToastOptions, callback?: () => void): void

显示失败提示,默认 iconerror

loading

oh.loading(msg?: string, options?: ToastOptions, callback?: () => void): void

显示 loading 类型的 Toast,默认文案为 加载中

confirm

oh.confirm(
  content: string,
  onConfirm?: () => void | Promise<void>,
  options?: ConfirmOptions,
): Promise<boolean>

显示确认弹窗。确认返回 true,取消返回 false

to

oh.to(url: string, options?: NavigateOptions): void
oh.to(msg: string, url: string, options?: ToastRouteOptions): void

跳转到非 tabBar 页面,对应 uni.navigateTo

redirect

oh.redirect(url: string, options?: RedirectOptions): void
oh.redirect(msg: string, url: string, options?: ToastRouteOptions): void

关闭当前页面并跳转,对应 uni.redirectTo

reLaunch

oh.reLaunch(url: string, options?: ReLaunchOptions): void
oh.reLaunch(msg: string, url: string, options?: ToastRouteOptions): void

关闭所有页面并跳转,对应 uni.reLaunch

tab

oh.tab(url: string, options?: SwitchTabOptions): void
oh.tab(msg: string, url: string, options?: ToastRouteOptions): void

跳转到 tabBar 页面,对应 uni.switchTab

back

oh.back(delta?: number): void
oh.back(msg: string, options?: BackOptions): void

返回上一页或指定层级,对应 uni.navigateBack

withLoading

oh.withLoading<T>(
  title: string,
  task: () => T | Promise<T>,
  options?: LoadingOptions,
): Promise<T>

uni.showLoading 包裹一个同步或异步任务,并自动关闭 loading。

lock

oh.lock<Args extends unknown[], Result>(
  task: (...args: Args) => Result | Promise<Result>,
  options?: LockOptions,
): (...args: Args) => Promise<Result | undefined>

给函数增加运行锁,防止重复点击、重复提交。

参数说明

ToastOptions

参数 类型 默认值 说明
icon "success" | "error" | "loading" | "none" "none" Toast 图标
ico "success" | "error" | "loading" | "none" - 兼容旧版本字段,等同于 icon
duration number 1500 提示展示时长,单位 ms
mask boolean false 是否显示透明蒙层
image string - 自定义图标图片路径
success UniApp.ShowToastOptions["success"] - uni.showToast 原生成功回调
fail UniApp.ShowToastOptions["fail"] - uni.showToast 原生失败回调
complete UniApp.ShowToastOptions["complete"] - uni.showToast 原生完成回调

ToastRouteOptions

ToastRouteOptions 继承 ToastOptions,额外支持:

参数 类型 默认值 说明
route object - 传给原生跳转 API 的参数,不包含 url

示例:

oh.to("保存成功", "/pages/list/index", {
  icon: "success",
  route: {
    animationType: "pop-in",
  },
})

ConfirmOptions

参数 类型 默认值 说明
title string "提示" 弹窗标题
confirmText string "确定" 确认按钮文案
cancelText string "取消" 取消按钮文案
showCancel boolean true 是否显示取消按钮
confirmColor string - 确认按钮颜色
cancelColor string - 取消按钮颜色
success UniApp.ShowModalOptions["success"] - uni.showModal 原生成功回调
fail UniApp.ShowModalOptions["fail"] - uni.showModal 原生失败回调
complete UniApp.ShowModalOptions["complete"] - uni.showModal 原生完成回调

BackOptions

参数 类型 默认值 说明
delta number 1 返回的页面层数

BackOptions 同时继承 ToastOptions,所以也可以传入 icondurationmask 等提示参数。

LoadingOptions

参数 类型 默认值 说明
mask boolean true 是否显示透明蒙层

LockOptions

参数 类型 默认值 说明
message string - 重复触发时的提示文案
delay number 0 任务结束后延迟多久解锁,单位 ms
onLocked () => void - 重复触发时的自定义处理

完整示例

import oh from "oopsoh"

const submit = oh.lock(async () => {
  await oh.withLoading("提交中", async () => {
    // await api.submitForm()
  })

  oh.to("提交成功", "/pages/list/index", {
    icon: "success",
    duration: 1500,
  })
}, {
  message: "正在提交,请勿重复点击",
})

TypeScript

oopsoh 自带类型声明,安装后即可获得类型提示。

import type {
  ToastOptions,
  ConfirmOptions,
  ToastRouteOptions,
  LockOptions,
} from "oopsoh"

旧版本的 OhOptions 类型仍然保留:

import type { OhOptions } from "oopsoh"

兼容说明

  • 保留 oh("提示", options, callback) 旧写法。
  • 保留 ico 字段,推荐新项目使用 icon
  • 新增默认导出 oh,推荐 import oh from "oopsoh"
  • 新增具名函数导出,支持按需导入。

建议与反馈

如果你在使用过程中有更好的想法,欢迎在 GitHub 或 Gitee 提 issue。

如果这个小库刚好帮你少写了一点重复代码,也欢迎点个 Star。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐