Skip to content
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

Closed
RubyLouvre opened this issue Jun 22, 2018 · 19 comments
Closed

转换小程序 #133

RubyLouvre opened this issue Jun 22, 2018 · 19 comments

Comments

@RubyLouvre
Copy link
Owner

RubyLouvre commented Jun 22, 2018

思路, 将用户的类,放到一个地方,得到它的所有数据
抽取其render为wxml

@zacksleo
Copy link

zacksleo commented Jul 3, 2018

@looch
Copy link

looch commented Aug 11, 2018

Taro 已经放弃使用template,目前使用的是小程序原生组件化。建议跟进。

@RubyLouvre
Copy link
Owner Author

本周工作重点

处理样式问题 (高)
redux例子 (高)
搞定 watch机制 (杨)
添加 postcss支持 (杨)
添加 别名机制 (杨)
添加 继承,循环,条件的例子(这仨要整到一个标签中) (祝)
添加 eslint支持 重点搞定它与vscode的使用, 参考taro (祝)
this.context支持 (钟)
modules改成类, 方便以后多线程编译(钟)

@RubyLouvre
Copy link
Owner Author

RubyLouvre commented Aug 27, 2018

本周重点

组件标签套嵌内容的支持(ok)
组件标签套嵌函数(render props)的支持
super不强制使用的支持 (ok)
组件使用了套嵌内容对应的wxml自动引用import的支持(现在只支持在pages中使用,如果组件套组件的情况出现 在components中,deps的set可能收集不全,需要一个很好的多次写入wxml的机制)
复杂的if for例子支持
eslint的提交修正 (ok)
redux例子
研究如何写测试 (延后)
处理组件标签套嵌内容时 出现在components的情况
URL的处理要兼容window系统 (ok)
React.createElement改用h短名字(ok)
拷贝静态资源

去哪儿风格的模板
商城风格的模板
企业官网的模板

@RubyLouvre
Copy link
Owner Author

       var a = {
            b: 1111, 
            c: {
                d: 333,
                ee: {
                    222: "6666",
                    a: a
                }, 
                k: a
            }
        }


        function safeClone(data) {
            var cache = []
            var map = new Map()
            var cloneObject = {}
            map.set(data, cloneObject);
            JSON.stringify(data, function (key, value) {
                var object = map.get(this);
                if (!object) {
                    return value
                }

                if (typeof value === 'object' && value !== null) {
                    if (cache.indexOf(value) !== -1) {
                        // Circular reference found, discard key
                        return;
                    }
                    object[key] = value
                    cache.push(value);
                } else {
                    object[key] = value
                }
                return value;
            });
            return cloneObject;
        }
        console.log(safeClone(a))

@RubyLouvre
Copy link
Owner Author

RubyLouvre commented Aug 29, 2018

常见问题

render 里面不能定义变量,即不能出现var, const, let语句。render里只能使用JSX来描述结构,不能使用React.createElement。
组件必须定义在components中
页面引用了组件了,如果组件有样式,那么页面的样式表也要import这个组件的样式表
为什么底部不出现TabBar? 这是小程序自身的BUG,详见 https://www.cnblogs.com/bellagao/p/6291880.html
路由跳转时,如何拿到当前路径与参数,原来是通过onLoad方法拿,现在你可以通过任何一个页面组件的生命周期钩子,访问this.props,里面就有path与query属性
静态资源统一放到src目录下的assets目录下
箭头函数里面不能使用this
不要在props, state, context里面放JSX,因为JSX的结构容易出现环引用,导到微信小程序内部的JSON.stringify出错

块狀元素不能放在内联元素中,因为编译之后 <view>无法在<text>中显示出来

@RubyLouvre
Copy link
Owner Author

image

@RubyLouvre
Copy link
Owner Author

本周工作重点

  1. 第三套模板
  2. 第二套模板的转盘问题,tabBar问题
  3. 第二套模板的日期选择器
  4. 实现在components目录下的组件套其他组件
  5. 性能优化 (大奔)
  6. 各种语法糖的支持 (杨)
  7. 官网

@RubyLouvre
Copy link
Owner Author

RubyLouvre commented Sep 13, 2018

支持render props,但要求只参传一个参数,并只能传this.props或this.state, 见去哪儿网示例

@RubyLouvre
Copy link
Owner Author

RubyLouvre commented Sep 18, 2018

编译器的重构思路

分为三层 命令接收层 编译层 生成层

编译层 有这样几个编译器

  1. 小程序编译器 mpTransform(原jsTransform.js)需要转译es6类为 React.toClass实例,建立组件与ReactWX的桥接,需要处理JSX ,里面会加入toComponent, toStyle, dispatchEvent等方法,用于打破小程序模板的限制(wxml, swan, axml都是弱模板,不能使用函数,因此里面的数据都需要在JSX 中diff后转换好),需要处理同目录下的同名JSON配置对象,然后产出这三种对象放到queue中
{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
  1. es编译器 esTransform, 用来搞定es67的语法糖与react, @react @component别名

  2. style编译器 styleTransform, 用来处理 less, sass

{type: "less", path: distPath, code: code: }  

非快应用形态下,style编译器编译后,会生成

{type: "css", path: distPath, code: code: }   

app.js components, pages下的文件走小程序编译器 ,
node_modules及其他目录走 es编译器 , 并且node_modules目录下的需要编译到dist/npm目录下

小程序编译器 又分为两大部分,核心编译器及实现差异化编译的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 生成文件或复制文件

@RubyLouvre
Copy link
Owner Author

开始快应用的研发。。。

@RubyLouvre
Copy link
Owner Author

RubyLouvre commented Sep 26, 2018

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>

@RubyLouvre
Copy link
Owner Author

本周重点

修复组件引用样式失效的BUG
修复业务组件使用语法糖失败的BUG
设计提交时检测样式表是否符合快应用的规范
设计一套表式表(主要是布局类名)
设计一套UI库
快应用的页面父类
快应用的更多细节收集
支付宝的webview页面
快应用的文件合并逻辑
新组件机制的开关与编译器里的对应实现

@RubyLouvre
Copy link
Owner Author

RubyLouvre commented Oct 11, 2018

原生组件的使用

如果在页面上使用自定义组件

页面的JS import了组件的JS,然后又在页面的JSON的usingComponents指定了它,就会报错
image
image
image

@RubyLouvre
Copy link
Owner Author

RubyLouvre commented Oct 12, 2018

页面的转译变化

"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>

{
    "navigationBarTextStyle": "#fff",
    "navigationBarBackgroundColor": "#0088a4",
    "navigationBarTitleText": "Demo",
    "backgroundColor": "#eeeeee",
    "backgroundTextStyle": "light"
}

{
    "navigationBarTextStyle": "#fff",
    "navigationBarBackgroundColor": "#0088a4",
    "navigationBarTitleText": "Demo",
    "backgroundColor": "#eeeeee",
    "backgroundTextStyle": "light"
   "usingComponents": {
        "anu-animal": "/components/Animal/index"
    }
}

最大的变化是wxml,少了这么多data-instance-uid, data-class-uid属性,组件标签不需要变成template标签,是原组件加anu-前缀小写化,并没有任何属性

@RubyLouvre
Copy link
Owner Author

RubyLouvre commented Oct 12, 2018

组件的转译变化

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

@RubyLouvre
Copy link
Owner Author

RubyLouvre commented Oct 12, 2018

如果一个组件用到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
应用了render props的子组件原来是这样的,现在翻译成wxml后会多出一个anu-render组件

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>

@RubyLouvre
Copy link
Owner Author

RubyLouvre commented Oct 13, 2018

要实现微信与小程序的通信,需要用到一些劫持手段,首先提交React.registerPage, React.registerComponent,它们的第一个参数都是类构造,我们为它们添加 reactInstances 数组,这样在特设的React 版本中,它们会进入onBeforeRender, onAfterRender

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

@RubyLouvre
Copy link
Owner Author

各种小程序的组件机制差异

微信在Component的配置对象提供了一些对象如methods, lifetimes,pageLifetimes,来减少其直辖的配置项
比如说lifetimes收纳了created、attached、ready、moved、detached这些生命周期钩子
pageLifetimes收纳了onShow, onHide这些与页面切换的钩子
methods收纳剩下的方法

支付宝的自定义组件机制没有properties,只有props,并且作用也不一样,props只是指定默认值,不是规定参数类型
支付宝也没有lifetimes与pageLifetimes对象,
生命周期函数的名字也不一样 didMount 、didUpdate 、didUnmount,数量也少了
支付宝支持独有的mixin机制
没有 dataset, selectComponent,selectAllComponents,getRelationNodes这些东西
支付宝没有created这样的钩子是相当麻烦的事,因此积级推动他们加上这个钩子!

百度的自定义组件机制与微信的较为相近,但也没有lifetimes与pageLifetimes对象,只有4种生命周期钩子
created attached ready detached
有selectComponent,selectAllComponents

快应用的页面与组件的配置对象都是一样,但它没有构造函数,只是要求我们export一个对象
有props对象,用来定义类型与默认值,也有与state相似的data对象,也有三个做了访问限制的private, protected, public对象
生命周期钩子上有onInit、onReady、onDestroy这三个

从组件的设计来看, 微信 > 百度 > 支付宝 > 快应用

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants