打造一个优雅的微信文章编辑器

5,718 阅读8分钟

费时耗力的富文本编辑器

相信使用过微信公众平台中富文本编辑器的朋友们都有体会,用「撰文5分钟,排版两小时」来形容一点儿也不过分。 对于一些只做内容运营的朋友们来说,可能还好,无非是写完内容然后进行一下排版,上面的格式化功能也基本上够用了。 但对于我们进行技术内容沉淀的程序猿来说可能就并不那么友好了。即使微信公众平台上支持「文章模板」,但实际上还是得小心翼翼的去填充替换内容,有时候无意中修改了原本的样式还注意不到。

之前访问了下百度和404搜索引擎,总结一下大家提供的方法,无非是三种:

  1. 下载Chrome浏览器插件Markdown Here,在上面先自定义好自己想要的css样式,然后再微信富文本编辑器上用markdown语法写好文章内容,再一键转换,但你会发现,效果差强人意;
  2. 使用第三方平台的微信排版器,如下图:
    微信排版器
    非常蛋疼是,基本上是卡片式写作,每写一段就要拖动出来一个新的卡片容器,然后继续写作。放肆!如泉涌的文思居然要被此等操作打断,士可忍孰不可忍;
  3. 使用原生桌面Markdown编辑器应用,在其中进行沉浸式写作,然后编写好一个替换特定元素的脚本,根据自己想要的样式而定,最后粘贴到线上的CKEditor富文本编辑器上,微调样式,然后全选复制粘贴到微信富文本编辑器上,流程是顺溜了,可是不够「Lazy」,I refuse~

首先我们需要在文章里面放入我们的代码片段;其次我们还要求代码片段需要语法高亮显示;第三在我们不是复制粘贴源码的情况下,手写代码需要snippet来提高码字速度;第四,我们更专注于思想的传播或是业务代码的逻辑又或是构建工具的搭建步骤,样式版式对我们来说,真的是不那么重要好吗?!但是身为程序猿,连那么简单的样式都搞不定,岂不是太丢人了。Emmmm...那就祭出我们程序猿创新创造的动力——“懒惰”!是的,我认为技术飞冲腾跃的一个很重要原因就是「Laziness」。「懒人经济」,可见一斑。

我们,不想将就了。

革故鼎新的微信文章编辑器

朋友们可以直接使用本叔的「微信文章格式化工具」:md.ironmaxi.com

快照如下:

微信文章格式化工具
微信文章格式化工具

工程目录结构:

.
├── dist  //生产文件夹
└── src  //源代码文件夹
│   ├── css  //样式代码文件夹
│   │   ├── pageThemes  //页面样式文件夹
│   │   └── themes  //代码样式文件夹
│   ├── imgs  //图片文件夹
│   └── js  //脚本文件夹
│   │   ├── google-code-prettify  //各种语言代码美化插件文件夹
│   │   ├── showdown-plugins  //markdown解析器的插件文件夹
│   │   └── theme  //存放控制页面样式和代码样式选择的业务逻辑组件文件夹
│   ├── CNAME
│   ├── demo.md  
│   ├── favicon.ico
│   ├── index.html
├──package.json
├──LICENSE
├──README.md
├──webpack.config.js  //调试用
└──webpack.production.config.js  //生产打包用
10 directories

该工程使用了模块化打包工具webpack,调试和生产都对应好了命令,大家可以直接使用。

package.json:

{
  "scripts": {
    "server": "NODE_ENV=development && webpack-dev-server --host 0.0.0.0 --port 5014 --inline --hot --progress --config ./webpack.config.js",
    "build": "NODE_ENV=production && webpack --progress --profile --color --display-modules --display-chunks --config ./webpack.production.config.js"
  },
}

直接在终端上进行调试、生产:

# 调试 http://localhost:5004/dist 进行访问
$ npm run server
# 生产
$ npm run build

详细的代码可以到Github仓库上clone下来参考,接下来分析一下该工具的搭建流程和思路。

工具构想

该工具一共两个页面,一个编辑页面,能够让我们把在markdown编辑器上编写好的内容直接全选复制并粘贴至此;另外一个预览页面,在编辑页面中触发预览功能时,切换至预览页面。

功能清单:

  1. 编辑页面能够收集所有用户编写的markdown文本,并在预览时自动转换成html文本并渲染到浏览器页面上
  2. 预览页面上,用户能根据自己的喜好切换页面排版格式和代码高亮样式
  3. 预览页面能够全选复制内容,并粘贴到微信富文本编辑器上,内容和样式没有遗漏,也没有出入
  4. 预览页面能够返回到编辑页面

至此,重难点已经可以敲黑板了:

  1. Markdown语法文本转换成HTML文本
  2. 对HTML文本中的代码片段进行语法高亮显示
  3. 完整复制渲染结果

重新造轮子已经不需要了,针对以上两个问题的解决方案如下:( 部分404页面,请科学上网:) )

  1. Markdown To HTML Converter: showdownjs.com
  2. Google Code Prettify: google-code-prettify
  3. Clipboard written in Javascript: clipboardjs.com

我们所要做的,就是把轮子组合起来,做「上层应用」。

工程构建配置

webpack.config.js是用于调试使用的配置,webpack.config.production.js是用于最后工程生产打包用。 配置文件有点长,避免占用篇幅,大家直接看源码,很清晰。前者仅是多了一份webpack-dev-server的对应配置:

devServer: {
    hot: true,
    inline: true,
    historyApiFallback: false,
    disableHostCheck: true,
},

首页模板文件 index.html

构建页面文档结构,很简单。下面一段script代码是为了百度统计,不需要的朋友直接删掉即可,需要的朋友注册一个百度账号,然后再百度统计应用里去获取一份统计用的script代码,直接粘贴过来就行了。

<script>
var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?5450f754e48ed6303fe9c7c617346a78";
  var s = document.getElementsByTagName("script")[0];
  s.parentNode.insertBefore(hm, s);
})();
</script>

工程入口文件 src/js/index.js

入口文件首先加载首页样式文件index.less,在js里加载主要是为了能够利用less-loader做编译,直接编译成css代码,并以<style>方式注入到首页模板文件index.html中。

入口文件还加载了如下整个工程中最为重要的依赖,稍后会简单讲解一下这几个文件的作用:

  • showdown.js
  • clipboard.min.js
  • run_prettify.js
  • code-theme.js
  • page-theme.js

做完一些准备工作之后,实例化了一个markdown语法解析器和一个微信文章md转换器并进行初始化。

require('../css/index.less');

var $ = require("./jquery-3.1.1.js");
var showdown = require("./showdown.js");
var Clipboard = require("./clipboard.min.js");
var CodeTheme = require("./theme/code-theme");
var PageTheme = require("./theme/page-theme");

require("./showdown-plugins/showdown-prettify-for-wechat.js");
require("./showdown-plugins/showdown-github-task-list.js");
require("./showdown-plugins/showdown-footnote.js");

require("./google-code-prettify/run_prettify.js");

// 准备工作 这样才确保webpack打包的style在前 自定义样式在后 才能起效
$('head').eq(0).append($('<link rel="stylesheet" href="./themes/github-v2.css" id="codeThemeId" />'));
$('head').eq(0).append($('<link rel="stylesheet" id="pageThemeId" />'));
$('.li-qrcode').on('mouseover', function(){
  $('.qrcode-container').show();
}).on('mouseleave', function(){
  $('.qrcode-container').hide();
});
$('img').each(function(){
  var _this = this;
  var newImg = new Image();
  newImg.onload = function(){
    $(_this).show();
  };
  newImg.src = this.src;
});

// 解析浏览中url中的Path 去除无用的参数
var kv = location.href.split('?')[1];
kv = kv && kv.split('&') || [];
var params = {};
$.each(kv, function(index, item) {
  var m = (item || '').split('=');
  if (m && m[0] && m[1]) {
    params[m[0]]= m[1];
  }
});

// 方便跨域加载资源
if (/\.ironmaxi\.com$/.test(location.hostname)) {
  document.domain = 'ironmaxi.com';
}

// 实例化markdown语法解析对象
var converter =  new showdown.Converter({
  // 省略,看源码
});

// 实例化微信文章markdown转换器
var WechatMakdowner = {
  // 省略,看源码
};

// 微信文章转换器初始化
WechatMakdowner.init();

showdown.js

官方网站:showdownjs.com Github地址: Github | showdownjs传送门 官方对其介绍的标语是:

Modern copy to clipboard. No Flash. Just 3kb gzipped.

这是一款用js实现的能把Markdown文本转成HTML文本的库,是基于John Gruber的原作品。嗯对,John Gruber就是Markdown语法的创始人。 该库既可以在浏览器也能在服务器中运行渲染。

Step 1:安装npm包

$ npm install --save showdown

Step 2:加载依赖并使用

var showdown  = require('showdown'),
    converter = new showdown.Converter(),
    text      = '#hello, markdown!',
    html      = converter.makeHtml(text);

ps:本工程直接拷贝出主要文件来使用了,没有安装npm包

clipboard.min.js

官方网站:clipboardjs.com Github地址: Github | clipboardjs传送门 官方对其介绍的标语是:

A Markdown to HTML converter written in Javascript!

这是一款极度轻量的用js实现粘贴板功能的库,使用也是极度方便。

Step 1:安装npm包

$ npm install --save clipboard

Step 2:加载依赖并使用

var Clipboard = require("clipboard");
new Clipboard('.btn');

ps:本工程直接拷贝出主要文件来使用了,没有安装npm包

run_prettify.js

官方文章网站: Google Code Archive Github地址: Github | google-code-prettify传送门 官方对其介绍的标语是:

An embeddable script that makes source-code snippets in HTML prettier.

它可以支持很多种语言的语法高亮显示,即便有些不在支持列表中的,也可以通过扩展插件来支持。优点众多:

  1. 在HTML中工作
  2. 支持代码中内嵌链接和行号
  3. API简单实用
  4. 够轻量
  5. 可通过CSS来自定义样式
  6. 支持类C、类BASH、类XML风格的语言,无需显式声明语言种类
  7. 为其他语言提供了可扩展接口
  8. 跨浏览器支持

Step 1:引入js入口文件

<script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>

Step2:直接实用

<pre class="prettyprint">class Voila {
public:
  // Voila
  static const string VOILA = "Voila";
  // will not interfere with embedded <a href="#voila2">tags</a>.
}</pre>

另外,针对不同的语言类型既可以显式声明:

<pre class="prettyprint lang-html">
  The lang-* class specifies the language file extensions.
  File extensions supported by default include:
    "bsh", "c", "cc", "cpp", "cs", "csh", "cyc", "cv", "htm", "html", "java",
    "js", "m", "mxml", "perl", "pl", "pm", "py", "rb", "sh", "xhtml", "xml",
    "xsl".
</pre>

也可以自动检查:

// 推荐
PR.prettyPrint()

code-theme.js

在渲染文本结果的页面提供各种代码高亮样式的切换功能 在./src/themes/目录下,存放了各种代码高亮的样式文件,样式文件均从Github Repo下载下来的 Github | 代码高亮样式库

我在其基础上,新增了一种命名为'material-dark'的样式文件,根据Atom Material Syntax编辑器插件来定制的,也是个人最喜欢的语法高亮样式。

page-theme.js

在渲染文本结果的页面提供页面格式的切换功能 在./src/pageThemes/目录下,存放了3种页面排版格式的文件,有需要的可以自己定制,很简单。

关于如何选用Markdown编辑器

markdown是统一语法,在不同的平台上选用不同的编辑器纯属看个人爱好。以下写上我的推荐,适合不同人群。

如果你是一位内容运营从业者,那么选择一款支持「正经」markdown语法标记的编辑器:

  • Mac
    • 「Mou」
    • 「Macdown」
    • 「MWeb」
  • Windows
    • 「马克飞象」

如果你是一位程序猿,那么如下都可以,或者就用你正在使用的代码编辑器,或许装上一个Markdown语法高亮插件即可:

  • 「Atom」
  • 「VScode」
  • 「SublimeText3」

写在最后

愿我们都能够纷繁勿扰的写作,毕竟在这个社会上,总该有个地方,我们能平静而愉悦地待着。


微信公众号