最新weex已经改为支持Vue,旧的代码.we代码随着更新迭代也会替换掉。项目还在继续推进weex的使用,随后会更新最新一些自己使用weex-vue的总结。
以下为旧版weex开发流程:
因
公司的app大量采用 hybrid 开发。iOS 在使用UIWebView时会消耗大量系统资源。 WKWebVIew 会是一个很好的解决方案。但是公司前端资源紧缺,让前端人员给iOS端做适配成本太高。
果
iOS端首先试用Weex。如果可以的话,不止可以替换原有的web界面,复用网页接口。还可以开发一些强排版的native界面,成熟之后,安卓直接使用。
参考文档
开发环境
- macOS 10.12.1
- atom (安装 language-weex 高亮)
- iTerm2
- homebrew
- brew install node //通过brew安装node
- npm install -g weex-toolkit *//通过node安装 weex-toolkit *
初始化工程
- 创建文件夹
$ mkdir bookcover
- 进入
bookcover
,初始化Weex工程
weex init
得到以下文件
prompt: Project Name: (detail) bookcover
file: .gitignore created.
file: README.md created.
file: index.html created.
file: package.json created.
file: src/weex-bootstrap.we created.
file: webpack.config.js created.
* 安装 package.json 中的依赖
``` npm install ```
` node_modules/` 会创建很多依赖文件
如果提示
`npm WARN babel-loader@6.2.5 requires a peer of babel-core@^6.0.0 but none was installed.
`
执行以下命令
` npm install babel-core`
* 编译项目
`npm run dev`
* 启动轻量服务器
`npm run serve`
打开浏览器,输入http://127.0.0.1:8080, 就会看到这个项目的效果.
以上步骤,一个weex 的基本项目已经创建好了。看详细讲解,可以看上边的两个链接和weex源码。
### 开始创建自己的 .we 文件
源码都在 `src` 目录下,现在已经包含一个`weex-bootstrap.we` 文件。
#### 查看源码 (三部分)
打开文件
`$ atom weex-bootstrap.we`
##### 布局 (View)
<template>
<div class="ct" style="height: {{ctHeight}}">
<image class="img" style="width: 400px; height: 400px;" src="{{img}}"></image>
<text style="font-size: 42;">Hello Weex!</text>
</div>
</template>
> template 是模板的意思,这样创建.we 的模板,其他文件调用时,使用文件名作为模板名字。 例如:`first.we`
// index.we
<template>
<div>
<first></first> // 模板名称
...
</div>
</template>
##### 样式
<style>
.ct {
width: 750;
align-items: center;
justify-content: center;
}
.img {
margin-bottom: 20px;
}
</style>
##### 数据+交互 (ViewModel)
<script>
module.exports = {
** 数据部分 **
data: {
ctHeight: 800,
img: '//gw.alicdn.com/tps/i2/TB1DpsmMpXXXXabaXXX20ySQVXX-512-512.png_400x400.jpg'
},
** 逻辑 **
ready: function () {
this.ctHeight = this.$getConfig().env.deviceHeight
}
}
</script>
### 组件间通讯
[参考 Weex 组件通讯](http://alibaba.github.io/weex/cn/doc/syntax/comm.html)
##### 从子组件向父组件通信
// 子视图代码 发送事件
test: function () {
this._parent.$emit('notify', {a: 1})
}
// 父视图代码 监听
this.$on('notify', function(event) {
}
`notify` 为父视图方法
`{a: 1}` 传给父视图的参数
##### 从父组件向子组件通信
// 父视图vm获取子视图,然后触发 changeImage
test: function (e) {
this.$vm('sub').$emit(
'changeImage',
'https://gtms02.alicdn.com/tps/i2/TB1QHKjMXXXXXadXVXX20ySQVXX-512-512.png' )
}
// 父视图监听 changeImage
方法
created: function() {
this.$on('changeImage', function (e) {
this.imageUrl = e.detail }.bind(this))
}
##### 子组件通讯
weex官网没有写,个人通过以下方法解决: `子视图1 ` -> `父视图` -> `子视图2`
#### We 生命周期
Weex 视图模型现在支持生命周期内的钩子函数,这些钩子函数能被写为组件选项:
* init: 在视图模型的构造函数开始调用时激活;
* created: 当视图模型监听默认数据,但还未编译模板时激活;
* ready: 当视图模型监听默认数据并且编译模板生成虚拟DOM后被激活。
#### 找节点
* 父找子节点
// index.we
<template>
<div>
<first id = 'goto-top'></first> // 模板名称
...
</div>
</template>
``` var el = this.$el('goto-top')```
* 父找子上下文
this.$vm('goto-top').setTitle('Updated')
* 子找父
```this._parent```
### 将 .we 文件打包成 .js
$ weex index.we -o .
得到 `index.js` 文件。
将`index.js` 导入 iOS工作区间。
### 实例
创建文件
├── module
│ ├── chapter.we
│ ├── header.we
│ ├── recommand.we
│ └── urls.js
├── src
│ ├── index.we
* `urls.js` 保存url地址
* `index.we` 为界面主入口
* 其他为子视图
index.we
<template>
<scroller>
<header id='header_id' style="margin-top: 128; " title="你好"></header>
<text onclick='updateTitle' style="padding: 40;">点我试试</text>
<chapter id='lastChapter'></chapter>
<recommand></recommand>
</scroller>
</template>
<script>
require('module/header.we');
require('module/chapter.we');
require('module/recommand.we');
...
</script>
> 因为index.we 为主视图,没有具体视图的实现,所以此处没有<style> 标签。
视图分为是三部分 `header`, `chapter`, `remmend` 。根视图为`scrollview`。
三部分各自请求自己需要说的数据,然后刷新视图。
### 扩展
#### 网络请求 (参考)
created: function() {
// 获取url
var url = apis.getHeaderUrl();
// 获取当前视图 ,在回调中使用this取不到子视图。
var self = this;
// 发送请求
stream.fetch({
method: 'POST',
url: url,
type: 'json',
body: 'bookId=0000&id=000×tamp=1481188025939&sign=000000000000'
}, function(res) {
try {
var result = res.data.state;
if (result == 200) {
var body = res.data.data;
self.initData(body);
modal.toast({
'message': 'header 请求成功',
'duration': 1
})
}else {
modal.toast({
'message': 'header 请求失败',
'duration': 1
})
}
} catch(e) {
modal.toast({
'message': e,
'duration': 1
})
}
}, function(res){
})
},
### Weex 原理
分为**Server** 和 **客户端** ,**服务器下发**
![weex-jsRender.png](http://upload-images.jianshu.io/upload_images/695270-57154d329ac937f7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
**weex 翻译成native**
| weex| native|
|-------|-------|
| style, attribute | WXDomObject |
| div, text,scoller, List... | WXComponent |
| script| WXModule |
| .we| WXSDKInstance |
### iOS支持 Weex
#### 环境
* xcode 8.1
* cocoapods 1.1.1
#### 步骤
* 创建支持pod项目 , `FirstWeex`
编辑Podfile
pod SDWebImage
pod WeexSDK
* 创建图片下载类
`WXImgLoaderDefaultImpl:NSObject<WXImgLoaderProtocol, WXModuleProtocol>`
实现 。iOS9之后记得配置info.plist 打开http请求
-
(id<WXImageOperationProtocol>)downloadImageWithURL:(NSString *)url imageFrame:(CGRect)imageFrame userInfo:(NSDictionary *)userInfo completed:(void(^)(UIImage *image, NSError *error, BOOL finished))completedBlock
{
if ([url hasPrefix:@"//"]) {
url = [@"http:" stringByAppendingString:url];
}
return (id<WXImageOperationProtocol>)[[SDWebImageManager sharedManager] downloadImageWithURL:[NSURL URLWithString:url] options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) {} completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (completedBlock) {
completedBlock(image, error, finished);
}
}];
}
* AppDelegate配置weex
-
(void)initWeex {
[WXAppConfiguration setAppGroup:@"Company"];
[WXAppConfiguration setAppName:@"projectName"];
[WXAppConfiguration setAppVersion:@"1.0"];[WXSDKEngine initSDKEnviroment];
[WXLog setLogLevel:WXLogLevelError];
// 图片下载
[WXSDKEngine registerHandler:[WXImgLoaderDefaultImpl new] withProtocol:@protocol(WXImgLoaderProtocol)];
}
* 加载 ViewController视图
-
(void)viewDidLoad {
[super viewDidLoad];// 加载weex 视图
[self render];
} -
(void)render {
[_instance destroyInstance];_instance = [[WXSDKInstance alloc] init];
_instance.viewController = self;
_instance.frame = CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds));__weak typeof(self) weakSelf = self;
_instance.onCreate = ^(UIView * view) {
[weakSelf.view addSubview:view];
};
_instance.onFailed = ^(NSError *error) {
NSLog(@"render onFailed");};
_instance.renderFinish = ^(UIView *view) {
NSLog(@"render finish");
};NSURL * url = _url;
if (!url) {
url = [[NSBundle mainBundle] URLForResource:@"index" withExtension:@"js"];
}if (url) {
[_instance renderWithURL:url options:@{@"bundleUrl":url.relativeString} data:nil];
}
}
此时会在 ViewController创建的时候,weex界面也会显示。
其实weex的本质也是在UIView,所以像native的视图是一样进行操作。