介绍
“转换” 意思是将"小程序"不支持的东西转换成它支持的东西。我在开发的小程序的过程中遇到了两种需要做“转换”的场景:
html 转换成 wxml
svg 转换成 canvas
我将在下文详细介绍我是怎么处理这两种情况的。
html 转换成 wxml
我们的产品在某些场景下,后端接口会直接传 html 字符串给前端。在 ReactJs 中,我们可以用 dangerouslySetInnerHTML 直接渲染 html 字符串(不一定安全),而 ”小程序“不支持 html ,因此必须对 html 进行处理。解决这个问题的步骤主要是:1. 将 html转换成 json ( 树结构) ;2. 将 json 转换成 wxml 。我在对问题做了调研后发现,现有一个库 wxParse 满足该转换的目的,但是在我看来,这个库做的事情太多,需要依赖文件过多,不满足只需要简单处理的需要,所以我决定自己写。
html 转换成 json
在参考了 html2json 与 himalaya 两个库的处理思路的基础上,我写了一个简单的解析库 htmlParser 。htmlParser 处理 html字符串分两步:
lexer: 生成标记(token)
function lex(html) {
let string = html
let tokens = []
while (string) {
// 先处理以 "" 开始的结束标签
if (string.indexOf("") === 0) {
const match = string.match(REGEXP.endTag)
if (!match) continue
// 通过 substring 截断这个标签的字符串长度
string = string.substring(match[0].length)
tokens.push({
tag: match[1],
type: 'tag-end',
})
continue
}
// 处理以 "
if (string.indexOf("
const match = string.match(REGEXP.startTag)
if (!match) continue
string = string.substring(match[0].length)
const tag = match[1]
const isEmpty = !!MAKER.empty[tag]
const type = isEmpty ? 'tag-empty' : 'tag-start'
const attributes = getAttributes(match[2])
tokens.push({
tag,
type,
attributes
})
continue
}
// 每个处理过程的其他部分字符串被当做 "text" 文本处理(暂时不处理其他情况)
const index = string.indexOf('
const text = index < 0 ? string : string.substring(0, index)
string = index < 0 ? "" : string.substring(index)
tokens.push({
type: "text",
text
})
}
return tokens
}
parser: 根据标记生成树
上面的 lexer 将 html 字符串分隔成了一个一个 token,然后,我们通过遍历所有的标识来构建树
function parse(tokens) {
let root = {
tag: "root",
children: []
}
let tagArray = [root]
tagArray.last = () => tagArray[tagArray.length - 1]
for (var i = 0; i < tokens.length; i++) {
const token = tokens[i]
if (token.type === 'tag-start') {
// 构建节点