基于 RegularJS 实现的小程序开发框架
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
bin pull Jun 19, 2018
lib
scripts
test
.babelrc
.gitignore change git ignore Jul 23, 2018
.jshintrc
.npmignore
.travis.yml Revert "bundling with rollup, use headless chrome for karma" Jan 22, 2018
LICENSE
README.md
bower.json
gulpfile.js add build:watch script Apr 19, 2018
package.json

README.md

mpregular

基于 RegularJS 实现的小程序开发框架,可以直接借助 RegularJS 语法和生态进行小程序开发。保证开发体验一致性的同时,也提高了 web 应用小程序应用 之间代码互相转换的效率。

特性

  • 一致的开发体验
  • 更低的学习成本
  • 更强的语法表现力
  • 更强的性能表现

template

HTML 标签和小程序标签存在差异,比如 div 和 view 之间的关系,RegularJS 的模版语法和小程序模版语法也不一样,因此需要在编译时对模版进行转换。

小程序的原生组件可以在 RegularJS 模版中直接使用,对应的属性名和事件名都是一样的,但需要注意的是事件绑定的语法稍有不同,需要使用 RegularJs 的语法进行事件绑定。

例如:

小程序:

<scroll-view
  scroll-y
  bindscroll="onScroll"
></scroll-view>

mpregular:

<scroll-view
  scroll-y
  on-scroll="{ this.onScroll( $event ) }"
></scroll-view>

Page 生命周期

  1. config,regular
  2. onLoad
  3. init,regular 页面组件及各个子组件
  4. onReady
  5. onShow
  6. onHide
  7. onUnload

如何使用:

export default {
  mpType: 'page',
  config() {
    // this.$mp.options 与 onLoad 中的 options 相同
    console.log('config', this.$mp.options);
  },
  init() {
    console.log('init');
  },
  onLoad(options) {
    console.log('onLoad', options);
  },
  onReady() {
    console.log('onReady');
  },
  onShow() {
    console.log('onShow');
  },
  onHide() {
    console.log('onHide');
  },
  onPullDownRefresh() {
    console.log('PullDownRefresh');
  },
  onReachBottom() {
    console.log('ReachBottom');
  },
  onPageScroll(options) {
    console.log('PageScroll', options);
  }
}

建议只在最外层的 Regular 实例中使用小程序相关的钩子函数,这样在转回 web 代码的时候工作量会相对减少

App 生命周期

TODO

支持特性

事件绑定

事件绑定遵循 Regular 的事件绑定语法,利用 on- 指令,对于小程序的原生事件的绑定,也是一样,将 bind 替换成 on-

比如 click 事件对应小程序中 tap 事件。

<button on-click="{ this.onClick($event) }">click</button>

对于小程序中特有的事件绑定方式,在 Regular 中利用指令修饰符实现。

catch{event} -> on-{event}.catch

<div on-touchstart.catch="{ this.onTouchStart($event) }"></div>

capturebind{event} -> on-{event}.capture

<div on-touchstart.capture="{ this.onTouchStart($event) }"></div>

catch-capture{event} -> on-{event}.catch-capture

<div on-touchstart.catch-capture="{ this.onTouchStart($event) }"></div>

处理函数中所返回的事件对象与小程序原生事件对象一致,保持不变。

filter

<span>{ time | dateFormat: 'yyyy-MM-dd' }</span>
import Regular from 'regularjs';

cosnt App = Regular.extend({

}).filter('dateFormat', function() {
  // your filter code here
});

export default App;

这里需要注意下写法,需要用到 Regular.extend,下面的方式目前是不支持的(后面版本会加上)

export default {
  filters: {
    // ...
  }
}

{#inc this.$body}

<!-- <Modal> definition -->
<div class="modal">
  {#inc this.$body}
</div>

<!-- use -->
<Modal>
  <head>Tips</head>
  <section>It's a tip</section>
</Modal>

目前只支持静态的模版,不支持动态的字符串编译,例如 #{inc templateStr} 是不支持的

{#if}

{#if mode === 1}
  <div>1</div>
{#elseif mode === 2}
  <div>2</div>
{#else}
  <div>other</div>
{/if}

语法与 Regular 一致。

{#list}

{#list soure as item by item_index}
  <div on-click="{ this.onItemClick(item) }">{ item.name }</div>
{/list}

语法与 Regular 一致,注意不要对大型列表进行 list 操作,否则容易出现性能问题。

指令

r-model

<input r-model="{ title }">
<textarea r-model="{ article }">

r-hide

隐藏元素指令。

<div r-hide="{ !show }"></div>

r-html

利用第三方开源库 wxParse 将 html 转换成 wxml 进行渲染。

<div r-html="{ !htmlStr }"></div>

r-style

<div r-style="{{ height: '30px' }}"></div>

r-class

<button r-class="{{ rounded: isRounded }}"></button>

性能优化

小程序官方文档中特别强调 setData 传递大数据时会大量占用 WebView JS 线程,对此 mpregular 做了特别的优化。

收集 view 中使用的数据

仅仅收集 template 中用到的数据,过滤没有用到的数据,将插值表达式执行的结果计算完成后,再通过 setData 传递到 view 线程。这样做,可以极大减少传输的数据量。

例如:

<!-- RegularJS template -->
<span>{ largeData.info.countdown.time }</span>
<!-- 转换后的小程序 wxml -->
<text>{ __holders[0] }</text>

对于上面这个插值,通常的做法是将 largeData 传递给 view,然后由 view 去解析这个对象,得到目标值。但是,如果这个值挂在一个非常大的对象上,那么每次都需要传递这个大对象,性能将会非常差。

mpregular 的做法是,每次值更改时,先将这个表达式的值计算出来,在这个例子里就是从 largetData 上取到 time 这个值,再将值写到 __holders[0], 通过 setData 传递给 view。这样每次更新的数据从一个大对象缩减到一个字符串,性能上会有很大提升。

同时,对于很复杂的插值表达式,也可以通过这种方式将计算结果设置到对应的 __holders 上。模版中的 filter、复杂表达式等特性,就是通过这一个机制实现的。

缓存更新数据,定期更新

频繁调用 setData 传递数据也会造成性能问题,因此 mpregular 会设置一个 buffer 缓存更新数据,这段事件内重复的数据会进行 merge,并定时进行更新,目前这个时间是 50ms。这一机制的实现与 mpvue 时类似的。

仍可能存在性能问题的情况

虽然 mpregular 对数据更新进行了内部优化,但是存在一些情况,无法避免大数据的传递。

{#list largeList as item}
<span>{ item.name }</span>
{/list}

{#list} 表达式里面会直接把 largeList 传递到 view 去进行遍历。所以,如果要遍历一个数组,最好是将 view 中要遍历的列表精简成只包含 view 中要使用的属性,提高数据更新时的性能。当然,也不必要过度优化,当渲染大型列表出现性能问题时,你可以尝试从这个角度去处理问题。

暂不支持

  • r-animation

工具

demo

reference