## 扩展 Weex HTML5
0.4 [cn](https://github.com/weexteam/article/issues/11)
### 简介
Weex是一个高可扩展性的跨平台动态化开发方案,你可以在现有组件基础上定制自己需要的三端组件。你可以为Weex API模块添加新的方法,或者创建新的API模块和新的加载器。按照以下几个步骤扩展你的组件,API或者加载器。
首先要明确的是,组件和API模块是基于weex的扩展,但是独立于weex,组件的定义本身是不需要依赖于weex的,这样有助于组件的分散化管理,去除中心化依赖。
其次,当你扩展一个组件,你需要同时扩展三端的组件(android, ios和web端),毕竟weex是一个重视三端一致体验的跨平台移动框架。你可以一个端一个端的扩展,也可以召唤其他端上的开发者来共同完成你在其他端上的组件(你总是可以在社区找到对某个功能有共同需求的开发者)。这里有一些在`android`端和`ios`端做扩展的文档可以参考。
你应该将你的扩展发布到weex开发者可以方便找到和使用的渠道,比如`npm`. 我们推荐你将你开发的组件发布到`npm`供其他weex开发者使用。
最重要的是,你的组件的命名需要遵守weex组件命名规范:以`weex-`开头作为组件的前缀,并且以`-<platform>`做为结尾后缀,除非你发布的包是三端的实现都包含在内的。这里有个`<weex-hello-web>`的例子作为参考,这里注册了一个简单的自定义的组件。
### 创建新组件
步骤:
1. 在你的组件实现中必须继承`Weex.Component`这个类, 并选择性的重写其中的一些方法.
2. 你的组件的exports需要暴露一个`init`方法,并在其中使用`Weex.registerComponent`注册你的组件.
3. 导出安装所需的 `init` 方法 (每一个 `weex-html5` 扩展必须在`export`类中含有 `init` 方法,用于另一个weex项目来`install`)
这里用一个例子展示如何扩展一个新的组件
~~~
const attr = {
// ...
}
const style = {
// ...
}
const event = {
// ...
}
// 每个扩展组件都需要实现一个init方法,Weex会通过这方法进行安装和注册.
function init (Weex) {
const Component = Weex.Component
const extend = Weex.utils.extend
// 组件的构造函数
function Hello (data) {
Component.call(this, data)
}
// prototype继承
Hello.prototype = Object.create(Component.prototype)
extend(Hello.prototype, proto)
// 配置属性、样式以及事件
extend(Hello.prototype, { attr })
extend(Hello.prototype, {
style: extend(Object.create(Component.prototype.style), style)
})
extend(Hello.prototype, { event })
Weex.registerComponent('weex-hello', Hello)
}
// 暴露init方法接口.
export default { init }
~~~
上述代码摘引自 [weex-hello-web/src/index.js](https://github.com/MrRaindrop/weex-hello-web/blob/master/src/index.js#L46-L65).
这个demo重写了基类Component中的`create`方法。你也可以选择重写Component中的一些其他方法来定制组件的行为。典型的方法包括:
* `create`: 创建组件的节点,在方法体中return这个节点.
* `createChildren` 创建子节点.
* `insertBefore` 在某个子节点之前插入一个新的子节点.
* `appendChild` 在子节点列表的最后加上一个节点.
* `removeChild` 移除一个子节点.
进阶: 更多关于组件定制和扩展的细节和代码展示,可以参考[weex主仓库的代码](https://github.com/alibaba/weex/tree/dev/html5/browser/extend/components),这里的组件基本上都是通过上述方式进行定义的。
重要的一点,注册组件的关键方法是`Weex.registerComponent`,如示例里的`weex-hello`组件的注册:
~~~
Weex.registerComponent('weex-hello', Hello)
~~~
上述代码摘引自 [weex-hello-web/src/index.js](https://github.com/MrRaindrop/weex-hello-web/blob/master/src/index.js#L62)
在某个需要使用该组件的weex项目中使用`Weex.install`方法安装该组件:
~~~
// import the original weex-html5.
import weex from 'weex-html5'
import hello from 'weex-hello'
// install the component.
weex.install(hello)
~~~
上述代码引自 [weex_extend_demo/src/main.js](https://github.com/MrRaindrop/weex_extend_demo/blob/master/src/main.js#L1-L5)
在你的`.we`文件中直接使用这个组件:
~~~
<template>
<div>
<weex-hello class="hello" style="txt-color:#fff;bg-color:green"
value="WEEX" onclick="handleClick">
</weex-hello>
</div>
</template>
~~~
上述代码引自[weex_extend_demo/demo/index.we](https://github.com/MrRaindrop/weex_extend_demo/blob/master/demo/index.we#L10-L15)
### 扩展API
你可以扩展新的API模块,或者为某个已有的模块添加新的API. 比如,你可以添加一个API模块叫做user,在里面添加一些用户登录登出处理的API,比如login, logout等等。你可以通过`require('@weex-module/moduleName)[methodName](arg1, arg2, ...)`(Module APIs)的方式调用你的API.
步骤:
1. 实现你的API module.
2. 在你的API安装模块里暴露一个`init`方法,并在这个方法里面使用`Weex.registerAPIModules` 注册你的API module.
这里用一个例子展示如何扩展一个新的API模块
创建一个文件`user.js`,在其中定义登录登出`login/logout`方法.
~~~
const user = {
// 定义用户登录方法.
login (callbackId) {
login.then(res => {
this.sender.performCallback(callbackId, res)
}).catch(err => {
this.sender.performCallback(callbackId, err)
})
},
// 定义用户登出方法.
logout (callbackId) {
logout.then(res => {
this.sender.performCallback(callbackId, res)
}).catch(err => {
this.sender.performCallback(callbackId, err)
})
}
}
// 定义user模块的元 (meta) 信息.
const meta = {
user: [{
name: 'login',
args: ['function']
}, {
name: 'logout',
args: ['function']
}]
}
export default {
init (Weex) {
// 注册这个模块,最后一个参数是模块的元信息.
Weex.registerApiModule('user', user, meta)
}
}
~~~
这个简单的user helper模块就实现好了,可以发布到npm上,我们可以给这个模块取个名字,比如说`weex-user-helper`。
在你的新的weex项目里安装这个模块:
~~~
import Weex from 'weex-html5'
import user from 'weex-user-helper'
Weex.install(user)
~~~
安装了这个模块,你就可以在dsl代码里引用这个模块干点事情了:
~~~
<template>
<div>
<div class="btn" onclick="handleClick">
<text>LOGIN</text>
</div>
</div>
</template>
<script>
var userHelper = require('@weex-module/user')
module.exports = {
methods: {
handleClick: function () {
userHelper.login(function () {
// ... do sth. in callback.
})
}
}
}
</script>
~~~
### 定制加载器loader
Loader仅用于weex-html5 (web端)加载dsl打包出来的bundle代码,native平台有其他的加载机制
已有的加载器包括`xhr`, `jsonp`和`source`. 你可以使用`weex.registerLoader`注册一个新的加载器。例如,你有一个获取`weex bundle`的服务`myServe.getWeexBundle`, 通过这个服务可以加载`weex bundle`,为此你可以定义一个加载器:
~~~
function loadByMyServe(pageId, callback) {
myServe.getWeexBundle(pageId).then(function (bundle) {
callback(bundle)
}).catch(function(err) {
callback(err)
})
}
// 暴露init方法用于Weex安装此加载器.
export default {
init (Weex) {
Weex.registerLoader('myserve', loadByMyServe)
}
}
~~~
在你的weex-html5项目的启动文件里安装并使用这个加载器:
~~~
import Weex from 'weex-html5'
// 或者import from './myserve.js',不管是import一个npm模块还是import一个文件.
import loader from 'myLoader'
Weex.install(loader)
// 在init方法里使用这个加载器加载bundle文件.
(function () {
function getUrlParam (key) {
const reg = new RegExp('[?|&]' + key + '=([^&]+)')
const match = location.search.match(reg)
return match && match[1]
}
const page = getUrlParam('page') || 'examples/build/index.js'
Weex.init({
appId: location.href,
loader: 'myserve', // 使用刚才定义的loader类型
source: page,
rootId: 'weex'
})
})();
~~~
以上是weex带来的扩展性里比较主要的一部分,更多实现细节可以在[weex代码库](https://github.com/alibaba/weex)以及weex的开源社区里找到。
- 快速上手教程
- 语法综述
- 数据绑定
- 样式和类
- 事件
- 显示逻辑控制
- 渲染逻辑控制
- 组件封装
- 找节点
- 组件通讯
- 页面配置和数据
- 自定义与调试
- 浏览器中预览
- 原生中预览
- 自定义原生组件
- 自定义原生接口
- H5渲染器调试
- 第三方库使用
- 将代码转换为Js Bundle
- 进阶教程
- 原理概述
- 数据绑定实现原理
- 集成到Android工程
- 集成到iOS
- 集成H5
- Android扩展
- iOS扩展
- H5扩展
- 参考内容
- 自举(Bootstrap)
- 组件定义
- 实例APIs
- 内置组件
- 通用属性
- 通用样式
- 文本样式
- 颜色
- 通用事件
- 特殊元素
- div
- scroller
- [list]
- [cell]
- [text]
- [image]
- [input]
- [switch]
- [slider]
- [indicator]
- [video]
- [a]
- [web]
- [wxc-tabbar]
- [wxc-navpage]
- 内置模块
- [dom]
- [stream]
- [modal]
- [animation]
- [navgator]
- 错误
- [JS Bundle Format]
- [JS Framework APIs]
- [Vitual DOM APIs]
- 案例
- Hello World
- Modal
- List
- Slider
- Animation
- More
- 服务和工具
- 命令行工具
- 开发工具
- 安卓开发工具
- IOS开发工具
- Transformer
- Playground App
- 帮助文档
- 视频教程