Skip to content
weact 用JSX快速开发小程序
JavaScript
Branch: master
Clone or download
jary
jary v0.6.2
Latest commit 7e24868 Feb 18, 2018
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.vscode FIX watching path; ADD help fro cli Jan 1, 2018
examples FIX relation of child Dec 31, 2017
rollup ADD promisify wx Jan 7, 2018
src FIX object rest spread Jan 12, 2018
.eslintrc.yml initial commit Dec 30, 2017
.gitignore
.npmignore
.travis.yml
CHANGELOG.md v0.6.1 Feb 13, 2018
LICENSE initial commit Dec 30, 2017
README.md
package.json v0.6.2 Feb 18, 2018
yarn.lock

README.md

weact 用JSX快速开发小程序

travis-ci Code coverage Dependence License

weact实现了用JSX和ES6/7来开发小程序,你可以在一个jsx文件中编写页面或组件,并把关联的JSX代码和引用包编译成小程序代码,然后在小程序开发者工具中调试代码。因为使用了JSX和ES标准语法,你可以轻松地把已有的JSX代码重构成小程序,当然你也可以使用喜欢的语法高亮,语法检查器等工具。

最新版本Version支持

  • JSX,ES6/7标准语法
  • 单文件开发小程序模块
  • 引用NPM包
  • async/await
  • Promise化微信小程序/小游戏API
  • 导入CSS/Sass/Less样式文件

下个小版本将支持

  • 用React方式开发小程序组件

安装包*./node_modules/weact-cli/examples/* 有使用weact的例子,也可以从https://github.com/haojy/weact-startup获取例子。

快速上手

教程

安装


在项目里安装weact-cli,

npm install -D weact-cli
npx weact

JSX小程序


让我们开始写一个Hello world的小程序,只需要两个文件:app.jsx,index.jsx, 通常页面代码会被放在./pages目录下,

src/
├── app.jsx
└── pages
    └── index.jsx

weact只把app.jsx作为目标文件,也就是说所有需要的页面需要在app.jsx中被import进来。在这个例子中,只有一个页面index可以import。我们还需要继承weact.App来声明小程序的app, 这里只export一个空的类, App.jsx 会详细说明怎么定义app,

// src/app.jsx
import { App } from 'weact'
import './pages/index.jsx' // app应用的页面,需要import

export default class extends App {
}

和app一样,所有页面要继承weact.Page,并被export才可以。与应用不同的是,页面有render()方法来定义显示部分,在render方法里返回JSX标签,在语法上这和React Component的render相同。weact会根据render方法里返回的标签,自动编译出WXML文件, 从JSX到WXML 会说明如何用JSX写出符合WXML定义的标签。weact.WXSS利用ES6字符串模版的能力,可以在jsx中声明符合WXSS语法的样式,这样样式就会被weact编译成对应的WXSS文件。

// src/pages/index.jsx
import { Page, WXSS } from 'weact'

WXSS`
.hi {
  color: blue;
}
`
export default class extends Page {
  render() {
    return (
      <view class="hi">
        Hello World!
      </view>
    )
  }
}

这样,一个基于JSX的小程序就完成了。

实战JSX开发小程序 中有更多的例子可以参考。

生成小程序


上面的代码都存放在./src目录下,然后执行

npx weact ./src # 等同于 weact ./src/app.jsx ./dist

在当前目录下会生成./dist目录,里面全是根据jsx文件编译出的小程序代码,

dist/
├── app.js
├── app.json
└── pages
    └── index
        ├── index.js
        ├── index.wxml
        └── index.wxss

微信开发者工具添加项目,项目目录设置成./dist, 然后就可以在模拟器中看到运行结果了。

从JSX到WXML


weact可以在语法上把JSX编译成WXML,下面列表给出两种语言的在语法上的对应关系。

语法 JSX WXML
数据绑定 <view>{message}</view> <view> {{ message }} </view>
属性 <view id={`${prefix}-item}`>hi</view> <view id="{{prefix}}-item">hi</view>
关键字 false <view checked={false}>hi</view> <view checked="{{false}}">hi</view>
关键字 <view checked>hi</view> <view checked="{{true}}">hi</view>
三元运算 <view hidden={flag ? true: false}>hi</view> <view hidden="{{flag ? true : false}}">hi</view>
算数运算 <view>{a + b} + {c} + d</view> <view>{{a + b}} + {{c}} + d</view>
逻辑判断 <view if={length > 5}>hi</view> <view wx:if="{{length > 5}}">hi</view>
字符串运算 <view>{"hello " + name}</view> <view>{{"hello " + name}}</view>
数组 <view for={[zero, 1, 2, 3, 4]}>
  {item}
</view>
<view wx:for="{{[zero, 1, 2, 3, 4]}}">
  {{item}}
</view>
对象 <view data={{ foo: 0, bar: 1 }}>hi</view> <view data="{{ foo: 0, bar: 1 }}">hi</view>
数据访问 <view>{object.key} {array[0]}</view> <view>{{object.key}} {{array[0]}}</view>
for 循环 <view for={array} key="message">
  {index}:{item.message}
</view>
<view wx:for="{{array}}" wx:key="message">
  {{index}}:{{item.message}}
</view>
if 条件 <view if={condition}>hi</view> <view wx:if="{{condition}}">hi</view>
if else <view if={x > 5}>1</view>
<view elif={x > 2}>2</view>
<view else>3</view>
<view wx:if="{{x > 5}}">1</view>
<view wx:elif="{{x > 2}}">2</view>
<view wx:else>3</view>
block 条件 <block if={true}>
  <view> 1 </view>
</block>
<block wx:if="{{true}}">
  <view> 1 </view>
</block>
block 循环 <block for={[1, 2, 3]}>
  <view>{index}:{item}</view>
</block>
<block wx:for="{{[1, 2, 3]}}">
  <view>{{index}}:{{item}}</view>
</block>
事件处理 <button bindtap={handleTap}>Next</button> <button bindtap="handleTap">Next</button>
onXXX == bindxxx <button onTap={this.handleTap}>Next</button> <button bindtap="handleTap">Next</button>

App.jsx


小程序在json文件中进行全局配置,用JSX把这些配置写成App的类属性,对比参考 小程序配置 。同样,App的 生命周期函数,自定义公共变量,自定义公共函数等属性 都可以写成类属性。weact把app.jsx编译成对应的app.json,app.js, app.wxss。

export default class extends App {

  debug = true

  window = {
    navigationBarTitleText: '你好,小程序',
    navigationBarTextStyle: 'black',
    navigationBarBackgroundColor: '#f4f5f6',
    backgroundColor: '#f4f5f6',
  }

  tabBar = {
    color: '#333333',
    backgroundColor: '#ffffff',
    list: [
      {
        pagePath: 'pages/index/index', // 编译后js路径
        text: '',
      },
      {
        pagePath: 'pages/page1/page1',
        text: 'Page 1',
      },
    ],
  }

  myData = '自定义公共变量',

  hello() { return '自定义公共函数' }

  // 生命周期�函数
  onLaunch() { console.log('app: hello world') }
  onShow() { console.log('app: yes, I am') }
  onHide() { console.log('app: just minutes') }
  onError() { console.log('app: woops') }
}

Page.jsx


类似App.jsx,页面的 生命周期函数和其他属性 也写成Page的类属性。除此之外,

  • Page的render()函数定义页面显示,
  • 标签使用参考小程序基础组件
  • 组件的事件处理函数在Page中直接定义类函数
export default class extends Page {

  data = {
    // 页面数据
  }

  myData = '自定义公共变量',

  handleTap() { console.log('自定义公共函数') }

  // 生命周期函数
  onLoad() { console.log('page index: loading...') }
  onShow() { console.log('page index: yes, I am') }
  onReady() { console.log('page index: I am ready now') }
  onHide() { console.log('page index: just minutes') }
  onUnload() { console.log('page index: bye...') }
  onReachBottom() { console.log('page index: we get to the most bottom') }
  onPullDownRefresh() { console.log('page index: pull down') }
  onPageScroll() { console.log('page index: scrolling...') }
  onShareAppMessage() { console.log('page index: share this') }

  render() {
    return (
      <view>
        Hello World!
        <button onTap={this.handleTap}>下一页</button>
        <navigator url="/pages/page1/page1">跳转到Page 1</navigator>
        <navigator url="/pages/page2/page2">跳转到Page 2</navigator>
      </view>
    )
  }
}

导入样式

weact支持在JSX文件中直接引用CSS/SASS/SCSS/LESS文件,所有引用的文件会被编译成单个样式文件app.wxss。根据具体使用的样式文件类型,安装对应的编译器

样式类型 安装包
css 内置,无需安装
sass/scss yarn add node-sass --dev
less yarn add less --dev
stylus yarn add stylus --dev

比如,

import './index.css'
import './page1.scss'du y
import './page2.less'

支持在单个文件中引用多个不同样式文件,只要安装好对应的编译器。

模版==函数式Component


小程序的模版可以理解成,没有状态的函数式Component。weact会把返回JSX标签的函数编译成模版,使用这类组件时,只要确保import的名字和定义的一样就可以。

// src/components/flex.jsx
export default function flex({
  direction,
}) {
  return (
    <view>
      <view class="section">
        <view>flex-direction: ${direction}</view>
        <view style={`display:flex;flex-direction:${direction};`}>
          <view class="flex-item bc_green">1</view>
          <view class="flex-item bc_red">2</view>
          <view class="flex-item bc_blue">3</view>
        </view>
      </view>
    </view>
  )
}
// src/pages/index.jsx
import { Page } from 'weact'
import flex from '../components/flex.jsx'


export default class extends Page {
  render() {
    return (
      <view>
        <flex direction="row" />
        <flex direction="column" />
      </view>
    )
  }
}

组件


用weact自定组件更类似写react Component,像Page一样显示声明继承Compnent类就可以。组件的属性可以用propTypesdefaultProps来定义,分别对应着properties[...].typeproperties[...].value。属性类型由weact.PropTypes定义如下

PropTypes 小程序属性类型
string String
number Number
bool Boolean
object Object
array Array

在下面的例子里ab就是组件属性。如果你了解react,你会比较熟悉这种定义Component的方式。 另外,自定义的方法和事件响应函数可以直接定义为类属性,weact在编译时把这些函数放在methods属性里。

import { Component, PropTypes } from 'weact'
export default class extends Component {
  static propTypes = {
    a: PropTypes.string
    b: PropTypes.bool
  }
  static defaultProps = {
    a: 'world',
    b: true,
  }
  state = {
    open: true,
    x: 'hi',
    item: {
      index: 0,
      time: '2016-09-15'
    }
  }

  render() {
    const { a, b } = this.props
    const { open } = this.state
    return (
      <view>
        <view x={b} y="str">hi {a} </view>
        <view for={[1, 2, 3]} > </view>
        <view for={array} for-index="i" for-item="node"> </view>
      </view>
    )
  }
}

组件关系

weact会根据父子组件的引用关系,自动编译出relations的定义。来看看下面的例子,父组件parent引用了子组件child。

// ./parent.jsx
import { Component, PropTypes } from 'weact'
import child from './child.jsx'
export default class extends Component {
  render() {
    return (
      <view>
        父级组件
        <child />
      </view>
    )
  }
}
// ./child.jsx
import { Component, PropTypes } from 'weact'
export default class extends Component {
  render() {
    return (
      <view>
        子级组件
      </view>
    )

  }
}

weact编译后在各自的js文件里自动生成关系定义,而不用手动定义。

// ./parent.js
  relations: {
    "../child/child": {
      type: "child"
    }
  },
// ./child.js
  relations: {
    "../parent/parent": {
      type: "parent"
    }
  },

React组件

TODO

引用模块


虽然小程序暂不支持直接引入NPM包,但支持类CommonJS的模块引用。weact在语法上实现ES模块间引用, 用babel-plugin-transform-modules-commonjs解析成CommonJS的包;NPM包也会被拷贝到modules目录下。weact模块并没有代码存在,暂时只为了符合语法。

import方式 JS/JSX 小程序
模块间 import reducer from './reducer' var _reducer = require("./reducer.js");
NPM包 import redux from 'redux' var _redux = require("modules/redux.js");
引用Page import './pages/index.jsx' app.json {"pages":["pages/index/index"]}
引用Component import Component from '../components/Component.jsx' *.json: {"usingComponents":{"Component":"../../components/Component/Component"}}
引用Template import MsgItem from './MsgItem.jsx' wxml <import src="../MsgItem.wxml" />

引用的NPM包需用npm或yarn安装

Promise和async/await


weact支持Promise的相关语法,也支持async/await。你可以在App和Page的类方法上使用async来定义异步函数,然后就可以在这函数内使用await来处理异步或Promise函数。为了方便用await方式调用微信小程序API的异步函数,weact内置的模块Promise化了这些接口,具体使用方法参考 Promise化微信小程序/小游戏API

// in page.jsx
import { wx } from 'weact'  // 引用Promise化的wx接口
export default class extends Page {
  async onLoad() {
    const wait = () => new Promise((resolve, reject) => {
      setTimeout(function() {
        resolve('小程序')
      }, 1000)
    })
    const who = await wait() // 调用自定异步函数
    console.info(who)
    const systemInfo = await wx.getSystemInfo() // 调用Promise化的wx接口
    console.info(systemInfo)
  }
}

async/await最终执行依赖于目标设备的支持

Promise化微信小程序/小游戏API


weact内置了Promise化的微信小程序和小游戏的API, 编译后会引入weact.js。Promise化的规则

  • 接口含参数successfail的API被Promise化,其他参数不变
  • success对应Promise.resolvefail对应Promise.reject
  • 参数complete暂不支持
  • 保留已有同步接口(Sync结尾的函数)和监听接口(以on/off开头的函数)
import { Page, wx } from 'weact'

export default class extends Page {
  state = {
    storage: 'nothing',
  }
  onLoad() {
    // 原接口 wx.getStorage({ key, success, fail, complete })
    wx.getStorage({ key: 'store' }) 
    .then(rs => {
      this.setState({ storage: rs})
    }, err => {
      this.setState({ storage: err.errMsg})
    })
  }
  render () {
    ...
  }

详细API的使用参考

命令行用法


使用: weact [options]

  • source 源码目录路径或app.jsx文件路径
  • target 代码生成路径=./dist

options:

  • -v, --version 显示版本
  • -h, --help 显示当前内容
  • -w, --watch Watch源码变化,自动更新代码

例子:

  • 在当前路径./dist目录下生成代码

weact examples/01.hello.world/

  • 指定代码生成路径

weact examples/01.hello.world/ ./your_distribution

  • watch模式, 根据源码改动,自动更新生成代码

weact -w examples/01.hello.world/

You can’t perform that action at this time.