利用Electron简单撸一个Markdown编辑器的方法(2)

<div> <div> <editor ref="aceeditor" v-model="input" @init="editorInit" lang="markdown" theme="twilight"></editor> <preview ref="previewor"></preview> </div> </div>

编辑区

左侧使用插件:require('vue2-ace-editor'),处理实时监听 Editor 输入 Markdown 内容,将内容传出去。

watch: { input: function(newContent, oldContent) { messageBus.newContentToRender(newContent); } },

其中这里的 messageBus 就是把 vue 和 ipcRenderer 相关逻辑事件放在一起的 main.js:

import Vue from 'vue'; import App from './App'; import 'buefy/dist/buefy.css'; import util from 'util'; import { ipcRenderer } from 'electron'; if (!process.env.IS_WEB) Vue.use(require('vue-electron')) Vue.config.productionTip = false export const messageBus = new Vue({ methods: { newContentToRender(newContent) { ipcRenderer.send('newContentToRender', newContent); }, saveCurrentFile() { } } }); // 监听 newContentToPreview,将 url2preview 传递给 vue 的newContentToPreview 事件 // 即,传给 Preview 组件获取 ipcRenderer.on('newContentToPreview', (event, url2preview) => { console.log(`ipcRenderer.on newContentToPreview ${util.inspect(event)} ${url2preview}`); messageBus.$emit('newContentToPreview', url2preview); }); /* eslint-disable no-new */ new Vue({ components: { App }, template: '<App/>' }).$mount('#app')

编辑器的内容,将实时由 ipcRenderer.send('newContentToRender', newContent); 下发出去,即由 Main 进程的 ipcMain.on('newContentToRender', function(event, content) 事件获取。

一个 Electron 应用只有一个 Main 主进程,很多和本地化东西 (如:本地存储,文件读写等) 更多的交由 Main 进程来处理。

如本案例中,想要实现的第一个功能就是,「可以自定义固定模块,如文章的头部,或者尾部」

我们使用一个插件:electron-store,用于存储头部和尾部内容,创建Class:

import { app } from 'electron' import path from 'path' import fs from 'fs' import EStore from 'electron-store' class Content { constructor() { this.estore = new EStore() this.estore.set('headercontent', `<img src="https://bimage.coding01.cn/logo.jpeg"> <section><span>本文 <span>111</span>字,需要 <span></span> 1分钟</span></section>`) this.estore.set('footercontent', `<hr> <strong>coding01 期待您继续关注</strong> <img src="https://bimage.coding01.cn/coding01_me.GIF" alt="qrcode">`) } // This will just return the property on the `data` object get(key, val) { return this.estore.get('windowBounds', val) } // ...and this will set it set(key, val) { this.estore.set(key, val) } getContent(content) { return this.headerContent + content + this.footerContent } getHeaderContent() { return this.estore.get('headercontent', '') } getFooterContent() { return this.estore.get('footercontent', '') } } // expose the class export default Content

注:这里只是写死的头部和尾部内容。

有了头尾部内容,和编辑器的 Markdown 内容,我们就可以将这些内容整合,然后输出给我们的右侧 Preview 组件了。

ipcMain.on('newContentToRender', function(event, content) { const rendered = renderContent(headerContent, footerContent, content, cssContent, 'layout1.html'); const previewURL = newContent(rendered); mainWindow.webContents.send('newContentToPreview', previewURL); });

其中,renderContent(headerContent, footerContent, content, cssContent, 'layout1.html') 方法就是将我们的头部、尾部、Markdown内容、css 样式和我们的模板 layout1.html 载入。这个就比较简单了,直接看代码:

import mdit from 'markdown-it'; import ejs from 'ejs'; const mditConfig = { html: true, // Enable html tags in source xhtmlOut: true, // Use 'https://www.jb51.net/' to close single tags (<br />) breaks: false, // Convert '\n' in paragraphs into <br> // langPrefix: 'language-', // CSS language prefix for fenced blocks linkify: true, // Autoconvert url-like texts to links typographer: false, // Enable smartypants and other sweet transforms // Highlighter function. Should return escaped html, // or '' if input not changed highlight: function (/*str, , lang*/) { return ''; } }; const md = mdit(mditConfig); const layouts = []; export function renderContent(headerContent, footerContent, content, cssContent, layoutFile) { const text = md.render(content); const layout = layouts[layoutFile]; const rendered = ejs.render(layout, { title: 'Page Title', content: text, cssContent: cssContent, headerContent: headerContent, footerContent: footerContent, }); return rendered; } layouts['layout1.html'] = ` <html> <head> <meta charset='utf-8'> <title><%= title %></title> <style> <%- cssContent %> </style> </head> <body> <div> <section> <%- headerContent %> </section> <div> <%- content %> </div> <section> <%- footerContent %> </section> </div> </body> </html> `;

这里,使用插件 markdown-it 来解析 Markdown 内容,然后使用ejs.render() 来填充模板的各个位置内容。这里,同时也为我们的目标:样式必须是可以自定义的 和封装各种不同情况下,使用不同的头部、尾部、模板、和样式提供了伏笔

当有了内容后,我们还需要把它放到「服务器」上,const previewURL = newContent(rendered);

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/20fa045bd3a8b0be260e6063021b091d.html