<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>coderyi</title>
    <description>生命不止，折腾不息</description>
    <link>http://localhost:4000/</link>
    <atom:link href="http://localhost:4000/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Fri, 10 Mar 2023 00:37:55 +0800</pubDate>
    <lastBuildDate>Fri, 10 Mar 2023 00:37:55 +0800</lastBuildDate>
    <generator>Jekyll v4.3.1</generator>
    
      <item>
        <title>Weex学习与实践(三):iOS原理篇</title>
        <description>&lt;p&gt;&lt;a href=&quot;http://coderyi.com/posts/weex1/&quot;&gt;Weex学习与实践(一):Weex,你需要知道的事&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://coderyi.com/posts/weex2/&quot;&gt;Weex学习与实践(二):iOS集成的tips&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://coderyi.com/posts/weex3/&quot;&gt;Weex学习与实践(三):iOS原理篇&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;本文主要介绍包括WeexSDK-iOS主要类介绍、Weex页面iOS端渲染流程、JS调用iOS方法&lt;/p&gt;

&lt;h3 id=&quot;主要类&quot;&gt;主要类&lt;/h3&gt;

&lt;h4 id=&quot;wxsdkengine&quot;&gt;WXSDKEngine&lt;/h4&gt;

&lt;p&gt;WXSDKEngine主要用于初始化WeexSDK的环境&lt;/p&gt;

&lt;p&gt;一开始会载入配置文件main.js并且注册一些默认的组件、模块以及handler&lt;/p&gt;

&lt;pre&gt;
+ (void)initSDKEnviroment:(NSString *)script
{
   
    [self _registerDefaultComponents];
    [self _registerDefaultModules];
    [self _registerDefaultHandlers];
    
    [[WXSDKManager bridgeMgr] executeJsFramework:script];
}

&lt;/pre&gt;

&lt;p&gt;在executeJsFramework前，会设置后JSContext的一些回调，例如&lt;/p&gt;
&lt;pre&gt;
    _jsContext[@&quot;callNative&quot;] = callNativeBlock;
&lt;/pre&gt;
&lt;p&gt;以方便JS调用native的方法。&lt;/p&gt;

&lt;p&gt;executeJsFramework调用的是JSContext的evaluateScript方法，把main.js运行到jS的环境里面，之后再通过JSValue调用invokeMethod方法，把前面所有的components，modules，handlers注册进入JS环境&lt;/p&gt;

&lt;h4 id=&quot;wxsdkinstance&quot;&gt;WXSDKInstance&lt;/h4&gt;

&lt;p&gt;一个WXSDKInstance就对应一个UIViewController,对应一个weex页面。&lt;/p&gt;

&lt;p&gt;主要用来渲染页面,一般通过renderWithURL方法，然后能够接收一些回调和一些视图相关的方法&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;onCreate //根视图rootView创建的时候
renderFinish//视图渲染完成
componentForRef //通过视图索引拿到对应的组件视图
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;wxbridgemanager&quot;&gt;WXBridgeManager&lt;/h4&gt;

&lt;p&gt;WXBridgeManager 是JS与iOS通过JSCore交互的类,相关的类还有WXBridgeContext、WXJSCoreBridge。&lt;/p&gt;

&lt;p&gt;比如调用JS&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
- (void)executeJsMethod:(WXBridgeMethod *)method
{
    if (!method) return;
    
    __weak typeof(self) weakSelf = self;
    WXPerformBlockOnBridgeThread(^(){
        [weakSelf.bridgeCtx executeJsMethod:method];
    });
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;JS调用native的话需要通过WXJSCoreBridge的registerCallNative方法&lt;/p&gt;

&lt;h4 id=&quot;wxcomponent&quot;&gt;WXComponent&lt;/h4&gt;

&lt;p&gt;组件基类，自己实现iOS端的组件需要继承它。相关的还有负责组件初始化的工厂类WXComponentFactory，以及WXComponentManager&lt;/p&gt;

&lt;h4 id=&quot;wxmoduleprotocol&quot;&gt;WXModuleProtocol&lt;/h4&gt;

&lt;p&gt;自定义module需要实现的协议&lt;/p&gt;

&lt;h3 id=&quot;weex页面ios端渲染流程&quot;&gt;weex页面iOS端渲染流程&lt;/h3&gt;

&lt;p&gt;首先在ViewController里的render放初始化WXSDKInstance，因为render会支持实时刷新，所以每次都需要先销毁这个实例。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    [_instance destroyInstance];
    _instance = [[WXSDKInstance alloc] init];

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;然后WXSDKManager会保存instanceId&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;        [WXSDKManager storeInstance:self forID:_instanceId];

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;然后会调用renderWithURL方法来载入script,在这里会判断是本地文件还是需要从服务器下载，&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- (void)renderWithURL:(NSURL *)url options:(NSDictionary *)options data:(id)data{
	    if ([url isFileURL]) {
        //from local
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSString *path = [url path];
            NSData *scriptData = [[NSFileManager defaultManager] contentsAtPath:path];
            NSString *script = [[NSString alloc] initWithData:scriptData encoding:NSUTF8StringEncoding];
            [weakSelf renderView:script options:newOptions data:data];
        });
    }else{
    	//from server
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;然后就会根据script文件渲染视图&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[weakSelf renderView:script options:newOptions data:data];

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;在这个方法里面首先会创建根视图，当创建完成时WXSDKInstance会收到onCreate的回调&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    //TODO WXRootView
    WXPerformBlockOnMainThread(^{
        self.rootView = [[WXView alloc] initWithFrame:self.frame];
        if(self.onCreate) {
            self.onCreate(self.rootView);
        }
    });

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;之后再通过bridge调用JS方法来开始创建实例&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    [self callJSMethod:@&quot;createInstance&quot; args:args];

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;然后这里会判断JSFramework也就是js有没有加载完成，然后再通过WXJSBridge的JSContext来执行js方法，这里调用的就是js的createInstance方法，args里面主要就是instanceID，we文件转化的js文件，和options。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- (void)callJSMethod:(NSString *)method args:(NSArray *)args
{
    [[_jsContext globalObject] invokeMethod:method withArguments:args];
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;最后js会调用JSContext的callCreateFinish回调，最后调用WXSDKInstance的createFinish方法来结束页面的渲染&lt;/p&gt;

&lt;h3 id=&quot;js调用ios方法&quot;&gt;JS调用iOS方法&lt;/h3&gt;

&lt;p&gt;首先要注册一个组件&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    [self registerModule:@&quot;dom&quot; withClass:NSClassFromString(@&quot;WXDomModule&quot;)];

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;注册module的时候 会通过下面方法&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-objective-c&quot;&gt;+ (void)registerModule:(NSString *)name withClass:(Class)clazz
{
    WXAssert(name &amp;amp;&amp;amp; clazz, @&quot;Fail to register the module, please check if the parameters are correct ！&quot;);
    
    NSString *moduleName = [WXModuleFactory registerModule:name withClass:clazz];
    NSDictionary *dict = [WXModuleFactory moduleMethodMapsWithName:moduleName];
    
    [[WXSDKManager bridgeMgr] registerModules:dict];
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;把所有通过宏注册的方法发送给js端&lt;/p&gt;

&lt;pre&gt;
WX_EXPORT_METHOD(@selector(createBody:))

&lt;/pre&gt;

&lt;p&gt;这会把方法暴露出来，并且方法名字是”wx_export_method_“加代码所在行号，wx_export_method_25&lt;/p&gt;

&lt;p&gt;组件、模块 是给js端用的，而handler则是给objc自己用的，所以不用发送消息给js端&lt;/p&gt;

&lt;p&gt;然后通过methodForSelector拿到WX_EXPORT_METHOD方法的返回值，并且保存到methods中&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- (void)registerModuleMethods {

            if ([currentClass respondsToSelector:selector]) {
                method = ((NSString* (*)(id, SEL))[currentClass methodForSelector:selector])(currentClass, selector);
            }
            [_methods setObject:method forKey:name];

}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;然后拿到WXModuleConfig组成的_moduleMap之后再发送给JS端&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    [[WXSDKManager bridgeMgr] registerModules:dict];

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这里就是前面提到的调用JSContext的invokeMethod把内容发送到JS端&lt;/p&gt;

&lt;p&gt;最后需要自己callNative的回调，当JS调用时就会传值到这里&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- (void)registerCallNative:(WXJSCallNative)callNative
{
    NSInteger (^callNativeBlock)(JSValue *, JSValue *, JSValue *) = ^(JSValue *instance, JSValue *tasks, JSValue *callback){
        NSString *instanceId = [instance toString];
        NSArray *tasksArray = [tasks toArray];
        NSString *callbackId = [callback toString];
        
        return callNative(instanceId, tasksArray, callbackId);
    };
    
    _jsContext[@&quot;callNative&quot;] = callNativeBlock;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;tasks里面包括方法的一些相关信息,包括module（比如dom），method（比如updateFinish），args&lt;/p&gt;

&lt;h1 id=&quot;weex-devtool-ios&quot;&gt;&lt;a href=&quot;https://github.com/weexteam/weex-devtool-iOS&quot;&gt;weex-devtool-iOS&lt;/a&gt;&lt;/h1&gt;

&lt;p&gt;weex-devtool-iOS	其实是 &lt;a href=&quot;https://github.com/square/PonyDebugger&quot;&gt;PonyDebugger&lt;/a&gt;的衍生品。&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.iliunian.com/2875.html&quot;&gt;使用PonyDebugger调试iOS应用&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/Flipboard/FLEX/blob/000e061d009bb7c64c8338f1715431ad9b5f1558/Classes/Network/PonyDebugger/FLEXNetworkObserver.m&quot;&gt;FLEXNetworkObserver&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Mon, 17 Oct 2016 00:00:00 +0800</pubDate>
        <link>http://localhost:4000/posts/weex3/</link>
        <guid isPermaLink="true">http://localhost:4000/posts/weex3/</guid>
        
        <category>Weex</category>
        
        
        <category>iOS</category>
        
      </item>
    
      <item>
        <title>Weex学习与实践(二):iOS集成的tips</title>
        <description>&lt;p&gt;&lt;a href=&quot;http://coderyi.com/posts/weex1/&quot;&gt;Weex学习与实践(一):Weex,你需要知道的事&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://coderyi.com/posts/weex2/&quot;&gt;Weex学习与实践(二):iOS集成的tips&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://coderyi.com/posts/weex3/&quot;&gt;Weex学习与实践(三):iOS原理篇&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;本文主要介绍包括iOS上集成Weex、iOS上扩展组件、iOS上扩展module&lt;/p&gt;

&lt;h3 id=&quot;ios上集成weex&quot;&gt;iOS上集成Weex&lt;/h3&gt;

&lt;p&gt;集成weex，需要WeexSDK、WXDevtool两个库以及阿里未开源的ATSDK-Weex。&lt;/p&gt;

&lt;p&gt;目前官方的alibaba/Weex仓库里面&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    pod 'WeexSDK', :path=&amp;gt;'../sdk/'
    pod 'WXDevtool', :path=&amp;gt;'../WXDevtool/'
    pod 'ATSDK-Weex', '0.0.1'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;它们直接使用的weex仓库的sdk,但是weex主仓库的WXDevtool已经不维护了，需要替换成，&lt;a href=&quot;https://github.com/weexteam/weex-devtool-iOS&quot;&gt;weexteam/weex-devtool-iOS&lt;/a&gt;的代码。&lt;/p&gt;

&lt;p&gt;另外也可以直接从cocoapods的源pod仓库，但是cocoapods的源都是打包成framework,很多文件并没有设置为public，所以导致很多头文件没有暴露出来。&lt;/p&gt;

&lt;p&gt;当然你也可以不用通过cocoapods集成，直接把代码拉进工程就可以，如果发生&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Unknown type name 'NSString'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;你可能需要把layout.c文件右侧的type改为Objective-C Source，或者直接修改为layout.m。&lt;/p&gt;

&lt;p&gt;基本上JS页面是在WXDemoViewController工作的，你可能需要接收页面刷新的通知，以支持实时刷新&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationRefreshInstance:) name:@&quot;RefreshInstance&quot; object:nil];
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;页面会维护一个WXSDKInstance实例，WXSDKInstance就是weex渲染的实例对象，提供了很多页面渲染相关的接口，比如renderWithURL、refreshInstance、destroyInstance等&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/weexteam/article/issues/18&quot;&gt;weex SDK 集成到工程 (integrate to ios) &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://open.taobao.com/doc2/detail?spm=a219a.7629140.0.0.tFddsV&amp;amp;&amp;amp;docType=1&amp;amp;articleId=104829&quot;&gt;Weex iOS SDK 集成指南&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;ios上扩展组件&quot;&gt;iOS上扩展组件&lt;/h3&gt;

&lt;p&gt;目前官方iOS这一块组件的代码在WeexSDK的component里面，组件有限，只有image，list，scroller等，如果想要实现自己的组件，首先需要继承WXComponent类。&lt;/p&gt;

&lt;p&gt;然后实现方法&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
{}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;注意这个方法不在主线程，这里面接收一些js传过来的参数，以在js端写的image标记为例子&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;image style=&quot;width: 100;height: 100;margin-top:20;margin-right:20;margin-left:220&quot; src=&amp;gt;&amp;lt;/image&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;到objc端就是&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ref:701
type:image
styles:
{
    height = 100;
    marginLeft = 220;
    marginRight = 20;
    marginTop = 20;
    width = 100;
}
attributes:
{
    src = &quot;https://avatars.githubusercontent.com/u/9892522?v=3&quot;;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;ref（结点的唯一标识符）&lt;/p&gt;

&lt;p&gt;然后在loadView的时候可能需要返回自己的objc组件&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;- (UIView *)loadView
{
    return [[WXImageView alloc] init];
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;然后你可以通过复写addEvent方法来增加一个change（UIControlEventValueChanged）、click（UIControlEventTouchUpInside）等事件&lt;/p&gt;

&lt;p&gt;如果是image组件的话，你可能需要接收图片地址，这个时候需要通过实现了WXImgLoaderProtocol的WXImgLoaderDefaultImpl来处理，WXImgLoaderDefaultImpl实现了downloadImageWithURL方法，这里面通过SDWebImage来下载一张图片。&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/weexteam/article/issues/17&quot;&gt;iOS 扩展 (extend to ios)&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;ios上扩展module&quot;&gt;iOS上扩展module&lt;/h3&gt;

&lt;p&gt;这一块的代码在module分组里面，包括网络库stream，持久化storage等，你可以扩展自己module。&lt;/p&gt;

&lt;p&gt;需要做的是实现WXModuleProtocol协议，并且写自己的方法就可以了，这里需要通过weex的宏把需要public的方法导出&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;WX_EXPORT_METHOD(@selector(fetch:callback:progressCallback:))

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;在module中目前是没有view的，但是你可以通过由js传过来的ref值拿到&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    WXComponent *targetComponent = [self.weexInstance componentForRef:nodeRef];
    CALayer *layer = targetComponent.layer;
    UIView *view = targetComponent.view;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;注意点&quot;&gt;注意点&lt;/h3&gt;

&lt;p&gt;1.如果设置js文件在bundle中载入的话，需要把build的js文件拖入工程，如果的你的we里面一开始就调用了js文件，由于只会buildwe文件，所以还需要把之前的js文件拖入工程，另外examples里面判断iOSAssets是这样的&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;      var isiOSAssets = bundleUrl.indexOf('file:///') &amp;gt;= 0 &amp;amp;&amp;amp; bundleUrl.indexOf('WeexDemo.app') &amp;gt; 0;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;你如果拖入自己的工程需要把WeexDemo.app的判断去掉&lt;/p&gt;

</description>
        <pubDate>Mon, 17 Oct 2016 00:00:00 +0800</pubDate>
        <link>http://localhost:4000/posts/weex2/</link>
        <guid isPermaLink="true">http://localhost:4000/posts/weex2/</guid>
        
        <category>Weex</category>
        
        
        <category>iOS</category>
        
      </item>
    
      <item>
        <title>Weex学习与实践(一):Weex,你需要知道的事</title>
        <description>&lt;p&gt;&lt;a href=&quot;http://coderyi.com/posts/weex1/&quot;&gt;Weex学习与实践(一):Weex,你需要知道的事&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://coderyi.com/posts/weex2/&quot;&gt;Weex学习与实践(二):iOS集成的tips&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://coderyi.com/posts/weex3/&quot;&gt;Weex学习与实践(三):iOS原理篇&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;本文主要介绍包括Weex基本介绍、Weex源码结构、初始化工程、we代码结构、Weex的生命周期、Weex的工作原理、页面间通信、boxmodel &amp;amp; flexbox、weex的缺点&lt;/p&gt;

&lt;h3 id=&quot;基本介绍&quot;&gt;基本介绍&lt;/h3&gt;

&lt;p&gt;A framework for building Mobile cross-platform UI&lt;/p&gt;

&lt;p&gt;怎么解释它呢？我的理解就是weex = react-native +vue ，使用vue的API风格，两端的实现方式则和react-native，weex 比rn的优点就是一次编写三端运行。&lt;/p&gt;

&lt;p&gt;IDE: Sublime Text + &lt;a href=&quot;https://github.com/vuejs/vue-syntax-highlight&quot;&gt;vue-syntax-highlight&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;命令行工具：&lt;a href=&quot;https://github.com/weexteam/weex-toolkit&quot;&gt;weex-toolkit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;调试工具: &lt;a href=&quot;https://github.com/weexteam/weex-devtool&quot;&gt;weex-devtool&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;weex分为组件component和模块（module）以及事件&lt;/p&gt;

&lt;p&gt;weex-components : &lt;a href=&quot;https://github.com/weexteam/weex-components&quot;&gt;weex-components&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;组件 就是各种标记组件，比如div 、slider、indicator等
通过下面这种方式使用&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;div&amp;gt;
  &amp;lt;image src=&quot;...&quot;&amp;gt;&amp;lt;/image&amp;gt;
  &amp;lt;text&amp;gt;...&amp;lt;/text&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;js模块&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;modal&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;@weex-module/modal&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;modal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toast&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;我是提示框&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;duration&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;  

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;其他的还有stream,dom，animation之类的&lt;/p&gt;

&lt;p&gt;事件&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &amp;lt;div onviewappear=&quot;viewappear&quot; onviewdisappear=&quot;viewdisappear&quot;&amp;gt;
          ......
  &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;weex源码结构&quot;&gt;Weex源码结构&lt;/h3&gt;

&lt;p&gt;package.json&lt;/p&gt;

&lt;p&gt;node_modules依赖，更重要的是里面包含了npm run xxx 等快捷命令。比如之前我们运行node.js程序是这样的：$ node xx.js。这里我们可以把它配置化，例如package.json文件中scripts的 “build:config”: “node build/config.frameworks.js”，其实就是npm run build:config 相当于执行了node build/config.frameworks.js&lt;/p&gt;

&lt;p&gt;start文件: 启动程序文件，里面包换编译和启动脚本：&lt;/p&gt;

&lt;p&gt;examples: 示例Demo&lt;/p&gt;

&lt;p&gt;android/ios/html： 各平台代码&lt;/p&gt;

&lt;p&gt;build：打包各平台的脚本，配置在package.json中。&lt;/p&gt;

&lt;p&gt;参考链接:&lt;a href=&quot;https://vczero.github.io/weex-learning/002_modify_example.html&quot;&gt;第2篇 了解Weex源码结构，修改example&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;初始化工程&quot;&gt;初始化工程&lt;/h3&gt;

&lt;p&gt;初始化工程前需要先安装 &lt;a href=&quot;http://brew.sh/index_zh-cn.html&quot;&gt;homebrew&lt;/a&gt;，然后按照下面步骤创建一个工程。&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;brew&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;//通过brew安装node&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;weex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toolkit&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;//通过node安装 weex-toolkit  &lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cocoapods&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;//安装iOS包管理工具 cocoapods&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;weex&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;init&lt;/span&gt;                     &lt;span class=&quot;c1&quot;&gt;//创建项目的文件&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;install&lt;/span&gt;                   &lt;span class=&quot;c1&quot;&gt;//依赖安装 package.json文件&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dev&lt;/span&gt;                   &lt;span class=&quot;c1&quot;&gt;//项目编译&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;serve&lt;/span&gt;                 &lt;span class=&quot;c1&quot;&gt;//启动轻量服务器  &lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这时有可能提示&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm WARN babel-loader@6.2.5 requires a peer of babel-core@^6.0.0 but none was installed.

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;你需要再&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm install babel-core

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这时，打开浏览器，输入http://127.0.0.1:8080, 就会看到这个项目的效果:&lt;/p&gt;

&lt;p&gt;参考链接:&lt;a href=&quot;https://vczero.github.io/weex-learning/003_init_project.html&quot;&gt;第3篇 初始化工程&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;npm run dev 干了什么呢？&lt;/p&gt;

&lt;p&gt;先看 package.json 文件&lt;/p&gt;

&lt;pre&gt;
{
  &quot;name&quot;: &quot;demo1&quot;,
  &quot;version&quot;: &quot;1.0.0&quot;,
  &quot;description&quot;: &quot;&quot;,
  &quot;main&quot;: &quot;index.js&quot;,
  &quot;scripts&quot;: {
    &quot;build&quot;: &quot;webpack&quot;,
    &quot;dev&quot;: &quot;webpack --watch&quot;,
    &quot;serve&quot;: &quot;serve -p 8080&quot;,
    &quot;test&quot;: &quot;echo \&quot;Error: no test specified\&quot; &amp;amp;&amp;amp; exit 1&quot;
  },
  &quot;keywords&quot;: [],
  &quot;author&quot;: &quot;&quot;,
  &quot;license&quot;: &quot;ISC&quot;,
  &quot;devDependencies&quot;: {
    &quot;serve&quot;: &quot;^1.4.0&quot;,
    &quot;webpack&quot;: &quot;^1.13.1&quot;,
    &quot;weex-html5&quot;: &quot;0.2.18&quot;,
    &quot;weex-loader&quot;: &quot;^0.1.5&quot;
  }
}

&lt;/pre&gt;

&lt;p&gt;npm run dev实际上相当于 webpack –watch&lt;/p&gt;

&lt;p&gt;webpack实际上是执行了默认的webpack.config.js配置文件&lt;/p&gt;

&lt;p&gt;webpack.config.js 引入webpack和weex-loader，entry属性是表示入口文件，output表示输出文件，默认输出到dist文件夹。&lt;/p&gt;

&lt;pre&gt;
require('webpack')
require('weex-loader')

var path = require('path')

module.exports = {
  entry: {
    main: path.join(__dirname, 'src', 'main.we?entry=true')
  },
  output: {
    path: 'dist',
    filename: '[name].js'
  },
  module: {
    loaders: [
      {
        test: /\.we(\?[^?]+)?$/,
        loaders: ['weex-loader']
      }
    ]
  }
}

&lt;/pre&gt;

&lt;p&gt;不过这个自动产生的webpack.config.js的文件有个坑就是，你添加一个新的we文件，他不会自动build为js文件
可以手动添加&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  entry: {
    main: path.join(__dirname, 'src', 'main.we?entry=true'),
    translate: path.join(__dirname, 'src', 'translate.we?entry=true')
  }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;不过推荐的是自己遍历所有的we文件&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;require('webpack')
require('weex-loader')

var path = require('path')
var fs = require('fs');

var entry = {};

function walk(dir, root) {
  var directory = path.join(__dirname, root, dir);
  fs.readdirSync(directory)
    .forEach(function(file) {
      var fullpath = path.join(directory, file);
      var stat = fs.statSync(fullpath);
      var extname = path.extname(fullpath);
      if (stat.isFile() &amp;amp;&amp;amp;
             (extname === '.we')) {
        var name = path.join(root, 'build', dir, path.basename(file, extname));
        entry[name] = fullpath + '?entry=true';
      } else if (stat.isDirectory() &amp;amp;&amp;amp;
                  file !== 'build') {
        var subdir = path.join(dir, file);
        walk(subdir, root);
      }
    });
}
walk('./', 'src');
module.exports = {
  entry: entry,
  output: {
    path: '.',
    filename: '[name].js'
  },
  module: {
    loaders: [
      {
        test: /\.we(\?[^?]+)?$/,
        loaders: ['weex-loader']
      }
    ]
  }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/hugojing/toolbox-weex/blob/master/webpack.config.js&quot;&gt;hugojing  - webpack.config.js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/duqian291902259/weex-demo-dusan/blob/master/webpack.config.js&quot;&gt;duqian291902259 - webpack.config.js&lt;/a&gt;
&lt;a href=&quot;https://vczero.github.io/weex-learning/003_init_project.html&quot;&gt;第3篇 初始化工程&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;入口文件index.html&lt;/p&gt;

&lt;p&gt;这里可以参考 &lt;a href=&quot;https://github.com/weexteam/article/issues/10&quot;&gt;Integrate Weex HTML5 to your project&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/MrRaindrop/weex_extend_demo&quot;&gt;weex_extend_demo&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;weex代码结构&quot;&gt;weex代码结构&lt;/h3&gt;

&lt;p&gt;template内必须包含唯一的根节点作为父容器, div就是一个很好的选择，里面则是一些Native Components&lt;/p&gt;

&lt;p&gt;style 支持盒子模型和Flexbox&lt;/p&gt;

&lt;p&gt;weex内置了响应式的支持，页面的宽度是以750来做为标准，自动适配所有手机；&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;子组件&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/div&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;子组件&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/div&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/div&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/template&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/style&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nl&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;computed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;y&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;events&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;custom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;created&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;ready&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/script&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;script里面包含很多ViewModel Options，&lt;/p&gt;

&lt;p&gt;data
methods
computed
init, created, ready
events&lt;/p&gt;

&lt;p&gt;如果需要在模板里实现更多的逻辑判断,你可以使用’computed property’.&lt;/p&gt;

&lt;p&gt;created是生命周期函数，这个时候模板还没有被渲染，常用来在这里定义数据的更新和获取；&lt;/p&gt;

&lt;p&gt;ready是生命周期函数，这个时候模板被渲染，常用来做一些自己上报等；&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/alibaba/weex/blob/dev/doc/references/cheatsheet.md&quot;&gt;weex- references - Weex Cheat Sheet&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;显然we文件的这些代码是不会被 native app 识别的，我们要想办法让这些代码可运行。所以我们同时做了三件事：&lt;/p&gt;

&lt;p&gt;1.在本地用一个叫做 transformer 的工具把这套代码转成纯 JavaScript 代码&lt;/p&gt;

&lt;p&gt;2.在客户端运行一个 JavaScript 引擎，随时接收 JavaScript 代码&lt;/p&gt;

&lt;p&gt;3.在客户端设计一套 JS Bridge，让 native 代码可以和 JavaScript 引擎相互通信&lt;/p&gt;

&lt;p&gt;所以紧接着第二步，就是用 transformer 对代码进行转换，变成客户端可运行的 JavaScript 代码&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cloud.githubusercontent.com/assets/206848/11239127/f7854634-8e24-11e5-8173-3417c63043a4.PNG&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/amfe/article/issues/14&quot;&gt;原图&lt;/a&gt;：本地开发时的 Weex Transformer 工作原理&lt;/p&gt;

&lt;p&gt;在 transformer 中，我们主要的工作就是对 HTML、CSS、JavaScript 代码进行解析和重组。这里我们用到了三个非常重要的库：&lt;/p&gt;

&lt;p&gt;HTML 解析工具：&lt;a href=&quot;https://www.npmjs.com/package/htmlparser&quot;&gt;htmlparser&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;CSS 解析工具：&lt;a href=&quot;https://www.npmjs.com/package/cssom&quot;&gt;cssom&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;JavaScript 解析工具：&lt;a href=&quot;https://www.npmjs.com/package/uglify-js&quot;&gt;uglify-js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/amfe/article/issues/15&quot;&gt;对无线电商动态化方案的思考（三） &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/amfe/article/issues/14&quot;&gt;对无线电商动态化方案的思考（二） &lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;weex-的生命周期&quot;&gt;Weex 的生命周期&lt;/h3&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;methods&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;

    &lt;span class=&quot;na&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;在初始化内部变量，并且添加了事件功能后被触发&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;created&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;完成数据绑定之后，模板编译之前被触发&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ready&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;模板已经编译并且生成了 Virtual DOM 之后被触发&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;destroyed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;在页面被销毁时调用&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/script&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;init内一般用于初始化一些内部变量，绑定一些自定义事件，这时还没有数据绑定，没有创建vdom，所以不能通过this获取到data和methods，也不能获取vdom的节点&lt;/p&gt;

&lt;p&gt;created 完成了数据绑定 ，但还未开始编译模板，可以通过this获取data和methods，但不能获取vdom的节点&lt;/p&gt;

&lt;p&gt;ready表示渲染完成 ，从子组件往上触发&lt;/p&gt;

&lt;p&gt;destroyed 组件销毁，比如页面跳转，从子组件开始往上触发&lt;/p&gt;

&lt;h3 id=&quot;weex的工作原理&quot;&gt;Weex的工作原理&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://res.infoq.com/articles/introducing-weex/zh/resources/QQ20160428162545.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://res.infoq.com/articles/introducing-weex/zh/resources/QQ20160428162748.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cloud.githubusercontent.com/assets/206848/11239145/0b0bd8e4-8e25-11e5-86e1-704adcfc6141.PNG&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.infoq.com/cn/articles/introducing-weex&quot;&gt;Weex详解：灵活的移动端高性能动态化方案 - 勾股&amp;amp;鬼道&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/amfe/article/issues/14&quot;&gt;对无线电商动态化方案的思考（二）&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;页面间通信&quot;&gt;页面间通信&lt;/h3&gt;

&lt;p&gt;页面跳转是通过指定下一个页面的url，然后通过openurl或者push的方式来跳转&lt;/p&gt;

&lt;p&gt;获取url的方式可以通过下面这段JS代码&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;function getAppBaseUrl(self) {
    var dir ='examples'
    var url = self.$getConfig().bundleUrl;
    var bundleUrl = url;
    bundleUrl = new String(bundleUrl);

    var nativeBase;
    var isAndroidAssets = bundleUrl.indexOf('file://assets/') &amp;gt;= 0;

    var isiOSAssets = bundleUrl.indexOf('file:///') &amp;gt;= 0;
    if (isAndroidAssets) {
      nativeBase = 'file://assets/';
    }
    else if (isiOSAssets) {
      nativeBase = bundleUrl.substring(0, bundleUrl.lastIndexOf('/') + 1);
    }
    else {
      var host = 'localhost:12580';
      var matches = /\/\/([^\/]+?)\//.exec(self.$getConfig().bundleUrl);
      if (matches &amp;amp;&amp;amp; matches.length &amp;gt;= 2) {
        host = matches[1];
      }
      nativeBase = 'http://' + host + '/' + dir + '/build/';
    }
    var h5Base = './index.html?page=./' + dir + '/build/';
    //Native端
    var base = nativeBase;
    //H5端
    if (typeof window === 'object') {
      base = h5Base;
    }
    return base
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://vczero.github.io/weex-learning/006_navigation.html&quot;&gt;第六篇 导航、页面跳转、stream、webview&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;页面通信有两种方式&lt;/p&gt;

&lt;p&gt;1.通过 url 参数传递。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/**
 * 获取URL参数
 */
getUrlParam: function (key) {
    var t = this.$getConfig().bundleUrl;
    var reg = new RegExp('[?|&amp;amp;]' + key + '=([^&amp;amp;]+)');
    var match = t.match(reg);
    return match &amp;amp;&amp;amp; match[1];
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;2.通过 localStorage 数据存储。&lt;/p&gt;

&lt;p&gt;如果是组件间通信不是页面通信，则参考：&lt;a href=&quot;https://github.com/weexteam/article/issues/16&quot;&gt;组件之间通信 - (Communicate Between Components)&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;boxmodel--flexbox&quot;&gt;boxmodel &amp;amp; flexbox&lt;/h3&gt;

&lt;p&gt;weex支持boxmodel 和flexbox&lt;/p&gt;

&lt;p&gt;下面这个是boxmodel&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://www.w3school.com.cn/i/ct_boxmodel.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;关于flexbox，可以看我的这篇文章[react-native的第一课&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;flexbox布局](http://coderyi.com/posts/react-native_first_lesson/#flexbox布局)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;weex的缺点&quot;&gt;weex的缺点&lt;/h3&gt;

&lt;p&gt;1.Weex将整个app的宽度定死在750px，然后其他都是根据scale进行计算的，会导致适配不方便。&lt;/p&gt;

&lt;p&gt;2.目前不支持iOS的presentViewController方法&lt;/p&gt;

&lt;p&gt;3.很多组件和模块需要自己扩展（比如datepicker，iconfont，摄像头，二维码等）&lt;/p&gt;

&lt;h3 id=&quot;几个小问题&quot;&gt;几个小问题&lt;/h3&gt;

&lt;p&gt;1.之前weex是只支持es5，现在可以支持es6了。&lt;a href=&quot;http://weex.help/topic/578c9649ac4eeead13b2a8f1&quot;&gt;精华 新版weex-loader@0.3.0-alpha，欢迎试用&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2.怎么断点调试？&lt;/p&gt;

&lt;p&gt;目前是可以断点调试的，可以参考下面文章&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/weexteam/article/issues/50&quot;&gt;Weex调试神器——Weex Devtools使用手册 &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/h5weex/h5weex-books/blob/master/%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/%E7%BA%BF%E4%B8%8A%E8%B0%83%E8%AF%95.md&quot;&gt;线上调试&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3.weex支持本地图片吗？&lt;/p&gt;

&lt;p&gt;根据官方答疑是可以的，但是我目前还没有尝试成功。&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/alibaba/weex/blob/doc/doc/faq.md#use-local-image&quot;&gt;faq:use-local-image&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4.&lt;a href=&quot;https://github.com/Jinjiang/weex-x&quot;&gt;weex-x&lt;/a&gt;的使用？&lt;/p&gt;

&lt;p&gt;5.promise怎么使用？&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/alibaba/weex/issues/1269&quot;&gt;issues - 1269&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;6.热更新方案是什么？&lt;/p&gt;

&lt;p&gt;最后，希望有越来越多的人把weex用起来。&lt;/p&gt;

</description>
        <pubDate>Mon, 17 Oct 2016 00:00:00 +0800</pubDate>
        <link>http://localhost:4000/posts/weex1/</link>
        <guid isPermaLink="true">http://localhost:4000/posts/weex1/</guid>
        
        <category>Weex</category>
        
        
        <category>iOS</category>
        
      </item>
    
      <item>
        <title>react-native的第一课</title>
        <description>&lt;p&gt;2016-01-22&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/coderyi&quot;&gt;coderyi&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#react-用于构建用户界面的javascript库&quot;&gt;React-用于构建用户界面的JavaScript库&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#flexbox布局&quot;&gt;Flexbox布局&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#组件的生命周期&quot;&gt;组件的生命周期&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#navigator&quot;&gt;Navigator&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#react-native与原生交互&quot;&gt;react-native与原生交互&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#es6与es5&quot;&gt;ES6与ES5&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#promise&quot;&gt;Promise&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#fetch&quot;&gt;fetch&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#npm&quot;&gt;npm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;react-用于构建用户界面的javascript库&quot;&gt;React-用于构建用户界面的JavaScript库&lt;/h3&gt;

&lt;p&gt;React是作为MVC中V存在的，React有一个JSX的编译器，JSX 让你可以用 HTML 语法去写 JavaScript 函数调用。&lt;/p&gt;

&lt;p&gt;举例JSX是以下写法：&lt;/p&gt;

&lt;pre&gt;
&amp;lt;div&amp;gt;
     &amp;lt;MyLabel  text={TextLabel} /&amp;gt;
     &amp;lt;MyTextfield /&amp;gt;
     &amp;lt;MyButton textlabel='OK' /&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;

&lt;p&gt;如果不经过JSX转化，你就必须用下面JavaScript的写法：&lt;/p&gt;

&lt;pre&gt;
React.createElement(&quot;div&quot;, null, 
     React.createElement(MyLabel, {text: TextLabel}), 
     React.createElement(MyTextfield, null), 
     React.createElement(MyButton, {textlabel: &quot;OK&quot;}))
&lt;/pre&gt;

&lt;p&gt;其实如果是写界面，JSX的XML风格就看起来比JavaScript人性化了。&lt;/p&gt;

&lt;p&gt;React 可以渲染 HTML 标签 (strings) 或 React 组件 (classes)，React 的 JSX 里约定分别使用首字母大、小写来区分本地组件的类和 HTML 标签。&lt;/p&gt;

&lt;p&gt;React 使用 Virtual DOM 来渲染 UI，当组件状态 state 有更改的时候，React 会自动调用组件的 render 方法重新渲染整个组件的 UI。&lt;/p&gt;

&lt;p&gt;React之所以快，就是因为没有直接操作DOM，组件 DOM 结构就是映射到这个虚拟 DOM 上，React 在这个虚拟 DOM 上实现了一个 diff 算法，当要更新组件的时候，会通过 diff 寻找到要变更的 DOM 节点，再把这个修改更新到浏览器实际的 DOM 节点上，所以实际上不是真的渲染整个 DOM 树。这个虚拟 DOM 是一个纯粹的 JS 数据结构，所以性能会比原生 DOM 快很多。&lt;/p&gt;

&lt;p&gt;React 操作具体可以看下图：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://www.ibm.com/developerworks/cn/web/wa-react-intro/figure1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Flux是Facebook用来构建用户端的web应用的应用程序体系架构。它通过利用数据的单向流动为React的可复用的视图组件提供了补充。Flux应用主要包括三部分：dispatcher、store和views（React components）,dispatcher处理动作分发，维护Store之间的依赖关系，store是数据和逻辑部分，views是React组件，这一层可以看作controller-views,作为视图同时响应用户交互，最后其实还有一个action部分，提供dispatcher传递数据给store&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://facebook.github.io/flux/img/flux-simple-f8-diagram-explained-1300w.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;参考链接：&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://reactjs.cn/react/index.html&quot;&gt;React-中文文档&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.ibm.com/developerworks/cn/web/wa-react-intro/&quot;&gt;React：创建可维护、高性能的 UI 组件&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://wiki.jikexueyuan.com/project/react-tutorial/&quot;&gt;极客学院-React 入门教程&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;flexbox布局&quot;&gt;Flexbox布局&lt;/h3&gt;

&lt;p&gt;Flex布局主要思想是让容器有能力让其子项目能够改变其宽度、高度(甚至顺序)，以最佳方式填充可用空间（主要是为了适应所有类型的显示设备和屏幕大小）。&lt;/p&gt;

&lt;p&gt;基本上，伸缩项目是沿着主轴（main axis），从主轴起点（main-start）到主轴终点（main-end）或者沿着侧轴（cross axis），从侧轴起点（cross-start）到侧轴终点（cross-end）排列。&lt;/p&gt;

&lt;p&gt;这里可以看一下flexbox的几个主要属性&lt;/p&gt;

&lt;p&gt;flex-direction（适用于伸缩容器，也就是伸缩项目的父元素）&lt;/p&gt;

&lt;p&gt;这个主要用来创建主轴，从而定义了伸缩项目放置在伸缩容器的方向。&lt;/p&gt;

&lt;pre&gt;
flex-direction: row | row-reverse | column | column-reverse	

&lt;/pre&gt;

&lt;p&gt;flex-wrap(适用于伸缩容器)
这个主要用来定义伸缩容器里是单行还是多行显示，侧轴的方向决定了新行堆放的方向。&lt;/p&gt;

&lt;pre&gt;
flex-wrap: nowrap | wrap | wrap-reverse	

&lt;/pre&gt;

&lt;p&gt;justify-content（适用于伸缩容器）&lt;/p&gt;

&lt;p&gt;这个是用来定义伸缩项目沿着主轴线的对齐方式。当一行上的所有伸缩项目都不能伸缩或可伸缩但是已经达到其最大长度时，这一属性才会对多余的空间进行分配。&lt;/p&gt;

&lt;pre&gt;
justify-content: flex-start | flex-end | center | space-between | space-around	

&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.css-tricks.com/wp-content/uploads/2013/04/justify-content.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;align-item（适用于伸缩容器）&lt;/p&gt;

&lt;p&gt;这个主要用来定义伸缩项目可以在伸缩容器的当前行的侧轴上对齐方式。可以把他想像成侧轴（垂直于主轴）的“justify-content”。&lt;/p&gt;
&lt;pre&gt;
align-items: flex-start | flex-end | center | baseline | stretch	

&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.css-tricks.com/wp-content/uploads/2013/04/align-content.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;align-content(适用于伸缩容器)&lt;/p&gt;

&lt;p&gt;这个属性主要是伸缩容器多行是主轴的对齐方式&lt;/p&gt;
&lt;pre&gt;
align-content: flex-start | flex-end | center | space-between | space-around | stretch	

&lt;/pre&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.css-tricks.com/wp-content/uploads/2014/05/align-items.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;参考链接：&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.w3cplus.com/css3/a-guide-to-flexbox.html&quot;&gt;一个完整的Flexbox指南&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;组件的生命周期&quot;&gt;组件的生命周期&lt;/h3&gt;

&lt;p&gt;React组件的生命周期如下图：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://7rf9ir.com1.z0.glb.clouddn.com/3-3-component-lifecycle.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;所以组件生命周期就是有三个阶段：&lt;/p&gt;

&lt;p&gt;实例化：当首次使用组件类时&lt;/p&gt;

&lt;p&gt;存在期：当实例已经生成，修改属性时&lt;/p&gt;

&lt;p&gt;销毁期：当组件卸载消亡时&lt;/p&gt;

&lt;p&gt;参考链接：&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.race604.com/react-native-component-lifecycle/&quot;&gt;React Native 中组件的生命周期&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;navigator&quot;&gt;Navigator&lt;/h3&gt;

&lt;p&gt;Navigator和NavigatorIOS都可以用来管理应用中“场景”的导航（也可以称作屏幕）。导航器建立了一个路由栈，用来弹出，推入或者替换路由状态。主要的区别在于NavigatorIOS使用了iOS中的UINavigationController类，而Navigator则完全用js重写了一个类似功能的React组件。&lt;/p&gt;

&lt;p&gt;关于Navigator，可以看一下下面的示例：&lt;/p&gt;
&lt;pre&gt;
// index.ios.js

var {
    View,
    Navigator
} = React;
var FirstPageComponent = require('./FirstPageComponent');

var SampleComponent = React.createClass({
    render: function() {
        var defaultName = 'FirstPageComponent';
        var defaultComponent = FirstPageComponent;
        return (
        &amp;lt;Navigator
          initialRoute={ { name: defaultName, component: defaultComponent } }
          configureScene={() =&amp;gt; {
            return Navigator.SceneConfigs.VerticalDownSwipeJump;
          }}
          renderScene={(route, navigator) =&amp;gt; {
            let Component = route.component;
            if(route.component) {
              return &amp;lt;Component {...route.params} navigator={navigator} /&amp;gt;
            }
          }} /&amp;gt;
        );

    }
});
&lt;/pre&gt;

&lt;p&gt;initialRoute={ { name: defaultName, component: defaultComponent } } 这个指定了默认的页面，也就是启动app之后会看到界面的第一屏。 需要填写两个参数: name 跟 component。&lt;/p&gt;

&lt;p&gt;configureScene 这个是页面之间跳转时候的动画，具体有哪些？可以看这个目录下，有源代码的: node_modules/react-native/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js&lt;/p&gt;

&lt;p&gt;renderScene,我们先看到回调里的两个参数:route, navigator。route里其实就是我们传递的name,component。navigator是一个Navigator的对象，这里是返回route.component组件，然后navigator作为props传递给了这个component，我们可以在FirstPageComponent里面通过props.navigator拿到。&lt;/p&gt;

&lt;pre&gt;
//FirstPageComponent.js
var {
    View,
    Text,
    TouchableOpacity
} = React;

var SecondPageComponent = require('./SecondPageComponent');

var FirstPageComponent = React.create({
    getInitialState: function() {
        return {
            id: 2,
        };
    },

    componentDidMount: function() {
    },

    _pressButton: function() {
        const { navigator } = this.props;
        if(navigator) {
            navigator.push({
                name: 'SecondPageComponent',
                component: SecondPageComponent,
                //这里多出了一个 params 其实来自于Navigator 里的一个方法的参数...
                params: {
                    id: this.state.id
                }
            });
        }
    },

    render: function() {
        return (
            &amp;lt;View&amp;gt;
                &amp;lt;TouchableOpacity onPress={this._pressButton}&amp;gt;
                    &amp;lt;Text&amp;gt;点我跳转并传递id&amp;lt;/Text&amp;gt;
                &amp;lt;/TouchableOpacity&amp;gt;
            &amp;lt;/View&amp;gt;
        );
    }
});

&lt;/pre&gt;

&lt;p&gt;在index.ios.js里面有&lt;/p&gt;
&lt;pre&gt;
            return &amp;lt;Component {...route.params} navigator={navigator} /&amp;gt;

&lt;/pre&gt;
&lt;p&gt;“…“就是把route.params每个key作为props的一个属性，所以在FirstPageComponent.js设置的params值，将在它push到的页面接收到。&lt;/p&gt;

&lt;pre&gt;
//SecondPageComponent.js
var {
    View,
    Text,
    TouchableOpacity,
} = React;

var FirstPageComponent = require('./FirstPageComponent');

var SecondPageComponent = React.create({
    getInitialState: function() {
        return {
            id: null
        };
    },
    componentDidMount: function() {
        //这里获取从FirstPageComponent传递过来的参数: id
        this.setState({
            id: this.props.id
        });
    },
    _pressButton: function() {
        const { navigator } = this.props;
        if(navigator) {
            navigator.pop();
        }
    },
    render: function() {
        return (
            &amp;lt;View&amp;gt;
                &amp;lt;Text&amp;gt;获得的参数: id={ this.state.id }&amp;lt;/Text&amp;gt;
                &amp;lt;TouchableOpacity onPress={this._pressButton}&amp;gt;
                    &amp;lt;Text&amp;gt;点我跳回去&amp;lt;/Text&amp;gt;
                &amp;lt;/TouchableOpacity&amp;gt;
            &amp;lt;/View&amp;gt;
        );
    }
});
&lt;/pre&gt;

&lt;p&gt;参考链接：&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://bbs.reactnative.cn/topic/20/%E6%96%B0%E6%89%8B%E7%90%86%E8%A7%A3navigator%E7%9A%84%E6%95%99%E7%A8%8B&quot;&gt;新手理解Navigator的教程&lt;/a&gt; 对于Navigator讲解的特别详细&lt;/p&gt;

&lt;h3 id=&quot;react-native与原生交互&quot;&gt;react-native与原生交互&lt;/h3&gt;
&lt;p&gt;在React Native中，一个“原生模块”就是一个实现了“RCTBridgeModule”协议的Objective-C类，其中RCT是ReaCT的缩写。&lt;/p&gt;

&lt;p&gt;为了实现RCTBridgeModule协议，你的类需要包含RCT_EXPORT_MODULE()宏。这个宏也可以添加一个参数用来指定在Javascript中访问这个模块的名字。如果你不指定，默认就会使用这个Objective-C类的名字。&lt;/p&gt;

&lt;p&gt;JS可以调用Native的方法，
Native代码：&lt;/p&gt;
&lt;pre&gt;
RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location (RCTResponseSenderBlock)callback)
{
  RCTLogInfo(@&quot;Pretending to create an event %@ at %@&quot;, name, location);
  NSArray *events = ...
  callback(@[[NSNull null], events]);
}

&lt;/pre&gt;

&lt;p&gt;JS调用如下&lt;/p&gt;
&lt;pre&gt;
var CalendarManager = require('react-native').NativeModules.CalendarManager;
CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey',(error,events) =&amp;gt; {
        if (error) {
            alert(error)
        }else{
           alert(events)
        };
});
&lt;/pre&gt;

&lt;p&gt;当然Native也可以调用JS
native调用&lt;/p&gt;
&lt;pre&gt;
#import &quot;RCTBridge.h&quot;
#import &quot;RCTEventDispatcher.h&quot;

@implementation CalendarManager

@synthesize bridge = _bridge;

- (void)calendarEventReminderReceived:(NSNotification *)notification
{
  NSString *eventName = notification.userInfo[@&quot;name&quot;];
  [self.bridge.eventDispatcher sendAppEventWithName:@&quot;EventReminder&quot;
                                               body:@{@&quot;name&quot;: eventName}];
}

@end
&lt;/pre&gt;

&lt;p&gt;在JS中订阅该事件&lt;/p&gt;
&lt;pre&gt;
var { NativeAppEventEmitter } = require('react-native');

var subscription = NativeAppEventEmitter.addListener(
  'EventReminder',
  (reminder) =&amp;gt; console.log(reminder.name)
);
...
// 千万不要忘记忘记取消订阅, 通常在componentWillUnmount函数中实现。
subscription.remove();
&lt;/pre&gt;

&lt;p&gt;基于上面的规则，react-native对很多原生模块进行了封装，比如UIView，他们实现RCTViewManager类，RCTViewManager实现了协议RCTBridgeModule，这样JS就可以使用native组件了。&lt;/p&gt;

&lt;p&gt;默认的情况下，react-native只注册一个RCTRootView，&lt;/p&gt;
&lt;pre&gt;
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                      moduleName:@&quot;CommunicateNativeDemo&quot;
                                               initialProperties:nil
                                                   launchOptions:launchOptions];

  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [UIViewController new];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];
&lt;/pre&gt;

&lt;pre&gt;
AppRegistry.registerComponent('CommunicateNativeDemo', () =&amp;gt; CommunicateNativeDemo);

&lt;/pre&gt;

&lt;p&gt;上面代码中注册的RCTRootView就是整个程序的入口，当然如果你有多个入口或者其他方面的需求，也可以注册多个，不native的不同地方使用JS模块。&lt;/p&gt;
&lt;pre&gt;
AppRegistry.registerComponent('FirstView', () =&amp;gt; CommunicateNativeDemo);
AppRegistry.registerComponent('SecondView', () =&amp;gt; CommunicateNativeDemo);
AppRegistry.registerComponent('ThirdView', () =&amp;gt; CommunicateNativeDemo);

&lt;/pre&gt;

&lt;p&gt;然后把这三个组件通过RCTRootView加载到原生上&lt;/p&gt;
&lt;pre&gt;
- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.title = @&quot;First View&quot;;
    AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:delegate.bridge moduleName:@&quot;FirstView&quot;];
    rootView.frame = CGRectMake(20, 84, [UIScreen mainScreen].bounds.size.width - 40, 200);
    [self.view addSubview:rootView];
}
&lt;/pre&gt;

&lt;p&gt;react-native中Obj-C和JavaScript通信原理简单说一下，和我们经常用的bridge差不多，Obj-C调用JavaScript很简单，可以通过webview的stringByEvaluatingJavaScriptFromString:方法调用JavaScript代码；JavaScript调用Obj-C，则是通过web view的代理方法shouldStartLoadWithRequest：来接收JavaScript的网络请求从而实现调用。&lt;/p&gt;

&lt;h3 id=&quot;es6与es5&quot;&gt;ES6与ES5&lt;/h3&gt;

&lt;p&gt;ECMAScript 是 JavaScript 语言的国际标准，JavaScript 是 ECMAScript 的实现。ECMAScript 5和ECMAScript 6分别是2009年和2015年发布的，下面列出一些主要的ES6与ES5的不同写法。&lt;/p&gt;

&lt;h6 id=&quot;引用&quot;&gt;引用&lt;/h6&gt;

&lt;p&gt;在ES5里，如果使用CommonJS标准，引入React包基本通过require进行，代码类似这样：&lt;/p&gt;

&lt;pre&gt;
//ES5
var React = require(&quot;react-native&quot;);
var {
    Image,
    Text,
    PropTypes
} = React;  //引用不同的React Native组件
&lt;/pre&gt;

&lt;p&gt;在ES6里，import写法更为标准&lt;/p&gt;

&lt;pre&gt;
//ES6
import React, {
    Image, 
    Text,
    PropTypes
} from 'react-native';
&lt;/pre&gt;

&lt;h6 id=&quot;导出单个类&quot;&gt;导出单个类&lt;/h6&gt;

&lt;p&gt;在ES5里，要导出一个类给别的模块用，一般通过module.exports来导出&lt;/p&gt;
&lt;pre&gt;
//ES5
var MyComponent = React.createClass({
    ...
});
module.exports = MyComponent;

&lt;/pre&gt;
&lt;p&gt;在ES6里，通常用export default来实现相同的功能：&lt;/p&gt;
&lt;pre&gt;
//ES6
export default class MyComponent extends React.Component{
    ...
}
&lt;/pre&gt;

&lt;h6 id=&quot;给组件定义方法&quot;&gt;给组件定义方法&lt;/h6&gt;

&lt;p&gt;给组件定义方法不再用 名字: function()的写法，而是直接用名字()，在方法的最后也不能有逗号了。&lt;/p&gt;
&lt;pre&gt;
//ES5 
var Photo = React.createClass({
    componentWillMount: function(){

    },
    render: function() {
        return (
            &amp;lt;Image source={this.props.source} /&amp;gt;
        );
    },
});
&lt;/pre&gt;
&lt;pre&gt;
//ES6
class Photo extends React.Component {
    componentWillMount() {

    }
    render() {
        return (
            &amp;lt;Image source={this.props.source} /&amp;gt;
        );
    }
}
&lt;/pre&gt;

&lt;h6 id=&quot;定义组件的属性类型和默认属性&quot;&gt;定义组件的属性类型和默认属性&lt;/h6&gt;

&lt;p&gt;在ES5里，属性类型和默认属性分别通过propTypes成员和getDefaultProps方法来实现&lt;/p&gt;
&lt;pre&gt;
//ES5 
var Video = React.createClass({
    getDefaultProps: function() {
        return {
            autoPlay: false,
            maxLoops: 10,
        };
    },
    propTypes: {
        autoPlay: React.PropTypes.bool.isRequired,
        maxLoops: React.PropTypes.number.isRequired,
        posterFrameSrc: React.PropTypes.string.isRequired,
        videoSrc: React.PropTypes.string.isRequired,
    },
    render: function() {
        return (
            &amp;lt;View /&amp;gt;
        );
    },
});

&lt;/pre&gt;
&lt;p&gt;在ES6里，可以统一使用static成员来实现&lt;/p&gt;
&lt;pre&gt;
//ES6
class Video extends React.Component {
    static defaultProps = {
        autoPlay: false,
        maxLoops: 10,
    };  // 注意这里有分号
    static propTypes = {
        autoPlay: React.PropTypes.bool.isRequired,
        maxLoops: React.PropTypes.number.isRequired,
        posterFrameSrc: React.PropTypes.string.isRequired,
        videoSrc: React.PropTypes.string.isRequired,
    };  // 注意这里有分号
    render() {
        return (
            &amp;lt;View /&amp;gt;
        );
    } // 注意这里既没有分号也没有逗号
}
&lt;/pre&gt;

&lt;h6 id=&quot;初始化state&quot;&gt;初始化state&lt;/h6&gt;

&lt;pre&gt;
//ES5 
var Video = React.createClass({
    getInitialState: function() {
        return {
            loopsRemaining: this.props.maxLoops,
        };
    },
})
&lt;/pre&gt;
&lt;p&gt;ES6下，有两种写法：&lt;/p&gt;

&lt;pre&gt;
//ES6
class Video extends React.Component {
    state = {
        loopsRemaining: this.props.maxLoops,
    }
}
&lt;/pre&gt;
&lt;p&gt;不过我们推荐更易理解的在构造函数中初始化（这样你还可以根据需要做一些计算）：&lt;/p&gt;

&lt;pre&gt;
//ES6
class Video extends React.Component {
    constructor(props){
        super(props);
        this.state = {
            loopsRemaining: this.props.maxLoops,
        };
    }
}
&lt;/pre&gt;

&lt;h6 id=&quot;把方法作为回调提供&quot;&gt;把方法作为回调提供&lt;/h6&gt;

&lt;p&gt;在JS中，this指的是，调用函数的那个对象。在ES5下，React.createClass会把所有的方法都bind一遍，这样可以提交到任意的地方作为回调函数，而this不会变化。&lt;/p&gt;
&lt;pre&gt;
//ES5
var PostInfo = React.createClass({
    handleOptionsButtonClick: function(e) {
        // Here, 'this' refers to the component instance.
        this.setState({showOptionsModal: true});
    },
    render: function(){
        return (
            &amp;lt;TouchableHighlight onPress={this.handleOptionsButtonClick}&amp;gt;
                &amp;lt;Text&amp;gt;{this.props.label}&amp;lt;/Text&amp;gt;
            &amp;lt;/TouchableHighlight&amp;gt;
        )
    },
});

&lt;/pre&gt;

&lt;p&gt;在ES6下，你需要通过bind来绑定this引用，或者使用箭头函数（它会绑定当前scope的this引用）来调用&lt;/p&gt;

&lt;pre&gt;
//ES6
class PostInfo extends React.Component
{
    handleOptionsButtonClick(e){
        this.setState({showOptionsModal: true});
    }
    render(){
        return (
            &amp;lt;TouchableHighlight 
                onPress={this.handleOptionsButtonClick.bind(this)}
                onPress={e=&amp;gt;this.handleOptionsButtonClick(e)}
                &amp;gt;
                &amp;lt;Text&amp;gt;{this.props.label}&amp;lt;/Text&amp;gt;
            &amp;lt;/TouchableHighlight&amp;gt;
        )
    },
}
&lt;/pre&gt;

&lt;p&gt;需要注意的是，不论是bind还是箭头函数，每次被执行都返回的是一个新的函数引用，因此如果你还需要函数的引用去做一些别的事情（譬如卸载监听器），那么你必须自己保存这个引用&lt;/p&gt;

&lt;pre&gt;
// 错误的做法
class PauseMenu extends React.Component{
    componentWillMount(){
        AppStateIOS.addEventListener('change', this.onAppPaused.bind(this));
    }
    componentDidUnmount(){
        AppStateIOS.removeEventListener('change', this.onAppPaused.bind(this));
    }
    onAppPaused(event){
    }
}

&lt;/pre&gt;
&lt;pre&gt;
// 正确的做法
class PauseMenu extends React.Component{
    constructor(props){
        super(props);
        this._onAppPaused = this.onAppPaused.bind(this);
    }
    componentWillMount(){
        AppStateIOS.addEventListener('change', this._onAppPaused);
    }
    componentDidUnmount(){
        AppStateIOS.removeEventListener('change', this._onAppPaused);
    }
    onAppPaused(event){
    }
}
&lt;/pre&gt;
&lt;p&gt;当然你也可以这样做&lt;/p&gt;
&lt;pre&gt;
// 正确的做法
class PauseMenu extends React.Component{
    componentWillMount(){
        AppStateIOS.addEventListener('change', this.onAppPaused);
    }
    componentDidUnmount(){
        AppStateIOS.removeEventListener('change', this.onAppPaused);
    }
    onAppPaused = (event) =&amp;gt; {
        //把方法直接作为一个arrow function的属性来定义，初始化的时候就绑定好了this指针
    }
}
&lt;/pre&gt;

&lt;p&gt;参考链接：&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://bbs.reactnative.cn/topic/15/react-react-native-%E7%9A%84es5-es6%E5%86%99%E6%B3%95%E5%AF%B9%E7%85%A7%E8%A1%A8&quot;&gt;React/React Native 的ES5 ES6写法对照表
&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;promise&quot;&gt;Promise&lt;/h3&gt;

&lt;p&gt;其实已经有一些第三方库实现了 Promise 的功能：Q、when、WinJS、RSVP.js，这些库和 JavaScript 原生 Promise 都遵守一个通用的、标准化的规范：CommonJS组织制定的异步模式编程规范Promises/A+，jQuery 有个类似的方法叫 Deferred，但不兼容 Promises/A+ 规范，于是会有点小问题，使用需谨慎。jQuery 还有一个 Promise 类型，它其实是 Deferred 的缩减版，所以也有同样问题。&lt;/p&gt;

&lt;p&gt;JavaScript是从ES6提供Promise对象的，这里简单讲一下原生的Promise。&lt;/p&gt;

&lt;p&gt;Promise 对象代表一个异步操作，有三种状态：Pending（进行中）、Resolved（已完成，又称 Fulfilled）和 Rejected（已失败）。Promise 对象的状态改变，只有两种可能：从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种情况发生，状态就凝固了，不会再变了，会一直保持这个结果。就算改变已经发生了，你再对 Promise 对象添加回调函数，也会立即得到这个结果。这与事件（Event）完全不同，事件的特点是，如果你错过了它，再去监听，是得不到结果的。&lt;/p&gt;

&lt;pre&gt;
var promise = new Promise(function(resolve, reject) {
 if (/* 异步操作成功 */){
 resolve(value);
 } else {
 reject(error);
 }
});

promise.then(function(value) {
 // success
}, function(value) {
 // failure
});
&lt;/pre&gt;

&lt;p&gt;Promise很好的解决了异步调用的问题，但是ES7 中有了更加标准的解决方案，新增了 async/await 两个关键词。async 可以声明一个异步函数，此函数需要返回一个 Promise 对象。await 可以等待一个 Promise 对象 resolve，并拿到结果。&lt;/p&gt;

&lt;p&gt;async/await 究竟是怎么解决异步调用的写法呢？简单来说，就是将异步操作用同步的写法来写。先来看下最基本的语法（ES7 代码片段）：&lt;/p&gt;
&lt;pre&gt;
const f = () =&amp;gt; {
  return new Promise((resolve, reject) =&amp;gt; {
    setTimeout(() =&amp;gt; {
      resolve(123);
    }, 2000);
  });
};

const testAsync = async () =&amp;gt; {
  const t = await f();
  console.log(t);
};

testAsync();
&lt;/pre&gt;

&lt;p&gt;对比 Promise&lt;/p&gt;

&lt;pre&gt;
const f = () =&amp;gt; {
  return new Promise((resolve, reject) =&amp;gt; {
    setTimeout(() =&amp;gt; {
      resolve(123);
    }, 2000);
  });
};

const testAsync = () =&amp;gt; {
  f().then((t) =&amp;gt; {
    console.log(t);
  });
};

testAsync();
&lt;/pre&gt;

&lt;p&gt;关于异步编程，JS里面还另一种访问就是RxJS，Reactive Programming，RP是什么，RP是针对异步数据流的编程，一定程度而言，RP并不算新的概念。Event Bus、点击事件都是异步流。Rx最近比较流行，下次有时间再看吧！&lt;/p&gt;

&lt;p&gt;参考链接：&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.html5rocks.com/zh/tutorials/es6/promises/&quot;&gt;JavaScript Promises&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.jianshu.com/p/063f7e490e9a&quot;&gt;Javascript 中的神器——Promise&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://segmentfault.com/a/1190000002566697&quot;&gt;JavaScript ES7 中使用 async/await 解决回调函数嵌套问题&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://blog.leancloud.cn/3910/?utm_source=tuicool&amp;amp;utm_medium=referral&quot;&gt;「大概可能也许是」目前最好的 JavaScript 异步方案 async/await&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://segmentfault.com/a/1190000004293922&quot;&gt;RxJS 教程&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;fetch&quot;&gt;fetch&lt;/h3&gt;

&lt;p&gt;JavaScript很长时间通过XMLHttpRequest来执行异步网络请求，XMLHttpRequest是基于事件的。&lt;a href=&quot;https://github.com/github/fetch&quot;&gt;fetch&lt;/a&gt;则是通过Promise来实现的，fetch的返回值是一个Promise对象&lt;/p&gt;

&lt;pre&gt;
fetch('https://mywebsite.com/endpoint/', {
  method: 'POST',
  headers: {
    'Accept': 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    firstParam: 'yourValue',
    secondParam: 'yourOtherValue',
  })
})
&lt;/pre&gt;

&lt;p&gt;如果要异步操作的话&lt;/p&gt;
&lt;pre&gt;
fetch('https://mywebsite.com/endpoint.php')
  .then((response) =&amp;gt; response.text())
  .then((responseText) =&amp;gt; {
    console.log(responseText);
  })
  .catch((error) =&amp;gt; {
    console.warn(error);
  });
&lt;/pre&gt;

&lt;p&gt;使用ES7的async/await语法来发起一个异步调用&lt;/p&gt;
&lt;pre&gt;
async getUsersFromApi() {
  try {
    let response = await fetch('https://mywebsite.com/endpoint/');
    return response.users;
  } catch(error) {
    throw error;
  }
}
&lt;/pre&gt;

&lt;p&gt;ES6中还有生成器（Generator），promise 和生成器（Generator）为开发者进行异步编程带来了极大便利。&lt;/p&gt;

&lt;p&gt;生成器函数其实是基于迭代器实现的，并且有如下的结构：&lt;/p&gt;
&lt;pre&gt;
function *myIterator() {
    while(condition) {
        yield value;    
    }   
}
&lt;/pre&gt;

&lt;p&gt;yield关键字负责返回结果，它会暂停迭代器函数的执行直到它被再一次的调用。它也会记住函数的状态， 而不是在下次执行的时候重新运行一切，它能够有效的记住上一次暂停的地方。&lt;/p&gt;

&lt;p&gt;将Fetch API和生成器组合起来使用的一个场景是长轮询。 长轮询是一种通过客户端不断发送请求给服务器直到获得响应的技术。生成器可以用于这样的场景来不断的yielding响应直到响应包含数据。&lt;/p&gt;

&lt;p&gt;现在让我们编写生成器函数来不断的调用这个API，每次迭代会返回一个Promise对象。&lt;/p&gt;
&lt;pre&gt;
    function *pollForWeatherInfo() {
        while(true) {
            yield fetch('/api/currentWeather', {
                method: 'get'   
            }).then(d =&amp;gt; d.json()); 
        }   
    }
&lt;/pre&gt;

&lt;p&gt;我们需要一个函数来不断的调用这个函数，并且检查每次返回的Promise是否存在天气信息。 可以使用一个在下一次迭代时调用的递归函数来实现，并且只在发现了从服务器返回的值的时候才暂停这一过程。 下面的代码展示了上述过程的实现&lt;/p&gt;
&lt;pre&gt;
function runPolling(generator){
    if(!generator){
        generator = pollForWeatherInfo();
    }

    var p = generator.next();
    p.value.then(function(d){
        if(!d.temperature){
            runPolling(generator);
        } else {
            console.log(d);
        }
    });
}

runPolling();
&lt;/pre&gt;

&lt;p&gt;参考链接：&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/sravikiran/FetchAPI-Generators&quot;&gt;示例代码源码-FetchAPI-Generators&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://wwsun.github.io/posts/async-api-using-fetch-and-generators.html&quot;&gt;使用Fetch API和ES6生成器来构建异步API&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;npm&quot;&gt;npm&lt;/h3&gt;

&lt;p&gt;react-native开发环境需要使用node.js,npm是Node.js默认的模块管理器，是一个命令行下的软件，用来安装和管理node模块。&lt;/p&gt;

&lt;p&gt;Node模块采用npm install命令安装。每个模块可以“全局安装”，也可以“本地安装”。两者的差异是模块的安装位置，以及调用方法。&lt;/p&gt;

&lt;p&gt;“全局安装”指的是将一个模块直接下载到Node的安装目录中，各个项目都可以调用。“本地安装”指的是将一个模块下载到当前目录的node_modules子目录，然后只有在当前目录和它的子目录之中，才能调用这个模块。一般来说，全局安装只适用于工具模块，比如npm和grunt。&lt;/p&gt;

&lt;p&gt;默认情况下，npm install命令是“本地安装”某个模块。&lt;/p&gt;

&lt;pre&gt;
$ npm install [package name]
$ npm install git://github.com/package/path.git
$ npm install git://github.com/package/path.git#0.1.0
$ npm install sax@latest
$ npm install sax@0.1.1
$ npm install sax@&quot;&amp;gt;=0.1.0 &amp;lt;0.2.0&quot;
&lt;/pre&gt;

&lt;p&gt;使用global参数，可以“全局安装”某个模块。global参数可以被简化成g参数。&lt;/p&gt;

&lt;pre&gt;
$ sudo npm install -global [package name]
$ sudo npm install -g [package name]
&lt;/pre&gt;

&lt;p&gt;–save：模块名将被添加到packages.json文件的dependencies，可以简化为参数-S。
–save-dev: 模块名将被添加到packages.json文件的devDependencies，可以简化为参数-D。&lt;/p&gt;

&lt;pre&gt;
$ npm install sax --save
$ npm install node-tap --save-dev
 或者
$ npm install sax -S
$ npm install node-tap -D
&lt;/pre&gt;

&lt;p&gt;npm install默认会安装dependencies字段和devDependencies字段中的所有模块，如果使用production参数，可以只安装dependencies字段的模块。&lt;/p&gt;

&lt;pre&gt;
$ npm install --production

&lt;/pre&gt;

&lt;p&gt;dependencies是项目中依赖的模块，如果你想要开发自己的npm模块，如果有人要使用，那么他们可能不需要你开发使用的外部测试或者文档框架。在这种情况下，最好将这些附属的项目列在devDependencies中。&lt;/p&gt;

&lt;p&gt;参考链接：&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://javascript.ruanyifeng.com/nodejs/npm.html&quot;&gt;npm模块管理器&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/ericdum/mujiang.info/issues/6&quot;&gt;npm的package.json中文文档&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://js.coach/react-native/&quot;&gt;react-native组件库&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Fri, 22 Jan 2016 00:00:00 +0800</pubDate>
        <link>http://localhost:4000/posts/react-native_first_lesson/</link>
        <guid isPermaLink="true">http://localhost:4000/posts/react-native_first_lesson/</guid>
        
        <category>跨平台</category>
        
        
        <category>iOS</category>
        
      </item>
    
  </channel>
</rss>
