Weex尝鲜
<p>Weex是阿里开源的类React Native技术,其实按知乎上的讨论基本可以说是整合Vue.js+React Native造的轮子( <a href="/misc/goto?guid=4959716521874749547" rel="nofollow,noindex">如何看待阿里无线前端发布的Weex?</a> )。Weex是一款轻量级的移动端跨平台动态性技术解决方案,主要致力于使用Web方式开发出Native性能的App。Weex学习成本较RN相对较低, 可以说就是使用简易版的HTML/CSS/JavaScript以及自定义的一些组件和规则开发.we文件,完成界面控件布局、样式、数据绑定以及简单的事件绑定等。Weex提供了node.js的小工具可以将.we文件转换成js bundle 文件,客户端引入了weex sdk就可以解析js bundle文件,最终完成页面渲染。接下来在简单尝试下weex。</p> <h2><strong>weex配置</strong></h2> <p>.we文件开发其实任何编辑器都可以,不过需要使用Node安装Weex提供的.we文件转换工具,该工具可以将.we文件转换成weex sdk能够识别和解析的js bundle文件。</p> <pre> npm install -g weex-toolkit</pre> <p>主要介绍下Android端配置:</p> <p>1、首先引入weex sdk,gradle添加weex依赖</p> <pre> compile 'com.taobao.android:weex_sdk:0.5.1@aar'</pre> <p>2、确保声明了网络权限</p> <pre> <uses-permission android:name="android.permission.INTERNET" /></pre> <p>3、配置ImageView加载网络图片形式</p> <p>weex需要我们手动配置网络图片加载,否则imageview将无法正常工作。通常我们可以使用第三方图片加载库,这里我引入了Picasso来帮助我们加载网络图片。配置时机可以放在Application初始化中,这样全局有效。</p> <pre> private void initWeex(){ InitConfig.Builder configBuilder = new InitConfig.Builder().setImgAdapter(new IWXImgLoaderAdapter() { @Override public void setImage(String url, ImageView view, WXImageQuality quality, WXImageStrategy strategy) { Picasso.with(getApplicationContext()).load(url).into(view); } }); WXSDKEngine.initialize(this, configBuilder.build()); }</pre> <p>通过以上配置,客户端基本的weex环境也就配置好了。</p> <h2><strong>.we文件开发</strong></h2> <p>.we文件主要包括三大部分, <template></template> 声明组件, <style></style> 定义组件样式, <script></script> 声明组件data、events,业务逻辑处理等,基本类似web端开发。template中可以使用{{}}进行data binding,将script中的data和events绑定到相应的组件中。具体语法不再介绍,下面是一个类似ViewPager的自动轮播banner例子。</p> <pre> <template> <div style="flex-direction: column;"> <slider class="slider" interval="2000" auto-play="true"> <div class="slider-pages" repeat="{{headline}}" onclick="openUrl(headline[$index].url)"> <image class="image" src="{{image}}"></image> <text class="title">{{title}}</text> </div> <indicator class="indicator" if="shouldShowIndicators()"></indicator> </slider> </div> </template> <style> .image { width: 750; height: 260; } .title { margin-top: 20; margin-bottom: 20; text-align: left; flex: 1; color: black; font-size: 35; } .slider { width: 750; height: 450; } .slider-pages { padding-top: 30; flex-direction: column; width: 750; height: 400; } .indicator { height: 20; width: 750; position:absolute; left: 1; bottom: 1; item-color: grey; item-selectedColor: orange; item-size: 20; } </style> <script> var weexModule = require('@weex-module/weexModule'); module.exports = { data: { headline:[] }, methods: { openUrl: function (url) { weexModule.startActivity(url, function(err){ console.log(err); }); }, shouldShowIndicators: function(){ return this.headline.length > 1; } } } </script></pre> <p>style默认屏幕宽度为750px,所以如果组件宽度为整屏宽度,直接定义为750即可。绑定onclick事件,其实只是属性设置并不是方法调用,如果不带对应方法不带参数直接使用方法名即可,但是其他地方如果进行方法调用,必须得加(),表示方法的调用,例如 if="shouldShowIndicators()" 。</p> <h2><strong>自定义Module</strong></h2> <p>在script中我们引用了自定义的Module,负责与Native端通信,处理具体的业务逻辑。要引用自定义Module需要事先使用WXSDKEngine的registerModule方法进行注册,可以在Application启动时注册一些通用的Module,也可以在需要使用时再去注册一些具体业务逻辑Module。</p> <pre> try { WXSDKEngine.registerModule("weexModule", WeexModule.class); } catch (WXException e) { e.printStackTrace(); }</pre> <p>自定义Module时,方法访问权限必须声明为public,并且必须使用@WXModuleAnno注解标识。这里,weexModule是个简单的负责Activity跳转的Module,并且回调了Activity启动结果。对应的WeexModule代码如下:</p> <pre> public class WeexModule extends WXModule { @WXModuleAnno public void startActivity(String url, String cb){ Log.d("weex", "========" + url); boolean error = false; try { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); mWXSDKInstance.getContext().startActivity(intent); } catch (ActivityNotFoundException e) { error = true; } Map<String, Object> result = new HashMap<>(1); result.put("error", error); WXBridgeManager.getInstance().callback(mWXSDKInstance.getInstanceId(), cb, result); } }</pre> <h2><strong>自定义Component</strong></h2> <p>weex目前只支持一些常用的组件,如果有需要,只要遵循weex规范,我们完全可以自定义组件。在配置weex客户端环境时,我们使用了第三方图片请求库Picasso使得imageview能够直接加载url。其实公司项目里已经有了强大的自造轮子——NetworkImageView,我们并不想引用其他库增加App size,但是template中无法直接使用Native组件,我们需要自定义Component进行简单的包装。例如:</p> <pre> @Component(lazyload = false) public class NetworkImageViewComponent extends WXImage { public WeexComponent(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, boolean isLazy) { super(instance, dom, parent, isLazy); } @Override protected void initView() { if (mContext != null) { mHost = new NetworkImageView(mContext); // 替换原生组件 ((NetworkImageView) mHost).setScaleType(ImageView.ScaleType.CENTER_CROP); } } @Override public View getView() { return super.getView(); } @WXComponentProp(name = "url") public void setImageUrl(String url) { ((NetworkImageView) mHost).setImage(url); } }</pre> <p>如上代码所示,通常自定义Component只需要重写initView方法,替换mHost为所需的原生组件即可。使用@WXComponentProp注解可以为组件添加自定义属性,在template中声明组件时设置属性就可以调用对应方法。最后和Module类似,自定义Component也需要向weex注册,可以在Application启动时注册通用Component,也可以在需要时注册业务耦合较大的Component。</p> <pre> try { WXSDKEngine.registerComponent("myimageview", NetworkImageViewComponent.class); } catch (WXException e) { e.printStackTrace(); }</pre> <p>经过以上操作我们已经可以在template中使用我们自定义的MyImageView了。简单修改下.we文件:</p> <pre> <template> <div style="flex-direction: column;"> <slider class="slider" interval="2000" auto-play="true"> <div class="slider-pages" repeat="{{headline}}" onclick="goWeexSite(headline[$index].url)"> <MyImageView class="image" url="{{image}}"></MyImageView> <text class="title">{{title}}</text> </div> <indicator class="indicator" if="shouldShowIndicators()"></indicator> </slider> </div> </template></pre> <p>这里值得注意的是,.we文件中的MyImageView在通过weex自动转换工具转换成的js bundle文件中type被标识为"myimageview",也就是说会转换为全小写,因此在注册Component时应该尽量使用小写key。当然我们也可以手动修改js bundle文件,不过自定义组件多了会比较繁琐。</p> <h2><strong>Native端渲染</strong></h2> <p>客户端渲染工作主要包括解析js bundle文件还原Native端组件,至于数据请求可以直接在Native端发送网络请求,也可以在script中通过js调用weex内置的网络请求Module——WXStreamModule的sendHttp方法进行网络请求,请求到的数据会通过WXBridgeManager回调给js端。测试时为了方便,直接在Native端进行网络请求,然后将请求到的数据塞给weex,weex进行render渲染,渲染成功后更新listview,将最终得到的native view塞进listview。调用weex渲染的主要代码如下:</p> <pre> JSONObject json = new JSONObject(); json.put("headline", array); //key和js端对应,相当于将数据塞进.we文件的data中 String template = WXFileUtils.loadFileContent("weex/index.js", getContext()); if (weexLayout == null) { wxsdkInstance.render("headline", template, null, json.toString(), -1, -2, WXRenderStrategy.APPEND_ASYNC); } else { wxsdkInstance.refreshInstance(json.toString()); }</pre> <p>测试时直接使用的客户端本地的由.we文件转换来的js bundle文件,生产环境通常应该从服务端拉取。需要注意的是,一个WXSDKInstance实例只负责一次页面渲染,如果想重新加载模版渲染页面,需要将WXSDKInstance实例destroy再重新new一个,如果后期只是更新数据直接refresh即可。另外,使用WXSDKInstance.registerRenderListener可以注册对渲染结果的监听。</p> <pre> @Override public void onViewCreated(WXSDKInstance instance, View view) { weexLayout = view; // 首次渲染成功拿到native view } @Override public void onRenderSuccess(WXSDKInstance instance, int width, int height) { adapter.notifyDataSetChanged(); // 更新listview } @Override public void onRefreshSuccess(WXSDKInstance instance, int width, int height) { adapter.notifyDataSetChanged(); // 更新listview } @Override public void onException(WXSDKInstance instance, String errCode, String msg) { Log.d("weex", "=======" + msg); }</pre> <p>onViewCreated会在首次渲染成功后回调,拿到了native view,剩下的一切都非常熟悉了,放到你期望的容器中显示即可。</p> <p> </p> <p>来自:http://www.jianshu.com/p/18fac5db8429</p> <p> </p>
本文由用户 WinfredTrae 自行上传分享,仅供网友学习交流。所有权归原作者,若您的权利被侵害,请联系管理员。
转载本站原创文章,请注明出处,并保留原始链接、图片水印。
本站是一个以用户分享为主的开源技术平台,欢迎各类分享!