Flipboard增加React组件渲染<canvas>,而不是DOM。该开源项目不少代码已经进入flipboard.com的生产阶段:Flipboard/react-canvas · GitHub
Facebook刚刚发布React.js是基于DOM渲染,通过算法计算虚拟DOM和实际物理DOM之间的差别,然后渲染差别达到快速性能。参考:使用React Native的第一印象,React.js单方向的数据流和声明API已经改变了人们构建应用的方式:flux模式
如果将React组件绑定到canvas布局(而不是DOM)会怎样呢?Flipboard进行了大胆尝试:
Flipboard已经有很长的构建面向移动设备的界面历史,他们发现移动应用相对原生应用感觉比较慢的是DOM,CSS动画和切换是在Web上最快速实现平滑动画的方式,但是它们有一些限制,而React Canvas考虑到大多数现代浏览器已经有硬件加速的canvas。
同时还有其他试图绑定Canvas绘图API实现React,它们更加注重在视觉效果和游戏。在构建不同用户界面上的重点不同导致React Canvas的差别,事实上,渲染到canvas是一个实现细节。
React Canvas给Web开发者带来熟悉的API,并带给他们一个高性能绘图引擎。
以使用Javascript实现页面滚动效果来说明,使用一个canvas元素实现滚动,当发生每个触摸事件时,当前渲染树被当前根据滚动偏移量计算的每个节点更新,整个渲染树然后重新使用新的坐标系渲染。这个过程会很慢,但是这里有一个重要的性能优化:可将绘图操作结果缓存在一个off-screen离屏canvas上,这个off-screen离屏canvas然后在稍后时间用来重画。
这种技术不但可用于图片层,文字和图形都可以,很费力的绘图操作是填充文字和图形图像,但是一旦等到这些层画完,能够使用off-screen离屏canvas快速重画它们。下图每个页面分为两个层,一个图片层和一个文字层,文字层包含很多组元素,在滚动动画的每一帧中,两个层使用缓存位图bitmap进行重画:
使用React Canvas的实现代码:
var ListView = React.createClass({ getInitialState: function () { return { scrollTop: 0 }; },
render: function () { var items = this.getVisibleItemIndexes().map(this.renderItem); return ( <Group onTouchStart={this.handleTouchStart} onTouchMove={this.handleTouchMove} onTouchEnd={this.handleTouchEnd} onTouchCancel={this.handleTouchEnd}> {items} </Group> ); },
renderItem: function (itemIndex) { // Wrap each item in a <Group> which is translated up/down based on // the current scroll offset. var translateY = (itemIndex * itemHeight) - this.state.scrollTop; var style = { translateY: translateY }; return ( <Group style={style} key={itemIndex}> <Item /> </Group> ); },
getVisibleItemIndexes: function () { // Compute the visible item indexes based on `this.state.scrollTop`. } });
|
触摸事件: // Create the Scroller instance on mount. componentDidMount: function () { this.scroller = new Scroller(this.handleScroll); },
// This is called by the Scroller at each scroll event. handleScroll: function (left, top) { this.setState({ scrollTop: top }); },
handleTouchStart: function (e) { this.scroller.doTouchStart(e.touches, e.timeStamp); },
handleTouchMove: function (e) { e.preventDefault(); this.scroller.doTouchMove(e.touches, e.timeStamp, e.scale); },
handleTouchEnd: function (e) { this.scroller.doTouchEnd(e.timeStamp); }
|
这么简单的代码体现了React的最好品质,触摸事件被声明地绑定在render()中,每个触摸事件转发到Scroller,在那里计算当前滚动距离顶部的偏移差值,从Scroller发出的每个滚动事件更新ListView组件的状态,只是更新屏幕上可见部分,所有这些在16毫秒内发生,因为React的比较算法非常快。React Canvas相比iOS/Andriod原生应用的优点,比如原生应用中不能从应用程序中复制一段文本,或者复制一个链接到浏览器,复制电话号码或地址。而基于DOM/Canvas能做到这些。
[该贴被banq于2015-02-11 17:13修改过]