本文主要介绍包括Weex基本介绍、Weex源码结构、初始化工程、we代码结构、Weex的生命周期、Weex的工作原理、页面间通信、boxmodel & flexbox、weex的缺点
基本介绍
A framework for building Mobile cross-platform UI
怎么解释它呢?我的理解就是weex = react-native +vue ,使用vue的API风格,两端的实现方式则和react-native,weex 比rn的优点就是一次编写三端运行。
IDE: Sublime Text + vue-syntax-highlight
命令行工具:weex-toolkit
调试工具: weex-devtool
weex分为组件component和模块(module)以及事件
weex-components : weex-components
组件 就是各种标记组件,比如div 、slider、indicator等 通过下面这种方式使用
<div>
<image src="..."></image>
<text>...</text>
</div>
js模块
let modal = require('@weex-module/modal');
modal.toast({
"message":"我是提示框",
"duration":2
});
其他的还有stream,dom,animation之类的
事件
<div onviewappear="viewappear" onviewdisappear="viewdisappear">
......
</div>
Weex源码结构
package.json
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
start文件: 启动程序文件,里面包换编译和启动脚本:
examples: 示例Demo
android/ios/html: 各平台代码
build:打包各平台的脚本,配置在package.json中。
初始化工程
初始化工程前需要先安装 homebrew,然后按照下面步骤创建一个工程。
$ brew install node //通过brew安装node
$ npm install -g weex-toolkit //通过node安装 weex-toolkit
$ sudo gem install cocoapods //安装iOS包管理工具 cocoapods
$ weex init //创建项目的文件
$ npm install //依赖安装 package.json文件
$ npm run dev //项目编译
$ npm run serve //启动轻量服务器
这时有可能提示
npm WARN babel-loader@6.2.5 requires a peer of babel-core@^6.0.0 but none was installed.
你需要再
npm install babel-core
这时,打开浏览器,输入http://127.0.0.1:8080, 就会看到这个项目的效果:
参考链接:第3篇 初始化工程
npm run dev 干了什么呢?
先看 package.json 文件
{ "name": "demo1", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "webpack", "dev": "webpack --watch", "serve": "serve -p 8080", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "serve": "^1.4.0", "webpack": "^1.13.1", "weex-html5": "0.2.18", "weex-loader": "^0.1.5" } }
npm run dev实际上相当于 webpack –watch
webpack实际上是执行了默认的webpack.config.js配置文件
webpack.config.js 引入webpack和weex-loader,entry属性是表示入口文件,output表示输出文件,默认输出到dist文件夹。
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'] } ] } }
不过这个自动产生的webpack.config.js的文件有个坑就是,你添加一个新的we文件,他不会自动build为js文件 可以手动添加
entry: {
main: path.join(__dirname, 'src', 'main.we?entry=true'),
translate: path.join(__dirname, 'src', 'translate.we?entry=true')
}
不过推荐的是自己遍历所有的we文件
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() &&
(extname === '.we')) {
var name = path.join(root, 'build', dir, path.basename(file, extname));
entry[name] = fullpath + '?entry=true';
} else if (stat.isDirectory() &&
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']
}
]
}
}
duqian291902259 - webpack.config.js 第3篇 初始化工程
入口文件index.html
这里可以参考 Integrate Weex HTML5 to your project
weex代码结构
template内必须包含唯一的根节点作为父容器, div就是一个很好的选择,里面则是一些Native Components
style 支持盒子模型和Flexbox
weex内置了响应式的支持,页面的宽度是以750来做为标准,自动适配所有手机;
<template>
<div>
<div>子组件</div>
<div>子组件</div>
</div>
</template>
<style>
</style>
<script>
module.exports = {
data: function () {
return {
x: 1,
y: 2
}
}
methods: {
foo: function () {
console.log('foo')
}
},
computed: {
z: function () {
return this.x + this.y
}
},
events: {
custom: function (e) {
console.log(e)
}
},
init: function () {},
created: function () {},
ready: function () {}
}
</script>
script里面包含很多ViewModel Options,
data methods computed init, created, ready events
如果需要在模板里实现更多的逻辑判断,你可以使用’computed property’.
created是生命周期函数,这个时候模板还没有被渲染,常用来在这里定义数据的更新和获取;
ready是生命周期函数,这个时候模板被渲染,常用来做一些自己上报等;
weex- references - Weex Cheat Sheet
显然we文件的这些代码是不会被 native app 识别的,我们要想办法让这些代码可运行。所以我们同时做了三件事:
1.在本地用一个叫做 transformer 的工具把这套代码转成纯 JavaScript 代码
2.在客户端运行一个 JavaScript 引擎,随时接收 JavaScript 代码
3.在客户端设计一套 JS Bridge,让 native 代码可以和 JavaScript 引擎相互通信
所以紧接着第二步,就是用 transformer 对代码进行转换,变成客户端可运行的 JavaScript 代码
原图:本地开发时的 Weex Transformer 工作原理
在 transformer 中,我们主要的工作就是对 HTML、CSS、JavaScript 代码进行解析和重组。这里我们用到了三个非常重要的库:
HTML 解析工具:htmlparser
CSS 解析工具:cssom
JavaScript 解析工具:uglify-js
Weex 的生命周期
<script>
module.exports = {
data: {},
methods: {},
init: function () {
console.log('在初始化内部变量,并且添加了事件功能后被触发');
},
created: function () {
console.log('完成数据绑定之后,模板编译之前被触发');
},
ready: function () {
console.log('模板已经编译并且生成了 Virtual DOM 之后被触发');
},
destroyed: function () {
console.log('在页面被销毁时调用');
}
}
</script>
init内一般用于初始化一些内部变量,绑定一些自定义事件,这时还没有数据绑定,没有创建vdom,所以不能通过this获取到data和methods,也不能获取vdom的节点
created 完成了数据绑定 ,但还未开始编译模板,可以通过this获取data和methods,但不能获取vdom的节点
ready表示渲染完成 ,从子组件往上触发
destroyed 组件销毁,比如页面跳转,从子组件开始往上触发
Weex的工作原理
页面间通信
页面跳转是通过指定下一个页面的url,然后通过openurl或者push的方式来跳转
获取url的方式可以通过下面这段JS代码
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/') >= 0;
var isiOSAssets = bundleUrl.indexOf('file:///') >= 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 && matches.length >= 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
}
页面通信有两种方式
1.通过 url 参数传递。
/**
* 获取URL参数
*/
getUrlParam: function (key) {
var t = this.$getConfig().bundleUrl;
var reg = new RegExp('[?|&]' + key + '=([^&]+)');
var match = t.match(reg);
return match && match[1];
}
2.通过 localStorage 数据存储。
如果是组件间通信不是页面通信,则参考:组件之间通信 - (Communicate Between Components)
boxmodel & flexbox
weex支持boxmodel 和flexbox
下面这个是boxmodel
关于flexbox,可以看我的这篇文章[react-native的第一课
- flexbox布局](http://coderyi.com/posts/react-native_first_lesson/#flexbox布局)
weex的缺点
1.Weex将整个app的宽度定死在750px,然后其他都是根据scale进行计算的,会导致适配不方便。
2.目前不支持iOS的presentViewController方法
3.很多组件和模块需要自己扩展(比如datepicker,iconfont,摄像头,二维码等)
几个小问题
1.之前weex是只支持es5,现在可以支持es6了。精华 新版weex-loader@0.3.0-alpha,欢迎试用
2.怎么断点调试?
目前是可以断点调试的,可以参考下面文章
3.weex支持本地图片吗?
根据官方答疑是可以的,但是我目前还没有尝试成功。
4.weex-x的使用?
5.promise怎么使用?
6.热更新方案是什么?
最后,希望有越来越多的人把weex用起来。