towxml 是什么?
微信小程序内置了一个组件可以让我们渲染富文本,也就是 <rich-text />
组件。但该组件能力较弱,并且主要是为了渲染由小程序端输入的富文本内容,面对复杂的富文本时,<rich-text />
组件可能无法完全还原富文本内容。
为了解决这个问题,我们可以使用开源的 sbfkcel/towxml 库。
Towxml 是一个可将HTML、Markdown转为微信小程序WXML(WeiXin Markup Language)的渲染库。用于解决在微信小程序中Markdown、HTML不能直接渲染的问题。
—— towxml 的 Github README
towxml 的构建
towxml 的使用非常简单,我们按照官方文档一步步走就可以了。
首先,我们需要先克隆项目源码,并安装依赖:
# 克隆项目到本地
git clone https://github.com/sbfkcel/towxml.git
# 进入项目并安装依赖
cd towxml
npm install / yarn
接着我们编辑项目根目录中的 config.js,根据注释,仅保留自己需要的功能。这里给出一份我的配置:
点我展开配置
module.exports = {
// LaTex公式、yuml解析服务架设参见 https://github.com/sbfkcel/markdown-server
// 数学公式解析API
latex: {
api: 'http://towxml.vvadd.com/?tex',
},
// yuml图解析APPI
yuml: {
api: 'http://towxml.vvadd.com/?yuml',
},
// markdown解析配置,保留需要的选项即可
markdown: [
'sub', // 下标支持
'sup', // 上标支持
'ins', // 文本删除线支持
'mark', // 文本高亮支持
'emoji', // emoji表情支持
// 'todo' // todo支持
],
// 代码高亮配置,保留需要的选项即可(尽量越少越好,不要随意调整顺序。部分高亮有顺序依赖)
highlight: [
// 'c-like',
// 'c',
// 'bash',
// 'css',
// 'dart',
// 'go',
// 'java',
// 'javascript',
// 'json',
// 'less',
// 'scss',
// 'shell',
// 'xml',
// 'htmlbars',
// 'nginx',
// 'php',
// 'python',
// 'python-repl',
// 'typescript',
// 'csharp',
// 'http',
// 'swift',
// 'yaml',
// 'markdown',
// 'powershell',
// 'ruby',
// 'makefile',
// 'lua',
// 'stylus',
// 'basic',
// '1c',
// 'abnf',
// 'accesslog',
// 'actionscript',
// 'ada',
// 'angelscript',
// 'apache',
// 'applescript',
// 'arcade',
// 'cpp',
// 'arduino',
// 'armasm',
// 'asciidoc',
// 'aspectj',
// 'autohotkey',
// 'autoit',
// 'avrasm',
// 'awk',
// 'axapta',
// 'bnf',
// 'brainfuck',
// 'cal',
// 'capnproto',
// 'ceylon',
// 'clean',
// 'clojure-repl',
// 'clojure',
// 'cmake',
// 'coffeescript',
// 'coq',
// 'cos',
// 'crmsh',
// 'crystal',
// 'csp',
// 'd',
// 'delphi',
// 'diff',
// 'django',
// 'dns',
// 'dockerfile',
// 'dos',
// 'dsconfig',
// 'dts',
// 'dust',
// 'ebnf',
// 'elixir',
// 'elm',
// 'erb',
// 'erlang-repl',
// 'erlang',
// 'excel',
// 'fix',
// 'flix',
// 'fortran',
// 'fsharp',
// 'gams',
// 'gauss',
// 'gcode',
// 'gherkin',
// 'glsl',
// 'gml',
// 'golo',
// 'gradle',
// 'groovy',
// 'haml',
// 'handlebars',
// 'haskell',
// 'haxe',
// 'hsp',
// 'hy',
// 'inform7',
// 'ini',
// 'irpf90',
// 'isbl',
// 'jboss-cli',
// 'julia-repl',
// 'julia',
// 'kotlin',
// 'lasso',
// 'latex',
// 'ldif',
// 'leaf',
// 'lisp',
// 'livecodeserver',
// 'livescript',
// 'llvm',
// 'lsl',
// 'mathematica',
// 'matlab',
// 'maxima',
// 'mel',
// 'mercury',
// 'mipsasm',
// 'mizar',
// 'mojolicious',
// 'monkey',
// 'moonscript',
// 'n1ql',
// 'nim',
// 'nix',
// 'nsis',
// 'objectivec',
// 'ocaml',
// 'openscad',
// 'oxygene',
// 'parser3',
// 'perl',
// 'pf',
// 'pgsql',
// 'php-template',
// 'plaintext',
// 'pony',
// 'processing',
// 'profile',
// 'prolog',
// 'properties',
// 'protobuf',
// 'puppet',
// 'purebasic',
// 'q',
// 'qml',
// 'r',
// 'reasonml',
// 'rib',
// 'roboconf',
// 'routeros',
// 'rsl',
// 'ruleslanguage',
// 'rust',
// 'sas',
// 'scala',
// 'scheme',
// 'scilab',
// 'smali',
// 'smalltalk',
// 'sml',
// 'sqf',
// 'sql',
// 'stan',
// 'stata',
// 'step21',
// 'subunit',
// 'taggerscript',
// 'tap',
// 'tcl',
// 'thrift',
// 'tp',
// 'twig',
// 'vala',
// 'vbnet',
// 'vbscript-html',
// 'vbscript',
// 'verilog',
// 'vhdl',
// 'vim',
// 'x86asm',
// 'xl',
// 'xquery',
// 'zephir'
],
// wxml原生标签,该系列标签将不会被转换
wxml: [
'view',
'video',
'text',
'image',
'navigator',
'swiper',
'swiper-item',
'block',
'form',
'input',
'textarea',
'button',
'checkbox-group',
'checkbox',
'radio-group',
'radio',
'rich-text',
// 可以解析的标签(html或markdown中会很少使用)
// 'canvas',
// 'map',
// 'slider',
// 'scroll-view',
// 'movable-area',
// 'movable-view',
// 'progress',
// 'label',
// 'switch',
// 'picker',
// 'picker-view',
// 'switch',
// 'contact-button'
],
// 自定义组件
components: [
'audio-player', // 音频组件,建议保留,由于小程序原生audio存在诸多问题,towxml解决了原生音频播放器的相关问题
// 'echarts', // echarts图表支持
// 'latex', // 数学公式支持
'table', // 表格支持
'todogroup', // todo支持
// 'yuml', // yuml图表支持
'img', // 图片解析组件
],
// 保留原本的元素属性(建议不要变动)
attrs: ['class', 'data', 'id', 'style'],
// 事件绑定方式(catch或bind),catch 会阻止事件向上冒泡。更多请参考:https://developers.weixin.qq.com/miniprogram/dev/framework/view/wxml/event.html
bindType: 'catch',
// 需要激活的事件
events: [
// 'touchstart',
// 'touchmove',
// 'touchcancel',
// 'touchend',
'tap', // 用于元素的点击事件
'change', // 用于todoList的change事件
],
// 图片倍数
dpr: 1,
// 代码块显示行号
showLineNumber: true,
};
进行构建:
npm run build / yarn build
执行完毕后,项目根目录就会多出构建好的 dist
文件夹了。
在小程序中使用
我们把上一节中构建好的 dist
目录复制到需要使用的小程序项目的根目录中,并重命名为 towxml
接下来我们就需要在项目中引入 towxml 包。
引入 towxml 组件
首先,我们需要在页面的 json 配置文件中引入 towxml 组件:
{
"usingComponents": {
"towxml": "/towxml/towxml"
}
}
在页面中插入组件
<view class="container">
<towxml nodes="{{article}}" />
</view>
引入并使用 towxml 解析方法
接下来我们需要引入 towxml 解析方法,这个方法负责解析富文本内容。
在 towxml 的官方文档 如何使用 这一节中,demo 代码需要在 app.js
中全局注册 towxml 解析方法:
// app.js
App({
// 引入`towxml3.0`解析方法
towxml:require('/towxml/index')
})
// page.js
const app = getApp();
onLoad() {
app.towxml(...);
}
如果你的小程序中处处充斥着富文本解析的需求,那么这样做当然是更简便的。但大部分小程序中的富文本解析只占一小部分,因此我们可以考虑在某个页面中单独引入 towxml 解析方法。
// page.js
import towxml from '../../vendor/towxml/index';
onLoad() {
towxml(...);
}
至于方法的使用和具体 API,请参考 官方文档中的 API 这一节。
onLoad() {
const result = app.towxml(`# Markdown`, "markdown", {
base: "https://xxx.com", // 相对资源的base路径
theme: "dark", // 主题,默认`light`
events: {
// 为元素绑定的事件方法
tap: (e) => {
console.log("tap", e);
},
},
});
// 更新解析数据
this.setData({
article: result,
isLoading: false,
});
}
注意取消 towxml 的格式化和代码检查
如果我们的小程序项目中使用了 Prettier 或者 ESLint,那么应当注意在 .prettierignore
和 .eslintignore
文件中添加对 towxml 目录的忽略。
更改 towxml 包在项目中的位置
在官方文档中,towxml 要求放置在小程序的根目录才能运行,如果我们放置到小程序的某个子目录中,比如 /vendor/towxml
,即使项目中的引用路径正确也会抛出异常。
好在我们可以通过修改 towxml/decode.json
中的文件路径解决这个问题。假如我们把 towxml 文件夹放在 /vendor/towxml
目录下,那么我们可以把文件内容修改为:
// towxml/decode.json
{
"component": true,
"usingComponents": {
"decode": "/vendor/towxml/decode",
"audio-player": "/vendor/towxml/audio-player/audio-player",
"table": "/vendor/towxml/table/table",
"todogroup": "/vendor/towxml/todogroup/todogroup",
"img": "/vendor/towxml/img/img"
}
}
重新编译小程序,就应该能够生效了。
在小程序分包中使用
towxml 虽然强大,但体积并不算小。笔者只打开了自己需要的功能,构建后的文件夹还是有 250KB。因此我们可以考虑把所有的富文本页面以及 towxml 拆成一个小程序分包。
新建分包
首先我们需要新建一个分包文件夹,比如 /subpackages/richTextRender
。
接着我们需要在 app.json
中注册这个分包:
{
"subpackages": [
{
"root": "subpackages/rickTextRender",
"pages": ["pages/articleDetail/articleDetail"]
}
],
}
把 towxml 移入分包中
移动 towxml 文件夹到 /subpackages/richTextRender/vendor/towxml
。
修改 decode.json
修改 /subpackages/richTextRender/vendor/towxml/decode.json
中的内容,保证文件路径和 towxml 所在的文件路径一致。
{
"component": true,
"usingComponents": {
"decode": "/subpackages/rickTextRender/vendor/towxml/decode",
"audio-player": "/subpackages/rickTextRender/vendor/towxml/audio-player/audio-player",
"table": "/subpackages/rickTextRender/vendor/towxml/table/table",
"todogroup": "/subpackages/rickTextRender/vendor/towxml/todogroup/todogroup",
"img": "/subpackages/rickTextRender/vendor/towxml/img/img"
}
}
在页面中使用 towxml
page.js:
// page.js
import towxml from '../../vendor/towxml/index';
onLoad() {
const result = towxml(...);
this.setData({ article: result })
}
page.json:
// page.json
{
"usingComponents": {
"towxml": "/subpackages/rickTextRender/vendor/towxml/towxml"
}
}
page.wxml:
<view class="container">
<towxml nodes="{{article}}" />
</view>