博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
React转微信小程序:双模板机制,React.template为小程序提供data
阅读量:5739 次
发布时间:2019-06-18

本文共 4899 字,大约阅读时间需要 16 分钟。

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

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

//源码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
; })}

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

clipboard.png

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

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

现在看小程序这边

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

//小程序专用 
;

小程序的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: {} }

那么小程序的模板变成

//小程序专用
;

而我们的render再经过编译变成()

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-jsxbabel插件实现

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

clipboard.png

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

var React = require("../../wechat");var Component = React.Componentvar miniCreatClass = React.miniCreatClassfunction 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找我。

转载地址:http://eafzx.baihongyu.com/

你可能感兴趣的文章
C++入门读物推荐
查看>>
TiDB 源码阅读系列文章(七)基于规则的优化
查看>>
面试中会遇到的正则题
查看>>
Spring之旅第八站:Spring MVC Spittr舞台的搭建、基本的控制器、请求的输入、表单验证、测试(重点)...
查看>>
数据结构与算法——常用排序算法及其Java实现
查看>>
你所不知的Webpack-多种配置方法
查看>>
React.js 集成 Kotlin Spring Boot 开发 Web 应用实例详解
查看>>
webpack+typescript+threejs+vscode开发
查看>>
python读excel写入mysql小工具
查看>>
如何学习区块链
查看>>
搜索问题的办法
查看>>
微信分销系统商城营销5大重点
查看>>
求职准备 - 收藏集 - 掘金
查看>>
htm5新特性(转)
查看>>
Linux-Centos启动流程
查看>>
php 设计模式
查看>>
后端技术精选 - 收藏集 - 掘金
查看>>
Laravel 服务容器
查看>>
mac安装kubernetes并运行echoserver
查看>>
多页架构的前后端分离方案(webpack+express)
查看>>