-
Notifications
You must be signed in to change notification settings - Fork 320
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
转换小程序 #133
Comments
Taro 已经放弃使用template,目前使用的是小程序原生组件化。建议跟进。 |
本周工作重点 处理样式问题 (高) |
本周重点 组件标签套嵌内容的支持(ok) 去哪儿风格的模板 |
|
常见问题 render 里面不能定义变量,即不能出现var, const, let语句。render里只能使用JSX来描述结构,不能使用React.createElement。 块狀元素不能放在内联元素中,因为编译之后 |
本周工作重点
|
支持render props,但要求只参传一个参数,并只能传this.props或this.state, 见去哪儿网示例 |
编译器的重构思路 分为三层 命令接收层 编译层 生成层 编译层 有这样几个编译器
{type: "js", path: distPath, code: code: style: styleObject, xml: xmlObject} //jsObject
{type: "json", path: distPath, code: JSON.stringify(code) } //jsonObject 需要合并用户定义JSON
{type: "xml", path: distPath, code: code: } //xmlObject distPath的扩展名视APP形态可能为wxml, swan, axml
{type: "less", path: distPath, code: code: } 非快应用形态下,style编译器编译后,会生成 {type: "css", path: distPath, code: code: } app.js components, pages下的文件走小程序编译器 , 小程序编译器 又分为两大部分,核心编译器及实现差异化编译的helpers,与jsx无关的helper应该放到外面的utiles目录下。 就像babel-preset一样, 不同的APP 类型会选择不同的helpers集合 ========= 生成阶段, 从queue中一个个pop出来以stream 的模式读写文件, 轻应用,需要将三种文件类型组合成一个ux文件 asset目录下的东西直接复制 index.js //命令行
config.js
queue.js
deps.js
utils
| xxx.js
| yyy.js
translator
| esTransform.js
| styleTransform.js
| miniTransform.js
| miniTransformPlugin.js
| wxHelpers
| buHelpers
| aliHelpers
| quickHelpers
| commonHelpers
generate.js 生成文件或复制文件 |
开始快应用的研发。。。 |
React添加这样一个方法 createComponent(clazz){
var props = {
instanceUid: String,
props: Object,
context: Object
}
return {
props: props,
properties: props,
data: {
props:{},
state:{}
},
attached(){ //onInit
var reactInstance = clazz.instances.props()
reactInstance.wxInstance = this;
this.reactInstance = reactInstance;
this.readyFn = reactInstance.componentDidMount || noop
reactInstance.componentDidMount = noop
this.setData({
state: reactInstance.state,
props: reactInstance.props,
context: reactInstance.context
})
},
dettach(){ //onDestroy
this.reactInstance.wxInstance = null;
this.reactInstance = null;
},
ready(){// onReady
this.readyFn.call(this.reactInstance)
}
}
}, 被依赖的页面或组件加上 <import src="../../../../components/Dog/index.wxml" />
<view>
<view>类继承的演示</view>
<template is="Dog" data="{{...data}}" wx:for="{{components.data424}}"
wx:for-item="data" wx:for-index="index" wx:key="*this"></template>
<xxx-dog></xxx-dog>
</view> {
"usingComponents": {
"xxx-dog": "/components/dog2/index"
}
} 翻译后的代码 'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _ReactWX = require('../../ReactWX');
var _ReactWX2 = _interopRequireDefault(_ReactWX);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// eslint-disable-next-line
function Dog() {}
Dog = _ReactWX2.default.toClass(Dog,_ReactWX2.default.Component, {
componentWillMount: function () {
// eslint-disable-next-line
console.log('Dog componentWillMount');
},
render: function () {
var h = _ReactWX2.default.createElement;
return h('view', { style: _ReactWX2.default.toStyle({ border: '1px solid #333' }, this.props, 'style608') }, '\u540D\u5B57\uFF1A', this.state.name, ' \u5E74\u9F84\uFF1A', this.state.age, ' \u5C81', h('button', { catchTap: this.changeAge.bind(this), 'data-tap-uid': 'e848', 'data-class-uid': 'c590', 'data-instance-uid': this.props.instanceUid }, '\u6362\u4E00\u4E2A\u5E74\u9F84'));;
},
classUid: 'c591'
}, {});
Component(_ReactWX2.default.createComponent(Dog))
exports.default = Dog dog3.wxml <view>
<view>dog2</view>
<text>名字:{{state.name}} 年龄:{{state.age}} 岁</text>
<slot></slot>
</view> |
本周重点 修复组件引用样式失效的BUG |
页面的转译变化 "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _ReactWX = require("../../../ReactWX.js");
var _ReactWX2 = _interopRequireDefault(_ReactWX);
var _index = require("../../../components/Animal/index.js");
var _index2 = _interopRequireDefault(_index);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}
function Express() {
this.state = {
title: "语法相关"
};
}
Express = _ReactWX2.default.toClass(
Express,
_ReactWX2.default.Component,
{
componentWillMount: function() {
// eslint-disable-next-line
console.log("syntax componentWillMount");
},
componentDidMount: function() {
// eslint-disable-next-line
console.log("syntax componentDidMount");
},
render: function() {
var h = _ReactWX2.default.createElement;
return h(
"view",
{ class: "container" },
h("view", { class: "page_hd" }, this.state.title),
h(_ReactWX2.default.toComponent, {
name: "aaa",
age: 16,
$$loop: "data1692",
is: _index2.default
})
);
},
classUid: "c974"
},
{}
);
Page(_ReactWX2.default.toPage(Express, "pages/demo/syntax/index"));
exports.default = Express; 新 "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _ReactWX = require("../../../ReactWX.js");
var _ReactWX2 = _interopRequireDefault(_ReactWX);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}
function Express() {
this.state = {
title: "语法相关"
};
}
Express = _ReactWX2.default.toClass(
Express,
_ReactWX2.default.Component,
{
componentWillMount: function() {
// eslint-disable-next-line
console.log("syntax componentWillMount");
},
componentDidMount: function() {
// eslint-disable-next-line
console.log("syntax componentDidMount");
},
render: function() {
var h = _ReactWX2.default.createElement;
return h(
"view",
{ class: "container" },
h("view", { class: "page_hd" }, this.state.title),
h(_ReactWX2.default.useComponent, {
name: "aaa",
age: 16,
is: 'Animal'
})
);
},
classUid: "c974"
},
{}
);
Page(_ReactWX2.default.registerPage(Express, "pages/demo/syntax/index"));
exports.default = Express; 旧 <import src="../../../components/Animal/index.wxml" />
<view class="container">
<view class="page_hd">{{state.title}}</view>
<template is="Animal" data="{{...data}}" wx:for="{{components.data1692}}" wx:for-item="data" wx:for-index="index" wx:key="{{index}}"></template>
</view> 新 <view class="container">
<view class="page_hd">{{state.title}}</view>
<anu-animal> </anu-animal>
</view> 旧
新
最大的变化是wxml,少了这么多 |
组件的转译变化 旧 'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _ReactWX = require('../../ReactWX.js');
var _ReactWX2 = _interopRequireDefault(_ReactWX);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}
function Animal(props) {
this.state = {
name: props.name,
age: props.age || 1
};
}
Animal = _ReactWX2.default.toClass(
Animal,
_ReactWX2.default.Component,
{
changeAge: function() {
this.setState({
age: ~~(Math.random() * 10)
});
},
componentDidMount: function() {
// eslint-disable-next-line
console.log("Animal componentDidMount");
},
componentWillReceiveProps: function(props) {
this.setState({
name: props.name
});
},
render: function() {
var h = _ReactWX2.default.createElement;
return h(
'view',
{
style: _ReactWX2.default.toStyle(
{ border: '1px solid #333' },
this.props,
'style1362'
)
},
'\u540D\u5B57\uFF1A',
this.state.name,
' \u5E74\u9F84\uFF1A',
this.state.age,
' \u5C81',
h(
'button',
{
catchTap: this.changeAge.bind(this),
'data-tap-uid': 'e1602',
'data-class-uid': 'c901',
'data-instance-uid': props.instanceUid,
},
'\u6362\u4E00\u4E2A\u5E74\u9F84'
)
);
},
classUid: 'c901'
},
{
defaultProps: {
age: 1,
name: 'animal'
}
}
);
exports.default = Animal; 新 Object.defineProperty(exports, '__esModule', {
value: true
});
var _ReactWX = require('../../ReactWX.js');
var _ReactWX2 = _interopRequireDefault(_ReactWX);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}
function Animal(props) {
this.state = {
name: props.name,
age: props.age || 1
};
}
Animal = _ReactWX2.default.toClass(
Animal,
_ReactWX2.default.Component,
{
changeAge: function() {
this.setState({
age: ~~(Math.random() * 10)
});
},
componentDidMount: function() {
// eslint-disable-next-line
console.log("Animal componentDidMount");
},
componentWillReceiveProps: function(props) {
this.setState({
name: props.name
});
},
render: function() {
var h = _ReactWX2.default.createElement;
return h(
'view',
{
style: _ReactWX2.default.toStyle(
{ border: '1px solid #333' },
this.props,
'style1362'
)
},
'\u540D\u5B57\uFF1A',
this.state.name,
' \u5E74\u9F84\uFF1A',
this.state.age,
' \u5C81',
h(
'button',
{
catchTap: this.changeAge.bind(this),
'data-tap-uid': 'e1602',
},
'\u6362\u4E00\u4E2A\u5E74\u9F84'
)
);
},
classUid: 'c901'
},
{
defaultProps: {
age: 1,
name: 'animal'
}
}
);
Component(_ReactWX2.default.registerComponent(Animal, 'Animal'));
exports.default = Animal; 旧 <template name="Animal"><view style="{{props['style1362'] }}">
名字:{{state.name}} 年龄:{{state.age}} 岁
<button catchtap="dispatchEvent" data-tap-uid="e1602" data-class-uid="c901" data-instance-uid="{{props.instanceUid}}">换一个年龄</button>
</view></template> 新 <view style="{{props['style1362'] }}">
名字:{{state.name}} 年龄:{{state.age}} 岁
<button catchtap="dispatchEvent" data-tap-uid="e1602">换一个年龄</button>
</view> 旧 {
} 新 {
"component": true
} |
如果一个组件用到render props, 比如 import React from '@react';
import MouseTracker from '@components/MouseTracker/index';
import Cursor from '@components/Cursor/index';
class P extends React.Component {
constructor() {
super();
this.state = {};
}
render() {
return (
<div>
<MouseTracker
render={state => {
return (
<div>
render props <Cursor mouse={state} />
</div>
);
}}
/>
</div>
);
}
}
export default P; 它会变成这样 //...略掉一些代码
P = _ReactWX2.default.toClass(
P,
_ReactWX2.default.Component,
{
render: function() {
var h = _ReactWX2.default.createElement;
return h(
'view',
null,
h(_ReactWX2.default.useComponent, {
render: state => {
return h(
'view',
null,
'render props ',
h(_ReactWX2.default.useComponent, { mouse: state, is: 'Cursor' })
);
},
is: 'MouseTracker',
renderUid: 'render888',//注意这里
})
);
},
classUid: 'c743',
},
{}
);
Page(_ReactWX2.default.registerPage(P, 'pages/demo/syntax/renderprops/index'));
exports.default = P; <view>
<anu-mousetracker>
</anu-mousetracker>
</view> 在useComponent的props多添加一个renderUid import React from '@react';
class MouseTracker extends React.Component {
constructor(props) {
super(props);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.state = { x: 4, y: 5 };
}
handleMouseMove(e) {
this.setState({
x: e.x,
y: e.y
});
}
render() {
return (
<div style={{ height: '1000rpx' }} onClick={this.handleMouseMove}>
<h1>随机点击页面!</h1>
<p>The current mouse position is ({this.state.x}, {this.state.y})</p>
<p>{this.props.render(this.state)}</p>
</div>
);
}
}
export default MouseTracker; <view bindtap="dispatchEvent" style="{{props['style807'] }}" data-click-uid="e868" data-class-uid="c691">
<view>随机点击页面!</view>
<view>The current mouse position is ({{state.x}}, {{state.y}})</view>
<view><anu-render renderUid="{{props.renderUid}}" ></anu-render></view>
</view> anu-render是一个巨无霸的组件,它会把整个项目中所有render props函数都转换为wxml,整到它的分支上 var _ReactWX = require('../../ReactWX.js');
var _ReactWX2 = _interopRequireDefault(_ReactWX);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Component({
properties: {
renderUid: String,
props: Object,
state: Object,
context: Object
},
data: {},
lifetimes: {
// 生命周期函数,可以为函数,或一个在methods段中定义的方法名
attached: function (e) {
},
moved: function () { },
detached: function () { },
},
}) <block>
<block wx:if="{{ renderUid == 'render888' }}">
<view>
render props <anu-cursor></anu-cursor>
</view>
</block>
</block> |
要实现微信与小程序的通信,需要用到一些劫持手段,首先提交 var registerComponents = {};
function useComponent(props) {
var name = props.is;
var clazz = registerComponents[name];
delete props.is;
var args = [].slice.call(arguments, 2);
args.unshift(clazz, props);
console.log('JSX使用', name, '组件');
return createElement.apply(null, args);
}
function registerComponent(type, name) {
registerComponents[name] = type;
var reactInstances = type.reactInstances = [];
var wxInstances = type.wxInstances = [];
console.log('注册', name, '组件');
return {
data: {
props: {},
state: {},
context: {}
},
methods: {
dispatchEvent: eventSystem.dispatchEvent
},
lifetimes: {
created: function () {
var instance = reactInstances.shift();
if (instance) {
console.log('created时为', name, '添加wx');
instance.wx = this;
this.reactInstance = instance;
} else {
console.log('created时为', name, '没有对应react实例');
wxInstances.push(this);
}
},
attached: function () {
if (this.reactInstance) {
updateMiniApp(this.reactInstance);
console.log('attached时更新', name);
} else {
console.log('attached时无法更新', name);
}
},
detached: function () {
this.reactInstance = null;
}
}
};
} onBeforeRender方法中,会设计拿到它对应的小程序组件实例,为它添加reactInstance,反过来,组件实例也要添加wx属性,即两种实例互相持有对方。有时,拿不到小程序实例,说明对方没实例化,那么可以将组件实例丢到reactInstances 数组中,让小程序在attached钩子中干这事 onBeforeRender还会为组件与组件的props添加一个instanceUid与延迟componentDidMount的执行 onBeforeRender: function (fiber) {
var type = fiber.type;
if (type.reactInstances) {
var name = fiber.name;
var noMount = !fiber.hasMounted;
var instance = fiber.stateNode;
if (!instance.instanceUid) {
var uuid = 'i' + getUUID();
instance.instanceUid = uuid;
type[uuid] = instance;
}
instance.props.instanceUid = instance.instanceUid;
if (type.wxInstances) {
//只处理通用组件
if (type.wxInstances.length && !instance.wx) {
var wx = instance.wx = type.wxInstances.shift();
wx.reactInstance = instance;
console.log('onBeforeRender时更新', name, instance.props);
}
if (!instance.wx) {
console.log('onBeforeRender时更新', name, '没有wx');
type.reactInstances.push(instance);
}
}
}
if (noMount && instance.componentDidMount) {
delayMounts.push({
instance: instance,
fn: instance.componentDidMount
});
instance.componentDidMount = noop;
}
}, onAfterRender则是执行updateMiniapp更新小程序的视图 onAfterRender: function (fiber) {
var instance = fiber.stateNode;
if (instance.wx) {
updateMiniapp(instance);
}
}, function updateMiniApp(instance) {
instance.wx.setData(safeClone({
props: instance.props,
state: instance.state || null,
context: instance.context
}));
} |
各种小程序的组件机制差异 微信在Component的配置对象提供了一些对象如methods, lifetimes,pageLifetimes,来减少其直辖的配置项 支付宝的自定义组件机制没有properties,只有props,并且作用也不一样,props只是指定默认值,不是规定参数类型 百度的自定义组件机制与微信的较为相近,但也没有lifetimes与pageLifetimes对象,只有4种生命周期钩子 快应用的页面与组件的配置对象都是一样,但它没有构造函数,只是要求我们export一个对象 从组件的设计来看, 微信 > 百度 > 支付宝 > 快应用 |
思路, 将用户的类,放到一个地方,得到它的所有数据
抽取其render为wxml
The text was updated successfully, but these errors were encountered: