npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

oopsoh

v2.0.2

Published

A lightweight uni-app interaction toolkit for toast, modal confirm, page navigation, loading and duplicate submit lock.

Downloads

301

Readme

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。