这是我用Electron和React创建markdown应用程序的方式

倪棋
2023-12-01

by Tzahi Vidas

由Tzahi Vidas

这是我用Electron和React创建markdown应用程序的方式 (Here’s how I created a markdown app with Electron and React)

This article is a step-by-step tutorial on how to create a basic markdown application using Electron and React.

本文是有关如何使用ElectronReact创建基本Markdown应用程序的分步教程

I’ll describe why, how, and what I used to create the markdown app, which I call Mook.

我将描述创建Markdown应用程序的原因,方式和用途,我将其称为Mook

The source code for Mook can be found on GitHub.

Mook的源代码可以在GitHub找到

动机 (Motivation)

There are a couple of reasons I started this project.

我开始这个项目有两个原因。

Recently, I’ve been seeing more impressive and interesting things that you can do with JavaScript. I’ve also been wanting to do something with Electron for a while now.

最近,我发现您可以使用JavaScript做更多令人印象深刻且有趣的事情。 我也一直想和Electron做一些事情。

I had always felt weird coding with JavaScript, and, as such, avoided it. Every time I tried to do something with JavaScript, I always felt like I was just hammering on a keyboard to get whatever it was to work.

我一直觉得用JavaScript编码很奇怪,因此避免了使用它。 每次我尝试使用JavaScript进行操作时,我总是觉得自己只是在敲击键盘以获取一切正常工作。

However, I recently found myself looking more into JavaScript. It suddenly felt like a good tool to use to solve some of the problems I’ve been working on.

但是,最近我发现自己对JavaScript有了更多的了解。 突然感觉它像是用来解决我一直在研究的一些问题的好工具。

On another note (see the pun?), whenever I use a note-taking application, I always feel like there’s a feature missing that I can find in another app. But the other app will not have the features that the third app might provide. And so I’m always on the lookout for new and better note-taking apps.

在另一个便笺上(见双关语?),每当我使用一个记笔记应用程序时,我总是觉得我在另一个应用程序中找不到某个功能。 但是另一个应用程序将不具有第三个应用程序可能提供的功能。 因此,我一直在寻找新的更好的笔记应用程序。

With these thoughts in mind, I decided to learn JavaScript while building a markdown notes editor with Electron.

考虑到这些想法,我决定在用Electron构建降价笔记编辑器时学习JavaScript。

要求 (Requirements)

Some of the requirements I came up with for the markdown app are as listed.Note that there are many more, but the following are on my initial list.

我对markdown应用程序提出的一些要求如下所示。请注意,还有很多要求,但以下是我的初始清单。

  • Editor and preview panes

    编辑器和预览窗格
  • Split screen between the editor and preview panes that can be dynamically moved

    在编辑器和预览窗格之间拆分屏幕,可以动态移动
  • Support for code blocks and code language highlighting

    支持代码块和代码语言突出显示
  • Support for saving and syncing notes on GitHub

    支持在GitHub上保存和同步注释
  • A hierarchy of notebooks and markdown notes

    笔记本和减价笔记的层次结构
  • Support for LaTeX / math equations in the editor

    在编辑器中支持LaTeX /数学方程式
  • Ability to group different notebooks with a shared topic

    能够对具有共享主题的不同笔记本进行分组
  • Ability to share notebooks on GitHub and on Dropbox, Google Docs and others.

    能够在GitHub和Dropbox,Google Docs等上共享笔记本。

堆栈 (The stack)

I had to make a few decisions for this project. For example:

我必须为此项目做出一些决定。 例如:

Should I use a boilerplate?

我应该使用样板吗?

Should I use React, AngularJS, Riot, or Vue?

我应该使用React, AngularJSRiotVue吗?

What kind of packages would I use?

我将使用哪种包装?

And so on.

等等。

In the end, I decided to avoid the boilerplate approach (at least for now). I did this because I wanted to build the foundations of the app myself and learn more about it in the process.

最后,我决定避免使用样板方法(至少目前如此)。 我这样做是因为我想自己建立应用程序的基础,并在此过程中进一步了解它。

I tried to build the app with React because I’ve heard a lot about it from friends. It appears that this is what the cool kids are using these days.

我尝试使用React构建应用程序,因为我从朋友那里听到了很多关于它的信息。 看来这是这些天好孩子使用的。

为应用程序创建环境 (Creating the environment for the app)

Because we are using React, we’ll start by creating a basic React application and then add Electron to it.

因为我们使用的是React,所以我们先创建一个基本的React应用程序,然后将Electron添加到其中。

We’ll start our project using create-react-app.

我们将使用create-react-app开始我们的项目。

准备环境 (Preparing the environment)

An easy way to create React applications with a basic configuration is to use the create-react-app.

使用基本配置创建React应用程序的一种简单方法是使用create-react-app

First, make sure that you have the latest node and npm versions on your machine. To check, run the following commands:

首先,请确保您的计算机上具有最新的节点和npm版本。 要检查,请运行以下命令:

node -vnpm -vyarn — version

When I was writing this article, these were the versions on my machine:

当我写这篇文章时,这些​​是我机器上的版本:

node = v8.4.0npm = 5.3.0yarn = 1.0.1

使用create-react-app创建一个React应用 (Creat a React app with create-react-app)

To install create-react-app as a global package, type the following command:

要将create-react-app安装为全局软件包,请键入以下命令:

npm install -g create-react-app

To create a new React app and cd in it:

要创建一个新的React应用并在其中进行cd

create-react-app mookcd mook

This is what our project looks like now. I’ve excluded the node_modules folder from view so that you can get a clear view of the project.

这就是我们的项目现在的样子。 我从视图中排除了node_modules文件夹,以便您可以清晰地查看项目。

tree -I “node_modules”.├── README.md├── package.json├── public│ ├── favicon.ico│ ├── index.html│ └── manifest.json├── src│ ├── App.css│ ├── App.js│ ├── App.test.js│ ├── index.css│ ├── index.js│ ├── logo.svg│ └── registerServiceWorker.js└── yarn.lock
2 directories, 13 files

Now that we have a basic React app, to see what it looks like, let’s run the start script that’s defined in the package.json file:

现在我们有了一个基本的React应用程序,看看它是什么样子,让我们运行package.json文件中定义的start脚本:

yarn run start

That starts a new browser window with the following page:

这将打开一个带有以下页面的新浏览器窗口:

安装电子 (Install Electron)

Electron allows us to build an application that has the ability to run across platforms.

Electron允许我们构建一个能够跨平台运行的应用程序。

To install the Electron package:

要安装电子包:

yarn add electron — dev

Open the package.json file.

打开package.json文件。

If everything’s OK, you should be able to see the Electron package in the devDependencies section of the file.

如果一切正常,您应该可以在devDependencies看到Electron软件包。 文件部分。

Update the package.json file with the following changes:

通过以下更改更新package.json文件:

  • To add the following line to the scripts section:

    要将以下行添加到脚本部分:
“electron-start”: “electron .”
  • To add a top-level main property and point it to the main Electron file (this file doesn’t exist yet, but we will be creating it shortly):

    要添加顶级main属性并将其指向主要的Electron文件(此文件尚不存在,但是我们很快会创建它):

“main”: “public/main.js”

The package.json file now looks like this:

package.json文件现在如下所示:

{  “name”: “mook”,  “version”: “0.1.0”,  “main”: “public/main.js”,  “private”: true,  “dependencies”: {    “react”: “¹⁵.6.1”,    “react-dom”: “¹⁵.6.1”,    “react-scripts”: “1.0.13”  },  “scripts”: {    “start”: “react-scripts start”,    “build”: “react-scripts build”,    “test”: “react-scripts test — env=jsdom”,    “eject”: “react-scripts eject”,    “electron-start”: “electron .”  },  “devDependencies”: {    “electron”: “¹.7.6”  }}

Next, we’ll add some of Electron’s events to control the application’s life cycle. We will implement the following events:

接下来,我们将添加一些Electron事件来控制应用程序的生命周期。 我们将实施以下事件:

  • ready: Runs when Electron has finished initializing. In the code, this will run createWindow, which creates a browser window with React’s local URL, http://localhost:3000, and sets the about panel and the mainWindow to null on close.

    ready 在Electron完成初始化后运行。 在代码中,这将运行createWindow 它将使用React的本地URL http://localhost:3000创建一个浏览器窗口,并在close将about面板和mainWindownull

  • activate: Runs when the application is activated. We’ll want to call the createWindow function to create a new window.

    activate 在激活应用程序时运行。 我们将要调用createWindow函数来创建一个新窗口。

  • window-all-closed: Emitted when all windows have been closed. This will close the app on all platforms, except Mac, which will only close the window but will explicitly require the user to quit the program.

    window-all-closed 关闭所有窗口时触发。 这将在除Mac之外的所有平台上关闭该应用程序,Mac仅会关闭窗口,但明确要求用户退出该程序。

Add the following code to public/main.js:

将以下代码添加到public/main.js

const electron = require(‘electron’);const app = electron.app;const BrowserWindow = electron.BrowserWindow;
let mainWindow;
function createWindow() {  mainWindow = new BrowserWindow({width: 900, height: 680});  mainWindow.loadURL(‘http://localhost:3000');
app.setAboutPanelOptions({    applicationName: “Mook”,    applicationVersion: “0.0.1”,  })
mainWindow.on(‘closed’, () => mainWindow = null);}
app.on(‘ready’, createWindow);
app.on(‘window-all-closed’, () => {  if (process.platform !== ‘darwin’) {    app.quit();  }});
app.on(‘activate’, () => {  if (mainWindow === null) {    createWindow();  }});

Make sure that React is still running in the background. If not, run it again with the following command:

确保React仍在后台运行。 如果没有,请使用以下命令再次运行它:

yarn run start

Open a new command line window in the project’s folder and run the following command:

在项目的文件夹中打开一个新的命令行窗口,然后运行以下命令:

yarn run electron-start

After you run the command, the following window opens:

运行命令后,将打开以下窗口:

If React is not running in the background, the Electron app will open with a blank white window.

如果React没有在后台运行,则Electron应用程序将打开,并带有空白的白色窗口。

创建稳定的开发和构建过程 (Creating a stable development and build process)

Now that we have a working template for our project using Electron and React, we need to make sure that we have a stable build for development and distribution.

现在我们有了使用Electron和React的项目的工作模板,我们需要确保我们有稳定的开发和发行版本。

What we have created until now is great for development, but eventually we want to create the distribution versions of the app for OS X, Windows, and Linux.

到目前为止,我们创建的内容非常适合开发,但是最终我们希望为OS X,Windows和Linux创建该应用程序的发行版。

I also didn’t like that we have to separately run the React server and Electron app in two different command line shells.

我也不喜欢我们必须在两个不同的命令行外壳中分别运行React服务器和Electron应用程序。

After doing some research into the topic, I found the following post, “From React to an Electron app ready for production” by @thekitze, which helped me a lot.

在对该主题进行了一些研究之后,我发现了@thekitze撰写的以下帖子“ 从React到准备投入生产的Electron应用程序 ”,这对我有很大帮助。

We will need to add the following packages to our project:

我们将需要在我们的项目中添加以下软件包:

  • electron-builder — A complete solution to package and build a ready-for distribution Electron app for MacOS, Windows, and Linux with “auto update” support out of the box. We will use this package to build our app for distribution.

    electronic-builder —打包和构建适用于MacOS,Windows和Linux的即用型Electron应用程序的完整解决方案,开箱即用。 我们将使用该软件包来构建我们的应用程序以进行分发。

  • concurrently — Runs commands concurrently. We will use this package to run React and Electron concurrently in one command.

    并发 - 并发运行命令。 我们将使用此包在一个命令中同时运行React和Electron。

  • wait-on — Command line utility and Node.js API, which will wait for files, ports, sockets, and http(s) resources to become available. We will use this package to wait for the React server to begin running before starting the Electron app.

    wait-on —命令行实用程序和Node.js API,它将等待文件,端口,套接字和http(s)资源变为可用。 在启动Electron应用程序之前,我们将使用此软件包等待React服务器开始运行。

Run the following commands to add these packages to our app:

运行以下命令以将这些软件包添加到我们的应用中:

yarn add electron-builder wait-on concurrently — dev

Since these packages are only required for development, we will add the flag — dev to the yarn add command. This will also automatically add the packages to the devDependencies part of package.json.

由于这些软件包仅是开发所必需的,因此我们将标志— dev yarn addyarn add命令中。 这还将自动将软件包添加到package.jsondevDependencies部分。

创建一个开发脚本 (Create a dev script)

We want to create a development script to use while we’re building the app. This will help us test new features that we developed in the application and also to debug and make sure that we’re not breaking anything while we’re editing the code.

我们要创建一个开发脚本,以便在构建应用程序时使用。 这将有助于我们测试在应用程序中开发的新功能,并有助于调试并确保在编辑代码时不会破坏任何内容。

We’ll add a new script in the scripts section of our package.json file:

我们将在package.json文件的scripts部分中添加一个新脚本:

“electron-dev”: “concurrently \”BROWSER=none yarn start\” \”wait-on http://localhost:3000 && electron .\””

There are a lot of things happening in this line, so let’s break it down:

此行中发生了很多事情,所以让我们分解一下:

  1. concurrently” Runs the following commands at the same time.

    同时” 同时运行以下命令。

  2. BROWSER=none yarn start” — Starts the react application and sets “BROWSER=none”. This means that the browser will not automatically open the React application.

    BROWSER =无纱线启动” -启动React应用程序并设置为“ BROWSER = none” 。 这意味着浏览器将不会自动打开React应用程序。

  3. wait-on http://localhost:3000 && electron” — Waits for the development server to start. Once it’s up, it will start the Electron application.

    等待http:// localhost:3000 &&电子” —等待开发服务器启动。 一旦启动,它将启动Electron应用程序。

Now, if you run the following from your command line, you will only get a single Electron application window with the React logo.

现在,如果您从命令行运行以下命令,则只会获得一个带有React徽标的Electron应用程序窗口。

yarn run electron-dev

创建一个构建脚本 (Create a build script)

Creating the build script is a bit easier.

创建构建脚本要容易一些。

We need to add a couple of scripts to the scripts section in the package.json file:

我们需要在package.json文件的scripts部分中添加几个脚本:

  • Here is a script to build the React app before building the Electron app:

    这是在构建Electron应用之前构建React应用的脚本:
“preelectron-pack”: “yarn build”
  • Here is a script for packaging the Electron app. This script builds the application package with electron-builder.

    这是打包Electron应用程序的脚本。 该脚本使用electronic-builder构建应用程序包。

“electron-pack”: “build — em.main=build/electron.js”

Next, we will have to specify the build property. This is because of a minor conflict between create-react-app and electron-builder. Both are using the build folder for a different purpose.

接下来,我们将必须指定build属性。 这是由于create-react-appelectronic-builder之间的微小冲突。 两者都将build文件夹用于其他目的。

In order to solve this conflict, we need to manually configure electron-builder’s correct folders for the build step. Add the following build section to the package.json file:

为了解决此冲突,我们需要在构建步骤中手动配置electronic-builder的正确文件夹。 将以下build部分添加到package.json文件:

“build”: {  “appId”: “com.mook”,  “files”: [    “build/**/*”,    “node_modules/**/*”  ],  “directories”: {    “buildResources”: “assets”  }}

We also need to add the homepage property to allow the packaged Electron app to find the JavaScript and CSS files:

我们还需要添加homepage属性,以允许打包的Electron应用程序找到JavaScript和CSS文件:

“homepage”: “./”

At this point, your package.json file should look like this:

此时,您的package.json文件应如下所示:

{  “name”: “mook”,  “version”: “0.1.0”,  “main”: “public/main.js”,  “homepage”: “./”,  “private”: true,  “scripts”: {    “start”: “react-scripts start”,    “build”: “react-scripts build”,    “test”: “react-scripts test — env=jsdom”,    “eject”: “react-scripts eject”,    “electron-start”: “electron .”,    “electron-dev”: “concurrently \”BROWSER=none yarn start\” \”wait-on http://localhost:3000 && electron .\””,    “electron-pack”: “build — em.main=build/main.js”,    “preelectron-pack”: “yarn build”  },  “dependencies”: {    “react”: “¹⁵.6.1”,    “react-dom”: “¹⁵.6.1”,    “react-scripts”: “1.0.13”,    “electron-is-dev”: “⁰.3.0”  },  “devDependencies”: {    “concurrently”: “³.5.0”,    “electron”: “¹.7.6”,    “electron-builder”: “¹⁹.27.7”,    “wait-on”: “².0.2”  },  “build”: {    “appId”: “com.mook”,    “files”: [      “build/**/*”,      “node_modules/**/*”    ],    “directories”: {      “buildResources”: “assets”    }  }}

The last step will be to update public/main.js. Until now, we’ve only supported the development version of the app. In production we won’t be able to use localhost:3000, instead we will serve the index.html file from the build folder.

最后一步是更新public/main.js 到目前为止,我们仅支持该应用程序的开发版本。 在生产环境中,我们将不能使用localhost:3000 ,而是从build文件夹提供index.html文件。

First, we need to install electron-is-dev, which will help us determine if Electron is running in development.

首先,我们需要安装electronic-is-dev ,这将帮助我们确定Electron是否正在开发中。

To install the electron-is-dev package:

要安装electron-is-dev软件包:

yarn add electron-is-dev

To update public/main.js to use electron-is-dev:

要将public/main.js更新为使用electronic-is-dev:

  • To add the package to the code:

    要将包添加到代码中:
const isDev = require(‘electron-is-dev’);const path = require(‘path’);
  • To change the mainWindow.loadURL functionality in the createWindow function:

    要在createWindow函数中更改mainWindow.loadURL功能:

mainWindow.loadURL(isDev ? ‘http://localhost:3000' : `file://${path.join(__dirname, ‘../build/index.html’)}`);

This code checks if we are in development mode, and if we are, it will use localhost:3000. Otherwise it will serve/build/index.html.

这段代码检查我们是否处于开发模式,如果使用,它将使用localhost:3000 。 否则,它将投放/build/index.html

Your public/main.js file should now look like this:

您的public/main.js文件现在应如下所示:

const electron = require(‘electron’);const app = electron.app;const BrowserWindow = electron.BrowserWindow;const isDev = require(‘electron-is-dev’);const path = require(‘path’);
let mainWindow;
function createWindow() {  mainWindow = new BrowserWindow({width: 900, height: 680});  mainWindow.loadURL(isDev ? ‘http://localhost:3000' : `file://${path.join(__dirname, ‘../build/index.html’)}`);
app.setAboutPanelOptions({    applicationName: “Mook”,    applicationVersion: “0.0.1”,  })
mainWindow.on(‘closed’, () => mainWindow = null);}
app.on(‘ready’, createWindow);
app.on(‘window-all-closed’, () => {  if (process.platform !== ‘darwin’) {    app.quit();  }});
app.on(‘activate’, () => {  if (mainWindow === null) {    createWindow();  }});

Now, let’s try to run the build script with the following command:

现在,让我们尝试使用以下命令运行构建脚本:

yarn run electron-pack

When the script run is complete, you should see a new folder named dist in your project’s directory. You can find your packaged application in the folder named after your operating system. For example, Mac users will be able to find the packaged application mook.app in the dist/mac folder.

脚本运行完成后,您应该在项目目录中看到一个名为dist的新文件夹。 您可以在以操作系统命名的文件夹中找到打包的应用程序。 例如,Mac用户将能够在dist/mac文件夹中找到打包的应用程序mook.app

When you run that file, you should get the same screen you get for the debug version:

运行该文件时,应该获得与调试版本相同的屏幕:

Excellent, we’ve just finished the build infrastructure for our app.

太好了,我们刚刚完成了应用程序的构建基础结构。

添加主要功能 (Adding main functionalities)

Now we’re able to start adding building blocks to our markdown app.

现在,我们可以开始向markdown应用程序添加构建基块了。

创建一个拆分窗格屏幕 (Creating a split pane screen)

Let’s start by adding the split pane component, react-split-pane, to our application.

首先,将拆分窗格组件react-split-pane添加到我们的应用程序中。

To install the react-split-pane package:

要安装react-split-pane软件包:

yarn add react-split-pane

To add the following JavaScript code to the src/App.js file:

要将以下JavaScript代码添加到src/App.js文件中:

  • Import react-split-pane:

    导入react-split-pane

import SplitPane from ‘react-split-pane’;
  • Replace the render function with the following code. This code adds the SplitPane element to the render function with two divs, one for the editor and one for the preview pane:

    用以下代码替换render函数。 这段代码将SplitPane元素添加到具有两个div的render函数中,一个用于编辑器,一个用于预览窗格:

render() {  return (    <div className=”App”>      <SplitPane split=”vertical” defaultSize=”50%”>        <div className=”editor-pane”>        </div>        <div className=”view-pane”>        </div>      </SplitPane>    </div>  );}

We also need to add some CSS.

我们还需要添加一些CSS。

To add the following code to src/App.css:

要将以下代码添加到src/App.css

.Resizer { background: #000; opacity: .4; z-index: 1; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; -moz-background-clip: padding; -webkit-background-clip: padding; background-clip: padding-box;}
.Resizer:hover { -webkit-transition: all 2s ease; transition: all 2s ease;}
.Resizer.horizontal { height: 11px; margin: -5px 0; border-top: 5px solid rgba(255, 255, 255, 0); border-bottom: 5px solid rgba(255, 255, 255, 0); cursor: row-resize; width: 100%;}
.Resizer.horizontal:hover { border-top: 5px solid rgba(0, 0, 0, 0.5); border-bottom: 5px solid rgba(0, 0, 0, 0.5);}
.Resizer.vertical { width: 11px; margin: 0 -5px; border-left: 5px solid rgba(255, 255, 255, 0); border-right: 5px solid rgba(255, 255, 255, 0); cursor: col-resize;}
.Resizer.vertical:hover { border-left: 5px solid rgba(0, 0, 0, 0.5); border-right: 5px solid rgba(0, 0, 0, 0.5);}.Resizer.disabled { cursor: not-allowed;}.Resizer.disabled:hover { border-color: transparent;}

If you refresh the app or run it with the command yarn run electron-dev, you should see the following screen, which is currently just an empty page divided into two panes:

如果您刷新应用程序或使用命令yarn run electron-dev运行它, 您应该看到以下屏幕,当前该屏幕只是一个空白页面,分为两个窗格:

You can play around with the separator bar and see how it resizes the different panes.

您可以使用分隔栏,并查看其如何调整不同窗格的大小。

创建编辑器和预览窗格 (Creating the editor and preview panes)

Now that we have our split screen, we need to add functionalities for the editor and preview panes.

现在我们有了分屏,我们需要为编辑器和预览窗格添加功能。

We want to set up the panes like they are usually set up in markdown editors, with the editor pane on the left and the preview pane on the right. We will write our markdown in the editor pane, and the preview pane will update every time we change something in the editor pane.

我们希望像通常在markdown编辑器中设置的那样设置窗格,左侧的编辑器窗格和右侧的预览窗格。 我们将markdown写在编辑器窗格中,并且每次在编辑器窗格中进行更改时,预览窗格都会更新。

创建编辑器窗格 (Creating the editor pane)

Let’s start with the editor pane.

让我们从编辑器窗格开始。

We will use CodeMirror, which is a JavaScript text editor.

我们将使用CodeMirror ,它是一个JavaScript文本编辑器。

Install the React package for code mirror React-CodeMirror. Because “Code mirror value doesn’t update with state change" in React-CodeMirror, we will install @skidding/react-codemirror , which solves that issue:

为代码镜像React代码安装React软件包。 因为在React-CodeMirror中代码镜像值不会随着状态变化而更新 ”,所以我们将安装@skidding/react-codemirror ,它可以解决该问题:

yarn add @skidding/react-codemirror

Create a new file called src/editor.js, with a new class called Editor that extends React’s Component class:

使用一个名为Editor的新类创建一个名为src/editor.js的新文件,该类扩展了React的Component类:

import React, { Component } from ‘react’;
class Editor extends Component {}
export default Editor;

This class will basically wrap the react-codemirror package that is a React component for CodeMirror.

此类基本上将包装react-codemirror包,该包是CodeMirror的React组件。

Next, we will import @skidding/react-codemirror and some CSS files that we want to use for the CodeMirror component, syntax highlighting, and markdown mode.

接下来,我们将导入@skidding/react-codemirror以及一些我们想用于CodeMirror组件,语法突出显示和markdown模式CSS文件。

We will also add a render function that will return the CodeMirror element and add a constructor to the Editor class. This constructor allows us to initialize the CodeMirror with a value from the main file.

我们还将添加一个render函数,该函数将返回CodeMirror元素,并将constructor添加到Editor类。 该构造函数使我们可以使用主文件中的值初始化Code​​Mirror。

We’ll set the CodeMirror component to markdown mode and the theme to monokai:

我们将CodeMirror组件设置为markdown模式,将主题设置为monokai

import React, { Component } from ‘react’;import CodeMirror from ‘@skidding/react-codemirror’;
require(‘codemirror/lib/codemirror.css’);require(‘codemirror/mode/javascript/javascript’);require(‘codemirror/mode/python/python’);require(‘codemirror/mode/xml/xml’);require(‘codemirror/mode/markdown/markdown’);require(‘codemirror/theme/monokai.css’);
class Editor extends Component {  constructor(props) {    super(props);  }
render() {    var options = {      mode: ‘markdown’,      theme: ‘monokai’,    }    return (      <CodeMirror value={this.props.value}  options={options} height=”100%”/>    );  }}
export default Editor;

In the src/App.js file, we will import editor.js (add to the beginning of the file):

src/App.js文件中,我们将导入editor.js (添加到文件的开头):

import Editor from ‘./editor.js’;

In the App class, let’s add a constructor with an initial value for our editor:

App 类,我们为编辑器添加一个具有初始值的构造函数:

constructor(props) {  super();
this.state = {    markdownSrc: “# Hello World”,  }}

In the render function of the App class, add the Editor component and set the value to markdownSrc:

App类的render函数中,添加Editor组件并将其值设置为markdownSrc

render() {  return (    <div className=”App”>      <SplitPane split=”vertical” defaultSize=”50%”>        <div className=”editor-pane”>          <Editor className=”editor” value={this.state.markdownSrc}/>        </div>        <div className=”view-pane”>        </div>      </SplitPane>    </div>  );}

The src/App.js file should look like this:

src/App.js文件应如下所示:

import React, { Component } from ‘react’;import logo from ‘./logo.svg’;import SplitPane from ‘react-split-pane’;import Editor from ‘./editor.js’;
import ‘./App.css’;
class App extends Component {  constructor(props) {    super();
this.state = {      markdownSrc: “# Hello World”,    }  }
render() {    return (      <div className=”App”>        <SplitPane split=”vertical” defaultSize=”50%”>          <div className=”editor-pane”>            <Editor className=”editor” value={this.state.markdownSrc}/>          </div>          <div className=”view-pane”>          </div>        </SplitPane>      </div>    );  }}
export default App;

Update the CSS file src/App.css with the following changes:

通过以下更改更新CSS文件src/App.css

  1. In the .App section (at the top of the file), remove text-align: center; so that the text is not aligned to the center.

    . App . App部分(位于文件顶部),删除text-align: center ; 这样文本就不会与中心对齐。

  2. Add the following CSS code, so that it will stretch the editor to full height and add a little padding to the right side of the text:

    添加以下CSS代码,以便它将编辑器拉伸到最大高度,并在文本的右侧添加一些填充:
.editor-pane { height: 100%;}
.CodeMirror { height: 100%; padding-top: 20px; padding-left: 20px;}
.ReactCodeMirror { height: 100%;}

Refresh the app or run it with the command yarn run electron-dev, and you should see the following screen:

刷新应用程序或使用yarn run electron-dev命令运行它,您应该看到以下屏幕:

创建预览窗格 (Creating the preview pane)

We want the right pane to be a live preview of the editor that is on the left pane.

我们希望右窗格是左窗格中编辑器的实时预览。

In order to do that, we will use the React-Markdown package:

为此,我们将使用React-Markdown包:

yarn add react-markdown

In the src\App.js file, add the following import:

src\App.js文件中,添加以下导入:

import ReactMarkdown from ‘react-markdown’;

Add the ReactMarkdown component inside the view-pane div:

view-pane div中添加ReactMarkdown组件:

<div className=”view-pane”>  <ReactMarkdown className=”result” source={this.state.markdownSrc} /></div>

Set the source of the ReactMarkdown component so that it is the same as the one in the editor, this.state.markdownSrc.

设置ReactMarkdown组件的源代码,使其与编辑器this.state.markdownSrc的源代码相同。

You can now run the yarn application and see the preview pane:

现在,您可以运行yarn应用程序,并查看预览窗格:

yarn run electron-dev

We can see the text in the preview pane. However, if we type something in the editor (left) pane, it won’t transfer to the preview (right) pane.

我们可以在预览窗格中看到文本。 但是,如果我们在编辑器(左)窗格中键入内容,它将不会转移到预览(右)窗格。

What we’re going to do is make every change in the editor pass to the preview, through the App class.

我们要做的是通过App类将编辑器中的所有更改传递给预览。

Adding the onMarkdownChange function to src\App.js will update markdownSrc with updated text from the editor. This function will run on every change that happens in the editor.

onMarkdownChange函数添加到src\App.js将使用来自编辑器的更新文本来更新markdownSrc 。 此功能将在编辑器中发生的所有更改上运行。

Add the following code to src\App.js:

将以下代码添加到src\App.js

constructor(props) {  super();
this.state = {    markdownSrc: “# Hello World”  }
this.onMarkdownChange = this.onMarkdownChange.bind(this);}
onMarkdownChange(md) {  this.setState({    markdownSrc: md  });}

In the render function, add the following to the Editor element:

render功能中,将以下内容添加到Editor元素:

<Editor className=”editor” value={this.state.markdownSrc} onChange={this.onMarkdownChange}/>

In the src/editor.js file, bind the onChange function of CodeMirror to the onChange of the parent:

src/editor.js文件中,将CodeMirroronChange函数绑定到父对象的onChange

constructor(props) {  super(props);
this.updateCode = this.updateCode.bind(this);}
updateCode(e) {  this.props.onChange(e);}

In the render function, add the following to the CodeMirror element:

render函数中,将以下内容添加到CodeMirror元素:

<CodeMirror value={this.props.value} onChange={this.updateCode} options={options} height=”100%”/>

The src/App.js file should look like:

src/App.js文件应如下所示:

import React, { Component } from ‘react’;import logo from ‘./logo.svg’;import SplitPane from ‘react-split-pane’;import Editor from ‘./editor.js’;import ReactMarkdown from ‘react-markdown’;
import ‘./App.css’;
class App extends Component {  constructor(props) {    super();
this.state = {      markdownSrc: “# Hello World”    }
this.onMarkdownChange = this.onMarkdownChange.bind(this);  }
onMarkdownChange(md) {    this.setState({      markdownSrc: md    });  }
render() {    return (      <div className=”App”>        <SplitPane split=”vertical” defaultSize=”50%”>          <div className=”editor-pane”>            <Editor className=”editor” value={this.state.markdownSrc} onChange={this.onMarkdownChange}/>          </div>          <div className=”view-pane”>            <ReactMarkdown className=”result” source={this.state.markdownSrc} />          </div>        </SplitPane>      </div>    );  }}
export default App;

The src/editor.js file now looks like this:

src/editor.js文件现在看起来像这样:

import React, { Component } from ‘react’;import CodeMirror from ‘@skidding/react-codemirror’;
require(‘codemirror/lib/codemirror.css’);require(‘codemirror/mode/javascript/javascript’);require(‘codemirror/mode/python/python’);require(‘codemirror/mode/xml/xml’);require(‘codemirror/mode/markdown/markdown’);require(‘codemirror/theme/monokai.css’);
class Editor extends Component {  constructor(props) {    super(props);
this.updateCode = this.updateCode.bind(this);  }
updateCode(e) {    this.props.onChange(e);  }
render() {    var options = {      mode: ‘markdown’,      theme: ‘monokai’,    }    return (      <CodeMirror value={this.props.value} onChange={this.updateCode} options={options} height=”100%”/>    );  }}
export default Editor;

When you reload the application, you should be able to update the editor on the left with text and see the changes on the preview pane on the right.

重新加载应用程序时,您应该能够用文本更新左侧的编辑器,并在右侧的预览窗格中查看更改。

Full source code can be found on GitHub.

完整的源代码可以在GitHub找到

下一步是什么? (What’s next?)

There are still many things that we need to accomplish here:

我们仍然需要在这里完成很多事情:

  1. Save and open files

    保存并打开文件
  2. Autosave while editing

    编辑时自动保存
  3. Toolbar / control over the layout of the panes

    工具栏/控制窗格的布局
  4. Backup notes on GitHub, Dropbox and others.

    在GitHub,Dropbox等上的备份说明。
  5. Support saving notes in groups or unified in a “notebook”

    支持将笔记分组保存或统一保存在“笔记本”中
  6. Support math equations in Medium

    Medium中支持数学方程式

  7. More amazing features!

    更多惊人的功能!

I guess that’s what we’ll be doing next time…

我想这就是我们下一次要做的事情……

Follow me on Twitter for updates about progress, upcoming features, or for any other reason.

Twitter上关注我,以获取有关进度,即将发布的功能或任何其他原因的更新。

会费 (Contributions)

You can contribute in any way you want. Any help is appreciated.Don’t hesitate to share your suggestions or comments.

您可以按自己想要的任何方式做出贡献。 感谢您的帮助。不要犹豫,分享您的建议或意见。

Also, if you want to see a feature that you think is important, feel free to ask in the comments below or just open an issue on GitHub.

另外,如果您想查看自己认为重要的功能,请随时在下面的评论中提问,或者在GitHub上发布问题。

翻译自: https://www.freecodecamp.org/news/heres-how-i-created-a-markdown-app-with-electron-and-react-1e902f8601ca/

 类似资料: