初步认识Weex

相比较于React Native的“Learn once, write anywhere”,Weex的口号是“Write once, run everywhere”。考虑到React Native比较任性的向下兼容性,我们也引入了Weex做一番了解。

本文主要分为以下几个部分:构建Hello World程序;集成到现有的iOS工程中;使用Weex的高级特性;如何为Weex做贡献;

Weex入门

1.1 Hello Weex

参考官方教程,我们需要先安装Node。在Mac上也可以通过Homebrew直接进行安装:brew install node

接着我们需要安装Weex CLI:npm install -g weex-toolkit,并确保版本号大于0.1.0:

<code class="hljs brainfuck has-numbering"><span class="hljs-comment">$</span> <span class="hljs-comment">weex</span> <span class="hljs-literal">-</span><span class="hljs-literal">-</span><span class="hljs-comment">version</span>
<span class="hljs-comment">info</span> <span class="hljs-comment">0</span><span class="hljs-string">.</span><span class="hljs-comment">3</span><span class="hljs-string">.</span><span class="hljs-comment">4</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li></ul>

至此,准备工作已经到位,我们可以开始编写Weex程序了。
创建一个名为helloweex.we的文件,并编写以下代码:

<code class="hljs xml has-numbering"><span class="hljs-tag"><<span class="hljs-title">template</span>></span>
  <span class="hljs-tag"><<span class="hljs-title">div</span>></span>
    <span class="hljs-tag"><<span class="hljs-title">text</span>></span>Hello Weex<span class="hljs-tag"></<span class="hljs-title">text</span>></span>
  <span class="hljs-tag"></<span class="hljs-title">div</span>></span>
<span class="hljs-tag"></<span class="hljs-title">template</span>></span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>

通过命令行在helloweex.we文件所在的目录下执行如下命令:

<code class="hljs vhdl has-numbering">$ weex helloweex.we 
info Fri Jul <span class="hljs-number">08</span> <span class="hljs-number">2016</span> <span class="hljs-number">14</span>:<span class="hljs-number">30</span>:<span class="hljs-number">31</span> GMT+<span class="hljs-number">0800</span> (CST)WebSocket  <span class="hljs-keyword">is</span> listening <span class="hljs-keyword">on</span> <span class="hljs-keyword">port</span> <span class="hljs-number">8082</span> 
info Fri Jul <span class="hljs-number">08</span> <span class="hljs-number">2016</span> <span class="hljs-number">14</span>:<span class="hljs-number">30</span>:<span class="hljs-number">31</span> GMT+<span class="hljs-number">0800</span> (CST)http  <span class="hljs-keyword">is</span> listening <span class="hljs-keyword">on</span> <span class="hljs-keyword">port</span> <span class="hljs-number">8081</span> </code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul>

此时,浏览器会打开一个新的标签页展示helloweex.we的执行效果:

_2016_07_08_2_34_04

注意到此时地址栏的内容http://127.0.0.1:8081/weex_tmp/h5_render/?hot-reload_controller&page=helloweex.js&loader=xhr包含着hot reload字样,所以可以自然联想到当我们在源文件做修改并保存后,该页面会自动刷新展示效果。

1.2 基础结构

上面的示例只是一个非常简单的雏形,而一个比较完整的Weex程序包括三个部分:模板(Template)、样式(Style)和脚本(Script)。

比如我们可以利用上文提到的hot reload,修改文本的颜色并实时查看效果:

<code class="hljs xml has-numbering"><span class="hljs-tag"><<span class="hljs-title">template</span>></span>
  <span class="hljs-tag"><<span class="hljs-title">div</span>></span>
    <span class="hljs-tag"><<span class="hljs-title">text</span> <span class="hljs-attribute">class</span>=<span class="hljs-value">"title"</span>></span>Hello Weex<span class="hljs-tag"></<span class="hljs-title">text</span>></span>
  <span class="hljs-tag"></<span class="hljs-title">div</span>></span>
<span class="hljs-tag"></<span class="hljs-title">template</span>></span>

<span class="hljs-tag"><<span class="hljs-title">style</span>></span><span class="css">
  <span class="hljs-class">.title</span> <span class="hljs-rules">{ <span class="hljs-rule"><span class="hljs-attribute">color</span>:<span class="hljs-value"> red</span></span>; <span class="hljs-rule">}</span></span>
</span><span class="hljs-tag"></<span class="hljs-title">style</span>></span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul>

_2016_07_08_2_47_03

接着我们添加上第三组成部分:脚本(Script):

<code class="hljs xml has-numbering"><span class="hljs-tag"><<span class="hljs-title">template</span>></span>
  <span class="hljs-tag"><<span class="hljs-title">div</span>></span>
    <span class="hljs-tag"><<span class="hljs-title">text</span> <span class="hljs-attribute">class</span>=<span class="hljs-value">"title"</span> <span class="hljs-attribute">onclick</span>=<span class="hljs-value">"onClickTitle"</span>></span>Hello Weex<span class="hljs-tag"></<span class="hljs-title">text</span>></span>
  <span class="hljs-tag"></<span class="hljs-title">div</span>></span>
<span class="hljs-tag"></<span class="hljs-title">template</span>></span>

<span class="hljs-tag"><<span class="hljs-title">style</span>></span><span class="css">
  <span class="hljs-class">.title</span> <span class="hljs-rules">{ <span class="hljs-rule"><span class="hljs-attribute">color</span>:<span class="hljs-value"> red</span></span>; <span class="hljs-rule">}</span></span>
</span><span class="hljs-tag"></<span class="hljs-title">style</span>></span>

<span class="hljs-tag"><<span class="hljs-title">script</span>></span><span class="javascript">
  module.exports = {
    methods: {
      onClickTitle: <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(e)</span> {</span>
        console.log(e);
        alert(<span class="hljs-string">'title clicked.'</span>);
      }
    }
  }
</span><span class="hljs-tag"></<span class="hljs-title">script</span>></span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li></ul>

这样一来,当我们点击文本的时候会出现如下效果:

_2016_07_08_2_50_33

更多语法相关内容可以参考官方文档

集成到iOS工程

2.1 概述

上面是从前端的角度来初步看Weex的基础效果,对于客户端来讲,这类框架的一个优势就是能够结合Native代码发挥作用。比如在人手紧张的情况下可以一次开发,然后应用在不同平台终端上。

所以,这里讨论下如何将其集成到现有的iOS工程项目当中。

  1. 参考官方文档,我们先从GitHub下载Weex源码
  2. 解压后将目录下的ios/sdk复制到现有的iOS工程目录下,并根据相对路径更新既有工程的podfile,然后执行pod update将Weex iOS SDK集成进既有的iOS项目中;
  3. 在iOS Native代码中初始化Weex SDK,然后创建出要展示Weex程序的ViewController,具体见如下描述;

2.2 在iOS应用上运行Weex程序

如何集成的文档中,前面说的比较清楚,但是在初始化Weex环境渲染Weex实例这两个小节中,可能是由于代码是从比较大的项目源码中摘录出来的,所以存在一些不必要或没有上下文的代码。

这里描述下在开发调试阶段运行Weex程序。

2.2.1 确定要运行的Weex程序

创建一个WeexDebugViewController,进行如下布局:

_2016_07_08_3_19_12

通过填入IP和文件名来定位我们要运行的Weex程序。此外,还可以结合weex helloweex.we --qr -h {ip or hostname}命令来生成二维码,进行扫描演示,不过解析二维码还是为了获取到Weex程序所在位置。

2.2.2 初始化Weex SDK

开发调试阶段我们可以先将Weex SDK的初始化放在这个WeexDebugViewController中:

<code class="hljs bash has-numbering">- (void)initWeex {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [WXAppConfiguration <span class="hljs-keyword">set</span>AppGroup:@<span class="hljs-string">"AliApp"</span>];
        [WXAppConfiguration <span class="hljs-keyword">set</span>AppName:@<span class="hljs-string">"WeexDemo"</span>];
        [WXAppConfiguration <span class="hljs-keyword">set</span>AppVersion:@<span class="hljs-string">"1.0.0"</span>];

        [WXSDKEngine initSDKEnviroment];

        [WXLog <span class="hljs-keyword">set</span>LogLevel:WXLogLevelVerbose];
    });
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul>

2.2.3 运行Weex程序的ViewController

点击ShowWeex按钮时,我们可以根据两个输入框的内容拼接出要运行的Weex程序的位置,然后将其赋值给用来渲染Weex实例的WeexShowcaseViewController

<code class="hljs objectivec has-numbering">- (<span class="hljs-keyword">void</span>)showWeex {
    <span class="hljs-built_in">NSString</span> *str = [<span class="hljs-built_in">NSString</span> stringWithFormat:@<span class="hljs-string">"http://%@:8081/%@"</span>, <span class="hljs-keyword">self</span><span class="hljs-variable">.ipField</span><span class="hljs-variable">.text</span>, <span class="hljs-keyword">self</span><span class="hljs-variable">.filenameField</span><span class="hljs-variable">.text</span>];
    WeexShowcaseViewController *vc = [WeexShowcaseViewController new];
    vc<span class="hljs-variable">.weexUri</span> = [<span class="hljs-built_in">NSURL</span> URLWithString:str];
    [<span class="hljs-keyword">self</span><span class="hljs-variable">.navigationController</span> pushViewController:vc animated:<span class="hljs-literal">YES</span>];
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>

接着我们来看看WeexShowcaseViewController的源码:

<code class="hljs objectivec has-numbering"><span class="hljs-preprocessor">#import <span class="hljs-title"><WeexSDK/WeexSDK.h></span></span>

<span class="hljs-class"><span class="hljs-keyword">@interface</span> <span class="hljs-title">WeexShowcaseViewController</span> ()</span>

<span class="hljs-keyword">@property</span> (<span class="hljs-keyword">nonatomic</span>, <span class="hljs-keyword">strong</span>) WXSDKInstance *weexSDK;

<span class="hljs-keyword">@end</span>

<span class="hljs-class"><span class="hljs-keyword">@implementation</span> <span class="hljs-title">WeexShowcaseViewController</span></span>

- (<span class="hljs-keyword">void</span>)dealloc {
    [_weexSDK destroyInstance];
}

- (<span class="hljs-keyword">void</span>)viewDidLoad {
    [<span class="hljs-keyword">super</span> viewDidLoad];
    <span class="hljs-comment">// Do any additional setup after loading the view.</span>

    <span class="hljs-keyword">self</span><span class="hljs-variable">.weexSDK</span><span class="hljs-variable">.viewController</span> = <span class="hljs-keyword">self</span>;
    <span class="hljs-keyword">self</span><span class="hljs-variable">.weexSDK</span><span class="hljs-variable">.frame</span> = <span class="hljs-keyword">self</span><span class="hljs-variable">.view</span><span class="hljs-variable">.frame</span>;

    [<span class="hljs-keyword">self</span><span class="hljs-variable">.weexSDK</span> renderWithURL:<span class="hljs-keyword">self</span><span class="hljs-variable">.weexUri</span>];

    __<span class="hljs-keyword">weak</span> typeof(<span class="hljs-keyword">self</span>) weakSelf = <span class="hljs-keyword">self</span>;
    <span class="hljs-keyword">self</span><span class="hljs-variable">.weexSDK</span><span class="hljs-variable">.onCreate</span> = ^(<span class="hljs-built_in">UIView</span> *view) {
        [weakSelf<span class="hljs-variable">.view</span> addSubview:view];
    };

    <span class="hljs-keyword">self</span><span class="hljs-variable">.weexSDK</span><span class="hljs-variable">.renderFinish</span> = ^(<span class="hljs-built_in">UIView</span> *view) {
        ;
    };

    <span class="hljs-keyword">self</span><span class="hljs-variable">.weexSDK</span><span class="hljs-variable">.onFailed</span> = ^(<span class="hljs-built_in">NSError</span> *error) {
        <span class="hljs-built_in">NSLog</span>(@<span class="hljs-string">"weexSDK onFailed : %@\n"</span>, error);
    };
}

- (WXSDKInstance *)weexSDK {
    <span class="hljs-keyword">if</span> (!_weexSDK) {
        _weexSDK = [WXSDKInstance new];
    }
    <span class="hljs-keyword">return</span> _weexSDK;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li></ul>

2.2.4 运行起来

回到终端上,切换到helloweex.we文件所在的目录,将Weex的dev server跑起来:

<code class="hljs livecodeserver has-numbering">$ weex -s .
info Fri Jul <span class="hljs-number">08</span> <span class="hljs-number">2016</span> <span class="hljs-number">15</span>:<span class="hljs-number">38</span>:<span class="hljs-number">59</span> GMT+<span class="hljs-number">0800</span> (CST)<span class="hljs-keyword">http</span>  is listening <span class="hljs-command"><span class="hljs-keyword">on</span> <span class="hljs-title">port</span> <span class="hljs-title">8081</span> </span>
info we <span class="hljs-built_in">file</span> <span class="hljs-operator">in</span> <span class="hljs-built_in">local</span> path . will be transformer <span class="hljs-built_in">to</span> JS bundle
please access <span class="hljs-keyword">http</span>://<span class="hljs-number">30.9</span><span class="hljs-number">.112</span><span class="hljs-number">.173</span>:<span class="hljs-number">8081</span>/ </code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>

然后在Native上填入对应的IP和程序文件名:

_2016_07_08_3_47_33

_2016_07_08_3_47_43

到此,将Weex集成到现有iOS工程中算初步告一段落。

Weex进阶

当集成工作完成后,会发觉现有功能不足以满足业务需求,所以Weex支持开发者做一些扩展。

3.1 实现Weex接口协议

之前的helloweex.we示例中只有一个文本元素,现在再添加一个图片元素:

<code class="hljs xml has-numbering"><span class="hljs-tag"><<span class="hljs-title">template</span>></span>
  <span class="hljs-tag"><<span class="hljs-title">div</span>></span>
    <span class="hljs-tag"><<span class="hljs-title">image</span> <span class="hljs-attribute">class</span>=<span class="hljs-value">"thumbnail"</span> <span class="hljs-attribute">src</span>=<span class="hljs-value">"http://image.coolapk.com/apk_logo/2015/0817/257251_1439790718_385.png"</span>></span><span class="hljs-tag"></<span class="hljs-title">image</span>></span>
    <span class="hljs-tag"><<span class="hljs-title">text</span> <span class="hljs-attribute">class</span>=<span class="hljs-value">"title"</span> <span class="hljs-attribute">onclick</span>=<span class="hljs-value">"onClickTitle"</span>></span>Hello Weex<span class="hljs-tag"></<span class="hljs-title">text</span>></span>
  <span class="hljs-tag"></<span class="hljs-title">div</span>></span>
<span class="hljs-tag"></<span class="hljs-title">template</span>></span>

<span class="hljs-tag"><<span class="hljs-title">style</span>></span><span class="css">
  <span class="hljs-class">.title</span> <span class="hljs-rules">{ <span class="hljs-rule"><span class="hljs-attribute">color</span>:<span class="hljs-value"> red</span></span>; <span class="hljs-rule">}</span></span>
  <span class="hljs-class">.thumbnail</span> <span class="hljs-rules">{ <span class="hljs-rule"><span class="hljs-attribute">width</span>:<span class="hljs-value"> <span class="hljs-number">100</span></span></span>; <span class="hljs-rule"><span class="hljs-attribute">height</span>:<span class="hljs-value"> <span class="hljs-number">100</span></span></span>; <span class="hljs-rule">}</span></span>
</span><span class="hljs-tag"></<span class="hljs-title">style</span>></span>

<span class="hljs-tag"><<span class="hljs-title">script</span>></span><span class="javascript">
  module.exports = {
    methods: {
      onClickTitle: <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(e)</span> {</span>
        console.log(e);
        alert(<span class="hljs-string">'title clicked.'</span>);
      }
    }
  }
</span><span class="hljs-tag"></<span class="hljs-title">script</span>></span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li></ul>

然后再执行:$ weex helloweex.we来运行查看效果:

_2016_07_08_4_28_01

可以在浏览器里看到这次多了一张图片。但是如果是运行在Native端,图片则得不到展示:

_2016_07_08_4_37_08

这是由于Weex SDK没有提供图片下载能力,需要我们来实现。

3.2 实现图片下载协议WXImgLoaderProtocol

这个基本可以参考官方文档来实现。

3.2.1 定义图片下载Handler

<code class="hljs objectivec has-numbering"><span class="hljs-preprocessor">#import <span class="hljs-title"><WeexSDK/WeexSDK.h></span></span>

<span class="hljs-class"><span class="hljs-keyword">@interface</span> <span class="hljs-title">WeexImageDownloader</span> : <span class="hljs-title">NSObject</span> <<span class="hljs-title">WXImgLoaderProtocol</span>></span>

<span class="hljs-keyword">@end</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>

3.2.2 实现协议接口

这个类必须遵循WXImgLoaderProtocol协议,并实现该协议定义的接口:

<code class="hljs objectivec has-numbering"><span class="hljs-preprocessor">#import <span class="hljs-title">"WeexImageDownloader.h"</span></span>
<span class="hljs-preprocessor">#import <span class="hljs-title"><SDWebImage/SDWebImageManager.h></span></span>

<span class="hljs-class"><span class="hljs-keyword">@implementation</span> <span class="hljs-title">WeexImageDownloader</span></span>

- (<span class="hljs-keyword">id</span><WXImageOperationProtocol>)downloadImageWithURL:(<span class="hljs-built_in">NSString</span> *)url
                                          imageFrame:(<span class="hljs-built_in">CGRect</span>)imageFrame
                                            userInfo:(<span class="hljs-built_in">NSDictionary</span> *)options
                                           completed:(<span class="hljs-keyword">void</span>(^)(<span class="hljs-built_in">UIImage</span> *image,  <span class="hljs-built_in">NSError</span> *error, <span class="hljs-built_in">BOOL</span> finished))completedBlock {
    <span class="hljs-keyword">return</span> (<span class="hljs-keyword">id</span><WXImageOperationProtocol>)[[SDWebImageManager sharedManager] downloadImageWithURL:[<span class="hljs-built_in">NSURL</span> URLWithString:url] options:<span class="hljs-number">0</span> progress:^(<span class="hljs-built_in">NSInteger</span> receivedSize, <span class="hljs-built_in">NSInteger</span> expectedSize) {
    } completed:^(<span class="hljs-built_in">UIImage</span> *image, <span class="hljs-built_in">NSError</span> *error, SDImageCacheType cacheType, <span class="hljs-built_in">BOOL</span> finished, <span class="hljs-built_in">NSURL</span> *imageURL) {
        <span class="hljs-keyword">if</span> (completedBlock) {
            completedBlock(image, error, finished);
        }
    }];
}

<span class="hljs-keyword">@end</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li></ul>

3.2.3 注册Handler

<code class="hljs css has-numbering"><span class="hljs-attr_selector">[WXSDKEngine registerHandler:[WeexImageDownloader new]</span> <span class="hljs-tag">withProtocol</span>:<span class="hljs-at_rule">@<span class="hljs-keyword">protocol(WXImgLoaderProtocol)];</span></span></code><ul style="" class="pre-numbering"><li>1</li></ul><ul style="" class="pre-numbering"><li>1</li></ul>

这样一来,再次运行程序就可以看到图片了:

_2016_07_08_5_45_09

这样设计的好处主要是考虑了不同App依赖的网络库或者图片下载缓存库不同,避免Weex强依赖于一些第三方库,遵循依赖抽象而不是具体的原则。

BTW,我个人感觉Weex缩写成WXWeexImageLoaderProtocol缩写成WXImgLoaderProtocol,不是很好看。

3.2 自定义UI组件

如果Weex的内置标签不足以满足要求时,我们可以自定义Native组件,然后暴露给.we文件使用。

比如我们可以定义一个WeexButton,继承自WXComponent,然后将其注册进Weex SDK:

<code class="hljs ruby has-numbering">[<span class="hljs-constant">WXSDKEngine</span> <span class="hljs-symbol">registerComponent:</span>@<span class="hljs-string">"weex-button"</span> <span class="hljs-symbol">withClass:</span>[<span class="hljs-constant">WeexButton</span> <span class="hljs-class"><span class="hljs-keyword">class</span>]];</span></code><ul style="" class="pre-numbering"><li>1</li></ul><ul style="" class="pre-numbering"><li>1</li></ul>

这样一来,我们就可以在.we文件中使用这个标签了:

<code class="hljs xml has-numbering"><span class="hljs-tag"><<span class="hljs-title">weex-button</span> <span class="hljs-attribute">class</span>=<span class="hljs-value">"button"</span> <span class="hljs-attribute">title</span>=<span class="hljs-value">"hello"</span>></span><span class="hljs-tag"></<span class="hljs-title">weex-button</span>></span></code><ul style="" class="pre-numbering"><li>1</li></ul><ul style="" class="pre-numbering"><li>1</li></ul>

标签中的属性我们可以在初始化函数中获得:

<code class="hljs objectivec has-numbering">- (instancetype)initWithRef:(<span class="hljs-built_in">NSString</span> *)ref
                       type:(<span class="hljs-built_in">NSString</span>*)type
                     styles:(nullable <span class="hljs-built_in">NSDictionary</span> *)styles
                 attributes:(nullable <span class="hljs-built_in">NSDictionary</span> *)attributes
                     events:(nullable <span class="hljs-built_in">NSArray</span> *)events
               weexInstance:(WXSDKInstance *)weexInstance {
    <span class="hljs-keyword">self</span> = [<span class="hljs-keyword">super</span> initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">self</span>) {
        _title = [WXConvert <span class="hljs-built_in">NSString</span>:attributes[@<span class="hljs-string">"title"</span>]];
    }
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">self</span>;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul>

通过这些属性,我们可以在组件生命周期中修改组件的样式,比如设置按钮的title:

<code class="hljs objectivec has-numbering">- (<span class="hljs-keyword">void</span>)viewDidLoad {
    [<span class="hljs-keyword">super</span> viewDidLoad];

    <span class="hljs-keyword">self</span><span class="hljs-variable">.innerButton</span> = [<span class="hljs-built_in">UIButton</span> buttonWithType:UIButtonTypeRoundedRect];
    <span class="hljs-keyword">self</span><span class="hljs-variable">.innerButton</span><span class="hljs-variable">.frame</span> = <span class="hljs-keyword">self</span><span class="hljs-variable">.view</span><span class="hljs-variable">.bounds</span>;
    [<span class="hljs-keyword">self</span><span class="hljs-variable">.view</span> addSubview:<span class="hljs-keyword">self</span><span class="hljs-variable">.innerButton</span>];
    [<span class="hljs-keyword">self</span><span class="hljs-variable">.innerButton</span> setTitle:<span class="hljs-keyword">self</span><span class="hljs-variable">.title</span> forState:UIControlStateNormal];
    [<span class="hljs-keyword">self</span><span class="hljs-variable">.innerButton</span> addTarget:<span class="hljs-keyword">self</span> action:<span class="hljs-keyword">@selector</span>(onButtonClick:) forControlEvents:UIControlEventTouchUpInside];
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul>

3.3 自定义模块

除了UI组件之外,有些时候我们希望JS层面能够调用Native的一些功能,比如通过JS代码让Native打开一个特定的ViewController。这时候,我们可以自定义一个模块向JS层面暴露API:

<code class="hljs objectivec has-numbering"><span class="hljs-keyword">@synthesize</span> weexInstance;

WX_EXPORT_METHOD(<span class="hljs-keyword">@selector</span>(call:withParam:callback:))
- (<span class="hljs-keyword">void</span>)call:(<span class="hljs-built_in">NSString</span> *)api withParam:(<span class="hljs-built_in">NSDictionary</span> *)param callback:(WXModuleCallback)callback {</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>

注意点如下:
1. 需要遵循WXModuleProtocol协议;
2. 需要合成(synthesizeweexInstance属性;
3. 使用WX_EXPORT_METHOD来暴露API;
4. 使用WXModuleCallback进行回调;

完成以上编码后,向Weex SDK注册:[WXSDKEngine registerModule:,就可以在.we文件中使用了:

<code class="hljs xml has-numbering"><span class="hljs-tag"><<span class="hljs-title">script</span>></span><span class="javascript">
  module.exports = {
    methods: {
      onClickTitle: <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(e)</span> {</span>
        <span class="hljs-keyword">var</span> mymodule = <span class="hljs-built_in">require</span>(<span class="hljs-string">'@weex-module/mymodule'</span>);
        mymodule.call(<span class="hljs-string">'api'</span>, {}, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(ret)</span> {</span>
        });
      }
    }
  }
</span><span class="hljs-tag"></<span class="hljs-title">script</span>></span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul>

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值