【黑科技】React-canvas助力HTML5

2019-05-17 admin

图片描述

1、什么是流畅的用户体验?

游戏的开发界有一个理论,就是当动画或者交互响应达到60FPS(60帧每秒)的时候,就可以定义为流畅,按此理论,那么每帧里所有操作必须在16ms完成。要想提高页面的用户体验,必须在性能上下功夫。最早做动画都是用 setTimeout来实现的,而 setTimeout的处理回调的时间精度都在 16ms 左右。所以,可以想象正常用页面这两个函数就已经 16 ms了,再加上reflow/repaint/compositing 卡顿或跳帧就是家常便饭了。不过还好的是w3c 标准和各浏览器厂商较早就支持了动画接口 RAF(RequestAnimationFrame 函数)来处理动画帧回调。解决了上述 setTimeout不足的问题。但是,另一个问题仍然没解决,当浏览器打开网页时,需要解析文档,在内存中生成DOM结构,如果遇到复杂的文档,这个过程是很慢的。如果遇上低端的手机浏览器,可以想象一下,如果网页上有上万个形状(不管是图片或CSS),生成DOM需要多久?更不要提与其中某一个形状互动了。

2、React是什么?

用户与浏览器互动,从技术上看就是用户在操作DOM,所有的DOM操作都是同步的,会堵塞浏览器。JavaScript操作DOM时,必须等前一个操作结束,才能执行后一个操作。只要一个操作有卡顿,整个网页就会短暂失去响应。浏览器重绘网页的频率是60FPS,JavaScript做不到在16毫秒内完成DOM操作,因此产生了跳帧。用户体验上的不流畅、不连贯就源于此。JavaScript语言运行效率本身很快,但是DOM太慢了,DOM拖慢JavaScript。为了解决这个问题,React出现了,React是 Facebook 推出的一个用来构建用户界面的 JavaScript 开源框架,React的最引人注目的特征就是引入了虚拟DOM(Virtual DOM)这个概念,在浏览器端用JavaScript实现了一套DOM API。基于React进行开发时所有的DOM构造都是通过虚拟DOM进行,每当用户界面需要变化时,React都会重新构建整个DOM树,然后React将当前整个DOM树和上一次的DOM树进行对比,得到DOM结构的区别,然后仅仅将需要变化的部分进行实际的浏览器DOM更新。React实现了代码最小化参与DOM操作的方法,大大提升了浏览器的性能。

3、Canvas是什么?

Canvas 是 HTML5 的画布元素,也一个原生的DOM 元素。它相当于一个“白板”,我们可以通过javascript在这块白板上增加文字与图像,“绘制”一些可视内容。目前大多数H5游戏和动画特效都是用canvas实现的。很多在微信里传播的小游戏和小应用,也是用canvas实现的。用canvas的话整个页面只用一个DOM 元素,并且浏览器只需要绘制一次形成一幅图。这大大降低了DOM 数量与渲染的复杂度。更好的是,canvas默认支持GPU硬件加速的,可以将原来 CPU 密集型操作变成 GPU 操作。提高了动画的流畅度。值得一提的是,微信浏览器的内核,也即是QQ浏览器 X5 内核已经内置了很多游戏引擎(比如白鹭游戏引擎与cocos2dx),供开发者开发canvas游戏,所以长时间来看,微信浏览器的画布性能将会越来越强大。

4、新的方法

大多数现代移动设备都拥有硬件加速的 canvas,我们为什么不利用起来呢?HTML5 游戏已经做到了。我们为什么不采用游戏的思路设计界面,在 canvas 上开发应用界面么,用canvas来渲染页面呢?相信你已经想到了,但是有人已经做到了,那就是Flipboard公司的React-canvas。React-canvas是什么呢?光看名字就知道这是跟react和canvas相关的。React-canvas,可以使我们用react技术渲染canvas。

5、React-canvas入门

React Canvas 是依赖于React的一个组件,它拥有了渲染到canvas的能力,它可以让我们脱离繁琐的canvas命令式绘图,使用简单的css布局(Layout)。接下来给大家演示一个简单的图文实现。

5.1.安装node

新时代的前端开发离不开node环境,所以,react-canvas也不例外,node安装的具体步骤不再赘述。记住,Node版本不低于4.0。

图片描述

5.2创建项目空间

在D:nodejsreactdemo创建文件夹,此为开发的根目录 打开到此目录,切换到命令行,执行 npm init,默认回车,初始化package.json

5.3安装框架和插件

需要在node环境上安装一系列框架 切换到命令行, 执行

npm install react

安装基础框架react(注:安装v0.13.0,新版本我没试验,不知是否可行), 执行

npm install jsx-loader

安装编译react用的jsx-loader插件, 执行

npm install react-canvas

安装核心框架react-canvas, 执行

npm install webpack

安装打包代码用的工具webpack。 然后创建文本文件index.html, 创建配置文件webpack.config.js, 创建js文件夹存放代码文件。 至此,你的工作环境下应该有

图片描述

其中node_modules文件夹下,应该至少有自动生成的react、react-canvas、webpack三个文件夹。

5.4让代码跑起来

打开index.html文件,代码如下:

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-type" content="text/html; charset=utf-8">
  <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  <title>react canvas第一步</title>
</head>
<body>
  <div id="main"></div>
  <script src="bundle.js"></script>
</body>
</html>

主页面只有一个id=maindiv标签,并外链一个js文件。 打开js文件夹,创建index.js,代码如下

var React = require('react');
var ReactCanvas = require('react-canvas');

var Surface = ReactCanvas.Surface;
var Image = ReactCanvas.Image;
var Text = ReactCanvas.Text;

var MyComponent = React.createClass({

// 界面渲染
  render: function () {
    var surfaceWidth = window.innerWidth;
    var surfaceHeight = window.innerHeight;
    var imageStyle = this.getImageStyle();
    var textStyle = this.getTextStyle();

    return (
      <Surface width={surfaceWidth} height={surfaceHeight} left={0} top={0}>
        <Image style={imageStyle} src='http://img1.gtimg.com/joke/pics/hv1/193/44/1996/129801313.png' />
        <Text style={textStyle}>
          哈哈,你来打我呀
        </Text>
      </Surface>
    );
  },
// 计算居中
  getImageHeight: function () {
    return Math.round(window.innerHeight / 2);
  },
   getImageWidth: function () {
    return Math.round(window.innerWidth / 2);
  },

//  图片样式
  getImageStyle: function () {
    return {
      top: this.getImageHeight() -32,
      left: this.getImageWidth() -32,
      width: 64,
      height: 64
    };
  },

// 文字样式
  getTextStyle: function () {
    return {
      top: this.getImageHeight() + 64,
      left: 0,
      width: window.innerWidth,
      height: 20,
      lineHeight: 20,
      fontSize: 12,
      textAlign : 'center'
    };
  }

});
React.render(<MyComponent />, document.getElementById('main'));

配置webpack.config.js

module.exports = {
    //入口文件
  entry: './js/main.jsx',
    //输出文件
  output: {
    path: __dirname,
    filename: 'bundle.js'
  },
module: {
    loaders: [
// 凡是遇到jsx、js结尾的,都用jsx-loader这个插件来加载,
 // 且启用harmony模式
      { test: /\.jsx$/, loader: 'jsx-loader?harmony'},
      { test: /\.js$/, loader: 'jsx-loader?harmony'},
    ]
  },
 // 表示这个依赖项是外部lib,遇到require它不需要编译,
 // 且在浏览器端对应window.React
  //externals: {
    //'react': 'window.React'
  //},
// 现在可以写 require('file') 代替 require('file.jsx')
  resolve: {
    root: __dirname,
    extensions: ['', '.js', '.jsx']
  }
};

配置完毕后,切换到命令行执行 webpack -p 命令,打包,编译 打包后在根目录下生成一个bundle.js,直接用浏览器打开,就可以看到效果了。

图片描述

线上demo地址:点我

6、语法及元素(标签、组件)

react-canvas的语法和react一样,如果你熟悉react,react-canvas很容易上手。react-canvas自定义了几个标签。这些标签也都是标准的React components

<Surface>

Surface是一个顶级标签,是一个容器,你可以把任何元素放在上面,可以把它看成canvas元素,整个项目要被套在一个surface里面。在上述示例中已经使用。

<Layer>

Layer 层级仅次于surface,可以放其他元素。 基本样式和属性例如top, width, left, height, backgroundColor and zIndex可以在这一层设置。

<Group>

Group是一个容器,因为react渲染组件时必须要有一个总的标签包含所有的散列标签,在react-canvas中,Group扮演了div的角色,可以用来做零散标签的父标签。把一系列相关联标签用Group封装起来,一方面可以提高代码的内聚,更加模块化,另一方面可以提高页面滚动时的性能。

<Text>

Text 是用来存放文本的,是一个弹性的标签,canvas不支持自动截断换行,而Text标签支持。

<Image>

Image 跟你想象的一样,用来放图片的。 但是它支持加载完毕后才显示,并且可以随意的隐藏。

<ListView>

ListView是一个列表,可以认为它相当于HTML页面里的ul或者native app中的UITableView ,它可以提高页面的滚动性能。 同时react-canvas给各个标签以事件支持,有touchstart,move,end,click等事件。

7、图文滚动列表

接下来介绍如何在 React Canvas 中创建一个达到60 fps ,分页的滚动列表。事实证明这实现起来非常容易, 修改main.js代码为

/** @jsx React.DOM */

'use strict';

var React = require('react');
var ReactCanvas = require('react-canvas');
// page文件负责渲染单个页面
var Page = require('./components/Page');
// data文件存放json格式的图文
var articles = require('./common/data');

var Surface = ReactCanvas.Surface;
var ListView = ReactCanvas.ListView;

var App = React.createClass({
// 渲染整个列表
  render: function () {
    var size = this.getSize();
    return (
      <Surface top={0} left={0} width={size.width} height={size.height}>
        <ListView
          style={this.getListViewStyle()}
          snapping={true}
          scrollingDeceleration={0.92}
          scrollingPenetrationAcceleration={0.13}
          numberOfItemsGetter={this.getNumberOfPages}
          itemHeightGetter={this.getPageHeight}
          itemGetter={this.renderPage} />
      </Surface>
    );
  },
// 渲染单页
  renderPage: function (pageIndex, scrollTop) {
    var size = this.getSize();
    var article = articles[pageIndex % articles.length];
    var pageScrollTop = pageIndex * this.getPageHeight() - scrollTop;
    return (
      <Page
        width={size.width}
        height={size.height}
        article={article}
        pageIndex={pageIndex}
        scrollTop={pageScrollTop} />
    );
  },
// 浏览器大小
  getSize: function () {
    return document.getElementById('main').getBoundingClientRect();
  },
// 整个列表的外观
  getListViewStyle: function () {
    var size = this.getSize();
    return {
      top: 0,
      left: 0,
      width: size.width,
      height: size.height,
    };
  },
 // 设置页面的可滚动的次数,若超过页面的数量,循环滚动
  getNumberOfPages: function () {
    return 9;
  },
// 计算单页的高度
  getPageHeight: function () {
    return this.getSize().height;
  }

});

React.render(<App />, document.getElementById('main'));

整个页面代码由一个surface,一个listview,9个page组成,可以上下屏滚动。react-canvas将网页变成了一个canvas,用户就等于在跟图片互动,这样就绕开了DOM,降低了操作时滞。而且,canvas可以被硬件加速,这样就提高了性能,体验非常流畅。

你可以查看这个线上的Demo点我,pc用户记得用chrome模拟手机浏览器。文章末尾附件里有完整实现的源代码。

8、React-canvas的优缺点

8.1优点

React-canvas使用一个 canvas 元素来绘制界面,完成滚动。在每一个触摸事件时,根据当前的滚动程度去更新渲染树。之后,整个渲染树使用新的坐标来重新渲染。在 canvas 上有个重要的技术叫离屏canvas(off-screen),可以现在内存中完成绘制,之后可以一次性复制到用户界面,并且使用离屏层重新绘制也是非常快的。React在界面更新之前会做虚拟 DOM 的 diff 。在render() 函数中只更新有变动的界面,React进一步提升了React-canvas的性能。流畅是React-canvas的主要优点。 代码基于react,因为react现在比较火,很多前端已经熟悉react的书写,react也有很多相关的组件,所以react-canvas比较应景,让一部分人很快的可以上手。另外兼容性也比较好,继承react和canvas的兼容性和跨平台优点。

8.2缺点

当前不成熟和不稳定,react一直在变动,所以React-canvas也会随之一并升级。react-canvas还不完善,很多DOM中的标签特性在目前react-canvas里面未能实现,比如无法对文本进行复制,这让使用React-canvas的时候会有一些限制。这个项目已经在Github上开源,作者也在对项目进行重构,期望下次更新的时候是一个功能强大的版本。另外,react-canvas的学习成本也比较高,使用react-canvas需要对react和canvas有一定的了解。

9、最后说两句

React Canvas并不能完全取代DOM。个人觉得只适用在移动web(或者webview)上,手机的硬件资源相对有限,用户互动又相对频繁,我们可以在我们的页面中性能要求最关键的地方去使用它,尤其是在微信浏览器中很常见滚动视图这部分。当渲染性能不是问题的时候, DOM 可能是一个更好的方法。事实上,对于某些元素比如输入字段,和音频/视频标签等,DOM是唯一的方法。从某种意义上说,react-canvas也算是一个混合( hybird )的应用程序。相比传统的原生应用,react-canvas内容全部是 web 。我们在开发中可以把界面基于 dom 实现,并在适当的地方使用 canvas 渲染。DOM和canvas各取所长,优势互补。React-canvas能将页面的交互和性能水平提升到可以与本地应用相竞争,这就是它引人注意的地方。

如果你对React感兴趣,想进一步了解React,加入我们的QQ群(784383520)吧!

[转载]原文链接:https://segmentfault.com/a/1190000019211481

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-65170.html

文章标题:【黑科技】React-canvas助力HTML5

相关文章
YouTube正式默认使用HTML5视频播放器
YouTube视频网站现在默认使用HTML5播放器,这意味着更好的性能、 稳定性、 电池寿命和甚至是更好的安全性。现在用户通过Chrome、IE 11、Safari 8和Beta版本的Firefox进行浏览的时候都默认使用HTML5视频播放...
2015-11-12
HTML5的5个不错的开发工具推荐
HTML5规范终于在今年正式定稿,对于从事多年HTML5开发的人员来说绝对是一个重大新闻。数字天堂董事长,DCloud CEO王安也发表了文章,从开发者和用户两个角度分析了HTML对两个人群的优势。其实,关于HTML5的开发工具,我们以往的...
2015-11-12
HTML5凭什么可以代替Flash
本世纪初,全球网络建设仍处于早期阶段,发达国家网民刚刚在从窄带向宽带网络过渡。由于网络带宽、PC运算速度等因素限制,早期的网站基本以静态文字和图片内容为主。但随着宽带网络在全球范围快速普及,网民对内容的需求也不断变化。死板的文字加图片的网站...
2015-11-12
React Native v0.13.3 发布,Facebook开源框架
React is a JavaScript library for building user interfaces. Just the UI: Lots of people use React as the V in MVC. Since...
2015-11-12
canvas图片绘制跨域问题解决方案Tainted canvases may not be exported
图片跨域问题的一般解决方法 当使用canvas绘制网络图片的时候,经常会出现“Tainted canvases may not be exported”报错,上网搜一下解决方案,应该给的都是给img添加crossOrigin属性,尝试了一下...
2018-04-19
HTML5究竟会火到什么地步
这已经是第N次,HTML5火热了起来,这次的火热是否可以延续? H5的最大优势就是可以在网页上直接调试和修改,而且更重要的是,它几乎不用考虑用户的机型与适配性问题。智能手机主要被分裂为两大系统:Android和iOS,一个做应用的团队,怎么...
2015-11-12
2015年3月国内浏览器市场份额概括,chrome占32.97
本报告数据,来源于百度统计所覆盖的超过150万的站点,而不是baidu.com的流量数据。 注:奇虎360浏览器份额在2010年10月至2011年3月,和2012年9月以来,两次大幅下降,是因为360浏览器去掉了原本的浏览器特征(User...
2015-11-12
Facebook发布React Native!
React.js Conf 2015会议上,Facebook发布了React Native。 React.js 是 Facebook 推出的一个用来构建用户界面的 JavaScript 库。 React中,把一切东西都看成组件,而且所有组件...
2015-11-12
HTML5这次的火热是否又是昙花一现?
即使你不是技术控,你也应该感受到过去一年时间身边发生的HTML5事件,去年由微信朋友圈引爆的《围住神经猫》以及之后一系列的小游戏,都证明了HTML5的营销价值。 HTML5已经出来很多年了,HTML5是一个基于浏览器的协作标准,可以让各种不...
2015-11-12
React Native 用JavaScript编写原生ios应用
ReactNative 可以基于目前大热的开源JavaScript库React.js来开发iOS和Android原生App。而且React Native已经用于生产环境——Facebook Groups iOS 应用就是基于它开发的。 Re...
2015-11-12
回到顶部