跳转正文

YModal ​

适用范围:Legacy Admin Kit / Schema(@yoyoboot/yoyo-admin-kit、旧 admin-vue)。新 admin-nuxtui 使用 Nuxt UI;本页不是新宿主的必经开发路线。

定位 / Owner ​

YModal 拥有通用容器、焦点、关闭交互与尺寸,不拥有字段、校验和保存请求。

需求选择
普通内容、详情、自定义操作YModal
侧边详情或长任务YDrawer
编辑、dirty 确认、保存继续、busyYEditorPanel
危险操作确认YConfirmDialog / YDangerConfirmDialog

基础用法 ​

ts
import { YModal, YButton } from '@yoyoboot/yoyo-admin-kit'
import '@yoyoboot/yoyo-admin-kit/styles.css'
import '@yoyoboot/yoyo-admin-kit/theme.css'

在应用入口加载一次样式。Modal 不要求业务 provider;示例仅用浏览器内存,不访问 HTTP,也不是持久化验收。

可运行示例

基础内容与操作区

最小受控开关,actions 使用共享底部布局。

查看同源 Vue 代码
<script setup lang="ts">
import { ref } from 'vue'
import { YButton, YModal } from '@yoyoboot/yoyo-admin-kit'
const open = ref(false)
</script>

<template>
  <YButton @click="open = true">查看详情</YButton>
  <YModal v-model:open="open" title="记录详情" description="通用容器不拥有保存逻辑。">
    <p>这里可以放置详情、说明或自定义内容。</p>
    <template #actions><YButton @click="open = false">完成阅读</YButton></template>
  </YModal>
</template>

尺寸、全屏与长内容 ​

可运行示例

尺寸与滚动

选择尺寸,修改输入,切换全屏,再滚动到底部。

查看同源 Vue 代码
<script setup lang="ts">
import { ref } from 'vue'
import { YButton, YInput, YModal } from '@yoyoboot/yoyo-admin-kit'
const open = ref(false)
const size = ref<'sm' | 'md' | 'lg'>('md')
const note = ref('切换全屏后内容仍在')
</script>

<template>
  <div style="display: flex; gap: 0.5rem; flex-wrap: wrap">
    <YButton v-for="value in (['sm', 'md', 'lg'] as const)" :key="value" variant="outline" @click="size = value; open = true">{{ value }} 尺寸</YButton>
  </div>
  <YModal v-model:open="open" title="尺寸与长内容" :size="size" allow-fullscreen>
    <YInput v-model="note" aria-label="保留的输入" />
    <p v-for="index in 32" :key="index" style="margin-block: 0.75rem">第 {{ index }} 段:正文独立滚动,底部操作仍可访问。</p>
    <template #actions><YButton @click="open = false">完成</YButton></template>
  </YModal>
</template>

关闭策略 ​

可运行示例

来源与同步拦截

禁用来源不发请求;父级直接关闭不走业务拦截。

尚无关闭请求

查看同源 Vue 代码
<script setup lang="ts">
import { ref } from 'vue'
import { YButton, YCheckbox, YModal, type YSurfaceCloseRequest } from '@yoyoboot/yoyo-admin-kit'
const open = ref(false)
const allowEscape = ref(true)
const allowOutside = ref(false)
const intercept = ref(true)
const lastRequest = ref('尚无关闭请求')
const modal = ref<InstanceType<typeof YModal> | null>(null)
function onClose(request: YSurfaceCloseRequest) {
  lastRequest.value = `${request.reason}:${intercept.value ? '已拦截' : '允许关闭'}`
  if (intercept.value) request.preventDefault()
}
</script>

<template>
  <YButton @click="open = true">体验关闭策略</YButton>
  <p role="status">{{ lastRequest }}</p>
  <YModal ref="modal" v-model:open="open" title="关闭策略" :close-on-escape="allowEscape" :close-on-outside="allowOutside" @close-request="onClose">
    <div style="display: grid; gap: 1rem">
      <YCheckbox v-model="allowEscape" label="允许 Escape" />
      <YCheckbox v-model="allowOutside" label="允许点击遮罩" />
      <YCheckbox v-model="intercept" label="同步拦截关闭请求" />
      <p role="status">{{ lastRequest }}</p>
    </div>
    <template #actions>
      <YButton variant="outline" @click="modal?.requestClose()">请求关闭</YButton>
      <YButton @click="open = false">父级直接关闭</YButton>
    </template>
  </YModal>
</template>

焦点与完成事件 ​

可运行示例

初始焦点和嵌套恢复

观察完成事件;关闭上层弹窗,检查焦点返回。

等待打开

查看同源 Vue 代码
<script setup lang="ts">
import { ref, useId } from 'vue'
import { YButton, YInput, YModal } from '@yoyoboot/yoyo-admin-kit'
const open = ref(false)
const nested = ref(false)
const value = ref('初始焦点进入这里')
const id = useId()
const events = ref<string[]>([])
const focusInput = () => document.getElementById(id)
function record(event: string) { events.value = [...events.value.slice(-5), event] }
</script>

<template>
  <YButton @click="open = true">体验焦点与事件</YButton>
  <p role="status">{{ events.join(' → ') || '等待打开' }}</p>
  <YModal v-model:open="open" title="焦点与生命周期" :initial-focus="focusInput" @after-enter="record('after-enter')" @after-leave="record('after-leave')">
    <YInput :id="id" v-model="value" aria-label="初始焦点字段" />
    <YButton variant="outline" @click="nested = true">打开上层弹窗</YButton>
    <p role="status">{{ events.join(' → ') }}</p>
  </YModal>
  <YModal v-model:open="nested" title="上层弹窗" size="sm">
    <p>关闭后焦点回到下层触发按钮;关闭下层后回到示例入口。</p>
  </YModal>
</template>

Public API ​

Props ​

名称类型默认值职责
titlestring必填可访问标题
descriptionstring未设置可见说明;缺省有隐藏说明
size'sm' / 'md' / 'lg''md'桌面宽度,移动端受视口约束
allowFullscreenbooleanfalse全屏/恢复,不重建正文
closeTextstring'关闭'关闭按钮可访问名称
closeDisabledbooleanfalse优先拒绝所有组件关闭请求
closeOnEscapebooleantrue允许 Escape
closeOnOutsidebooleantrue允许外部点击
showClosebooleantrue仅控制关闭按钮可见性
initialFocus() => HTMLElement / null / undefined未设置当前容器内可交互元素,否则回退
restoreFocusToHTMLElement / null打开前焦点失效则回退上层可交互目标

Models / Events / Slots / Expose ​

接口类型/参数时机与语义
v-model:openboolean,默认 false父级拥有最终显隐权
close-requestYSurfaceCloseRequest合法关闭请求;同步 preventDefault() 阻止关闭
after-enter无参数当前打开过渡完成,无动画也通知一次
after-leave无参数当前关闭过渡完成,无动画也通知一次
defaultslot可滚动正文
header-actionsslot标题区次级操作
actionsslot固定操作区,启用 task 布局
requestClose()expose,voidprogrammatic 来源,遵循相同拦截链

YSurfaceCloseRequest.reason 为 close-button | escape | outside | programmatic。异步 dirty 确认应先同步阻止请求,再由 EditorPanel 或既有业务 owner 处理。父级 open=false 是权威覆盖,不发关闭请求,不能代替安全离开入口。隐藏关闭按钮时须提供其他可达退出操作。

能力与迁移 ​

能力当前边界
尺寸、全屏、嵌套 popup、任务操作区已有能力,继续保留
来源、取消、initialFocus、完成事件源码提供;采用制品前核对版本
非模态、拖动缩放、全局 openModal当前未提供

YDialog 是 deprecated 同对象兼容别名。新代码使用 YModal;旧 Dialog 页面 保留迁移入口。EditorPanel 新 surface 是 modal | drawer,旧 dialog 输入集中规范化为 modal。

Live Workbench ​

/frontend-module-demo/component-workbench/modal;旧 /dialog 入口仍可访问。

Verification / Source ​

  • packages/yoyo-admin/admin-kit/src/ui/components/modal/YModal.vue
  • packages/yoyo-admin/admin-kit/tests/unit/ui/dialog/dialog-behavior.spec.ts
  • 同源示例:docs/对外文档/参考/既有Kit与Schema/示例/弹窗/。

YoyoBoot · 从真实项目走向可复用能力