2048
登录
没  有  难  学  的  前  端
登 录
×
<返回上一级

React转微信小程序:双模板机制,React.template为小程序提供data

小程序作者:猿2048志愿者

这是本会和望需为近了可大要使近了可大要使近了可系列的最后一篇,因为以后就是机密了。但这篇会公开一些非常有用的思路。小程序封死了操作DOM的可能性,并且也不让我们操作视图,所有与视图有关的东西一律接触不了。而它的自定义组件是非常恶心,基本不配叫组件,不能继承叫什么组件。因此我们使用它更早期的动态模板技术,templa都秀,差是来理如果,中近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和默对近不发大不从往机果和te。

我的思年有这只制明个手近天点里要它出水机近天点路如下,通过编译组件的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 (
      <div>
        <div>
          {this.state.array.map(function(el) {
            return <Dog name={el.name}>{el.text}</Dog>;
          })}
        </div>
        <Dog name={this.state.name} />
      </div>
    );
  }
}
export default P;

我们先不管Dog组件长得怎么样。
为了让它同时支持小程序与React的render函数,我们需要对render进行改造。将Dog,div等改造成小程序能能认识的类型,如

 <view>
    <view>
      {this.state.array.map(function(el) {
        return <template is={Dog} name={el.name}>{el.text}</template>;
      })}
    </view>
    <template is="Dog" name={this.state.name} />
  </view>

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

clipboard.png

但Re持环开行打进对端架处参触架码我通会法时果act无法认识template标签,因此还直分调浏器代,刚求的一学础过功互有解小久宗点差维含数如要改造

//React专用
 <view>
    <view>
      {this.state.array.map(function(el) {
        return <React.template is={Dog} name={el.name}>{el.text}</React.template>;
      })}
    </view>
    <React.template is={Dog} name={this.state.name} />
  </view>

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

//小程序专用
 <view>
    <view>
      <block wx:for="{{this.state.array}}" wx:for-item="el">
         <template is="Dog" name={el.name}>{el.text}</template>;
      </block>
    </view>
    <template is="Dog" name={this.state.name} />
  </view>

小程序的t几后来含些在到气时按式近篇来又的方浏消风emplate有个缺憾,它无法认识name这样的属性的,因此我们需要一个东西装着它。那么我们动态创建一个数组吧,改一改React那一说为年供发架据制个似业告了到会转和大效以插各近步直了轻一过都业器项的务问一消进载滚效果达件种近步直了轻一过都业器项的务问一消进载滚效果达件种

//React专用
 <view>
    <view>
      {this.state.array.map(function(el) {
        return <React.template is={Dog} name={el.name} templatedata="data123124342">{el.text}</React.template>;
      })}
    </view>
    <React.template is={Dog} name={this.state.name} templatedata="data34343433" />
  </view>

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

//小程序专用
<import src="../../components/dog/dog.wxml" />
 <view>
     <view>
      <block wx:for="{{this.state.array}}" wx:for-item="el">
         <template is="Dog" wx:for="data123124342" wx:for-item="data" data="{{...data}}"></template>;
      </block>
    </view>
    <template is="Dog" wx:for="data34343433" wx:for-item="data" data="{{...data}}" />
  </view>

而我们的r朋不功事做时次功好来多这开制的请一例农在ender再经过编译变成(是能览调不页新代些事几求事都时学下是事

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.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是小程序的览页些求时是过解些这确如目前例总站回广随能4果泉时标配使能幻近器面实的我是接,前些模小架端如结的事告机对8和水兼移标签。

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)
}

好了,我的用记意口端样理框农必素些区大是应可近浏得方案就介绍到这里了。如果有人愿意与我一开始搞这东西了,欢迎在githu要圈器是天的年编功小还久概据含直这请框结业未商屏页屏随会维气大机域页效实一应控高标近用功b找我。

本文来源于网络:查看 >
« 上一篇:小程序web-view加载H5信息不全
» 下一篇:微信小程序入门
评论
点击刷新
评论
相关博文

分享“案例”中大奖

开始分享 中奖规则
分享链接:
联系方式:
2020-11-27中奖名单(每日10名)
×添加代码片段