背景
之前做了个项目类似于“水印相机“,需求是在调用相机时增加水印模板,水印有不同的样式和类型,拍照后也在照片上打上相同的水印,可以参考下图:
老板的需求是在微信小程序上实现,本想直接用canvas搞定,mvp情况下不考虑复用情况前端写死几个模板,需要迭代的时候,copy一下改改参数重新上线就是了
可惜强烈要求做到后台配置化(预览/编辑/新建/删除/…),且不需要研发人员进入就可以完成日常迭代,那就只好考虑换一套方案了
需求关键点
- 设计直接输出程序可用的模板数据
- 后台配置模板上线
- 小程序内可使用(获取数据)
方案描述
- 恰好之前有跑过imgcook(什么是imgcook?)的demo,可以通过sketch直接导出wxml到imgcook,让非技术同学也可以通过可视化导出程序可用的数据
- 拿到wxml之后在后台管理界面拉一个页面出来作后台配置,确认后模板字符串到数据库
- 小程序端解析编辑后的模板字符串(wxml),将其转换为canvas代码实现动态展示,需要魔改下wxml-to-canvas插件
这套方案基本上满足了配置化的要求,可以让运营/设计同学直接发布模板而不需要占用研发资源,实现成本相对来说比较低,且都可作为插件形式,不影响原先逻辑
编写模板
设计稿转imgcook可用文件
设计常用的一些软件(ps/sketch/figma/….),其实本身是有自身的scheme形式,通过scheme可以导出自己需要的数据形态,像imgcook就做了一个sketch的插件
通过插件可以直接导出imgcook可编辑的数据形态,当然为了效果更好设计需要遵循它的一些规范(后续为了方便就直接用imgcook原生的编辑器进行演示)
由静态文件转动态模板
因为设计给出的图是一个静态图,但我们需要的是一个文本可替换,甚至有一些交互逻辑的动态模板,所以需要按照一定的规范进行二次编辑
文本替换
模板的用户昵称,及相关属性需要根据后台返回动态生成,可以通过imgcook的编辑器能力将其替换为表达式
if判断
并不是模板的所有项都必须显示,比如”天气“可能是个可选项,不需要展示的时候可以同样通过imgcook的编辑器能力将其替换为表达式即可,当然变量命名为了后续解析方便可以约定一些格式标识是属于if类型
我这里的话会在后面加一个驼峰的Visible,标识该文本需要控制是否显示
扩展
获取wxml
编辑完成后点击导出即可获得可用的文本,我这边直接因为是给小程序用直接导出的wxml,至此imgcook的任务就结束了
录入数据库
这里附上一个简单录入模板界面,大致流程: 上方input将导出的模板字符串复制进来后,自动识别出”{{}}“表达式和”wx:if“关键字,并在水印字段编辑中进行展示(字段编辑和模板字符串为双向绑定)
进行再次调整,并输入一些默认值之后即可选择保存录入数据库
至于预览,可以直接用html-to-canvas转一道就好了
模板展示
此时已经可以从接口拿到模板字符串,但要注意这只是一堆字符串,并非结构化数据,要进行渲染的话需要将模板内的占位符全部替换为有效数据
解析模板字符串
可以直接用正则匹配的方式进行解析,不过从0手撸一个实在是太耗时了,直接使用htmlParser将节点转为json,获取关键字和占位符,替换为服务端 + 客户端本地(经纬度/陀螺仪/…)数据
因为后续canvas渲染需要用wxml和style,这里需要将所有元素的内联css抽出组成一个单独json,最后再将json再转回wxml
traversalHtml(html, data) {
// 解决转义问题
html = html.replace(/[\b\f\r\t\\]/g, '');
// 返回结果
return new Html2Canvas(html, data).traversalHtml();
}
canvas渲染
web端有html-to-canvas,小程序端也有wxml-to-canvas,将上面转换后的wxml模板和style json对象丢进去即可正常渲染
drawTemplate(templateParams) {
this.widget = this.selectComponent('.widget');
const p1 = this.widget
.renderToCanvas({
wxml: templateParams.wxml,
style: templateParams.style,
})
.then(res => {
// 绘制完成
this.drawOver(res);
});
}
总结
本文主要是记录一次之前的思路,很多东西没写很细,如果有这方面需求可以详细看下文中用到的几个技术栈和js库
本身没什么难度,主要是模板的抽取和转换比较麻烦
可以展望下,如果用canvas直接写一些简单的页面页面的话,是不是可以也可以实现小程序的热更新?