Skip to content

服务

NetNexus UI 提供无需在模板中预放置组件的通知服务和确认弹窗服务。两者通过 netnexus-ui/services 导出,也可从根入口导入。

样式准备

已使用完整组件样式时无需重复引入:

js
import 'netnexus-ui/style.css';

只使用服务时,服务样式仍会引用主题 Token,因此要同时引入:

js
import 'netnexus-ui/theme.css';
import 'netnexus-ui/services.css';

Notification

基础用法

js
import { notificationService } from 'netnexus-ui/services';

notificationService.success('保存成功');
notificationService.warning('连接不稳定', 5);
notificationService.error(new Error('保存失败'));

持续显示加载通知,并在任务结束时主动关闭:

js
import { notificationService } from 'netnexus-ui/services';

async function save() {
    const closeLoading = notificationService.loading('正在保存…');

    try {
        await saveToServer();
        closeLoading();
        notificationService.success('保存成功');
    } catch (error) {
        closeLoading();
        notificationService.error(error);
    }
}

API

五种通知方法都使用相同的参数顺序:

text
notificationService.success(content, duration?, onClose?)
notificationService.error(content, duration?, onClose?)
notificationService.warning(content, duration?, onClose?)
notificationService.info(content, duration?, onClose?)
notificationService.loading(content, duration?, onClose?)
方法默认持续时间ARIA live 行为
success3 秒role="status"polite
error3 秒role="alert"assertive
warning3 秒role="alert"assertive
info3 秒role="status"polite
loading不自动关闭role="status"polite

参数说明:

参数说明
contentError 使用其 messagenull/undefined 变为空字符串;其他值通过 String() 转换
duration单位为秒;数值大于 0 时自动关闭,0 或负数时持续显示
onClose通知退出动画结束并移除 DOM 后调用

每个方法返回一个关闭函数。在浏览器中,该函数还带有相同值的 idkey

js
const close = notificationService.info('后台任务已开始', 0, () => {
    console.log('通知已关闭');
});

console.log(close.id);
console.log(close.key);

// 下面两种方式都能关闭该通知。
close();
// notificationService.destroy(close.key);

批量关闭:

js
notificationService.destroy();

destroy(activeKey) 会关闭对应的活动通知。当前实现中,如果传入的 key 不存在,也会继续关闭全部通知;不要把未经确认的 key 直接传给 destroy()

通知内容使用 textContent 写入,不会解析 HTML,也不接受 VNode。关闭按钮始终可以手动关闭通知。

ConfirmDialog

基础用法

js
import { confirmDialogService } from 'netnexus-ui/services';

function removeProject(project) {
    confirmDialogService.confirm({
        title: '删除项目',
        content: `确定删除“${project.name}”吗?`,
        okText: '删除',
        cancelText: '保留',
        okType: 'danger',
        async onOk() {
            await deleteProject(project.id);
        },
        onCancel() {
            console.log('用户取消删除');
        }
    });
}

onOk 返回 Promise 时,确定按钮会进入“处理中...”状态并阻止重复操作。Promise 完成后弹窗关闭;若 onOk 抛错或拒绝,当前实现会输出警告并保持弹窗打开。

选项

选项类型默认行为
titlestring确认操作
contentstring | () => VNodeChild空内容
okTextstring确定
cancelTextstring取消
okType'default' | 'danger'danger 时使用主按钮样式
maskClosablebooleanfalse,点击遮罩不关闭
onOk() => void | Promise<void>确定时调用
onCancel() => void | Promise<void>取消按钮、关闭按钮、Escape 或可关闭遮罩触发

返回的 handle 可跳过回调直接销毁弹窗:

js
const dialog = confirmDialogService.confirm({
    title: '等待确认',
    content: '这个弹窗会在 10 秒后自动移除。'
});

window.setTimeout(() => dialog.destroy(), 10_000);

移除所有由服务创建的确认弹窗:

js
confirmDialogService.destroyAll();

VNode 内容与文本输入

content 函数可以返回 Vue VNode。服务还提供一个轻量的原生输入框 VNode 工厂:

vue
<script setup>
    import { h, ref } from 'vue';
    import { confirmDialogService } from 'netnexus-ui/services';

    const projectName = ref('');

    function openCreateDialog() {
        confirmDialogService.confirm({
            title: '创建项目',
            content: () =>
                h('div', [
                    h('p', '请输入项目名称:'),
                    confirmDialogService.textInput({
                        value: projectName.value,
                        maxlength: 40,
                        placeholder: '例如:gateway',
                        'onUpdate:value': value => {
                            projectName.value = value;
                        },
                        onPressEnter: event => {
                            console.log('按下 Enter', event);
                        }
                    })
                ]),
            async onOk() {
                await createProject(projectName.value);
                projectName.value = '';
            }
        });
    }
</script>

<template>
    <NnButton @click="openCreateDialog">创建项目</NnButton>
</template>

textInput() 不是公开组件,而是返回原生 <input> VNode 的辅助函数。当前运行时读取以下字段:

字段行为
value输入框当前值
maxlength原生最大长度属性
placeholder原生占位文本
onUpdate:value每次原生 input 事件后接收字符串
onPressEnter按 Enter 时接收键盘事件

其 TypeScript 参数当前声明为 Record<string, unknown>,不会为以上字段提供精确自动补全。

交互与无障碍

  • 弹窗使用 role="dialog"aria-modal="true",标题与正文会关联到对应的 ARIA 属性。
  • 打开时优先聚焦 .nn-confirm-input,否则聚焦第一个可交互元素或弹窗本身。
  • Tab 和 Shift+Tab 会被限制在最上层确认弹窗内。
  • 只有最上层弹窗响应 Escape;关闭后会在适当时恢复之前的焦点。
  • 弹窗存在期间会锁定 body 滚动,并对多个服务弹窗共享计数。
  • onCancel 抛错时会记录警告,但弹窗仍会关闭。

已知边界

  • 两项服务都依赖 document。服务端或其他无 DOM 环境中不会渲染:确认框返回空操作 handle;通知会立即调用 onClose 并返回空操作函数。
  • 通知类型声明要求关闭函数具有 id/key,但无 DOM 分支返回的空操作函数没有这两个属性。
  • 通知只支持字符串化内容,没有 VNode、HTML、位置、最大数量或按 key 更新 API。
  • 确认弹窗通过独立的 createApp() 挂载,不继承主应用的 provide、插件或全局组件上下文。VNode 内容应使用已导入的组件或原生节点。
  • 确认弹窗的默认可见文案为中文;当前没有全局 locale 配置。
  • 手动 destroy()destroyAll() 不调用 onOkonCancel

相关源码

Released under the MIT License.