无边框窗口与自定义标题栏

系统标题栏是插件界面里唯一不属于你的部分。它在不同系统上长得不一样、占掉几十像素高度、样式你改不了。无边框窗口就是把这块壳去掉,界面完全由你掌控。

一行配置开启

把 main.frame 设为 false:

{
    "id": "LB5UL2P0Q9FFF",
    "version": "1.0.0",
    "name": "Hello World",
    "logo": "/logo.png",
    "keywords": [],
    "main": {
        "frame": false,
        "url": "index.html",
        "width": 640,
        "height": 480
    }
}

frame 默认是 true。设为 false 后,窗口不带有任何外壳——没有边框、没有标题栏、没有系统工具栏,只剩网页内容。

代价是你必须自己补齐这些原生能力:拖拽移动窗口、最小化、最大化、关闭。少做一个,用户就会觉得「这插件怎么关不掉」。

可拖拽区:用 app-region

无边框窗口默认不可拖拽。要让用户按住某块区域移动窗口,需要用 CSS 属性 -webkit-app-region: drag 明确指定。

整窗可拖:

<body style="-webkit-app-region: drag">
</body>

更常见的做法是只让标题栏可拖:

.titlebar {
    -webkit-app-region: drag;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 12px;
    user-select: none;
}

关键陷阱:拖拽区和按钮互斥

这是无边框窗口最容易踩的坑。如果整个窗口或标题栏设成了 drag,里面的按钮会点不动——因为鼠标事件被窗口移动抢走了。必须在按钮上反向声明 no-drag:

.titlebar {
    -webkit-app-region: drag;
}

.titlebar button,
.titlebar .interactive {
    -webkit-app-region: no-drag;
}

这条规则是无边框窗口能不能用的分水岭。写了 drag 忘了写 no-drag,界面上所有按钮都会失效,而且现象很迷惑——用户能拖动窗口(说明插件在运行),但点按钮没反应。

另外注意,官方明确说明当前只支持矩形形状。所以不能做成「只有文字区域可拖、图标区域不可拖」这种不规则形状,只能按矩形块划分。

完整示例:自定义标题栏

HTML:

<body>
    <div class="titlebar">
        <span class="title">批量重命名</span>
        <div class="window-buttons">
            <button id="btn-min" title="最小化">—</button>
            <button id="btn-max" title="最大化">▢</button>
            <button id="btn-close" title="关闭">×</button>
        </div>
    </div>
    <div class="content">
        <p>把下面这段话放进你的插件里:</p>
    </div>
</body>

CSS:

body {
    margin: 0;
    font-family: -apple-system, "Segoe UI", sans-serif;
    background: #ffffff;
}

.titlebar {
    -webkit-app-region: drag;
    height: 38px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-left: 14px;
    background: #f5f5f5;
    border-bottom: 1px solid rgba(0,0,0,.08);
    user-select: none;
}

.title {
    font-size: 13px;
    font-weight: 500;
}

/* 按钮必须脱离拖拽区 */
.window-buttons {
    -webkit-app-region: no-drag;
    display: flex;
}

.window-buttons button {
    width: 44px;
    height: 38px;
    border: 0;
    background: transparent;
    cursor: pointer;
    font-size: 13px;
    color: #555;
}

.window-buttons button:hover {
    background: rgba(0,0,0,.06);
}

#btn-close:hover {
    background: #e81123;
    color: #fff;
}

JS:

eagle.onPluginCreate(async () => {
    const theme = await eagle.app.theme;
    document.body.setAttribute('theme', theme);

    document.querySelector('#btn-min').addEventListener('click', () => {
        eagle.window.minimize();
    });

    document.querySelector('#btn-max').addEventListener('click', async () => {
        if (await eagle.window.isMaximized()) {
            await eagle.window.unmaximize();
        } else {
            await eagle.window.maximize();
        }
    });

    document.querySelector('#btn-close').addEventListener('click', () => {
        eagle.window.hide();
    });
});

eagle.onThemeChanged((theme) => {
    document.body.setAttribute('theme', theme);
});

实施步骤

  1. 把 main.frame 设为 false,main.url 指向你的页面。
  2. 在页面顶部写 .titlebar 容器,里面放标题文字和三个按钮容器。
  3. 给 .titlebar 加 -webkit-app-region: drag,给按钮容器加 -webkit-app-region: no-drag。
  4. 在 onPluginCreate 里给三个按钮分别绑定 eagle.window.minimize()、maximize/unmaximize 切换、eagle.window.hide()。
  5. 注册 eagle.onThemeChanged,让标题栏跟随主程序配色。
  6. 显式设置 maximizable、resizable 等开关,和你的界面设计一致。
  7. 把 backgroundColor 设成标题栏底色,避免打开瞬间白闪。
  8. 按 F12 逐项验证:拖动窗口、点三个按钮、切换主题、缩放窗口。

配套的窗口能力开关

用了自定义标题栏后,系统的窗口按钮就没了,需要在配置层面把不该有的行为关掉:

{
    "main": {
        "frame": false,
        "url": "index.html",
        "width": 640,
        "height": 480,
        "minimizable": true,
        "maximizable": false,
        "resizable": false,
        "alwaysOnTop": false,
        "backgroundColor": "#f5f5f5"
    }
}

backgroundColor 在无边框窗口里格外重要:无边框意味着窗口打开的第一帧就完全暴露给你,如果你没设背景色,用户会看到一团白闪,然后才变成你的界面。把 backgroundColor 设成你标题栏的颜色,视觉上是连续的。

进阶组合

无边框 + 置顶 + 鼠标穿透,可以做出桌面挂件:

{
    "main": {
        "frame": false,
        "url": "index.html",
        "width": 260,
        "height": 120,
        "alwaysOnTop": true,
        "backgroundColor": "#00000000"
    }
}
await eagle.window.setAlwaysOnTop(true);
await eagle.window.setOpacity(0.9);
await eagle.window.setIgnoreMouseEvents(true);   // 鼠标穿透
// 需要交互时再关掉穿透
await eagle.window.setIgnoreMouseEvents(false);

用颜色取样器、色板显示这类小工具适合这么做。需要提醒的是:这类插件要清楚说明它会常驻屏幕,审核标准里「与核心功能无关的高权限行为」是要被检查的项。

常见坑

设了 drag 却忘了 no-drag,所有按钮失效。 这是无边框窗口第一大坑。规则很简单:所有可点击元素都要显式声明 -webkit-app-region: no-drag。

拖拽区里放了输入框。 输入框也是可交互元素,同样需要 no-drag。否则用户点输入框会变成拖动窗口,光标闪烁都不出现。

延伸注意: * 忘了 -webkit-app-region 不支持非矩形。 想做「圆形头像区可拖、旁边文字不可拖」是做不到的,只能切成若干矩形块。

整理人:WorkBuddy