资讯专栏INFORMATION COLUMN

我在开发"小程序"中做的一些"转换"的工作

pepperwang / 1514人阅读

摘要:介绍转换意思是将小程序不支持的东西转换成它支持的东西。我在开发的小程序的过程中遇到了两种需要做转换的场景转换成转换成我将在下文详细介绍我是怎么处理这两种情况的。总结以上,就是我在开发小程序中对与做的一些转换的经历。

介绍

“转换” 意思是将"小程序"不支持的东西转换成它支持的东西。我在开发的小程序的过程中遇到了两种需要做“转换”的场景:

html 转换成 wxml

svg 转换成 canvas

我将在下文详细介绍我是怎么处理这两种情况的。

html 转换成 wxml

我们的产品在某些场景下,后端接口会直接传 html 字符串给前端。在 ReactJs 中,我们可以用 dangerouslySetInnerHTML 直接渲染 html 字符串(不一定安全),而 ”小程序“不支持 html ,因此必须对 html 进行处理。解决这个问题的步骤主要是:1. 将 html 转换成 json ( 树结构) ;2. 将 json 转换成 wxml 。我在对问题做了调研后发现,现有一个库 wxParse 满足该转换的目的,但是在我看来,这个库做的事情太多,需要依赖文件过多,不满足只需要简单处理的需要,所以我决定自己写。

html 转换成 json

在参考了 html2jsonhimalaya 两个库的处理思路的基础上,我写了一个简单的解析库 htmlParser htmlParser 处理 html字符串分两步:

lexer: 生成标记(token

function lex(html) {
  let string = html
  let tokens = []

  while (string) {
    // 先处理以 "

parser: 根据标记生成树
上面的 lexerhtml 字符串分隔成了一个一个 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") {
      // 构建节点
      const node = {
        type: "Element",
        tagName: token.tag,
        attributes: Object.assign({}, {
          class: token.tag
        }, token.attributes),
        children: []
      }
      tagArray.push(node)
      continue
    }
    if (token.type === "tag-end") {
      let parent = tagArray[tagArray.length - 2]
      let node = tagArray.pop()
      // 将该节点加入父节点中
      parent.children.push(node) 
      continue
    }
    if (token.type === "text") {
      // 往该节点中加入子元素
      tagArray.last().children.push({
        type: "text",
        content: replaceMark(token.text)
      })
      continue
    }
    if (token.type === "tag-empty") { 
     // 往该节点中加入子元素
      tagArray.last().children.push({
        type: "Element",
        tagName: token.tag,
        attributes: Object.assign({}, {
          class: token.tag
        }, token.attributes),
      })
      continue
    }
  }
  return root
}

整个程序的运行结果举例:

var html = "
" htmlParser(html) # 转换结果 { "tag": "root", "children": [{ "type": "Element", "tagName": "div", "attributes": { "style": "height:10rpx;width: 20rpx;" }, "children": [ { "type": "Element", "tagName": "img", "attributes": { src: "http://xxx.jpg", class: "image" } }] }] }

以上,我们完成了 html字符串的转换,完整代码请戳 htmlParser

json 转换成 wxml

在熟悉了“小程序”框架的基础上,发现需要借助模板 template ,将 json 数据填充进 template,并根据元素类型渲染相应的 wxml 组件以达到转换目的。比如:

# 定义一个名称为 html-image 的模板

/* 使用模板
   其中 json 的结构为: {
      "type": "Element",
      "tagName": "img",
      "attributes": {
          src: "http://xxx.jpg",
          class: "image"
      }
    }
 */

这样,我们就能转化成功了。

而因为模板没有引用自身的能力,只能使用笨办法使用多个同样内容,但是模板名称不一样的模板来解决嵌套的层级关系,而嵌套的层级取决于使用的模板个数