Quasar QBar 组件完整指南:打造平台化的顶部栏与无边框 Electron 窗口标题栏
【免费下载链接】quasarQuasar Framework - Build high-performance VueJS user interfaces in record time项目地址: https://gitcode.com/gh_mirrors/qu/quasar
QBar 是 Quasar Framework 提供的一个轻量级 Vue 组件,用于在移动端或桌面端应用中构建顶部栏(Top Bar)——例如桌面应用里的窗口控制按钮区(最小化/最大化/关闭)、菜单栏,或移动端的状态栏。本指南将以docs/src/pages/vue-components/bar.md文档为核心,结合 QBar 源码 与官方示例,讲解其 API、平台化样式、与其他组件的组合方式,以及它在无边框 Electron 应用中的关键实战用法,帮助你快速掌握 QBar 并应用到真实项目中。
QBar 是什么
QBar 是一个小型布局组件,专门用于创建不同类型移动端/桌面端网站或应用中的顶部栏。在桌面应用中,QBar 通常承载关闭、最小化、最大化按钮以及应用菜单控制项;在移动端则常用于模拟系统状态栏(信号、Wi-Fi、电量、时间等)。官方文档特别指出:QBar 对无边框(frameless)Electron 应用尤为有用,可以将其集成进 QHeader 中使用。
从实现上看,QBar 的组件结构非常简单清晰。其完整源码位于 ui/src/components/bar/QBar.js,核心逻辑如下:
export default /*#__PURE__*/ createComponent({ name: 'QBar', props: { ...useDarkProps, dense: Boolean }, setup(props, { slots }) { const $q = useQuasar() const isDark = useDark(props, $q) const classes = computed( () => 'q-bar row no-wrap items-center' + ` q-bar--${props.dense ? 'dense' : 'standard'} ` + ` q-bar--${isDark() ? 'dark' : 'light'}` ) return () => h( 'div', { class: classes.value, role: 'toolbar' }, hSlot(slots.default) ) } })可以看到,QBar 本质上渲染为一个div元素,自带row no-wrap items-center三个 Flex 布局类(内容水平排列、不换行、垂直居中),并依据 props 动态拼接q-bar--dense/q-bar--standard与q-bar--dark/q-bar--light修饰类,最终输出role="toolbar"。
API 速览
QBar 的公开 API 非常收敛,只有两个 props 和一个默认插槽,定义于 ui/src/components/bar/QBar.json:
| 名称 | 类型 | 说明 |
|---|---|---|
dense | Boolean | 是否使用紧凑模式,减小高度与内边距 |
dark | Boolean | null(默认 null) | 背景颜色变亮(照亮父级背景),与默认"加深背景"行为相反;若为null则跟随全局深色模式 |
default插槽 | — | 放置 QBar 内容(图标、文本、按钮、菜单等) |
dense:紧凑模式
dense为true时,QBar 切换到紧凑布局:高度更矮、内边距更小、字号更小。官方测试 ui/src/components/bar/QBar.test.js 对这一行为做了验证:
test('type Boolean has effect', async () => { const wrapper = mount(QBar) const target = wrapper.get('.q-bar') expect(target.classes()).not.toContain('q-bar--dense') await wrapper.setProps({ dense: true }) await flushPromises() expect(target.classes()).toContain('q-bar--dense') })dark:深色模式感知
dark的行为值得单独说明。其实现依赖 ui/src/composables/private.use-dark/use-dark.js 中的useDarkcomposable:
export const useDarkProps = { dark: { type: Boolean, default: null } } export default function useDark(props, $q) { return () => (props.dark === null ? $q.dark.isActive : props.dark) }即:不传dark(保持null)时,QBar 自动跟随 Quasar 全局深色模式($q.dark.isActive);显式传入true/false则强制覆盖。官方文档对dark的补充说明是:"组件背景色会照亮父级背景(与默认的加深背景相反);除非你为它指定了 CSS 背景色,否则该行为生效。"测试用例也同时覆盖了dark: true与dark: null两种情形。
快速上手:基础用法
QBar 的用法非常直观,把内容放进<q-bar>标签即可:
<q-bar> <q-icon name="laptop_chromebook" /> <div>My App</div> <q-space /> <q-btn dense flat icon="minimize" /> <q-btn dense flat icon="crop_square" /> <q-btn dense flat icon="close" /> </q-bar>其中q-space会把左右两侧的内容推开(等价于flex: 1的占位),是 QBar 布局中的常用搭档;q-btn使用dense flat让按钮贴合工具栏的紧凑风格。
平台化样式:复刻 MacOS / Windows / iOS / Android 顶栏
官方文档将 QBar 最常见的应用场景按操作系统风格分成了四类示例,完整可运行代码位于docs/src/examples/QBar/目录下,可直接参考复刻:
MacOS 风格
MacOS 示例(docs/src/examples/QBar/MacOS.vue)包含两种形态:一是带 Apple Logo、应用名、菜单项、状态图标(AirPlay、电池、Wi-Fi、时间、搜索)的完整菜单栏;二是 MacOS 特色的"红黄绿"窗口控制圆点(使用q-btn dense flat round搭配不同颜色的小圆点图标实现):
<q-bar> <q-btn dense flat round icon="lens" size="8.5px" color="red" /> <q-btn dense flat round icon="lens" size="8.5px" color="yellow" /> <q-btn dense flat round icon="lens" size="8.5px" color="green" /> <div class="col text-center text-weight-bold"> My-App </div> </q-bar> <q-bar dark class="bg-primary text-white"> <!-- 深色模式下的同款布局 --> </q-bar>注意示例中通过<script setup>从@quasar/extras/fontawesome-v7引入fabApple图标,说明 QBar 内部完全复用 Quasar 的图标体系。
Windows 风格
Windows 示例(docs/src/examples/QBar/Windows.vue)是经典的菜单栏 + 窗口控制按钮(最小化、还原、关闭):
<q-bar> <div class="cursor-pointer">File</div> <div class="cursor-pointer">Edit</div> <div class="cursor-pointer gt-xs">View</div> <div class="cursor-pointer gt-xs">Window</div> <div class="cursor-pointer">Help</div> <q-space /> <q-btn dense flat icon="minimize" /> <q-btn dense flat icon="crop_square" /> <q-btn dense flat icon="close" /> </q-bar>示例同时给出了bg-black text-white的深色变体,并通过gt-xs实现响应式隐藏。
iOS / Android 风格
iOS(docs/src/examples/QBar/iOS.vue)与 Android(docs/src/examples/QBar/Android.vue)示例则演示了用 QBar 模拟移动端状态栏:运营商名、信号/网络图标、Wi-Fi、电量、时间等。两者都用到了dense模式以获得更矮的状态栏高度:
<q-bar dense class="bg-teal text-white"> <q-icon :name="fasSignal" /> <div>mobi-net</div> <div>4G</div> <q-icon :name="fasWifi" /> <q-space /> <q-icon name="near_me" /> <div>100%</div> <q-icon :name="fasBatteryFull" /> </q-bar>与其他组件组合使用
官方文档专门列出了 QBar 与三种组件的组合范式,均有完整示例:
QBar + QMenu:桌面菜单栏
在 QBar 中直接嵌套<q-menu>,即可实现带下拉菜单的桌面应用菜单栏(File / Edit / Preferences…),支持多级子菜单(通过anchor="top end" self="top start"控制弹出位置)。完整示例见 docs/src/examples/QBar/Menu.vue,典型结构:
<q-bar> <div class="cursor-pointer non-selectable"> File <q-menu> <q-list dense style="min-width: 100px"> <q-item clickable v-close-popup> <q-item-section>Open...</q-item-section> </q-item> <!-- ... --> </q-list> </q-menu> </div> <q-space /> <q-btn dense flat icon="minimize" /> <q-btn dense flat icon="close" /> </q-bar>QBar + QDialog:对话框标题栏
在q-card顶部放置 QBar 作为对话框的标题区,配合v-close-popup实现点击关闭,并区分浅色/深色两种弹窗。完整示例见 docs/src/examples/QBar/Dialog.vue。
QBar + QHeader + QToolbar:应用整体顶栏
官方文档强调 QBar 与无边框 Electron 场景的搭配,示例 docs/src/examples/QBar/Header.vue 展示了"QHeader 内先放 QBar(窗口控制按钮),下方再放普通工具栏/菜单栏"的双层结构:
<q-header elevated> <q-bar> <q-icon name="laptop_chromebook" /> <div>Google Chrome</div> <q-space /> <q-btn dense flat icon="minimize" /> <q-btn dense flat icon="crop_square" /> <q-btn dense flat icon="close" /> </q-bar> <!-- 下层:菜单栏等普通内容 --> </q-header>无边框 Electron 窗口实战
QBar 最典型的实战场景是无边框 Electron 应用。官方为此提供了专门的指南文档 docs/src/pages/quasar-cli-vite/developing-electron-apps/frameless-electron-window.md,核心思路如下:
1. 主进程:关闭系统窗口边框
在src-electron/electron-main中将BrowserWindow配置为frame: false,并注册窗口控制 IPC 监听(最小化、最大化/还原、关闭),同时从event.sender解析窗口以确保每个渲染进程只控制自己的窗口:
const mainWindow = new BrowserWindow({ // ...other settings frame: false // <-- add this }) function registerWindowControls() { ipcMain.on('window:minimize', event => { BrowserWindow.fromWebContents(event.sender)?.minimize() }) ipcMain.on('window:toggle-maximize', event => { const win = BrowserWindow.fromWebContents(event.sender) if (!win) return win.isMaximized() ? win.unmaximize() : win.maximize() }) ipcMain.on('window:close', event => { BrowserWindow.fromWebContents(event.sender)?.close() }) }2. 预加载脚本:向渲染进程暴露窗口 API
通过contextBridge.exposeInMainWorld暴露myWindowAPI,供渲染进程调用:
contextBridge.exposeInMainWorld('myWindowAPI', { minimize() { ipcRenderer.send('window:minimize') }, toggleMaximize() { ipcRenderer.send('window:toggle-maximize') }, close() { ipcRenderer.send('window:close') } })3. 渲染进程:QBar 承载窗口控制与拖拽
无边框窗口必须提供可拖拽区域,官方推荐在 QBar 上直接使用q-electron-drag辅助类:
<q-bar class="q-electron-drag"> <q-icon name="laptop_chromebook" /> <div>Google Chrome</div> <q-space /> <q-btn aria-label="Minimize" dense flat icon="minimize" @click="minimize" /> <q-btn aria-label="Maximize" dense flat icon="crop_square" @click="toggleMaximize" /> <q-btn aria-label="Close" dense flat icon="close" @click="closeApp" /> </q-bar>要点:
q-electron-drag:让用户可以从该区域拖拽移动窗口;- 交互子元素:
QBtn会自动排除拖拽行为,覆盖层内容(菜单、对话框、通知、tooltip)默认也不会触发拖拽(v2.27+);其余交互元素需手动添加q-electron-drag--exception; - 多模式兼容:按钮点击方法内可用
import.meta.env.QUASAR_ELECTRON_MODE守卫 Electron API 调用,使同一套代码同时兼容 SPA/PWA/SSR 等模式;也可用v-if="isElectron"仅在 Electron 模式下渲染窗口控制条(const isElectron = import.meta.env.QUASAR_ELECTRON_MODE)。
响应式布局建议
官方文档给出了两条响应式建议:
- 优先使用 Visibility 相关的 Quasar CSS 类(如
gt-xs、gt-md、lt-md等)来控制 QBar 内部元素在不同窗口宽度下的显隐,相关用法见 docs/src/pages/style/visibility.md——例如gt-md表示仅在大于 medium(lg 和 xl)窗口时显示。前面 MacOS / Windows 示例中的gt-xs、gt-md正是这一用法的体现; - 需要更精细的断点控制时,可以自写 CSS media breakpoint,或结合 QResizeObserver 监听容器尺寸变化。
无障碍(Accessibility)
自 v2.25 起,QBar 与 QToolbar 一样携带role="toolbar"(这一点也能在源码 ui/src/components/bar/QBar.js 的h('div', { role: 'toolbar' }, ...)中直接确认)。无障碍实践要点:
- 当页面包含多个工具栏时,应为 QBar 提供
aria-label加以区分; - QBar 内的所有控件都是独立的 Tab 焦点停靠点(Tab stops),需要保证键盘可达性;
- 更详细的规范可参考 QToolbar 的无障碍章节。
样式原理:从 Sass 变量到最终外观
QBar 的视觉样式全部由 ui/src/components/bar/QBar.sass 定义,理解它能帮你精准定制:
.q-bar background: rgba(0,0,0,.2) // 默认:轻微加深背景 > .q-icon margin-left: 2px > div, > div + .q-icon margin-left: 8px > .q-btn margin-left: 2px > .q-icon:first-child, > .q-btn:first-child, > div:first-child margin-left: 0 // 首个元素去掉左边距 &--standard padding: 0 12px height: $bar-height font-size: 18px > div font-size: $bar-inner-font-size .q-btn font-size: $bar-button-font-size &--dense padding: 0 8px height: $bar-dense-height font-size: $bar-dense-font-size .q-btn font-size: $bar-dense-button-font-size &--dark background: rgba(255,255,255,.15) // 深色模式:照亮背景相关尺寸变量定义于 ui/src/css/variables.sass 的 L547-L552:
$bar-inner-font-size : 16px !default $bar-button-font-size : 11px !default $bar-dense-font-size : 14px !default $bar-dense-button-font-size : 8px !default $bar-height : $bar-inner-font-size * 2 !default // 32px $bar-dense-height : $bar-dense-font-size + 10px !default // 24px由此可推算出:标准模式高度约 32px、密集模式高度约 24px;这些 Sass 变量均带!default,意味着你可以通过 Quasar 的 Stylus/Sass 变量覆盖机制在应用中自定义 QBar 的尺寸体系。此外,样式层面对图标、普通元素(div)与按钮采用了不同的间距(2px / 8px / 2px),这也是 QBar 内混排图标与文本时视觉整齐的原因。
可靠性保障:单元测试与 SSR 水合测试
QBar 的稳定性由两组测试支撑:
- 单元测试ui/src/components/bar/QBar.test.js:覆盖
denseprop 的类名切换、darkprop 的true/null两种行为,以及默认插槽内容渲染; - SSR 水合测试ui/src/components/bar/QBar.hydration.test.js 与其夹具 ui/src/components/bar/QBar.hydration.fixtures.js:验证 QBar 在服务端渲染后客户端能干净地水合(无控制台报错),确保它在 SSR 场景下同样可靠。
小结
QBar 是一个 API 极简但适配性极强的 Quasar 组件:两个 props(dense、dark)加上一个默认插槽,配合 Flex 布局类与 Sass 变量体系,即可复刻 MacOS、Windows、iOS、Android 四种平台的顶部栏样式;与 QMenu、QDialog、QHeader 的组合让它能够胜任菜单栏、对话框标题栏与整体应用顶栏;而在无边框 Electron 应用中,QBar 配合q-electron-drag与窗口控制 IPC,构成了官方推荐的标题栏解决方案。深入阅读 QBar 源码 与其示例目录docs/src/examples/QBar/,可以进一步掌握每个平台风格的细节实现。
【免费下载链接】quasarQuasar Framework - Build high-performance VueJS user interfaces in record time项目地址: https://gitcode.com/gh_mirrors/qu/quasar
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考