UNPKG

13.6 kBMarkdownView Raw
1# weact 用JSX快速开发小程序
2
3[![travis-ci](https://travis-ci.org/haojy/weact.svg?branch=master)](https://travis-ci.org/haojy/weact)
4[![Code coverage](https://codecov.io/gh/haojy/weact/branch/master/graph/badge.svg)](https://codecov.io/github/haojy/weact?branch=master")
5[![Dependence](https://david-dm.org/haojy/weact/status.svg)](https://david-dm.org/haojy/weact)
6[![License](https://img.shields.io/npm/l/weact-cli.svg)](https://github.com/haojy/weact/blob/master/LICENSE)
7
8
9weact实现了用JSX和ES6/7来开发小程序,你可以在一个jsx文件中编写页面或组件,并把关联的JSX代码和引用包编译成小程序代码,然后在*小程序开发者工具*中调试代码。因为使用了JSX和ES标准语法,你可以轻松地把已有的JSX代码重构成小程序,当然你也可以使用喜欢的语法高亮,语法检查器等工具。支持
10
11* JSX,ES6/7标准语法
12* 单文件开发小程序模块
13* 引用NPM包
14* 自动添加组件关系
15* 在jsx文件中编写小程序样式WXSS
16
17## 快速上手
18
19- [ 安装 ](#安装)
20- [ JSX小程序 ](#JSX小程序)
21- [ 生成小程序 ](#生成小程序)
22- [ 从JSX到WXML ](#从JSX到WXML)
23- [ App.jsx ](#App.jsx)
24- [ Page.jsx ](#Page.jsx)
25- [ 模版==函数式Component ](#模版==函数式Component)
26- [ 组件 ](#组件)
27- [ 引用模块 ](#引用模块)
28- [ 命令行用法 ](#命令行用法)
29
30
31### 安装
32---
33
34在项目里安装*weact-cli*,
35```bash
36npm install -D weact-cli
37npx weact
38```
39
40### JSX小程序
41---
42
43让我们开始写一个Hello world的小程序,只需要两个文件:app.jsx,index.jsx, 通常页面代码会被放在`./pages`目录下,
44```
45src/
46├── app.jsx
47└── pages
48 └── index.jsx
49```
50
51weact只把app.jsx作为目标文件,也就是说所有需要的页面需要在app.jsx中被import进来。在这个例子中,只有一个页面index可以import。我们还需要继承`weact.App`来声明小程序的app, 这里只export一个空的类,[ App.jsx ](#App.jsx)会详细说明怎么定义app,
52```javascript
53// src/app.jsx
54import { App } from 'weact'
55import './pages/index.jsx' // app应用的页面,需要import
56
57export default class extends App {
58}
59```
60
61和app一样,所有页面要继承`weact.Page`,并被export才可以。与应用不同的是,页面有`render()`方法来定义显示部分,在render方法里返回JSX标签,在语法上这和React Component的render相同。weact会根据render方法里返回的标签,自动编译出WXML文件,[ 从JSX到WXML ](#从JSX到WXML)会说明如何用JSX写出符合WXML定义的标签。`weact.WXSS`利用ES6字符串模版的能力,可以在jsx中声明符合WXSS语法的样式,这样样式就会被weact编译成对应的WXSS文件。
62
63```javascript
64// src/pages/index.jsx
65import { Page, WXSS } from 'weact'
66
67WXSS`
68.hi {
69 color: blue;
70}
71`
72export default class extends Page {
73 render() {
74 return (
75 <view class="hi">
76 Hello World!
77 </view>
78 )
79 }
80}
81```
82
83这样,一个基于JSX的小程序就完成了。
84> 在[ 实战JSX开发小程序 ](https://github.com/haojy/weact-startup) 中有更多的例子可以参考。
85
86### 生成小程序
87---
88
89上面的代码都存放在`./src`目录下,然后执行
90```bash
91npx weact ./src # 等同于 weact ./src/app.jsx ./dist
92```
93
94在当前目录下会生成`./dist`目录,里面全是根据jsx文件编译出的小程序代码,
95```
96dist/
97├── app.js
98├── app.json
99└── pages
100 └── index
101 ├── index.js
102 ├── index.wxml
103 └── index.wxss
104```
105*微信开发者工具*添加项目,项目目录设置成`./dist`, 然后就可以在模拟器中看到运行结果了。
106
107### 从JSX到WXML
108---
109
110weact可以在语法上把JSX编译成WXML,下面列表给出两种语言的在语法上的对应关系。
111
112语法 | JSX | WXML
113----|-----|-----
114数据绑定 | `<view>{message}</view>` | `<view> {{ message }} </view>`
115属性 | ``<view id={`${prefix}-item}`>hi</view>`` | `<view id="{{prefix}}-item">hi</view>`
116关键字 false | `<view checked={false}>hi</view>` | `<view checked="{{false}}">hi</view>`
117关键字 | `<view checked>hi</view>` | `<view checked="{{true}}">hi</view>`
118三元运算 | `<view hidden={flag ? true: false}>hi</view>` | `<view hidden="{{flag ? true : false}}">hi</view>`
119算数运算 | `<view>{a + b} + {c} + d</view>` | `<view>{{a + b}} + {{c}} + d</view>`
120逻辑判断 | `<view if={length > 5}>hi</view>` | `<view wx:if="{{length > 5}}">hi</view>`
121字符串运算 | `<view>{"hello " + name}</view>` | `<view>{{"hello " + name}}</view>`
122数组 | `<view for={[zero, 1, 2, 3, 4]}>`<br/>&nbsp;&nbsp;`{item}`<br/>`</view>` | `<view wx:for="{{[zero, 1, 2, 3, 4]}}">`<br/>&nbsp;&nbsp;`{{item}}`<br/>` </view>`
123对象 | `<view data={{ foo: 0, bar: 1 }}>hi</view>` | `<view data="{{ foo: 0, bar: 1 }}">hi</view>`
124数据访问 | `<view>{object.key} {array[0]}</view>` | `<view>{{object.key}} {{array[0]}}</view>`
125for 循环 | `<view for={array} key="message">`<br/>&nbsp;&nbsp;`{index}:{item.message}`<br/>`</view>` | `<view wx:for="{{array}}" wx:key="message">`<br/>&nbsp;&nbsp;`{{index}}:{{item.message}}`<br/>`</view>`
126if 条件 | `<view if={condition}>hi</view>` | `<view wx:if="{{condition}}">hi</view>`
127if else | `<view if={x > 5}>1</view>`<br/>`<view elif={x > 2}>2</view>`<br/>`<view else>3</view>` | `<view wx:if="{{x > 5}}">1</view>`<br/>`<view wx:elif="{{x > 2}}">2</view>`<br/>`<view wx:else>3</view>`
128block 条件 | `<block if={true}>`<br/>&nbsp;&nbsp;`<view> 1 </view>`<br/>` </block>` | `<block wx:if="{{true}}">`<br/>&nbsp;&nbsp;`<view> 1 </view>`<br/>` </block>`
129block 循环 | `<block for={[1, 2, 3]}>`<br/>&nbsp;&nbsp;`<view>{index}:{item}</view>`<br/>`</block>` | `<block wx:for="{{[1, 2, 3]}}">`<br/>&nbsp;&nbsp;`<view>{{index}}:{{item}}</view>`<br/>`</block>`
130事件处理 | `<button bindtap={handleTap}>Next</button>`| `<button bindtap="handleTap">Next</button>`
131onXXX == bindxxx | `<button onTap={this.handleTap}>Next</button>` | `<button bindtap="handleTap">Next</button>`
132
133### App.jsx
134---
135
136小程序在json文件中进行全局配置,用JSX把这些配置写成App的类属性,对比参考[ 小程序配置 ](https://mp.weixin.qq.com/debug/wxadoc/dev/framework/config.html)。同样,App的[ 生命周期函数,自定义公共变量,自定义公共函数等属性 ](https://mp.weixin.qq.com/debug/wxadoc/dev/framework/app-service/app.html)都可以写成类属性。weact把app.jsx编译成对应的app.json,app.js, app.wxss。
137
138```javascript
139export default class extends App {
140
141 debug = true
142
143 window = {
144 navigationBarTitleText: '你好,小程序',
145 navigationBarTextStyle: 'black',
146 navigationBarBackgroundColor: '#f4f5f6',
147 backgroundColor: '#f4f5f6',
148 }
149
150 tabBar = {
151 color: '#333333',
152 backgroundColor: '#ffffff',
153 list: [
154 {
155 pagePath: 'pages/index/index', // 编译后js路径
156 text: '🏠',
157 },
158 {
159 pagePath: 'pages/page1/page1',
160 text: 'Page 1',
161 },
162 ],
163 }
164
165 myData = '自定义公共变量',
166
167 hello() { return '自定义公共函数' }
168
169 // 生命周期函数
170 onLaunch() { console.log('app: hello world') }
171 onShow() { console.log('app: yes, I am') }
172 onHide() { console.log('app: just minutes') }
173 onError() { console.log('app: woops') }
174}
175```
176
177### Page.jsx
178---
179
180类似App.jsx,页面的[ 生命周期函数和其他属性 ](https://mp.weixin.qq.com/debug/wxadoc/dev/framework/app-service/page.html)也写成Page的类属性。除此之外,
181- Page的`render()`函数定义页面显示,
182- 标签使用参考[小程序基础组件](https://mp.weixin.qq.com/debug/wxadoc/dev/component/)
183- 组件的事件处理函数在Page中直接定义类函数
184
185```javascript
186export default class extends Page {
187
188 data = {
189 // 页面数据
190 }
191
192 myData = '自定义公共变量',
193
194 handleTap() { console.log('自定义公共函数') }
195
196 // 生命周期函数
197 onLoad() { console.log('page index: loading...') }
198 onShow() { console.log('page index: yes, I am') }
199 onReady() { console.log('page index: I am ready now') }
200 onHide() { console.log('page index: just minutes') }
201 onUnload() { console.log('page index: bye...') }
202 onReachBottom() { console.log('page index: we get to the most bottom') }
203 onPullDownRefresh() { console.log('page index: pull down') }
204 onPageScroll() { console.log('page index: scrolling...') }
205 onShareAppMessage() { console.log('page index: share this') }
206
207 render() {
208 return (
209 <view>
210 Hello World!
211 <button onTap={this.handleTap}>下一页</button>
212 <navigator url="/pages/page1/page1">跳转到Page 1</navigator>
213 <navigator url="/pages/page2/page2">跳转到Page 2</navigator>
214 </view>
215 )
216 }
217}
218
219```
220
221
222### 模版==函数式Component
223---
224
225小程序的模版可以理解成,没有状态的函数式Component。weact会把返回JSX标签的函数编译成模版,使用这类组件时,只要确保import的名字和定义的一样就可以。
226
227```javascript
228// src/components/flex.jsx
229export default function flex({
230 direction,
231}) {
232 return (
233 <view>
234 <view class="section">
235 <view>flex-direction: ${direction}</view>
236 <view style={`display:flex;flex-direction:${direction};`}>
237 <view class="flex-item bc_green">1</view>
238 <view class="flex-item bc_red">2</view>
239 <view class="flex-item bc_blue">3</view>
240 </view>
241 </view>
242 </view>
243 )
244}
245```
246
247```javascript
248
249// src/pages/index.jsx
250import { Page } from 'weact'
251import flex from '../components/flex.jsx'
252
253
254export default class extends Page {
255 render() {
256 return (
257 <view>
258 <flex direction="row" />
259 <flex direction="column" />
260 </view>
261 )
262 }
263}
264```
265
266### 组件
267---
268
269用weact自定组件更类似写*react Component*,像Page一样显示声明继承Compnent类就可以。组件的属性可以用`propTypes``defaultProps`来定义,分别对应着`properties[...].type``properties[...].value`。属性类型由`weact.PropTypes`定义如下
270
271PropTypes | 小程序属性类型
272----------|-------------
273*string* | *String*
274*number* | *Number*
275*bool* | *Boolean*
276*object* | *Object*
277*array* | *Array*
278
279在下面的例子里*a**b*就是组件属性。如果你了解*react*,你会比较熟悉这种定义Component的方式。
280另外,自定义的方法和事件响应函数可以直接定义为类属性,weact在编译时把这些函数放在`methods`属性里。
281
282```javascript
283import { Component, PropTypes } from 'weact'
284export default class extends Component {
285 static propTypes = {
286 a: PropTypes.string
287 b: PropTypes.bool
288 }
289 static defaultProps = {
290 a: 'world',
291 b: true,
292 }
293 state = {
294 open: true,
295 x: 'hi',
296 item: {
297 index: 0,
298 time: '2016-09-15'
299 }
300 }
301
302 render() {
303 const { a, b } = this.props
304 const { open } = this.state
305 return (
306 <view>
307 <view x={b} y="str">hi {a} </view>
308 <view for={[1, 2, 3]} > </view>
309 <view for={array} for-index="i" for-item="node"> </view>
310 </view>
311 )
312 }
313}
314```
315
316#### 组件关系
317
318weact会根据父子组件的引用关系,自动编译出`relations`的定义。来看看下面的例子,父组件parent引用了子组件child。
319
320```javascript
321// ./parent.jsx
322import { Component, PropTypes } from 'weact'
323import child from './child.jsx'
324export default class extends Component {
325 render() {
326 return (
327 <view>
328 父级组件
329 <child />
330 </view>
331 )
332 }
333}
334```
335
336```javascript
337// ./child.jsx
338import { Component, PropTypes } from 'weact'
339export default class extends Component {
340 render() {
341 return (
342 <view>
343 子级组件
344 </view>
345 )
346
347 }
348}
349```
350
351weact编译后在各自的js文件里自动生成关系定义,而不用手动定义。
352```javascript
353// ./parent.js
354 relations: {
355 "../child/child": {
356 type: "child"
357 }
358 },
359```
360```javascript
361// ./child.js
362 relations: {
363 "../parent/parent": {
364 type: "parent"
365 }
366 },
367```
368### 引用模块
369---
370
371虽然小程序暂不支持直接引入NPM包,但支持类CommonJS的模块引用。weact在语法上实现ES模块间引用, 用*babel-plugin-transform-modules-commonjs*解析成CommonJS的包;NPM包也会被拷贝到*modules*目录下。*weact*模块并没有代码存在,暂时只为了符合语法。
372
373import方式 | JS/JSX | 小程序
374----------|--------|-------
375模块间 | `import reducer from './reducer'` | `var _reducer = require("./reducer.js");`
376NPM包 | `import redux from 'redux'` | `var _redux = require("modules/redux.js");`
377引用Page | `import './pages/index.jsx'` | *app.json* `{"pages":["pages/index/index"]}`
378引用Component | `import Component from '../components/Component.jsx'` | *\*.json*: `{"usingComponents":{"Component":"../../components/Component/Component"}}`
379引用Template | `import MsgItem from './MsgItem.jsx'` | *wxml* `<import src="../MsgItem.wxml" />`
380
381> 引用的NPM包需用npm或yarn安装
382
383### 命令行用法
384
385使用: weact [options] <source> <target>
386
387- source 源码目录路径或app.jsx文件路径
388- target 代码生成路径=./dist
389
390options:
391* -v, --version 显示版本
392* -h, --help 显示当前内容
393* -w, --watch Watch源码变化,自动更新代码
394
395__例子__:
396
397- 在当前路径./dist目录下生成代码
398
399`weact examples/01.hello.world/`
400
401- 指定代码生成路径
402
403`weact examples/01.hello.world/ ./your_distribution`
404
405- watch模式, 根据源码改动,自动更新生成代码
406
407`weact -w examples/01.hello.world/`
\No newline at end of file