React转微信小程序:双模板联动 您所在的位置:网站首页 react做小程序 React转微信小程序:双模板联动

React转微信小程序:双模板联动

2022-07-15 16:30| 来源: 网络整理| 查看: 265

这是本系列的最后一篇。小程序封死了操作DOM的可能性,并且也不让我们操作视图,所有与视图有关的东西一律接触不了。而它的自定义组件是非常恶心,基本不配叫组件,不能继承叫什么组件。因此我们使用它更早期的动态模板技术,template。

我的思路如下,通过编译组件的render方法,将里面的自定义组件变成template类,然后在template类中自己初始化,得到props, state再传给小程序的template标签。换言之,有两套模板。

//源码 import { Page } from "../wechat"; import "./page.css"; import Dog from "../components/dog/dog"; const e = "e"; class P extends Page { constructor(props) { super(props); this.state = { name: 'hehe', array: [ {name: "dog1",text: "text1"}, {name: "dog2",text: "text2"}, {name: "dog3",text: "text3"}, ] }; } onClick() { console.log("test click1" + e); } render() { return ( {this.state.array.map(function(el) { return {el.text}; })} ); } } export default P;

我们先不管Dog组件长得怎么样。

为了让它同时支持小程序与React的render函数,我们需要对render进行改造。将Dog,div等改造成小程序能能认识的类型,如

{this.state.array.map(function(el) { return {el.text}template>; })} view> view>

这个转译是如何实现呢,我们可以通一个插件 syntax-jsx, 它会在visitor遍历出JSX的开标签,闭标签,属性及{}容器。

但React无法认识template标签,因此还要改造

//React专用 {this.state.array.map(function(el) { return {el.text}; })}

现在看小程序这边

小程序无法认识{},需要改变成wx:for指令

//小程序专用 {el.text};

小程序的template有个缺憾,它无法认识name这样的属性的,因此我们需要一个东西装着它。那么我们动态创建一个数组吧,改一改React那边:

//React专用 {this.state.array.map(function(el) { return {el.text}; })}

templatedata这个属性及它的值是babel在编译时创建的,React.template到时会在this.data.state添加data123124342数组,内容为一个个对象,这些对象是通过Dog.props, Dog.defaultProps, Dog.state组成。结构大概是{ props: {}, state: {} }

那么小程序的模板则改成这样,去掉各种template不认识的东西,加上wx:for属性,它对应React方的templatedata值。然后template有一个data属性,通过对象解构,完美把所有属性(除方法)传到dog的模板中。

//小程序专用 ;

然后我们再把React的render方法改成React.createElement形式:

import { Page } from "../wechat"; import "./page.css"; import Dog from "../components/dog/dog"; const e = "e"; class P extends Page { constructor(props) { super(props); this.state = { name: 'hehe', array: [ {name: "dog1",text: "text1"}, {name: "dog2",text: "text2"}, {name: "dog3",text: "text3"}, ] }; } onClick() { console.log("test click1" + e); } render() { return ( React.createElement( "div", null, React.createElement( "div", null, this.state.array.map(function(el) { return React.createElement(React.template, { name: el.name, children: el.text, is: Dog, templatedata:"data34343433" }); }) ), React.createElement(React.template, { is: Dog, name: this.state.name, templatedata:"data34343433" }) ); } export default P;

上面的转译工作可以通过transform-react-jsx babel插件实现

class P extends Page这种es6定义类的方式,小程序可能也不认识,或者通过babel编译后也太复杂。比如说taro将Dog这个类变成这样:

有长有臭,因此我们最好在React中提供一个定义类的方法,叫miniCreateClass。如此一来我们就能将Dog转换得很简洁

var React = require("../../wechat"); var Component = React.Component var miniCreatClass = React.miniCreatClass function Dog() {} let Dog = miniCreatClass(Dog, Component, { render: function () { return React.createElement("view", null, this.state.name ) } }, {}); module.exports.default = Dog;

我们再看Page类。小程序定义页面是通过 Page 工厂实现的,大概是Page({data: {}})。小程序在这里的令计很方便我们进行hack,因为一个Page类只会有一个实例。

Page(createPage(P))

createPage的实现大既这样:

function createPage(PageClass) { var instance = ReactDOM.render(React.createElement(PageClass), { type: "div", root: true }); var config = { data: { state: instance.state, props: instance.props }, onLoad: function() { instance.$wxPage = this; }, onUnload: function() { instance.componentWillUnmount && instance.componentWillUnmount(); } }; instance.allTemplateData.forEach(function(el) { if (config.data[el.templatedata]) { config.data[el.templatedata].push(el); }else{ config.data[el.templatedata] = [el]; } }); return config; }

最后是React.template的实现,它负责组装给template的数据,这个template是小程序的标签。

React.template = function(props){ //这是一个无状态组件,负责劫持用户传导下来的类,修改它的原型 var clazz = props.is; var a = classzz.prototype; var componentWillMount = a.componentWillMount; a.componentWillMount = function(){ var ref = this._reactInternalRef; var arr = ref._owner.allTemplateData || (ref._owner.allTemplateData = []); arr.push({ props: this.props, state: this.state, templatedata: props.templatedata }) componentWillMount && componentWillMount.call(this) } var componentWillUpdate = a.componentWillUpdate; //...再上面一样 return React.createElement(clazz, props) }

好了,我的方案就介绍到这里了。如果有人愿意与我一开始搞这东西了,欢迎在github找我。

RubyLouvre/anu



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有