Окна
deno desktop доступен начиная с Deno v2.9.0. Если у вас более ранняя версия, обновите Deno, чтобы использовать его.
Класс Deno.BrowserWindow управляет нативными окнами. Окно открывается автоматически при запуске вашего бинарного файла и переходит на локальный HTTP-сервер. **Первый** созданный вами new Deno.BrowserWindow() использует это начальное окно; каждое последующее создание открывает новое. Все окна используют одну среду выполнения Deno: на процесс приходится одна асинхронная среда выполнения, независимо от количества открытых окон.
Полный пример приложения, которое управляет окном, меню приложения и упаковкой, см. в примере denidian.
Создание окон
// The first construction adopts the implicit startup window.
const win = new Deno.BrowserWindow({ title: "My App" });
// Subsequent constructions open additional windows.
const base = Deno.env.get("DENO_SERVE_ADDRESS")!; // "tcp:127.0.0.1:<port>"
const port = base.split(":").pop();
const settings = new Deno.BrowserWindow({
title: "Settings",
width: 420,
height: 320,
});
settings.navigate(`http://127.0.0.1:${port}/settings`);
Конструктор принимает объект BrowserWindowOptions:
| Параметр | Тип | По умолчанию | Примечания |
|---|---|---|---|
title | string | нет | Заголовок окна. |
width | number | 800 | Начальная ширина в логических пикселях. |
height | number | 600 | Начальная высота в логических пикселях. |
x, y
| number | нет | Начальное положение; если не указано, окно располагается по центру. |
resizable | boolean | true | Можно ли изменять размер окна. |
alwaysOnTop | boolean | false | Закрепить окно поверх остальных. |
frameless | boolean | false | Убрать строку заголовка и рамку окна. Задаётся только при создании. |
noActivate | boolean | false | Плавающая панель, которая не активируется и не перехватывает фокус. Задаётся только при создании. |
transparentTitlebar | boolean | false | Слить строку заголовка с содержимым. Задаётся только при создании. |
new Deno.BrowserWindow() немедленно открывает (или использует) окно. Окно остаётся открытым, пока не будет вызван close() или пока пользователь не закроет его средствами ОС.
frameless, noActivate и transparentTitlebar можно задать только при создании. frameless + noActivate — основные компоненты всплывающих окон области уведомлений / строки меню; см. Tray.attachPanel.
Несколько окон независимы: у каждого свои размер, положение, состояние фокуса и веб-представление. Они могут переходить по разным путям или к разным источникам, задавать собственные привязки и генерировать собственные события.
Жизненный цикл
win.show();
win.hide();
win.focus();
win.close(); // sends close request, fires "close" event
win.reload(); // reload the webview's current document
if (win.isClosed()) { /* … */ }
if (win.isVisible()) { /* … */ }
У каждого окна есть постоянный числовой идентификатор:
console.log(win.windowId);
Закрытие окна не останавливает среду выполнения; процесс продолжает работать, пока не будут закрыты все окна (или пока вы не вызовете Deno.exit()).
Размер и положение
const [w, h] = win.getSize();
win.setSize(800, 600);
const [x, y] = win.getPosition();
win.setPosition(100, 100);
if (win.isResizable()) { /* … */ }
win.setResizable(false);
if (win.isAlwaysOnTop()) { /* … */ }
win.setAlwaysOnTop(true);
Размеры указаны в логических пикселях. Масштабирование HiDPI обрабатывается ОС.
Сохранение размера и положения
Deno не запоминает размер и положение окна между запусками, и не следует рассчитывать на то, что ОС восстановит их: некоторые оконные менеджеры это делают, но многие — нет (например, в Linux/KDE при каждом запуске окно открывается с параметрами конструктора по умолчанию). Если вы хотите, чтобы окно повторно открывалось там, где его оставил пользователь, сохраните его геометрию в конфигурации приложения и восстановите при следующем запуске.
Передайте сохранённые значения конструктору, а затем записывайте геометрию при каждом её изменении:
const file = `${Deno.env.get("HOME")}/.myapp-window.json`;
let saved: { width?: number; height?: number; x?: number; y?: number } = {};
try {
saved = JSON.parse(await Deno.readTextFile(file));
} catch {
// First run, or no saved state yet — fall back to defaults.
}
const win = new Deno.BrowserWindow({
title: "My App",
width: saved.width ?? 800,
height: saved.height ?? 600,
x: saved.x,
y: saved.y,
});
async function save() {
const [width, height] = win.getSize();
const [x, y] = win.getPosition();
await Deno.writeTextFile(file, JSON.stringify({ width, height, x, y }));
}
win.addEventListener("resize", save);
win.addEventListener("move", save);
Заголовок
win.setTitle("My App: Untitled");
Используйте постоянный префикс и уникальный для документа суффикс: именно это пользователи видят в переключателях окон, доке и на панели задач.
Навигация
const port = Deno.env.get("DENO_SERVE_ADDRESS")!.split(":").pop();
win.navigate(`http://127.0.0.1:${port}`);
Навигация работает с любыми URL, которые может загрузить встроенное веб-представление, чаще всего — с локальным HTTP-сервером (см. раздачу по HTTP), а также с URL https://, URL file:// и URL data:.
В многостраничных приложениях используйте маршрутизацию локального HTTP-сервера, а не переключение окон. Для модальных диалогов лучше создать дочернее окно, а не переходить на другую страницу.
События
Deno.BrowserWindow — это EventTarget. Подписывайтесь с помощью addEventListener или присвойте обработчик соответствующему свойству on<event>.
win.addEventListener("resize", (e) => {
console.log("resized to", e.detail.width, e.detail.height);
});
win.onfocus = () => console.log("focused");
win.onblur = () => console.log("blurred");
| Событие | Когда возникает |
|---|---|
resize | Изменился размер окна. |
move | Изменилось положение окна. |
focus | Окно получило фокус. |
blur | Окно потеряло фокус. |
close | Пользователь запросил закрытие окна. |
keydown | При активном окне была нажата клавиша. |
keyup | Клавиша была отпущена. |
mousemove | Указатель переместился над окном. |
mouseenter | Указатель вошёл в область окна. |
mouseleave | Указатель покинул область окна. |
mousedown | Была нажата кнопка мыши. |
mouseup | Была отпущена кнопка мыши. |
click | Щелчок мышью пришёлся на окно. |
dblclick | Двойной щелчок пришёлся на окно. |
wheel | Была прокручена колёсиком мыши или тачпадом. |
menuclick | Был выбран пункт меню приложения. |
contextmenuclick | Был выбран пункт контекстного меню. |
События указателя и клавиатуры соответствуют их аналогам в браузере (KeyboardEvent, MouseEvent, WheelEvent). resize, move, menuclick и contextmenuclick — это CustomEvents с данными detail; описание событий меню см. в разделе Меню.
win.addEventListener("keydown", (e) => {
if (e.key === "Escape") win.close();
});
Выполнение JavaScript в веб-представлении
const result = await win.executeJs(
"document.querySelectorAll('li').length",
);
console.log(result); // number of <li> on the current page
executeJs выполняет код в основном мире веб-представления и возвращает результат. Значение пересекает границу между областями выполнения, поэтому оно должно быть сериализуемым в JSON; если скрипт выбрасывает исключение, возвращённый промис отклоняется с этим значением.
Для более гибкого взаимодействия между Deno и веб-представлением используйте привязки.
Дескриптор нативного окна
const surface = win.getNativeWindow();
getNativeWindow() оборачивает нативную поверхность окна в Deno.UnsafeWindowSurface, чтобы вы могли выполнять отрисовку в ней с помощью WebGPU. Сначала запросите графический адаптер; вызов выбрасывает исключение, если активного контекста WebGPU нет:
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter!.requestDevice();
const surface = win.getNativeWindow();
const context = surface.getContext("webgpu");
// configure `context` with `device` and draw…
После получения поверхности close() понижается до hide(), чтобы нативные дескрипторы, на которых основана поверхность, не были уничтожены во время работы WebGPU.
Полное пошаговое руководство — настройка контекста, отрисовка геометрии и запуск цикла отрисовки — см. в разделе Отрисовка с помощью WebGPU.
Инструменты разработчика
win.openDevtools(); // both isolates
win.openDevtools({ deno: false }); // renderer only
win.openDevtools({ renderer: false }); // Deno runtime only
См. раздел Инструменты разработчика.
Закрытие приложения
Среда выполнения завершает работу, когда не остаётся открытых окон и других активных асинхронных задач (таймеров, ожидающих запросов fetch и т. д.). Чтобы завершить работу явно:
Deno.exit(0);
Чтобы отменить закрытие (например, показать диалог «Сохранить?»), подпишитесь на close и вызовите event.preventDefault():
win.addEventListener("close", async (e) => {
if (hasUnsavedChanges) {
e.preventDefault();
const ok = await win.executeJs("confirm('Discard changes?')");
if (ok) win.close();
}
});
Последнее обновление:
© 2018–2025 the Deno authors
Licensed under the MIT License.
https://docs.deno.com/runtime/desktop/windows