VUE 组件转换为微信小程序组件的方法(3)

//ExportDefault 到 Component构造器的转换 ExportDefaultDeclaration(path) { //创建 CallExpression Component({}) function insertBeforeFn(path) { const objectExpression = t.objectExpression(propertiesAST); test = t.expressionStatement( t.callExpression(//创建名为 Compontents 的调用表达式,参数为 objectExpression t.identifier("Compontents"),[ objectExpression ] ) ); //最终得到的语法树 console.log("test",test) } if (path.node.type === "ExportDefaultDeclaration") { if (path.node.declaration.properties) { //提取属性并存储 propertiesAST = path.node.declaration.properties; //创建 AST 包裹对象 insertBeforeFn(path); } //得到我们最终的转换结果 console.log(generate(test, {}, code).code);

对于 ExportDefault => Component 构造器转换还有一种转换思路 下面我们看一下:

[1] 第一种思路是先提取 ExportDefault 内部所有节点的 AST ,并做处理,然后创建Component构造器,插入提取处理后的 AST,得到最终的 AST

//propertiesAST 这个就是我们拿到的 AST,然后在对应的分支内做对应的处理 以下分别为 data,methods,props,其他的钩子同样处理即可 propertiesAST.map((item, index) => { if (item.type === "ObjectProperty") { //props 替换为 properties if (item.key.name === "props") { item.key.name = "properties"; } } else if (item.type === "ObjectMethod") { if (path.node.key.name === "mounted") { path.node.key.name = "ready"; } else if (path.node.key.name === "created") { path.node.key.name = "attached"; } else if (path.node.key.name === "destroyed") { path.node.key.name = "detached"; } else if (path.node.type === "ThisExpression") { if (path.parent.property.name === "$emit") { path.parent.property.name = "triggerEvent"; } } else { void null; } } } else if (path.node.key.name === "methods") { path.traverse({ enter(path) { if (path.node.type === "ThisExpression") { if (path.parent.property.name === "$emit") { path.parent.property.name = "triggerEvent"; } } } }) } else { //... console.log("node type", item.type); } });

[2] 第二种思路呢,就是我们上面展示的这种,不过有一个关键的地方要注意一下:

//我把 ExportDefaultDeclaration 的处理放到最后来执行,拿到 AST 首先进行转换。然后在创建得到新的小程序组件JS部分的 AST 即可 traverse(ast, { enter(path) {}, ObjectProperty(path) {}, ObjectMethod(path) {}, //...... ExportDefaultDeclaration(path) { //... } })

如果你想在 AST 开始处与结尾处插入,可使用 path 操作:

path.insertBefore( t.expressionStatement(t.stringLiteral("start..")) ); path.insertAfter( t.expressionStatement(t.stringLiteral("end..")) );

注:关于微信小程序不支持 computed , 与 watch,我们具体的初期采用的方案是挂载 computed 和 watch 方法到每一个微信小程序组件,让小程序组件也支持这两个功能。

六,VUE 组件转换为微信小程序组件中 的 Data 部分的处理:

关于 Data 部分的处理实际上就是:函数表达式转换为对象表达式 (FunctionExpression 转换为 ObjectExpression)

转换之前的 JavaScript 代码

export default { data(){//函数表达式 return { num: 10000, arr: [1, 2, 3], obj: { d1: "val1", d2: "val2" } } } }

处理后我们得到的

export default { data: {//对象表达式 num: 10000, arr: [1, 2, 3], obj: { d1: "val1", d2: "val2" } } };

通过如上的代码对比,我们看到了我们的转换前后代码的变化:

转换前后 AST 树对比图明确转换目标:

我们对 JavaScript 动了什么手脚(亦可封装成babel插件):

const ast = babylon.parse(code, { sourceType: "module", plugins: ["flow"] }); //AST 转换node、nodetype很关键 traverse(ast, { enter(path) { //打印出node.type console.log("enter: " + path.node.type); } })

我们的转换部分都尽量在一个 Traverse 中处理,减少 AST 树遍历的性能消耗

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/05a528f1ccbb158eb13b1a8e2c63ec99.html