1. やりたいこと
Tauri v2でWebviewWindowを使ってサブウィンドウを開きたい
2. 選択肢
以下の2つの方法があるようです
1. フロントエンドでWebviewWindowプラグインを使って実行する方法
2. バックエンドでWebviewWindowBuilderを使ってプラグインを自作する方法
普通にサブウィンドウを開くだけなら既存プラグインで十分なので、1の方法でやっていきます。また、フロントエンドはReactを選択します
3. 手順
- プラグインのpermissionを設定する
- 表示するビューのroutingを設定する
- 呼び出し側のビューを作成する
- サブウィンドウのビューを作成する
3-1. プラグインのpermissionを設定する
以下2つを追加します
- 実行して良いウィンドウを追加する
(windowsにsubを追加) - プラグインのpermissionを追加する
(core:webviewプラグインのallow-create-webview-window機能の許可を追加)
デフォルトプロジェクトに追加すると以下のようになります
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "Capability for the main window",
"windows": ["main", "sub"],
"permissions": [
"core:default",
"opener:default",
"core:webview:allow-create-webview-window" # 追加
]
}
3-2. 表示するビューのroutingを設定する
React Routerを使うので環境にインストールします
npm i @tauri-apps/plugin-window @tauri-apps/plugin-dialog
/subにSubViewコンポーネントを割り当てます
import { createHashRouter, RouterProvider } from "react-router";
import MainView from "./MainView";
import SubView from "./SubView";
const router = createHashRouter([
{ path: "/", element: <MainView /> },
{ path: "/sub", element: <SubView /> },
]);
export default function App() {
return <RouterProvider router={router} />;
}
3-3. 呼び出し側のビューを作成する
サブウィンドウの呼び出しはnew WebviewWindow()により実行します。第1引数にウィンドウ名を書き、第2引数のurl:にWebViewのURLを書きます。使用するウィンドウ名"sub"が/src-tauri/capabilities/default.jsonのwindowsで許可されていて、React RouterによりWebViewのURLにビューが待機していれば正常に呼び出すことができます
import { WebviewWindow } from "@tauri-apps/api/webviewWindow";
export default function MainView() {
const openSubWindow = async () => {
// 新しいウィンドウを開く
const photo_selector = new WebviewWindow("sub", {
url: "/#/sub",
title: "設定",
width: 900,
height: 600,
visible: true,
resizable: true,
});
// 作成完了イベント
photo_selector.once("tauri://created", () => {
console.log("サブウィンドウが作成されました");
});
// エラーイベント
photo_selector.once("tauri://error", (e) => {
console.error("サブウィンドウ作成に失敗", e);
});
}
return <div>
<h1>メインウィンドウです</h1>
<button onClick={openSubWindow}>クリックするとサブウィンドウを開きます</button>
</div>
}
3-4. サブウィンドウのビューを作成する
呼び出されるビューは適当なコンポーネントで構いません
export default function SubView() {
return <h1>サブウィンドウです</h1>;
}
3-5. 完成したコード
この記事のコードが以下にあります
https://github.com/haneya-studio/tauri_subwindow_sample
4. 値をやりとりする
サブウィンドウとの間で値をやり取りしたくなることが多いと思います
2つやり方があるようなのでそれぞれ紹介します
4-1. URL経由で渡す
ReactRouterを使っているので、URLにオプションを付けて渡すことができます。Vueの場合もVueRouterを使えば同様にできます
import { useLocation } from "react-router-dom";
export default function SubView() {
const location = useLocation();
const params = new URLSearchParams(location.search);
const folder = params.get("folder");
const mode = params.get("mode");
return (
<div>
<h1>サブウィンドウ</h1>
<p>フォルダ: {folder}</p>
<p>モード: {mode}</p>
</div>
);
}
送る側はurlに付けて送るだけです
const photo_selector = new WebviewWindow("sub", {
// url: "/#/sub",
url: `/#/sub?folder=${encodeURIComponent(folder)}&mode=edit`,
title: "設定",
width: 1400,
height: 800,
visible: true,
resizable: true,
});
4-2. イベント送受信で渡す
tauriのeventを使うと変数やオブジェクトを渡すことができます
emitToしたときにlistenしていればイベントを拾えるので、更新をかけたりも自在にできます
import { emitTo } from "@tauri-apps/api/event";
await emitTo("main", "addPhoto", path); // mainウィンドウのaddPhotoイベントにpathを渡す
受け取る側はlistenを置くだけでイベントを受け取ってくれますが、再レンダリングされたときに重複してリスナが作成されないようにuseEffectで作成します
import { listen, emitTo, type Event } from "@tauri-apps/api/event";
useEffect(() => {
let active = true;
let unlisten: (() => void) | undefined;
(async () => {
const stop = await listen<photoSelectorPayload>("addPhoto", (event: Event<photoSelectorPayload>) => {
if (!active) return;
if (event.payload.path) {
console.log("受け取ったデータ:", event.payload.path);
}
});
unlisten = stop;
})();
return () => {
active = false;
if (unlisten) unlisten();
};
}, []);
まとめ
ググっても日本語の記事が出てこなかったので一応まとめておきます
レッツトライ