Electron簡易編輯器實現:打開保存文件,自定義菜單,代碼高亮提示等功能

ipcmain.jsjavascript

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.jscss

var {ipcRenderer,remote}=require('electron');
var fs=require('fs');

document.title='無標題'

//獲取文本框dom

var textAreaDom=document.querySelector("#textArea");

/*

問題:
    一、新建 打開 保存的問題

    二、若是已經保存 第二次保存的時候不提示直接保存

    三、判斷文件是否已經保存  改變軟件左上角的內容

*/

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.htmlhtml

<!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.jsjava

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.

備註:node

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()

運行項目:git

npm start
相關文章
相關標籤/搜索