ipcmain.js
var {Menu,shell,ipcMain,BrowserWindow,app} =require('electron'); var template = [ { label: '文件', submenu: [ { label: '新建', accelerator:"Ctrl+N", click: function(){ //主進程通知渲染進程操作文件 BrowserWindow.getFocusedWindow().webContents.send('action','new'); } }, { label: '打開', accelerator:"Ctrl+O", click: function(){ //主進程通知渲染進程操作文件 BrowserWindow.getFocusedWindow().webContents.send('action','open'); } }, { accelerator:"Ctrl+S", label: '保存', click: function(){ BrowserWindow.getFocusedWindow().webContents.send('action','save'); } }, { type: 'separator' }, { label: '打印', accelerator:"Ctrl+P", click: function(){ //打印功能通過 webContents https://electronjs.org/docs/api/web-contents BrowserWindow.getFocusedWindow().webContents.print(); } }, { label: '退出', accelerator:"Ctrl+Q", click: function(){ //要提示用戶保存 未保存的文件 //主進程通知渲染進程執行退出操作 BrowserWindow.getFocusedWindow().webContents.send('action','exit'); } } ] }, { label: '編輯', submenu: [ { label: '撤銷', role: 'undo' }, { label: '恢復', role: 'redo' }, { type: 'separator' }, { label: '截切', role: 'cut' }, { label: '復制', role: 'copy' }, { label: '黏貼', role: 'paste' }, { label: '刪除', role: 'delete' }, { label: '全選', role: 'selectall' } ] }, { label: '視圖', submenu: [ { label: '加載', role: 'reload' }, { label: '縮小', role: 'zoomin' }, { label: '放大', role: 'zoomout' }, { label: '重置縮放', role: 'resetzoom' }, { type: 'separator' }, { label: '全屏', role: 'togglefullscreen' } ] }, { label: '幫助', submenu: [ { label: '關於', click() { shell.openExternal('https://www.itying.com'); } } ] } ]; var m=Menu.buildFromTemplate(template); Menu.setApplicationMenu(m); //右鍵菜單 const contextMenuTemplate=[ { label: '撤銷', role: 'undo' }, { label: '恢復', role: 'redo' }, { type: 'separator' }, { label: '截切', role: 'cut' }, { label: '復制', role: 'copy' }, { label: '黏貼', role: 'paste' }, { type: 'separator' }, //分隔線 { label: '全選', role: 'selectall' } //Select All菜單項 ]; var contextMenu=Menu.buildFromTemplate(contextMenuTemplate); // 監聽右鍵事件 ipcMain.on('contextMenu',function(){ contextMenu.popup(BrowserWindow.getFocusedWindow()) }) //監聽客戶端的退出操作 ipcMain.on('exit-app',()=>{ app.quit(); })
ipcrender.js
var {ipcRenderer,remote}=require('electron'); var fs=require('fs'); document.title='無標題' //獲取文本框dom var textAreaDom=document.querySelector("#textArea"); /* 問題: 1、新建 打開 保存的問題 2、如果已經保存 第二次保存的時候不提示直接保存 3、判斷文件是否已經保存 改變軟件左上角的內容 */ var isSave=true; //判斷文件是否保存 var currentFile=''; //保存當前文件的路徑 //內容變化的時候 讓isSave等於false textAreaDom.oninput=function(){ if(isSave){document.title+=" *"} isSave=false; } document.addEventListener('contextmenu',function(e){ e.preventDefault(); ipcRenderer.send('contextMenu'); }) //監聽主進程的操作 ipcRenderer.on('action',function(event,action){ console.log(action); switch(action){ case "new": //判斷文件是否保存 如果沒有保存提示 並保存 askSaveDialog(); textAreaDom.value=''; break; case "open": //判斷文件是否保存 如果沒有保存提示 並保存 askSaveDialog(); //通過dialog打開文件 var dir= remote.dialog.showOpenDialog({ properties:['openFile'] }); if(dir){ var fsData=fs.readFileSync(dir[0]); //獲取文件里面的東西 // textAreaDom.value=fsData; editor.setValue(fsData.toString()); //注意傳入的數據 } break; case "save": saveCurrentDoc(); break; case "exit": askSaveDialog(); //同步方法 //通知主進程退出應用 ipcRenderer.send('exit-app') break; } }) //判斷文件師傅保存並執行保存功能 function askSaveDialog(){ if(!isSave){ var index=remote.dialog.showMessageBox({ type:"question", message:'是否要保存此文件?', buttons:['Yes','No'] }) if(index==0){ //執行保存操作 saveCurrentDoc(); } } } //執行保存的方法 function saveCurrentDoc(){ if(!currentFile){ //當前文件路徑不存在 提示保存 var dir=remote.dialog.showSaveDialog({ defaultPath:'aaa.txt', filters: [ {name: 'All Files', extensions: ['*']} ] }); if(dir){ currentFile=dir; fs.writeFileSync(currentFile,editor.getValue()); isSave=true; //改變軟件的標題 document.title=currentFile; } }else{ // editor.getValue() 獲取編輯器的值 // fs.writeFileSync(currentFile,textAreaDom.value); fs.writeFileSync(currentFile,editor.getValue()); isSave=true; //改變軟件的標題 document.title=currentFile; } }
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="./static/css/index.css">
</head>
<body>
<textarea id="textArea"></textarea>
</body>
<link rel=stylesheet href="static/codemirror/doc/docs.css">
<link rel="stylesheet" href="static/codemirror/lib/codemirror.css">
<script src="static/codemirror/lib/codemirror.js"></script>
<script src="static/codemirror/addon/selection/selection-pointer.js"></script>
<script src="static/codemirror/mode/xml/xml.js"></script>
<script src="static/codemirror/mode/javascript/javascript.js"></script>
<script src="static/codemirror/mode/css/css.js"></script>
<script src="static/codemirror/mode/vbscript/vbscript.js"></script>
<script src="static/codemirror/mode/htmlmixed/htmlmixed.js"></script>
<script>
// Define an extended mixed-mode that understands vbscript and
// leaves mustache/handlebars embedded templates in html mode
var mixedMode = {
name: "htmlmixed",
scriptTypes: [{matches: /\/x-handlebars-template|\/x-mustache/i,
mode: null},
{matches: /(text|application)\/(x-)?vb(a|script)/i,
mode: "vbscript"}]
};
var editor = CodeMirror.fromTextArea(document.getElementById("textArea"), {
mode: mixedMode,
selectionPointer: true
});
</script>
<style>
.CodeMirror{
height: 100%;
}
</style>
<script src="./renderer/ipcRenderer.js"></script>
</html>
index.js
import { app, BrowserWindow } from 'electron';
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require('electron-squirrel-startup')) { // eslint-disable-line global-require
app.quit();
}
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;
const createWindow = () => {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
});
// and load the index.html of the app.
mainWindow.loadURL(`file://${__dirname}/index.html`);
// Open the DevTools.
mainWindow.webContents.openDevTools();
// Emitted when the window is closed.
mainWindow.on('closed', () => {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null;
});
//引入icpMain
require('./main/ipcMain.js');
};
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow();
}
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and import them here.
備注:
CodeMirror在線編輯器插件: github地址:https://github.com/codemirror/CodeMirror 官網:http://codemirror.net/ CodeMirror api: http://codemirror.net/doc/manual.html#api 使用CodeMirror: 1.下載: 2、看文檔使用 http://codemirror.net/mode/index.html 注意: https://github.com/codemirror/CodeMirror CodeMirror最新版本使用的是es6的語法,但是由於nodejs不支持 es6的import 所以我們的項目里面沒法用最新的版本 教程使用的是codemirror-5.2 下載codemirror-5.2,然后看官方文檔使用 插件要設置和獲取值: doc.setValue設置值 doc.getValue 或獲取值 var editor = CodeMirror.fromTextArea(document.getElementById("textArea"), { mode: mixedMode, selectionPointer: true }); editor.setValue() editor.getValue() codemirror-5.2修改codemirror.js的地方: 17行左右: this.CodeMirror = mod(); 改為 window.CodeMirror = mod(); 8400行左右 return string.split(/\r\n?|\n/); 改為 return string.toString().split(/\r\n?|\n/); 或者可以不修改,但是傳入數據必須是string fsData.toString()
運行項目:
npm start
