stack
<stack> 按模板声明顺序层叠直接子组件,后声明的子组件覆盖先声明的子组件。BlueOS 不支持 z-index,<div> 沿主轴排列、子项不会重叠。遮罩弹框、图片角标、水印等叠层界面使用 <stack>。组件支持通用属性。
<stack> 的每个直接子组件占据同一块区域,覆盖关系由声明顺序决定:模板中越靠后的子组件越靠近用户。
| 容器 | 子组件排列 | 典型用途 |
|---|---|---|
<stack> | 层叠,后声明的覆盖先声明的 | 遮罩弹框、角标、水印 |
<div> | flex 主轴排列,子项不重叠 | 横向或纵向常规布局 |
Web 用 z-index 控制叠放顺序。BlueOS 不支持该属性,叠放顺序只由模板中的先后顺序决定。不支持的样式列表见布局与样式。
实现遮罩弹框
Section titled “实现遮罩弹框”Web 页面用 position: fixed 加上 z-index 把遮罩和弹框抬到最上层。BlueOS 没有 z-index,等价做法是用 <stack> 铺满屏幕并设置半透明背景作为遮罩,弹框面板作为其子组件叠在上层。
系统确认弹窗也可使用 vw-alert。需要自定义遮罩、布局或按钮样式时,使用 <stack>。
Web 写法(不能在 BlueOS 中运行)
Section titled “Web 写法(不能在 BlueOS 中运行)”Web 对照代码
<!-- Modal --><div id="modal" class="fixed inset-0 z-50 flex items-center justify-center p-4" role="dialog" aria-modal="true"> <!-- 遮罩 --> <div class="absolute inset-0 bg-black/50 backdrop-blur-sm transition-opacity duration-300" ></div>
<!-- 弹框 --> <div class="relative z-10 w-full max-w-md overflow-hidden rounded-2xl bg-white shadow-2xl ring-1 ring-black/5 transition-all duration-300 dark:bg-zinc-900 dark:ring-white/10" > <!-- Header --> <div class="flex items-center justify-between px-6 py-5"> <div> <h2 class="text-lg font-semibold text-zinc-900 dark:text-white"> 确认操作 </h2>
<p class="mt-1 text-sm text-zinc-500 dark:text-zinc-400"> 此操作执行后将无法撤销。 </p> </div>
<!-- Close --> <button type="button" class="rounded-full p-2 text-zinc-400 transition hover:bg-zinc-100 hover:text-zinc-600 dark:hover:bg-zinc-800 dark:hover:text-zinc-200" aria-label="关闭" > <svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" > <path stroke-linecap="round" d="M6 6l12 12M18 6L6 18" /> </svg> </button> </div>
<!-- Content --> <div class="px-6 pb-6"> <p class="text-sm leading-6 text-zinc-600 dark:text-zinc-300"> 确定要继续执行这个操作吗?请确认你的选择。 </p> </div>
<!-- Footer --> <div class="flex justify-end gap-3 border-t border-zinc-100 bg-zinc-50/80 px-6 py-4 dark:border-zinc-800 dark:bg-zinc-950/50" > <button type="button" class="rounded-lg px-4 py-2 text-sm font-medium text-zinc-600 transition hover:bg-zinc-200/70 dark:text-zinc-300 dark:hover:bg-zinc-800" > 取消 </button>
<button type="button" class="rounded-lg bg-zinc-900 px-4 py-2 text-sm font-medium text-white shadow-sm transition hover:bg-zinc-700 active:scale-[0.98] dark:bg-white dark:text-zinc-900 dark:hover:bg-zinc-200" > 确定 </button> </div> </div></div>Web 写法把遮罩和弹框写成两个定位层,再用 z-50、z-10 指定谁在上面。其中 z-index、<button>、<svg>、backdrop-blur 和 gap 在 BlueOS 中均不可用。
BlueOS 写法
Section titled “BlueOS 写法”将下列代码保存为自定义组件(例如 dialog.ux)。页面通过 <import> 引入后,用 visible 控制显隐。
根节点用 show 绑定 visible。用 if 绑定 prop 时,编译器会丢弃指令,弹窗会一直显示。<stack> 设置 fixed 铺满屏幕,背景色作为遮罩;面板作为子组件,借助 items-center 与 justify-center 居中,无需计算 left / top。
<script>export default { props: { visible: { default: false }, title: { default: '' }, content: { default: '' }, confirmText: { default: '' }, cancelText: { default: '' }, confirmVariant: { default: 'primary' }, // primary | danger maskClosable: { default: true }, },
data: { isDanger: false, hasFooter: false, },
onInit() { // props 在 onInit 时可能还未绑定,派生状态放到 $watch 里随 prop 刷新 this.$watch('confirmVariant', 'syncState') this.$watch('confirmText', 'syncState') this.$watch('cancelText', 'syncState') this.syncState() },
syncState() { this.isDanger = this.confirmVariant === 'danger' this.hasFooter = !!(this.confirmText || this.cancelText) },
handleMask() { if (!this.maskClosable) return this.$emit('close') },
handleConfirm() { this.$emit('confirm') },
handleCancel() { this.$emit('cancel') },}</script>
<template> <!-- 根节点用 show 控制显隐;用 if 绑定 prop 时编译器会丢弃指令,弹窗会一直显示 --> <stack show="{{ visible }}" class="b-dialog__mask fixed left-0 top-0 h-full w-full flex-col items-center justify-center" onclick="handleMask"> <!-- 面板:作为 stack 子项自然居中,无需 left/top 计算 --> <div class="b-dialog__panel flex-col items-center rounded-[32px] bg-white px-10 pb-10 pt-12"> <text if="{{ title }}" class="text-[34px] font-bold text-[#1a1a1a]">{{ title }}</text> <text if="{{ content }}" class="mt-6 text-center text-[28px] text-[#4a4a4a]">{{ content }}</text>
<div if="{{ hasFooter }}" class="mt-10 w-[80%] flex-col items-center"> <input if="{{ confirmText }}" type="button" value="{{ confirmText }}" class="b-dialog__btn {{ isDanger ? 'b-dialog__btn--danger' : 'b-dialog__btn--primary' }}" onclick="handleConfirm" /> <input if="{{ cancelText }}" type="button" value="{{ cancelText }}" class="b-dialog__btn b-dialog__btn--secondary mt-5" onclick="handleCancel" /> </div> </div> </stack></template>
<style> @tailwind utilities;
/* 遮罩 */ .b-dialog__mask { background-color: rgba(0, 0, 0, 0.6); }
/* 面板:80% 宽度,由父 flex 居中 */ .b-dialog__panel { width: 80%; }
/* 按钮 */ .b-dialog__btn { width: 100%; height: 80px; border-radius: 40px; font-size: 28px; }
.b-dialog__btn--primary { background-color: #456fff; color: #ffffff; }
.b-dialog__btn--danger { background-color: #ff4444; color: #ffffff; }
.b-dialog__btn--secondary { background-color: #f2f3f5; color: #1a1a1a; }
/* 圆表:面板圆角下调 */ @media screen and (device: watch-round) { .b-dialog__panel { border-radius: 24px; padding-left: 32px; padding-right: 32px; } }</style>与 Web 写法的对应关系:
| Web | BlueOS |
|---|---|
外层 fixed + z-50 | <stack> 设置 fixed,铺满屏幕 |
遮罩层 absolute + 半透明背景 | <stack> 自身的 background-color |
弹框 relative + z-10 | <stack> 中后声明的面板子组件 |
<button> | <input type="button"> |
| 任意 HTML 文本节点 | 可见文字放在 <text> 中 |
支持通用事件。