Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to transfer React to WeChat Mini Programs

2025-04-11 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

本篇内容主要讲解"React怎么转微信小程序",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"React怎么转微信小程序"吧!

微信小程序是面向配置对象编程,不暴露Page,App,Component等核心对象的原型,只提供三个工厂方法,因此无法实现继承。App,Page,Component所在的JS的依赖处理也很弱智,你需要声明在同一目录下的json文件中。

比如说

Component({

properties: {},

data: {},

onClick: function(){}

})

properties与data都是同一个东西,properties只是用来定义data中的数据的默认值与类型,相当于React的defaultProps与propTypes。如何转换呢?

import {Component} form "./wechat"

Class AAA extends Component{

constructor(props){

super(props);

this.state = {}

}

static propTypes = {}

static defaultProps = {}

onClick(){}

render(){}

}

export AAA;

首先我们要提供一个wechat.js文件,里面提供Component, Page, App 这几个基类,现在只是空实现,但已经足够了,保证它在调试不会出错。我们要的是`Class AAA extends Component`这个语句的内容。学了babel,对JS语法更加熟悉了。这个语句在babel6中称为ClassExpression,到babel7中又叫ClassDeclaration。babel有一个叫"babel-traverse"的包,可以将我们的代码的AST,然后根据语法的成分进行转换(详见这文章 https://yq.aliyun.com/articles/62671)。ClassDeclaration的参数为一个叫path的对象,我们通过 path.node.superClass.name 就能拿到Component这个字样。如果我们的类定义是下面的这样,path.node.superClass.name 则为App。

Class AAA extends App{

constructor(props){

super(props);

this.state = {}

}

}

App, Page, Component对应的json差异很大,拿到这个可以方便我们区别对待。

然后我们继续定义一个ImportDeclaration处理器,将import语句去掉。

定义ExportDefaultDeclaration与ExportNamedDeclaration处理器,将export语句去掉。

到这里我不得不展示一下我的转码器的全貌了。我是通过rollup得到所有模块的路径与文件内容,然后通过babel进行转译。babel转换是通过babel.transform。babel本来就有许多叫babel-plugin-transform-xxx的插件,它是专门处理那些es5无法识别的新语法。我们需要在这后面加上一个新插件叫miniappPlugin

// https://github.com/RubyLouvre/anu/blob/master/packages/render/miniapp/translator/transform.js

const syntaxClassProperties = require("babel-plugin-syntax-class-properties")

const babel = require('babel-core')

const visitor = require("./visitor");

var result = babel.transform(code, {

babelrc: false,

plugins: [

'syntax-jsx',

// "transform-react-jsx",

'transform-decorators-legacy',

'transform-object-rest-spread',

miniappPlugin,

]

})

function miniappPlugin(api) {

return {

inherits: syntaxClassProperties,

visitor: visitor

};

}

miniappPlugin的结构异常简单,它继承一个叫syntaxClassProperties的插件,这插件原来用来解析es6 class的属性的,因为我们的目标也是抽取React类中的defaultProps, propsTypes静态属性。

visitor的结构很简单,就是各种JS语法的描述。

const t = require("babel-types");

module.exports = {

ClassDeclaration: 抽取父类的名字与转换构造器,

ClassExpression: 抽取父类的名字与转换构造器,

ImportDeclaration(path) {

path.remove() //移除import语句,小程序会自动在外面包一层,变成AMD模块

},

ExportDefaultDeclaration(path){

path.remove() //AMD不认识export语句,要删掉,或转换成module.exports

},

ExportNamedDeclaration(path){

path.remove() //AMD不认识export语句,要删掉,或转换成module.exports

}

}

我再介绍一下visitor的处理器是怎么用的,处理器其实会执行两次。我们的AST树每个节点会被执行两次,如果学过DFS的同学会明白,第一次访问后,做些处理,然后进行它内部的节点,处理后再访问一次。于是visitor也可以这样定义。

ClassDeclaration:{

enter(path){},

exit(path){}

}

如果以函数形式定义,那么它只是作为enter来用。

AST会从上到下执行,我们先拿到类名的名字与父类的名字,我们定义一个modules的对象,保存信息。

enter(path) {

let className = path.node.superClass ? path.node.superClass.name : "";

let match = className.match(/\.?(App|Page|Component)/);

if (match) {

//获取类的组件类型与名字

var componentType = match[1];

if (componentType === "Component") {

modules.componentName = path.node.id.name;

}

modules.componentType = componentType;

}

},

我们在第二次访问这个类定义时,要将类定义转换为函数调用。即

Class AAA extends Component ---> Component({})

实现如下,将原来的类删掉(因此才在exit时执行),然后新建一个函数调用语句。我们可以通过babel-types这个句实现。具体看这里。比如说:

const call = t.expressionStatement(

t.call_Expression(t.identifier("Component"), [ t.object_Expression([])])

);

path.replaceWith(call);

就能产生如下代码,将我们的类定义从原位置替换掉。

Component({})

但我们不能是一个空对象啊,因此我们需要收集它的方法。

我们需要在visitors对象添加一个ClassMethod处理器,收集原来类的方法。类的方法与对象的方法不一样,对象的方法叫成员表达式,需要转换一下。我们首先弄一个数组,用来放东西。

var methods = []

module.exports= {

ClassMethod: {

enter(path){

var methodName = path.node.key.name

var method = t.ObjectProperty(

t.identifier(methodName),

t.function_Expression(

null,

path.node.params,

path.node.body,

path.node.generator,

path.node.async

)

);

methods.push(method)

}

}

然后我们在ClassDeclaration或ClassExpression的处理器的exit方法中改成:

const call = t.expressionStatement(

t.call_Expression(t.identifier("Component"), [ t.object_Expression(methods)])

);

path.replaceWith(call);

于是函数定义就变成

Component({

constructor:function(){},

render:function(){},

onClick: function(){}

})

到这里,我们开始另一个问题了。小程序虽然是抄React,但又想别出心裁,于是一些属性与方法是不一样的。比如说data对应state, setData对应setState,早期的版本还有forceUpdate之类的。data对应一个对象,你可以有千奇百怪的写法。

this.state ={ a: 1}

this["state"] = {b: 1};

this.state = {}

this.state.aa = 1

你想hold住这么多奇怪的写法是很困难的,因此我们可以对constructor方法做些处理,然后其他方法做些约束,来减少转换的成本。什么处理constructor呢,我们可以定义一个onInit方法,专门劫持constructor方法,将this.state变成this.data。

function onInit(config){

if(config.hasOwnProperty("constructor")){

config.constructor.call(config);

}

config.data = config.state|| {};

delete config.state

return config;

}

Component(onInit({

constructor:function(){},

render:function(){},

onClick: function(){}

}))

具体实现参这里,本文就不贴上来了。

RubyLouvre/anu

那this.setState怎么转换成this.setData呢。这是一个函数调用,语法上称之为**CallExpression**。我们在visitors上定义同名的处理器。

Call_Expression(path) {

var callee = path.node.callee || Object;

if ( modules.componentType === "Component" ) {

var property = callee.property;

if (property && property.name === "setState") {

property.name = "setData";

}

}

},

至少,将React类定义转换成Component({})调用方式 成功了。剩下就是将import语句处理一下,因为要小程序中,如果这个组件引用了其他组件,需要在其json中添加useComponens对象,将这些组件名及链接写上去。换言之,小程序太懒了,处处都要手动。有了React转码器,这些事可以省掉。

其次是render方法的转换,怎么变成一个wxml文件呢,`{}单花括号的内容要转换成`"{{}}"`双引号+双花括号 ,wx:if, wx:for的模拟等等,且听下回分解。

到此,相信大家对"React怎么转微信小程序"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report