🧩

初めてのElectron vol.04 [簡易ToDoリスト完成]

2022/01/31に公開

記事はbookへ統合されます

https://zenn.dev/isana_citrus/books/90372c9fe6554d

vol.04 今回の内容

第四回です。今回でToDoリストは区切ります。

  • 完了したものを消す
  • 全削除ボタンを付ける(electron menu の実装)
  • 非アクティブでもキーボードショートカットで呼び出せるようにする

前回予告したもののうちキーボードショートカット以外を付けて完成とします
なお見た目にはこだわりません
html+cssなのでググればいっぱい出てくると思うので、わざわざ取り扱う必要がないと判断してます
ぶっちゃけ自分で使わないものを作るのに飽きました、次のやつからは自分で使うものを作っていきます

では書いていきましょー

完了したものを消すやつを実装

今回は簡単な実装にするため
Storeから<li>で表示する際にidを連番で振っておく
<li>要素をclickしたときにclickされたli要素のidを読み取って
Storeから消す。流れで実装していきます。

todolist.js

./todolist.js
 //Storeデータをmain.jsからとってきて表示する処理
 async function listview() {
     const ul = document.querySelector("#ToDolist");//id=ToDolistを取得する
     const clone = ul.cloneNode(false); //ul要素の中身以外を拝借
     const ToDoList = await window.dataapi.getlist();
+    let i = 0;//index番号用
     for (const item of ToDoList) {
         const li = document.createElement("li");//li elementを作る
         const todotext = document.createTextNode(item);//itemをテキストノードにする
         li.appendChild(todotext);//liにtodotextを入れる
+        li.dataset.id = i;//data-id=index番号を記録させる
+        li.onclick = todo_delete;//li要素をclickされたときの
         clone.appendChild(li);//ulに作ったliを入れる
+        i = i + 1;//indexを1進める
     }
     ul.parentNode.replaceChild(clone, ul); //入れ替える
 }
+async function todo_delete(event) {
+    const del_index = event.target.dataset.id;//data-idを取り出す
+    const ToDoList = await window.dataapi.getlist();//store読み込み
+    ToDoList.splice(del_index, 1);//indexの場所を一個消す
+    await window.dataapi.setlist(ToDoList);//store保存
+    listview(); //表示更新
+}
 //起動時初期化用
 listview();

あまり解説することはありませんね
まあ私自身もJSあまり知らないので解説はできませんが…
上にも書いた通り
clickされた要素の[data-id]を読んでstoreからdata-id番目のデータを消して
表示を更新してます
動作確認はまとめてやります

全部消すやつの実装+menuを作る

全部消すやつの実装はメニューからの操作を想定し、
削除操作→メインプロセスで削除処理→レンダラープロセスに完了通知
という形をとります

削除の部分

まず削除部分を実装する

./main.js
 app.on("ready", function () {
     //省略
 }
+// 全件削除処理
+function todo_all_del() {
+    Store_Data.delete('ToDoList');//ToDoListのデータを削除
+    mainWindow.webContents.send("todo_all_delete");//mainWindowへipc通信を送信
+}
 // IPC通信(DataAPI関係)

特に難しいことはしてないのでノー解説

preload.jsに追加(main→renderer)

メインプロセスからレンダラープロセスへipcが通るようにします

./preload.js
 const { contextBridge, ipcRenderer } = require("electron");
 contextBridge.exposeInMainWorld(
     'dataapi', {
     getlist: () => ipcRenderer.invoke("getlist"),
     setlist: (data) => ipcRenderer.invoke("setlist", data),
+    //受信用処理
+    on_todo_all_del: (func) => {
+        ipcRenderer.on("todo_all_delete", (event, ...args) => func(...args));
+    }
+    //受信はこう
+    //on: (channel, func) => {ipcRenderer.on(channel, (event, ...args) => func(...args));},
    
 }); 

メニューがらみの実装

https://www.electronjs.org/ja/docs/latest/api/menu
上記を参考に./main.jsの後ろに実装します

./main.js へ追記
/////////////////////
//MENUテンプレ
/////////////////////
// 実行環境がmacOSならtrue
const isMac = (process.platform === 'darwin');  // 'darwin' === macOS
const menu_temp = [
   {
       label: "ファイル",
       submenu: [
           {
               label: "アイテムを消す",
               click() {
                   todo_all_del();
               }
           },
           {
               label: "終了",
               accelerator: isMac ? "Command+Q" : "Ctrl+Q",//三項演算子というらしい
               click() {
                   app.quit();
               }
           }
       ]
   }
];

//MacならMac用のメニューを先頭においておく
if (isMac) {
   menu_temp.unshift({
       label: app.name,
       role: "appMenu",
   });
}
//パッケージ化されてなければ開発者ツールを開けるようにする
if (!app.isPackaged) {
   menu_temp.push({
       label: "開発者ツール",
       submenu: [
           {
               label: "開発者ツール",
               accelerator: process.platform == "darwin" ? "Command+Shift+I" : "Ctrl+Shift+I",
               click(item, focusedwindow) {
                   focusedwindow.toggleDevTools();
               }
           },
           {
               label: "リロード",
               accelerator: process.platform == "darwin" ? "Command+Alt+R" : "Ctrl+Alt+R",
               role: 'forceReload',
           }
       ]
   });
}
//メニューをセット
Menu.setApplicationMenu(Menu.buildFromTemplate(menu_temp));

macとwindowsでメニューが違うので記載がややこしくなります
windowsは普通に左上から「ファイル」「編集」みたいな構成ですが
macの場合「リンゴマーク」「app名」「ファイル」「編集」って感じで
app名が余計に追加されてます
なのでmac用めにゅーを先頭に置く処理があります

全部消したときに表示を更新させる

./todolist.js
+//メインプロセスからのipcを受け取る
+window.dataapi.on_todo_all_del(() => {
+    listview();
+});
 //起動時初期化用
 listview();

動作確認

一連の動き


めっちゃタイプミスしてる(笑)
ちゃんと項目クリックで消えるし、全消しもできる
メニューがキャプチャーできてないけど
なのでこんな表示ですよスクショ

いかがでしたでしょうか

今回で一区切り、ほんとに簡単な基本をやってきました
まだまだ自分も学習中ですが、GUIが結構簡単に作れてしまうのはjavascript系のいいところだと思います
またguiで使う技術がweb技術なので記述方法など凝ったものを作りたくなったらそこら中に転がってるのもよしですね
これが続けばもうすこし凝ったものを作っていきたいと思います

最後に

よかったらTwitterやってます。フォローしてやってください
https://twitter.com/Isana_Citrus
次回以降更新する場合はbookにするのでよろしくお願いいたします(追記)

Discussion