<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/rss.xsl" type="text/xsl"?>
<rss version="2.0">
  <channel>
    <title>IT瘾html5推荐</title>
    <link>https://itindex.net/categories/html5</link>
    <description>IT社区推荐资讯 - ITIndex.net</description>
    <language>zh</language>
    <copyright>https://itindex.net/</copyright>
    <generator>https://itindex.net/</generator>
    <docs>http://backend.userland.com/rss</docs>
    <image>
      <url>https://itindex.net/images/logo.gif</url>
      <title>IT社区推荐资讯 - ITIndex.net</title>
      <link>https://itindex.net/categories/html5</link>
    </image>
    <item>
      <title>html5选择摄像头 android - Enable rear camera with HTML5 - Stack Overflow</title>
      <link>https://itindex.net/detail/59326-html5-%E9%80%89%E6%8B%A9-%E6%91%84%E5%83%8F%E5%A4%B4</link>
      <description>&lt;div&gt;    &lt;p&gt;Check out    &lt;a href="https://simpl.info/getusermedia/sources/"&gt;https://simpl.info/getusermedia/sources/&lt;/a&gt; that shows how you can select sources using&lt;/p&gt;  &lt;pre&gt;   &lt;code&gt;MediaStreamTrack.getSources(gotSources);&lt;/code&gt;&lt;/pre&gt;  &lt;p&gt;You can then select the source and pass it in as optional into getUserMedia&lt;/p&gt;  &lt;pre&gt;   &lt;code&gt;var constraints = {
  audio: {
    optional: [{sourceId: audioSource}]
  },
  video: {
    optional: [{sourceId: videoSource}]
  }
};
navigator.getUserMedia(constraints, successCallback, errorCallback);&lt;/code&gt;&lt;/pre&gt;  &lt;p&gt;It is now fully available in Stable Chrome and mobile (As of v30)&lt;/p&gt;  &lt;p&gt;详见源码：&lt;/p&gt;  &lt;p&gt;https://github.com/samdutton/simpl/blob/gh-pages/getusermedia/sources/js/main.js   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;html：&lt;/p&gt;  &lt;table&gt;   &lt;tr&gt;    &lt;td&gt;&amp;lt;div id=&amp;quot;container&amp;quot;&amp;gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;     &lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;  &amp;lt;h1&amp;gt;&amp;lt;a href=&amp;quot;     &lt;a href="https://simpl.info/index.html" rel="noreferrer noopener" target="_blank"&gt;../../index.html&lt;/a&gt;&amp;quot; title=&amp;quot;simpl.info home page&amp;quot;&amp;gt;simpl.info&amp;lt;/a&amp;gt; MediaStreamTrack.getSources&amp;lt;/h1&amp;gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;     &lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;  &amp;lt;div class=&amp;quot;select&amp;quot;&amp;gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;    &amp;lt;label for=&amp;quot;audioSource&amp;quot;&amp;gt;Audio source: &amp;lt;/label&amp;gt;&amp;lt;select id=&amp;quot;audioSource&amp;quot;&amp;gt;&amp;lt;/select&amp;gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;  &amp;lt;/div&amp;gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;     &lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;  &amp;lt;div class=&amp;quot;select&amp;quot;&amp;gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;    &amp;lt;label for=&amp;quot;videoSource&amp;quot;&amp;gt;Video source: &amp;lt;/label&amp;gt;&amp;lt;select id=&amp;quot;videoSource&amp;quot;&amp;gt;&amp;lt;/select&amp;gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;  &amp;lt;/div&amp;gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;     &lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;  &amp;lt;video muted autoplay&amp;gt;&amp;lt;/video&amp;gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;     &lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;  &amp;lt;script src=&amp;quot;     &lt;a href="https://simpl.info/getusermedia/sources/js/main.js" rel="noreferrer noopener" target="_blank"&gt;js/main.js&lt;/a&gt;&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;     &lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;  &amp;lt;p&amp;gt;This demo requires Chrome 30 or later.&amp;lt;/p&amp;gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;     &lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;  &amp;lt;p&amp;gt;For more information, see &amp;lt;a href=&amp;quot;     &lt;a href="https://www.html5rocks.com/en/tutorials/getusermedia/intro/" rel="noreferrer noopener" target="_blank"&gt;https://www.html5rocks.com/en/tutorials/getusermedia/intro/&lt;/a&gt;&amp;quot; title=&amp;quot;Media capture article by Eric Bidelman on HTML5 Rocks&amp;quot;&amp;gt;Capturing Audio &amp;amp;amp; Video in HTML5&amp;lt;/a&amp;gt; on HTML5 Rocks.&amp;lt;/p&amp;gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;     &lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;&amp;lt;a href=&amp;quot;     &lt;a href="https://github.com/samdutton/simpl/blob/gh-pages/getusermedia/sources/js/main.js" rel="noreferrer noopener" target="_blank"&gt;https://github.com/samdutton/simpl/blob/gh-pages/getusermedia/sources/js/main.js&lt;/a&gt;&amp;quot; title=&amp;quot;View source for this page on GitHub&amp;quot; id=&amp;quot;viewSource&amp;quot;&amp;gt;View source on GitHub&amp;lt;/a&amp;gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;     &lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;   &lt;tr&gt;    &lt;td&gt;&lt;/td&gt;    &lt;td&gt;&amp;lt;/div&amp;gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;Last time i developped that code, soo here is the version which i use : you call directly the function whichCamera in your code and you specefic which camera &amp;quot;user&amp;quot;,&amp;quot;environment&amp;quot; or &amp;quot;computer&amp;quot;&amp;apos;if you are runing in a computer)&lt;/p&gt;    &lt;pre&gt;      &lt;code&gt;`//----------------------------------------------------------------------
//  whichCamera(Type)
//    For smartphone or tablet :
//     Start the type={user,environment} camera.
//    For computer it&amp;apos;s simple :
//      type = &amp;quot;computer&amp;quot;.
//----------------------------------------------------------------------
var streamSrc, cameraType;
function whichCamera(type){

  var cameraFacing;
  cameraType = type;
  if( type == &amp;quot;user&amp;quot;)
    cameraFacing = 0;
  else if( type == &amp;quot;environment&amp;quot;)
    cameraFacing = 1;
  else if( type == &amp;quot;computer&amp;quot;){
    cameraFacing = 2;
  }
  console.log(type+&amp;quot; index : &amp;quot;+cameraFacing);

  //  Here we list all media devices, in order to choose between
  //  the front and the rear camera.
  //      videoDevices[0] : user Camera
  //      videoDevices[1] : environment Camera
  //  Then set the video resolution.
  navigator.mediaDevices.enumerateDevices()
  .then(devices =&amp;gt; {
    var videoDevices, videoDeviceIndex, constraints;
    //  Initialize the array wich will contain all video resources IDs.
    //  Most of devices have two video resources (Front &amp;amp; Rear Camera).
    videoDevices = [0,0];
    //  Simple index to browse the videa resources array (videoDevices).
    videoDeviceIndex = 0;
    //  devices.forEach(), this function will detect all media resources (Audio, Video) of the device
    //  where we run the application.
    devices.forEach(function(device) {
      console.log(device.kind + &amp;quot;: &amp;quot; + device.label +
        &amp;quot; id = &amp;quot; + device.deviceId);
      // If the kind of the media resource is video,
      if (device.kind == &amp;quot;videoinput&amp;quot;) {
        //  then we save it on the array videoDevices.
        videoDevices[videoDeviceIndex++] =  device.deviceId;
        console.log(device.deviceId+&amp;quot; = &amp;quot;+videoDevices[videoDeviceIndex-1]);
      }
    });
    console.log(&amp;quot;Camera facing =&amp;quot;+cameraFacing+&amp;quot; ID = &amp;quot;+videoDevices[videoDeviceIndex-1]);

    // Here we specified which camera we start,
    //  videoDevices[0] : Front Camera
    //  videoDevices[1] : Back Camera
    if( cameraFacing != &amp;quot;computer&amp;quot;){
      constraints = { deviceId: { exact: videoDevices[cameraFacing]  }};
      return navigator.mediaDevices.getUserMedia({ video:
                                                          constraints,
                                                          width: { min: 1280, ideal: 1600, max: 1920 },
                                                          height: { min: 720, ideal: 1200, max: 1080 }
                                                  }
                                                );
    }else
      return navigator.mediaDevices.getUserMedia({ video: true });
    })
    //  Then we retrieve the link to the video stream.
    .then(stream =&amp;gt; {
      if (window.webkitURL) {
        video.src = window.webkitURL.createObjectURL(stream);
        localMediaStream = stream;
        console.log(localMediaStream +&amp;quot; = &amp;quot;+ stream)
      } else if (video.mozSrcObject !== undefined) {
        video.mozSrcObject = stream;
        console.log(video.mozSrcObject +&amp;quot; = &amp;quot;+ stream)
      } else if (video.srcObject !== undefined) {
        video.srcObject = stream;
        console.log(video.srcObject +&amp;quot; = &amp;quot;+ stream)
      } else {
        video.src = stream;
        console.log(video.src +&amp;quot; = &amp;quot;+ stream)
      }
      streamSrc = stream;
    })
    .catch(e =&amp;gt; console.error(e));

}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/59326-html5-%E9%80%89%E6%8B%A9-%E6%91%84%E5%83%8F%E5%A4%B4</guid>
      <pubDate>Sun, 03 Mar 2019 11:20:50 CST</pubDate>
    </item>
    <item>
      <title>有支持M3U8格式的HTML5播放器吗？ - 知乎</title>
      <link>https://itindex.net/detail/58537-%E6%9C%89%E6%94%AF-m3u8-%E6%A0%BC%E5%BC%8F</link>
      <description>&lt;div&gt;    &lt;p&gt;最近接触了这一块，简单说下吧。&lt;/p&gt;    &lt;p&gt;m3u8 是一种基于      &lt;a href="https://link.zhihu.com/?target=http%3A//en.wikipedia.org/wiki/HTTP_Live_Streaming" rel="nofollow noreferrer" target="_blank"&gt;HTTP Live Streaming&lt;/a&gt;文件视频格式，它主要是存放整个视频的基本信息和分片(Segment)组成。目前 由 Apple.inc 率先提出的 HLS  协议在 Mac 的 Safari 上原生支持，你可以直接通过&lt;/p&gt;    &lt;div&gt;      &lt;pre&gt;        &lt;code&gt;video.src = &amp;apos;xxx.m3u8&amp;apos;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;p&gt;来实现。&lt;/p&gt;    &lt;p&gt;如果你希望兼容所有的浏览器的话, 你需要知道 Chrome 和 Firefox 支持的 Media Source Extensions（   非常不理想，在IE和国内具备兼容模式的极速浏览器下） 的情况：&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;img src="data:image/svg+xml;utf8,&lt;svg%20xmlns='http://www.w3.org/2000/svg'%20width='1224'%20height='456'&gt;&lt;/svg&gt;" width="1224"&gt;&lt;/img&gt;    &lt;p&gt;目前 Youtube 和 Netflix 等主流视频网站，即使 FB 的 newsfeed 里面的视频也采用了 HLS 的解决方案，大致实现流程如下：&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;img src="data:image/svg+xml;utf8,&lt;svg%20xmlns='http://www.w3.org/2000/svg'%20width='1370'%20height='996'&gt;&lt;/svg&gt;" width="1370"&gt;&lt;/img&gt;    &lt;p&gt;其核心，在于对于 m3u8 的文件解析和 通过 XHR 去完成对分片内容二进制文件的获取，然后使用 MSE 的 appendBuffer 去进行 buffer 的封装，然后自己完成合流的工作。&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;目前国内的，bilibili 最早实现了基于 MSE 解决方案的播放器，大概为什么他们必须用 MSE 而不是 优酷 和 腾讯 的 多 video 方案，可能是钱少，视频转MP4需要大量服务器，当然 MSE  这是技术的趋势。&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;前面废话太多直接上推荐吧：&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;优先推荐 video.js 的方案，因为它支持多个播放核心，而且插件非常多，你只需要使用&lt;/p&gt;    &lt;p&gt;      &lt;a href="https://link.zhihu.com/?target=https%3A//github.com/videojs/videojs-contrib-hls" rel="nofollow noreferrer" target="_blank"&gt;videojs/videojs-contrib-hls&lt;/a&gt;就可以了。&lt;/p&gt;    &lt;p&gt;再安利一个非常纯粹的方案，就是      &lt;a href="https://link.zhihu.com/?target=https%3A//github.com/video-dev/hls.js" rel="nofollow noreferrer" target="_blank"&gt;hls.js&lt;/a&gt;它需要你手进行 video 的绑定。&lt;/p&gt;    &lt;p&gt;75 Team 也开源 的一个播放器：      &lt;a href="https://link.zhihu.com/?target=https%3A//github.com/Chimeejs/chimee" rel="nofollow noreferrer" target="_blank"&gt;Chimeejs/chimee&lt;/a&gt;&lt;/p&gt;    &lt;p&gt;      &lt;br /&gt;&lt;/p&gt;    &lt;p&gt;当然我们  team 也会开源一款类似 youtube 的播放核心。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;a href="https://github.com/jackzhang1204/sewise-player"&gt;https://github.com/jackzhang1204/sewise-player&lt;/a&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;h3&gt;功能列表：&lt;/h3&gt;  &lt;ul&gt;   &lt;li&gt;支持HTML5，Flash视频播放技术。&lt;/li&gt;   &lt;li&gt;支持多平台，PC包括Windows, MacOS, Linux等。Mobile包括Android, IOS, Windows Phone等。&lt;/li&gt;   &lt;li&gt;支持多浏览器兼容，如IE6/7/8/9/10、Google Chrome、Firefox、safari、Opera等。&lt;/li&gt;   &lt;li&gt;支持多种视频格式，如mp4、m3u8、oga、webm、theora、flv、f4v等。&lt;/li&gt;   &lt;li&gt;支持多种协议直播流，如rtmp、hls、http等。&lt;/li&gt;   &lt;li&gt;支持Flash播放m3u8文件，以及AES-128解码播放。&lt;/li&gt;   &lt;li&gt;支持PC与Mobile平台播放器自动识别功能。&lt;/li&gt;   &lt;li&gt;支持浏览器HTML5与Flash特性检测。&lt;/li&gt;   &lt;li&gt;支持HTML5不同视频格式地址Fallback兼容播放功能。&lt;/li&gt;   &lt;li&gt;支持Flash Fallback到HTML5视频播放功能。&lt;/li&gt;   &lt;li&gt;支持播放地址AMF, AJAX, JOSNP类型请求。&lt;/li&gt;   &lt;li&gt;支持自定义HTML5与Flash皮肤，让您无需了解专业的编码技术也可以制作出超烗风格的皮肤。&lt;/li&gt;   &lt;li&gt;支持前置广告（swf, 图片, 视频）。&lt;/li&gt;   &lt;li&gt;支持字幕。&lt;/li&gt;   &lt;li&gt;支持多种播放参数设定，并支持启动参数设置。&lt;/li&gt;   &lt;li&gt;支持丰富的api接口，以此可以快速打造功能强大的插件&lt;/li&gt;&lt;/ul&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/58537-%E6%9C%89%E6%94%AF-m3u8-%E6%A0%BC%E5%BC%8F</guid>
      <pubDate>Fri, 20 Jul 2018 15:55:03 CST</pubDate>
    </item>
    <item>
      <title>移动端 HTML5 video 视频播放实践</title>
      <link>https://itindex.net/detail/57120-%E7%A7%BB%E5%8A%A8-html5-video</link>
      <description>&lt;p&gt;移动端 HTML5 使用原生 &amp;lt;video&amp;gt; 标签播放视频，目前正被广泛的使用，虽然在各个平台上存在各种各样的兼容问题，给开发者带来不小的障碍，不过根据前人的经验，我们还是能从中找到蛛丝马迹来解决在开发中遇到的问题。&lt;/p&gt;
 &lt;p&gt;此篇文章，主要是总结我在项目中遇到的一些坑，也为后面的小伙伴在使用 video 标签时，提供一些思路和方法。&lt;/p&gt;
 &lt;p&gt;在移动端售后项目中，我主要遇到两个问题：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;iOS WebView 中异步添加 video 标签无法播放。&lt;/li&gt;
  &lt;li&gt;iPhone6s iOS WebView 中异步添加 video 标签需要点击两次才能播放。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;一、项目背景&lt;/h3&gt;
 &lt;p&gt;提升网购用户体验，还是要聚焦在售后服务的环节上。所以此次售后体验的飞跃项目（从京东 app -我的-退换/售后进入）对 H5 页面进行了重构，对业务功能进行了升级。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://jdc.jd.com/wp-content/uploads/2017/06/enter-e1496906602273.jpg"&gt;   &lt;img alt="enter" height="400" src="http://jdc.jd.com/wp-content/uploads/2017/06/enter-388x690.jpg" width="224"&gt;&lt;/img&gt;&lt;/a&gt;     &lt;a href="http://jdc.jd.com/wp-content/uploads/2017/06/1684811389.png"&gt;   &lt;img alt="1684811389" height="400" src="http://jdc.jd.com/wp-content/uploads/2017/06/1684811389-388x690.png" width="224"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;其中一个升级模块就是在申请售后环节，在之前仅有拍照基础上，增加了音频和  &lt;strong&gt;小视频&lt;/strong&gt;的功能，借此机会为用户提供更丰富的多媒体反馈功能。技术上采用的是 H5 + JDReact 结合的模式。用户在点击录视频 icon 会触发调用React原生应用录制小视频，后端同学采用轮询方式往 H5 页面动态添加 video 标签。之后用户可以马上点击刚刚录制的小视频播放观看。算是在申请时候为用户增加的一个更为直观反馈的功能，也便于京东客服的处理。&lt;/p&gt;
 &lt;h3&gt;二、了解 video 标签一些基本的属性&lt;/h3&gt;
 &lt;p&gt;既然决定用 video 标签实现视频回显播放，那么先了解 video 标签都有哪些重要的属性。&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;th&gt;属性名字&lt;/th&gt;
   &lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;src&lt;/td&gt;
   &lt;td&gt;视频媒体地址&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;autoplay&lt;/td&gt;
   &lt;td&gt;自动播放。iOS 蜂窝网络和 safari 中不支持。WebView 中可单独配置开启。 安卓可能支持该属性&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;loop&lt;/td&gt;
   &lt;td&gt;循环播放。iOS 支持，Android 可能支持&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;controls&lt;/td&gt;
   &lt;td&gt;播放器控制条。iOS 和 Android 支持&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;width&lt;/td&gt;
   &lt;td&gt;视频的宽。iOS 和 Android 都需要给出&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;height&lt;/td&gt;
   &lt;td&gt;视频的高。iOS 和 Android 都需要给出&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;poster&lt;/td&gt;
   &lt;td&gt;封面图片。iOS 支持，Android 不一定支持，而且各产商表现差异大&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;对于 width  和 height，比较流行的做法还是以 1px * 1px 的形式放在视觉边缘的位置。以此避免隐藏和设置 0 宽高的 video，使得视频处于未激活状态。另外 poster 封面的在各个平台的兼容性并不好，体验较差。所以我直接用 &amp;lt;img /&amp;gt; 来做一个初始化展示的效果图。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt; &lt;pre&gt;&amp;lt;div class=&amp;quot;video-wrap&amp;quot;&amp;gt;
    &amp;lt;img src=&amp;quot;../media/demo.jpg&amp;quot;&amp;gt;
    &amp;lt;video id=&amp;quot;video&amp;quot; height=&amp;quot;2&amp;quot; width=&amp;quot;1&amp;quot; src=&amp;quot;../videoDemo.mp4;&amp;quot;&amp;gt;&amp;lt;/video&amp;gt;
    &amp;lt;span class=&amp;quot;play&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/div&amp;gt;&lt;/pre&gt; &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;这里有一个小技巧，对于宽高。初始设定，可以使用 1px * 2px。对于安卓手机全屏播放基本会初始竖屏播放，而不是先横屏播放，然后加载视频后得到视频宽高比后再切换成竖屏播放。&lt;/p&gt;
 &lt;h3&gt;三、了解 video 标签一些基本的方法&lt;/h3&gt;
 &lt;p&gt;在打算使用 video 标签时，我专门去网上找了一些资料。这样可以在遇到兼容性的时候做到有备无患。&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;th&gt;方法&lt;/th&gt;
   &lt;th&gt;iOS&lt;/th&gt;
   &lt;th&gt;Android&lt;/th&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;play&lt;/td&gt;
   &lt;td&gt;只是要播放视频，响应的是 video.play() 方法，并不代表已经开始播放&lt;/td&gt;
   &lt;td&gt;和 iOS 一样，仅是响应 video.play() 方法&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;durationchange&lt;/td&gt;
   &lt;td&gt;会执行一次，一定会获取到视频的 duration&lt;/td&gt;
   &lt;td&gt;可能会执行多次，只有最后一次才能获取到真实的 duration，前面的 duration 都是0；但低版本 Android 可能获取到的 duration 是 0 或 1&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;canplay&lt;/td&gt;
   &lt;td&gt;可以认为是视频元素没有问题，可以运行，没有更多含义了，基本用不上&lt;/td&gt;
   &lt;td&gt;同 iOS&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;canplaythrough&lt;/td&gt;
   &lt;td&gt;会有明确的缓冲，表示可以流畅播放了&lt;/td&gt;
   &lt;td&gt;没有什么用，视频仍然会卡住，数据可能还没有开始加载&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;playing&lt;/td&gt;
   &lt;td&gt;明确表示播放开始了&lt;/td&gt;
   &lt;td&gt;依然没有用，视频可能并没有开始播放&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;progress&lt;/td&gt;
   &lt;td&gt;有明确的下载，可以获取到当前的 buffer，并且全部下载完毕后不在触发&lt;/td&gt;
   &lt;td&gt;不一定有明确的数据下载，并且全部下载完毕后依然继续触发&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;timeupdate&lt;/td&gt;
   &lt;td&gt;会有明确的进度变化，可以获取到currentTime&lt;/td&gt;
   &lt;td&gt;进度不一定变化，currentTime 可能总是 0，但是第一次有 currentTime 变化的timeupdate 事件一定代表了视频开始播放了&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;error&lt;/td&gt;
   &lt;td&gt;iOS 中会有明确的错误抛出&lt;/td&gt;
   &lt;td&gt;Android 中某些浏览器会莫名其妙的抛出 error&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;stalled&lt;/td&gt;
   &lt;td&gt;网络状况不佳，导致视频下载中断&lt;/td&gt;
   &lt;td&gt;在没有 play 之前，也可能会抛出该事件&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;虽然 video 的方法有很多，但是兼容性还是比较头疼的。不过在项目我仅仅用到了 play，load 方法。下面说一下我遇到的问题吧。&lt;/p&gt;
 &lt;h5&gt;iOS WebView 中异步添加 video 标签无法播放。&lt;/h5&gt;
 &lt;p&gt;在售后的项目中，因为需要支持 JDReact 原生应用提供多媒体功能。所以小视频只需要在京东 app 内 WebView 做适配就可以。第一个问题就出现了。后端将视频 video 标签动态添加到页面中后，iOS app 内点击播放。发现无法播放。而在安卓版的京东 app 内 x5 内核的浏览器是可以播放的。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt; &lt;pre&gt;mediaWrapper.delegate(&amp;apos;.load-video .video-wrap&amp;apos;,&amp;apos;click&amp;apos;,function(){        
        video.play();
        video.addEventListener(&amp;apos;ended&amp;apos;,function(){
            video.webkitExitFullscreen();
        });
});&lt;/pre&gt; &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;当然有小伙伴会表示，那不动态添加 video 标签，采用更换 src 的方式来回显用户录制的小视频。经过测试，依然无法播放。究其原因，video 标签和audio 标签不同于一般的 img 多媒体标签，更换 DOM 或者属性值就能使其激活生效。video 标签和 audio 标签本身具有了时间特性，因而采用了不同的模式。所以在播放视频之前，需要调用 video 的 load 方法来重新加载更新视频。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt; &lt;pre&gt;mediaWrapper.delegate(&amp;apos;.load-video .video-wrap&amp;apos;,&amp;apos;click&amp;apos;,function(){
        if(videoIsPlay){
            video.play();
            return false;
        }
        video.load();//PAY ATTENTION!                
        video.play();

        video.addEventListener(&amp;apos;ended&amp;apos;,function(){
        video.webkitExitFullscreen();
            videoIsPlay = true;
        });
});&lt;/pre&gt; &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;iPhone7  的京东 app 可以播放视频了。感觉革命已经成功。突然发现自己的 iPhone6s 依然不能播放，再点一次突然又可以播放了。这又是什么原因？&lt;/p&gt;
 &lt;h5&gt;iPhone6s iOS WebView 中异步添加 video 标签需要点击两次才能播放&lt;/h5&gt;
 &lt;p&gt;我们先看一下需要点两次效果图。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://jdc.jd.com/wp-content/uploads/2017/06/1.gif"&gt;   &lt;img alt="1" height="400" src="http://jdc.jd.com/wp-content/uploads/2017/06/1.gif" width="238"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;京东 app 采用的内嵌 UIWebView 内核浏览器，如果比较古老的话，会触发需要用户点两次 bug。load 方法和 play 方法在 iOS 上都是需要用户手动触发的。就算你在点击回调里写两次 load 方法或者 play 方法依然是没用的。不过可以有效利用移动端 click 事件的 300ms 延迟特点来解决两次点击播放问题。给 video 同时绑定两个事件 tap 和 click 事件，在 tap 事件和 click 都调用 load 方法。并且在 click 事件中调用 play 方法。这样就能完美解决该问题了。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt; &lt;pre&gt;mediaWrapper.delegate(&amp;apos;.load-video .video-wrap&amp;apos;,&amp;apos;tap&amp;apos;,function(){
      var video = document.getElementById(&amp;apos;my-video&amp;apos;); 
      if(videoIsPlay){
          return false;
      }
      video.load(); 
});&lt;/pre&gt; &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;看一下修改后的效果图：&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://jdc.jd.com/wp-content/uploads/2017/06/work.gif"&gt;   &lt;img alt="work" height="400" src="http://jdc.jd.com/wp-content/uploads/2017/06/work.gif" width="238"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;四、最后总结&lt;/h3&gt;
 &lt;p&gt;我的移动端的经验还不是很丰富，对于 video 标签，只能说里面水太深~。不过赶在618之前圆满的完成了售后客服的飞跃项目，获得不少成长，感谢并肩战斗的后端、设计、产品等同学，特别感谢封面设计：竹子。最后我们来整体看一下售后小视频的功能吧。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://jdc.jd.com/wp-content/uploads/2017/06/all.gif"&gt;   &lt;img alt="all" height="400" src="http://jdc.jd.com/wp-content/uploads/2017/06/all.gif" width="238"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;h3&gt;参考资料&lt;/h3&gt;
 &lt;p&gt;HTML5 Video Events and API&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://www.w3.org/2010/05/video/mediaevents.html"&gt;https://www.w3.org/2010/05/video/mediaevents.html&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;Exploring HTML 5’s Audio/Video Multimedia Support&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://www.devx.com/webdev/Article/43324"&gt;http://www.devx.com/webdev/Article/43324&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;移动端 HTML5 &amp;lt;video&amp;gt; 视频播放优化实践&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://zhaoda.net/2014/10/30/html5-video-optimization/"&gt;http://zhaoda.net/2014/10/30/html5-video-optimization/&lt;/a&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>前端开发</category>
      <guid isPermaLink="true">https://itindex.net/detail/57120-%E7%A7%BB%E5%8A%A8-html5-video</guid>
      <pubDate>Mon, 26 Jun 2017 13:32:16 CST</pubDate>
    </item>
    <item>
      <title>让ie6 7 8 9支持html5 websocket</title>
      <link>https://itindex.net/detail/56427-ie6-html5-websocket</link>
      <description>&lt;div&gt;
  &lt;p&gt;结果：&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0122/1620/7cf05b19-5b6a-38d6-9462-937545c3c647.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0122/1614/bac1b93a-b610-3abb-aceb-1410424e0852.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0122/1616/899332e1-456c-39c4-9db3-a0330954e99d.png"&gt;&lt;/img&gt;   &lt;br /&gt;    &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0122/1618/b0355e76-b642-3eff-a728-819be6d01715.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;p&gt;　　从github上的    &lt;a href="https://github.com/gimite/web-socket-js" target="_blank"&gt;web-socket-js &lt;/a&gt;(socket.io好像也是用这个做的他们的flash替代传输方式)改过来的。不过值得注意的是里面的flash websocket代理文件,文件实在是很大，有174k&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://images.cnitblog.com/blog/625679/201410/291224577227539.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt;很好奇，就反编译看下，&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://images.cnitblog.com/blog/625679/201410/291228430344771.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt;是flex做的，这点很不喜欢，因为我没有flex builder也不想因为去改代码重新装一个，然后mx包下面的是flex的组件，com包下是adobe封装的socket和两个加密包 .&lt;/p&gt;
  &lt;p&gt;最下面那个包才是最主要的，代码不是很复杂，就是利用actionscript3的socket,与那边服务端socket握手，传递消息，不过区别是，在connect的时候要把header封装成websocket的样子&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://images.cnitblog.com/blog/625679/201410/291252088943441.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://images.cnitblog.com/blog/625679/201410/291253024406215.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt;这也是flash模拟websocket的原理。事实上，直接用flash的socket就可以完成与服务端的双向信息传递，不过缺点是需要在服务端的socket代码写很多其他的代码，比如多线程，信息解析等，直接用websocket就不用写那些多余的代码了。&lt;/p&gt;
  &lt;p&gt;我花了点时间把源码里面和加密有关的代码都注释掉，加密的代码都是和wss（类似于https）有关的，用flash编译了一下，主要就是把mx包加到flash编译里面，flex是臃肿版的flash，结果大小只有20k!原来加密让文件大太多了！&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;websocket.js&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;define(&amp;quot;websocket&amp;quot;, function() {
(function() {
  if (window.WEB_SOCKET_FORCE_FLASH) {
    // Keeps going.
  } 
  else if (window.WebSocket) {
    return;
  } else if (window.MozWebSocket) {
    // Firefox.
    window.WebSocket = MozWebSocket;
    return;
  }
  var logger;
  if (window.WEB_SOCKET_LOGGER) {
    logger = WEB_SOCKET_LOGGER;
  } else if (window.console &amp;amp;&amp;amp; window.console.log &amp;amp;&amp;amp; window.console.error) {
    logger = window.console;
  } else {
    logger = {log: function(){ }, error: function(){ }};
  }
  window.WebSocket = function(url, protocols, proxyHost, proxyPort, headers) {
    var self = this;
    self.__id = WebSocket.__nextId++;
    WebSocket.__instances[self.__id] = self;
    self.readyState = WebSocket.CONNECTING;
    self.bufferedAmount = 0;
    self.__events = {};
    if (!protocols) {
      protocols = [];
    } else if (typeof protocols == &amp;quot;string&amp;quot;) {
      protocols = [protocols];
    }
    self.__createTask = setTimeout(function() {
      WebSocket.__addTask(function() {
        self.__createTask = null;
        WebSocket.__flash.create(
            self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null);
      });
    }, 0);
  };
  WebSocket.prototype.send = function(data) {
    if (this.readyState == WebSocket.CONNECTING) {
      throw &amp;quot;INVALID_STATE_ERR: Web Socket connection has not been established&amp;quot;;
    }
    var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data));
    if (result &amp;lt; 0) { // success
      return true;
    } else {
      this.bufferedAmount += result;
      return false;
    }
  };
  WebSocket.prototype.close = function() {
    if (this.__createTask) {
      clearTimeout(this.__createTask);
      this.__createTask = null;
      this.readyState = WebSocket.CLOSED;
      return;
    }
    if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) {
      return;
    }
    this.readyState = WebSocket.CLOSING;
    WebSocket.__flash.close(this.__id);
  };
  WebSocket.prototype.dispatchEvent = function(event) {
    var events = this.__events[event.type] || [];
    for (var i = 0; i &amp;lt; events.length; ++i) {
      events[i](event);
    }
    var handler = this[&amp;quot;on&amp;quot; + event.type];
    if (handler) handler.apply(this, [event]);
  };
  WebSocket.prototype.__handleEvent = function(flashEvent) {
    if (&amp;quot;readyState&amp;quot; in flashEvent) {
      this.readyState = flashEvent.readyState;
    }
    if (&amp;quot;protocol&amp;quot; in flashEvent) {
      this.protocol = flashEvent.protocol;
    }
    var jsEvent;
    if (flashEvent.type == &amp;quot;open&amp;quot; || flashEvent.type == &amp;quot;error&amp;quot;) {
      jsEvent = this.__createSimpleEvent(flashEvent.type);
    } else if (flashEvent.type == &amp;quot;close&amp;quot;) {
      jsEvent = this.__createSimpleEvent(&amp;quot;close&amp;quot;);
      jsEvent.wasClean = flashEvent.wasClean ? true : false;
      jsEvent.code = flashEvent.code;
      jsEvent.reason = flashEvent.reason;
    } else if (flashEvent.type == &amp;quot;message&amp;quot;) {
      var data = decodeURIComponent(flashEvent.message);
      jsEvent = this.__createMessageEvent(&amp;quot;message&amp;quot;, data);
    } else {
      throw &amp;quot;unknown event type: &amp;quot; + flashEvent.type;
    }
    this.dispatchEvent(jsEvent);
  };
  WebSocket.prototype.__createSimpleEvent = function(type) {
    if (document.createEvent &amp;amp;&amp;amp; window.Event) {
      var event = document.createEvent(&amp;quot;Event&amp;quot;);
      event.initEvent(type, false, false);
      return event;
    } else {
      return {type: type, bubbles: false, cancelable: false};
    }
  };
  WebSocket.prototype.__createMessageEvent = function(type, data) {
    if (window.MessageEvent &amp;amp;&amp;amp; typeof(MessageEvent) == &amp;quot;function&amp;quot; &amp;amp;&amp;amp; !window.opera) {
      return new MessageEvent(&amp;quot;message&amp;quot;, {
        &amp;quot;view&amp;quot;: window,
        &amp;quot;bubbles&amp;quot;: false,
        &amp;quot;cancelable&amp;quot;: false,
        &amp;quot;data&amp;quot;: data
      });
    } else if (document.createEvent &amp;amp;&amp;amp; window.MessageEvent &amp;amp;&amp;amp; !window.opera) {
      var event = document.createEvent(&amp;quot;MessageEvent&amp;quot;);
        event.initMessageEvent(&amp;quot;message&amp;quot;, false, false, data, null, null, window, null);
      return event;
    } else {
      return {type: type, data: data, bubbles: false, cancelable: false};
    }
  };
  WebSocket.CONNECTING = 0;
  WebSocket.OPEN = 1;
  WebSocket.CLOSING = 2;
  WebSocket.CLOSED = 3;
  WebSocket.__isFlashImplementation = true;
  WebSocket.__initialized = false;
  WebSocket.__flash = null;
  WebSocket.__instances = {};
  WebSocket.__tasks = [];
  WebSocket.__nextId = 0;
  WebSocket.loadFlashPolicyFile = function(url){
    WebSocket.__addTask(function() {
      WebSocket.__flash.loadManualPolicyFile(url);
    });
  };
  WebSocket.__initialize = function() {
    if (WebSocket.__initialized) return;
    WebSocket.__initialized = true;
    if (WebSocket.__swfLocation) {
      window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;
    }
  };
  WebSocket.__onFlashInitialized = function() {
    setTimeout(function() {
      WebSocket.__flash =main.get_flash_obj(&amp;quot;webSocketFlash&amp;quot;);
      WebSocket.__flash.setCallerUrl(location.href);
      WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);
      for (var i = 0; i &amp;lt; WebSocket.__tasks.length; ++i) {
        WebSocket.__tasks[i]();
      }
      WebSocket.__tasks = [];
    }, 0);
  };
  WebSocket.__onFlashEvent = function() {
    setTimeout(function() {
      try {
        var events = WebSocket.__flash.receiveEvents();
        for (var i = 0; i &amp;lt; events.length; ++i) {
          WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]);
        }
      } catch (e) {
        logger.error(e);
      }
    }, 0);
    return true;
  };
  WebSocket.__log = function(message) {
    logger.log(decodeURIComponent(message));
  };
  WebSocket.__error = function(message) {
    logger.error(decodeURIComponent(message));
  };
  WebSocket.__addTask = function(task) {
    if (WebSocket.__flash) {
      task();
    } else {
      WebSocket.__tasks.push(task);
    }
  };
})();
return WebSocket;
});&lt;/pre&gt;
 
  &lt;p&gt;websocket_main.js&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;require([&amp;apos;html5/websocket&amp;apos;,&amp;apos;avalon-min&amp;apos;],function(WebSocket,avalon){
    var $=function(id){
        return document.getElementById(id);
    };
    WEB_SOCKET_DEBUG = true;
    var ws;
        ws = new WebSocket(&amp;quot;ws://localhost:8888/new-msg/socket&amp;quot;);
        ws.onopen = function() {
            output(&amp;quot;onopen&amp;quot;);
        };
        ws.onmessage = function(e) {
            output(&amp;quot;onmessage: &amp;quot; + e.data);
        };
        ws.onclose = function() {
            output(&amp;quot;onclose&amp;quot;);
        };
        ws.onerror = function() {
            output(&amp;quot;onerror&amp;quot;);
        };
    avalon.bind($(&amp;apos;send&amp;apos;),&amp;apos;click&amp;apos;,function(){
            var input = $(&amp;quot;input1&amp;quot;);
            ws.send(input.value);
            output(&amp;quot;send: &amp;quot; + input.value);
            input.value = &amp;quot;&amp;quot;;
            input.focus();
    });
    avalon.bind($(&amp;apos;close&amp;apos;),&amp;apos;click&amp;apos;,function(){
            ws.close();
    });
    function output(str) {
        var log = document.getElementById(&amp;quot;log&amp;quot;);
        var escaped = str.replace(/&amp;amp;/, &amp;quot;&amp;amp;amp;&amp;quot;).replace(/&amp;lt;/, &amp;quot;&amp;amp;lt;&amp;quot;)
                .replace(/&amp;gt;/, &amp;quot;&amp;amp;gt;&amp;quot;).replace(/&amp;quot;/, &amp;quot;&amp;amp;quot;&amp;quot;); // &amp;quot;
        log.innerHTML = escaped + &amp;quot;&amp;lt;br&amp;gt;&amp;quot; + log.innerHTML;
    }
});&lt;/pre&gt;
 HTML：
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=UTF-8&amp;quot;&amp;gt;
&amp;lt;title&amp;gt;Insert title here&amp;lt;/title&amp;gt;
&amp;lt;script src=&amp;quot;http://localhost/twitter/js/libs/seed-min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;http://localhost/twitter/js/libs/flash_embed.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;quot;http://localhost/twitter/js/main.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;input1&amp;quot;&amp;gt;
    &amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Send&amp;quot; id=&amp;apos;send&amp;apos;&amp;gt;
    &amp;lt;button id=&amp;apos;close&amp;apos;&amp;gt;close&amp;lt;/button&amp;gt;
    &amp;lt;div id=&amp;quot;log&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div id=&amp;apos;a&amp;apos; style=&amp;apos;width: 1px; height: 1px;&amp;apos;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;
        flash_object.embedSWF(&amp;apos;http://localhost:8888/swf/WebSocketMain.swf&amp;apos;, &amp;apos;a&amp;apos;, &amp;apos;webSocketFlash&amp;apos;, &amp;apos;100%&amp;apos;, &amp;apos;100%&amp;apos;);
    &amp;lt;/script&amp;gt;
    &amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;apos;http://localhost/twitter/js/libs/html5/websocket_main.js&amp;apos;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;
 
  &lt;p&gt; &lt;/p&gt;
  &lt;div&gt;
   &lt;div&gt; &lt;/div&gt;
&lt;/div&gt;
  &lt;p&gt;下面很重要，在运行前一定要开启服务端(python)的socket&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;import socket
import time
from threading import Thread

class returnCrossDomain(Thread):
    def __init__(self,connection):
        Thread.__init__(self)
        self.con = connection
    def run(self):
        clientData  = self.con.recv(1024)
        xmlData  = &amp;apos;&amp;apos;&amp;apos;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;&amp;apos;&amp;apos;&amp;apos;
        xmlData += &amp;apos;&amp;apos;&amp;apos;&amp;lt;cross-domain-policy&amp;gt;&amp;lt;policy-file-request/&amp;gt;&amp;apos;&amp;apos;&amp;apos;
        xmlData += &amp;apos;&amp;apos;&amp;apos;&amp;lt;allow-access-from domain=&amp;quot;*&amp;quot; to-ports=&amp;quot;*&amp;quot; /&amp;gt;&amp;apos;&amp;apos;&amp;apos;
    xmlData += &amp;apos;&amp;apos;&amp;apos;&amp;lt;/cross-domain-policy&amp;gt;\0&amp;apos;&amp;apos;&amp;apos;
        try:
            self.con.send(xmlData)
        except Excepiton,e:
            pass
        self.con.close()
def main():
    sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    sock.bind((&amp;apos;localhost&amp;apos;,843))
    sock.listen(10000000)
    print &amp;apos;socket&amp;apos;
    while True:
        try:
            connection,address = sock.accept()
            returnCrossDomain(connection).start()
        except:
            time.sleep(1)

if __name__==&amp;quot;__main__&amp;quot;:
    main()&lt;/pre&gt;
 
  &lt;p&gt;服务端用python的tornado写的，也一样在运行前开启tornado&lt;/p&gt;
  &lt;pre&gt;# -*- coding: utf-8 -*-
import base
import tornado.websocket

def send_message(message):
    for handler in ChatSocketHandler.socket_handlers:
        handler.write_message(message)

class ChatSocketHandler(tornado.websocket.WebSocketHandler):
    socket_handlers = set()

    def open(self):
        ChatSocketHandler.socket_handlers.add(self)
        print &amp;apos;websocket&amp;apos;
        send_message(&amp;apos;A new user has entered the chat room.&amp;apos;)

    def on_close(self):
        ChatSocketHandler.socket_handlers.remove(self)
        print &amp;apos;websocket close&amp;apos;
        send_message(&amp;apos;A user has left the chat room.&amp;apos;)

    def on_message(self, message):
        print &amp;apos;message:&amp;apos;+message
        send_message(message)&lt;/pre&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;tornado很好的封装了websocket，用起来很简单，加上flash模拟websocket兼容不支持websocket的浏览器，这样可以完美的利用高效的websocket.&lt;/p&gt;
  &lt;p&gt;如果嫌弃flash的话，还是用ajax长连接，tornado很好的支持ajax长连接，性能很好.&lt;/p&gt;
  &lt;p&gt;socket.io也是个不错的选择，提供了多种传输方案。&lt;/p&gt;
  &lt;p&gt; WebSocketMain.swf文件及源码见附件&lt;/p&gt;
  &lt;p&gt;   &lt;strong&gt; &lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
          
   &lt;br /&gt; &lt;br /&gt;
   &lt;ul&gt;
    本文附件下载:
    
        &lt;li&gt;   &lt;a href="http://dl.iteye.com/topics/download/88483db9-2e68-38f4-8bd4-05883ff91a57"&gt;flash_websocket.zip&lt;/a&gt; (320.1 KB)&lt;/li&gt;
    
  &lt;/ul&gt;

           &lt;br /&gt; &lt;br /&gt;
          
             &lt;a href="http://sheng.iteye.com/blog/2347036#comments"&gt;已有   &lt;strong&gt;0&lt;/strong&gt; 人发表留言，猛击-&amp;gt;&amp;gt;  &lt;strong&gt;这里&lt;/strong&gt;&amp;lt;&amp;lt;-参与讨论&lt;/a&gt;
          
           &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;
ITeye推荐
 &lt;br /&gt;
 &lt;ul&gt;  &lt;li&gt;   &lt;a href="http://www.iteye.com/clicks/433" target="_blank"&gt;—软件人才免语言低担保 赴美带薪读研！— &lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
 &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;
          
        &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/56427-ie6-html5-websocket</guid>
      <pubDate>Fri, 23 Dec 2016 20:52:15 CST</pubDate>
    </item>
    <item>
      <title>html5实现本地图片预览功能</title>
      <link>https://itindex.net/detail/55671-html5-%E5%9B%BE%E7%89%87-%E5%8A%9F%E8%83%BD</link>
      <description>&lt;div&gt;
  &lt;p&gt;1.利用FileReader进行图片本地预览&lt;/p&gt;
  &lt;p&gt;    FileReader类型实现的是一种异步文件读取机制，用来把文件读入内存，并且读取文件中的数据。各大浏览器的支持情况：&lt;/p&gt;
  &lt;p&gt;    &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0117/9483/c3cc627f-8f64-3a21-9706-5d7af3110ee4.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;h2&gt;   &lt;strong&gt;    &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/FileReader/FileReader" title="The documentation about this has not yet been written; please consider contributing!"&gt;     &lt;code&gt;构造方法&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/h2&gt;
  &lt;h2&gt;   &lt;code&gt;var reader = new     &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/FileReader/FileReader" title="The documentation about this has not yet been written; please consider contributing!"&gt;FileReader()&lt;/a&gt;；&lt;/code&gt;&lt;/h2&gt;
  &lt;p&gt;为了读取文件中的数据，FileReader提供了如下几个方法：&lt;/p&gt;
  &lt;p&gt;readAsText(file,encoding)：以纯文本的形式读取文件，将读取到的文本保存在result属性中，第二个参数指定编码类型，可选。&lt;/p&gt;
  &lt;p&gt;readAsDataURL(file)：读取文件并将文件以数据URL的形式保存在result属性中。&lt;/p&gt;
  &lt;p&gt;readAsBinaryString(file): 读取文件并将一个字符串保存在result属性中，字符串中的每一个字符表示一个字节。&lt;/p&gt;
  &lt;p&gt;readAsArrayBuffer(file): 将一个包含文件内容的ArrayBuffer保存在result。&lt;/p&gt;
  &lt;p&gt;了解了FileReader的基本使用后，来实现下图片的本地预览功能：&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;&amp;lt;input type=&amp;quot;file&amp;quot; name=&amp;quot;inputfile&amp;quot; accept=&amp;quot;image/*&amp;quot; onchange=&amp;quot;readFile(this.files[0])&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;preview&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/pre&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;function readFile(f){
    var reader = new FileReader();
    reader.readAsDataURL(f); //base64编码
   reader.onload = function(){
         var preview = document.querySelector(&amp;apos;#preview&amp;apos;);
         var img = document.createElement(&amp;quot;img&amp;quot;);
         img.src = reader.result;
         preview.appendChild(img);
    }
   reader.onerror = function(e){
         console.log(&amp;quot;Error&amp;quot;+e);
   }
}&lt;/pre&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt; 页面效果看起来是这个样子的：&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0117/9485/10c9f997-a46d-3bba-a80a-7169ec47ce7d.png"&gt;&lt;/img&gt;   &lt;br /&gt; 当选择图片后就可以本地预览啦，结合ajax实现图片上传预览功能。&lt;/p&gt;
  &lt;p&gt;效果图：   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0117/9487/22017fb6-4964-3965-8b96-ed99703724d3.png"&gt;&lt;/img&gt;   &lt;br /&gt; 2.URL.createObjectURL()进行图片本地预览&lt;/p&gt;
  &lt;p&gt;        &lt;strong&gt;URL.createObjectURL() &lt;/strong&gt;静态方法会创建一个    &lt;code&gt;DOMString&lt;/code&gt;，它的 URL 表示参数中的对象。这个 URL 的生命周期和创建它的窗口中的    &lt;code&gt;document&lt;/code&gt; 绑定。这个新的URL 对象表示着指定的    &lt;code&gt;File&lt;/code&gt; 对象或者    &lt;code&gt;Blob&lt;/code&gt; 对象。&lt;/p&gt;
  &lt;h2&gt;   &lt;strong&gt;    &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/FileReader/FileReader" title="The documentation about this has not yet been written; please consider contributing!"&gt;     &lt;code&gt;构造方法&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/h2&gt;
  &lt;h2&gt;
   &lt;code&gt;    &lt;em&gt;objectURL &lt;/em&gt;&lt;/code&gt;   &lt;code&gt; = &lt;/code&gt;URL.createObjectURL(blob);  //参数blob：是用来创建 URL 的    &lt;code&gt;file&lt;/code&gt; 对象或者    &lt;code&gt;Blob&lt;/code&gt; 对象​
&lt;/h2&gt;
  &lt;p&gt;在每次调用    &lt;code&gt;createObjectURL() &lt;/code&gt;方法时，都会创建一个新的 URL 对象，即使你已经用相同的对象作为参数创建过。当不再需要这些 URL 对象时，每个对象必须通过调用window.URL.revokeObjectURL()方法来释放。浏览器会在文档退出的时候自动释放它们，但是为了获得最佳性能和内存使用状况，你应该在安全的时机主动释放掉它们。&lt;/p&gt;
  &lt;p&gt;HTML结构与之前一样。&lt;/p&gt;
  &lt;pre&gt;if (window.URL) {
     var preview = document.querySelector(&amp;apos;#preview&amp;apos;);
     var img = document.createElement(&amp;quot;img&amp;quot;);
     img.src = window.URL.createObjectURL(f);
     img.onload = function(){
	   window.URL.revokeObjectURL(this.src); //释放内存
     }
     preview.appendChild(img);
}&lt;/pre&gt;
  &lt;p&gt; 效果如上。&lt;/p&gt;
&lt;/div&gt;
          
           &lt;br /&gt; &lt;br /&gt;
          
             &lt;a href="http://jcao54.iteye.com/blog/2304166#comments"&gt;已有   &lt;strong&gt;0&lt;/strong&gt; 人发表留言，猛击-&amp;gt;&amp;gt;  &lt;strong&gt;这里&lt;/strong&gt;&amp;lt;&amp;lt;-参与讨论&lt;/a&gt;
          
           &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;
ITeye推荐
 &lt;br /&gt;
 &lt;ul&gt;  &lt;li&gt;   &lt;a href="http://www.iteye.com/clicks/433" target="_blank"&gt;—软件人才免语言低担保 赴美带薪读研！— &lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
 &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;
          
        &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/55671-html5-%E5%9B%BE%E7%89%87-%E5%8A%9F%E8%83%BD</guid>
      <pubDate>Thu, 09 Jun 2016 21:13:19 CST</pubDate>
    </item>
    <item>
      <title>三天学会HTML5——SVG和Canvas的使用</title>
      <link>https://itindex.net/detail/55165-%E5%A4%A9%E5%AD%A6-html5-svg</link>
      <description>&lt;div&gt;
  &lt;p&gt;在第一天学习了HTML5的一些非常重要的基本知识，今天将进行更深层学习&lt;/p&gt;
  &lt;p&gt;首先来回顾第一天学习的内容，第一天学习了新标签，新控件，验证功能，应用缓存等内容。&lt;/p&gt;
  &lt;p&gt;第2天将学习如何使用Canvas 和使用SVG 实现功能&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;h2&gt;Lab1—— 使用Canvas&lt;/h2&gt;
  &lt;p&gt;Canvas 是指定了长度和宽度的矩形画布，我们将使用新的HTML5 JavaScript，可使用HTML5 JS API 来画出各种图形。&lt;/p&gt;
  &lt;p&gt;初始化&lt;/p&gt;
  &lt;p&gt;1. 创建HTML页面&lt;/p&gt;
  &lt;pre&gt;&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;
  &lt;p&gt;2. 在Body标签内添加Canvas&lt;/p&gt;
  &lt;pre&gt;&amp;lt;canvas id=&amp;quot;MyCanvas&amp;quot; width=&amp;quot;500px&amp;quot; height=&amp;quot;500px&amp;quot; style=&amp;quot;border:1px solid black;&amp;quot;&amp;gt;

&amp;lt;/canvas&amp;gt; &lt;/pre&gt;
  &lt;p&gt;3. 在&amp;lt;head&amp;gt;标签内添加Script 标签&lt;/p&gt;
  &lt;pre&gt;&amp;lt;head&amp;gt;

&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;

&amp;lt;/script&amp;gt;

&amp;lt;/head&amp;gt;&lt;/pre&gt;
  &lt;p&gt;4. 在Script 标签内创建JavaScript 函数 Draw ，Draw函数能够访问Canvas 对象&lt;/p&gt;
  &lt;pre&gt;function Draw()

{
        var ctx = document.getElementById(&amp;apos;MyCanvas&amp;apos;).getContext(&amp;quot;2d&amp;quot;);      
        //Canvas Code Comes Here
}&lt;/pre&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;h3&gt;Lab 1.1 使用 Path&lt;/h3&gt;
  &lt;p&gt;Path 由0个或多个Sub Path组成，每个Sub path 是是由一个或多个终点组成，每个终点是通过直线或曲线连接的。&lt;/p&gt;
  &lt;p&gt;Lab1.1.1 使用Single 创建Path;&lt;/p&gt;
  &lt;p&gt;脚本片段：&lt;/p&gt;
  &lt;pre&gt;ctx.beginPath();

ctx.strokeStyle = &amp;quot;blue&amp;quot;;

ctx.moveTo(75, 50);

ctx.lineTo(75, 100);

ctx.stroke();

ctx.strokeStyle = &amp;quot;red&amp;quot;;

ctx.lineTo(25, 100);

ctx.stroke();&lt;/pre&gt;
  &lt;p&gt;输出：&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/D.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;上述示例中Path 是由2个子路径组成的。&lt;/p&gt;
  &lt;p&gt;BeginPath—— 创建新路径&lt;/p&gt;
  &lt;p&gt;strokeStyle 用于设置样式&lt;/p&gt;
  &lt;p&gt;每次调用Stroke 方法，所有的子路径都会使用当前的Style 重新画。&lt;/p&gt;
  &lt;h3&gt;Lab 1.1.2 使用Multiple Begin Path创建Path&lt;/h3&gt;
  &lt;p&gt;核心代码：&lt;/p&gt;
  &lt;pre&gt;ctx.beginPath();

ctx.strokeStyle = &amp;quot;blue&amp;quot;;

ctx.moveTo(75, 50);

ctx.lineTo(75, 100);

ctx.stroke();

ctx.beginPath();

ctx.moveTo(75, 100);

ctx.strokeStyle = &amp;quot;red&amp;quot;;

ctx.lineTo(25, 100);

ctx.stroke();&lt;/pre&gt;
  &lt;p&gt;输出：&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/E.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;h3&gt;Lab1.1.3 理解ClosePath&lt;/h3&gt;
  &lt;p&gt;核心代码：&lt;/p&gt;
  &lt;pre&gt;ctx.beginPath();

ctx.strokeStyle = &amp;quot;blue&amp;quot;;

ctx.moveTo(75, 50);

ctx.lineTo(75, 100);

ctx.lineTo(25, 100);

ctx.closePath();

ctx.stroke();&lt;/pre&gt;
  &lt;pre&gt;输出：&lt;/pre&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/F.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;h3&gt;Lab1.1.4 理解Fill&lt;/h3&gt;
  &lt;p&gt;核心代码&lt;/p&gt;
  &lt;pre&gt;ctx.beginPath();

ctx.moveTo(75, 50);

ctx.lineTo(75, 100);

ctx.lineTo(25, 100);

ctx.fillStyle = &amp;quot;red&amp;quot;;

ctx.fill();&lt;/pre&gt;
  &lt;p&gt;输出：&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/G.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;h3&gt;Lab1.1.5 画曲线&lt;/h3&gt;
  &lt;p&gt;quadraticCurveTo 函数定义了四个参数，前两个点是控制点，用于曲率计算，后两个参数是终点的曲度核心代码：&lt;/p&gt;
  &lt;pre&gt;ctx.beginPath();

ctx.moveTo(175, 50)

ctx.quadraticCurveTo(60, 360, 175, 300);

ctx.stroke()&lt;/pre&gt;
  &lt;p&gt;输出：&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/H.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;h2&gt;Lab 1.2 使用Rectangle&lt;/h2&gt;
  &lt;p&gt;Lab1.2.1 画矩形&lt;/p&gt;
  &lt;pre&gt;ctx.fillStyle=&amp;quot;red&amp;quot;;

ctx.fillRect(75, 75, 150, 150);

           

ctx.strokeStyle = &amp;quot;black&amp;quot;;

ctx.lineWidth = 5;

ctx.strokeRect(175,175,150,150);&lt;/pre&gt;
  &lt;p&gt;输出:&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/I.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;h3&gt;Lab1.2.2 清除矩形&lt;/h3&gt;
  &lt;p&gt;代码：&lt;/p&gt;
  &lt;pre&gt;ctx.fillStyle=&amp;quot;red&amp;quot;;

ctx.fillRect(75, 75, 250, 250);

ctx.clearRect(125, 125, 100, 100);&lt;/pre&gt;
  &lt;p&gt;输出&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/J.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;h2&gt;Lab 1.3 使用渐变色&lt;/h2&gt;
  &lt;p&gt;Lab1.3.1 使用线性渐变色&lt;/p&gt;
  &lt;pre&gt;var grd = ctx.createLinearGradient(75, 75, 225, 75);

grd.addColorStop(0, &amp;quot;black&amp;quot;);

grd.addColorStop(0.2, &amp;quot;magenta&amp;quot;);

grd.addColorStop(0.4, &amp;quot;blue&amp;quot;);

grd.addColorStop(0.6, &amp;quot;green&amp;quot;);

grd.addColorStop(0.8, &amp;quot;yellow&amp;quot;);

grd.addColorStop(1, &amp;quot;red&amp;quot;);

ctx.fillStyle = grd

ctx.fillRect(75, 75, 150, 150);&lt;/pre&gt;
  &lt;p&gt;输出&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/K.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt;注意：&lt;/p&gt;
  &lt;p&gt;reateLinearGradient 包含四个参数x1,y1,x2,y2&lt;/p&gt;
  &lt;p&gt;1. 如果x1=x2 并且y1!=y2,渐变色改变的方向则是水平。&lt;/p&gt;
  &lt;p&gt;2. 如果y1=y2 并且x1!=x2, 渐变色方向是垂直的。&lt;/p&gt;
  &lt;p&gt;3. 如果x1!=x2且y1!=y2,渐变色方向则为对角。&lt;/p&gt;
  &lt;p&gt;AddColorStop 函数包含两个参数。&lt;/p&gt;
  &lt;p&gt;1. 0到1 之间的数字,用来表示渐变色起始和终点的位置。&lt;/p&gt;
  &lt;p&gt;2. Color;&lt;/p&gt;
  &lt;p&gt;Lab1.3.2 使用圆形渐变&lt;/p&gt;
  &lt;p&gt;代码：&lt;/p&gt;
  &lt;pre&gt;var grd = ctx.createRadialGradient(150, 150, 5, 150, 150,85);

grd.addColorStop(0, &amp;quot;orange&amp;quot;);

grd.addColorStop(0.2, &amp;quot;magenta&amp;quot;);

grd.addColorStop(0.4, &amp;quot;blue&amp;quot;);

grd.addColorStop(0.6, &amp;quot;green&amp;quot;);

grd.addColorStop(0.8, &amp;quot;yellow&amp;quot;);

grd.addColorStop(1, &amp;quot;red&amp;quot;);

ctx.fillStyle = grd

ctx.fillRect(75, 75, 150, 150);&lt;/pre&gt;
  &lt;p&gt;输出&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/l.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt;CreateRadialGradiant包含6个参数，x1,y1,r1,x2,y2,r2&lt;/p&gt;
  &lt;p&gt;1, x1,y1,r1代表开始圆形的圆心和半径&lt;/p&gt;
  &lt;p&gt;2. x2,y2,r2 表示结束圆的圆心和半径&lt;/p&gt;
  &lt;p&gt;Lab 1.4 使用圆形&lt;/p&gt;
  &lt;p&gt;核心代码：&lt;/p&gt;
  &lt;pre&gt;ctx.beginPath();

ctx.fillStyle=&amp;quot;yellow&amp;quot;;

ctx.strokeStyle=&amp;quot;green&amp;quot;;

ctx.lineWidth = &amp;quot;8&amp;quot;;

ctx.arc(100, 175, 85, 0, 2*Math.PI);

ctx.fill();

ctx.stroke();


ctx.beginPath();

ctx.fillStyle = &amp;quot;green&amp;quot;;

ctx.strokeStyle = &amp;quot;yellow&amp;quot;;

ctx.lineWidth = &amp;quot;8&amp;quot;;

ctx.arc(285, 175, 85, 0, 1 * Math.PI);

ctx.fill();

ctx.stroke();&lt;/pre&gt;
  &lt;pre&gt; &lt;/pre&gt;
  &lt;pre&gt;输出：&lt;/pre&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/m.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;pre&gt;DrawArc 函数包含5个参数，x,y,r,sa,ea&lt;/pre&gt;
  &lt;pre&gt;x 和y 表示圆心&lt;/pre&gt;
  &lt;pre&gt;r表示半径&lt;/pre&gt;
  &lt;pre&gt;sa 和ea 是开始边缘和结束边缘&lt;/pre&gt;
  &lt;h2&gt;Lab1.5 使用Text&lt;/h2&gt;
  &lt;p&gt;代码：&lt;/p&gt;
  &lt;pre&gt;ctx.beginPath();

ctx.font = &amp;quot;30px Segoe UI&amp;quot;;

ctx.fillText(&amp;quot;www.StepByStepSchools.Net&amp;quot;,0, 150);&lt;/pre&gt;
  &lt;pre&gt;输出：&lt;/pre&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/n.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;pre&gt;fillText/stokeText具有三个参数&lt;/pre&gt;
  &lt;pre&gt;1. 实际输出的文本&lt;/pre&gt;
  &lt;pre&gt;2. x,y 是可选值。&lt;/pre&gt;
  &lt;pre&gt;Lab 1.6 Scale&lt;/pre&gt;
  &lt;pre&gt;ctx.strokeRect(75, 75, 75, 75);

ctx.scale(2,2);

ctx.strokeRect(75, 75, 75, 75);&lt;/pre&gt;
  &lt;p&gt;输出：&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/o.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;h2&gt;Lab 1.7 旋转&lt;/h2&gt;
  &lt;p&gt;代码片段：&lt;/p&gt;
  &lt;pre&gt;ctx.rotate(0.2);

ctx.strokeRect(75, 75, 75, 75);&lt;/pre&gt;
  &lt;p&gt;输出：&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/p.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;h2&gt;Lab 1.8 转换&lt;/h2&gt;
  &lt;p&gt;代码：&lt;/p&gt;
  &lt;pre&gt;ctx.strokeRect(0, 0, 150, 150);

ctx.translate(150, 150);

ctx.strokeRect(0, 0, 150, 150);&lt;/pre&gt;
  &lt;p&gt;输出：&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/q.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;pre&gt; &lt;/pre&gt;
  &lt;h2&gt;Lab 1.9 保存和重置Canvas 的状态&lt;/h2&gt;
  &lt;pre&gt;ctx.fillStyle=&amp;quot;red&amp;quot;;

ctx.fillRect(75, 75, 150, 150);


ctx.fillStyle = &amp;quot;blue&amp;quot;;             

ctx.fillRect(90, 90, 50, 50);


ctx.save();


ctx.fillStyle = &amp;quot;yellow&amp;quot;;

ctx.fillRect(90, 160, 50, 50);


ctx.save();

ctx.fillStyle = &amp;quot;green&amp;quot;;

ctx.restore();

ctx.restore();

ctx.fillRect(160, 160, 50, 50);&lt;/pre&gt;
  &lt;p&gt;输出&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/r.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt;Lab 1.10 使用图像&lt;/p&gt;
  &lt;pre&gt;vari = new Image();
i.src = &amp;quot;Desert.jpg&amp;quot;;
i.onload = function () {
    //Draw Squqre
ctx.strokeStyle = &amp;quot;green&amp;quot;;
ctx.lineWidth = 5;
ctx.drawImage(i, 0, 0);
ctx.strokeRect(60, 120, 70, 80);

    //draw Text
ctx.strokeStyle = &amp;quot;yellow&amp;quot;;
ctx.font = &amp;quot;30px Segoe UI&amp;quot;;
ctx.lineWidth = 1;
ctx.strokeText(&amp;quot;My Home&amp;quot;, 80, 40);

    //Draw Arrow
ctx.beginPath();
ctx.strokeStyle = &amp;quot;red&amp;quot;;
ctx.lineWidth = 2;
ctx.moveTo(110, 110);
ctx.lineTo(125, 40);

ctx.moveTo(110, 110);
ctx.lineTo(100, 90);

ctx.moveTo(110, 110);
ctx.lineTo(126, 95);
ctx.stroke();
};&lt;/pre&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;输出：&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/s.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;h2&gt;Lab1.11 使用Canvas 生成动画&lt;/h2&gt;
  &lt;p&gt;一旦在Canvas 填充好东西就无法修改，可采用以下方法来修改：&lt;/p&gt;
  &lt;p&gt;1. 使用ClearRect 函数删除存在的元素&lt;/p&gt;
  &lt;p&gt;2. 添加新属性重画元素&lt;/p&gt;
  &lt;p&gt;当以上策略与传统的JS 函数结合，可使用TimeOut 或SetInterval 方法来实现，可产生动画。&lt;/p&gt;
  &lt;p&gt;代码：&lt;/p&gt;
  &lt;pre&gt;var interval;
var x = 0, y = 0;
functiondrawInAnimation()
{
varctx = document.getElementById(&amp;apos;MyCanvas&amp;apos;).getContext(&amp;quot;2d&amp;quot;);

ctx.beginPath();
ctx.moveTo(x, y);
ctx.clearRect(x , y, 50, 50);
if (x &amp;gt;document.getElementById(&amp;apos;MyCanvas&amp;apos;).width) {

        x = 0;
        y += 50;
if (y + 50 &amp;gt;document.getElementById(&amp;apos;MyCanvas&amp;apos;).height)
        {
            x = 0; y = 0;
        } 
    }
else {
        x += 15;
    }
ctx.fillStyle = getRndColor();
ctx.fillRect(x, y,50,50);
}
functiongetRndColor() {
var r = 255 * Math.random() | 0,
        g = 255 * Math.random() | 0,
        b = 255 * Math.random() | 0;
    return &amp;apos;rgb(&amp;apos; + r + &amp;apos;,&amp;apos; + g + &amp;apos;,&amp;apos; + b + &amp;apos;)&amp;apos;;
}

interval = setInterval(&amp;quot;drawInAnimation()&amp;quot;, 15);&lt;/pre&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;输出：&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" height="360" src="http://www.codeproject.com/KB/aspnet/889679/T.gif" width="640"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;h2&gt;Lab 2 使用SVG 工作&lt;/h2&gt;
  &lt;p&gt;如Canvas,SVG 支持在矩形中画图像，接下来将了解到Canvas 与SVG 的区别。&lt;/p&gt;
  &lt;p&gt;初始化&lt;/p&gt;
  &lt;p&gt;1. 新建HTML页面&lt;/p&gt;
  &lt;pre&gt;&amp;lt;html&amp;gt;

&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;&amp;lt;/body&amp;gt;

&amp;lt;/html&amp;gt;&lt;/pre&gt;
  &lt;pre&gt;2. 在body 标签内新建Canvas :&lt;/pre&gt;
  &lt;pre&gt;&amp;lt;SVG id=&amp;quot;MySVG&amp;quot; width=&amp;quot;500px&amp;quot; height=&amp;quot;500px&amp;quot; style=&amp;quot;border:1px solid black;&amp;quot;&amp;gt;

&amp;lt;/SVG &amp;gt; &lt;/pre&gt;
  &lt;pre&gt; &lt;/pre&gt;
  &lt;h3&gt;Lab2.1 画出多种形状&lt;/h3&gt;
  &lt;pre&gt;代码：&lt;/pre&gt;
  &lt;pre&gt;&amp;lt;svg width=&amp;quot;205&amp;quot; height=&amp;quot;200&amp;quot;&amp;gt;


    &amp;lt;!--surrounding border--&amp;gt;

    &amp;lt;rect x=&amp;quot;0&amp;quot; y=&amp;quot;0&amp;quot; width=&amp;quot;205&amp;quot; height=&amp;quot;200&amp;quot; style=&amp;quot;fill: rgb(199, 240, 185);&amp;quot;&amp;gt; &amp;lt;/rect&amp;gt;

    &amp;lt;!--surrounding border--&amp;gt;



    &amp;lt;!--Hat Start--&amp;gt;

    &amp;lt;rect x=&amp;quot;78&amp;quot; y=&amp;quot;10&amp;quot; width=&amp;quot;44&amp;quot; height=&amp;quot;70&amp;quot; style=&amp;quot;fill: black; stroke: black; &amp;quot;&amp;gt;&amp;lt;/rect&amp;gt;

    &amp;lt;ellipse cx=&amp;quot;100&amp;quot; cy=&amp;quot;20&amp;quot; rx=&amp;quot;67&amp;quot; ry=&amp;quot;12&amp;quot; stroke=&amp;quot;white&amp;quot;

                stroke-width=&amp;quot;0.5&amp;quot; fill=&amp;quot;black&amp;quot;&amp;gt;&amp;lt;/ellipse&amp;gt;          

    &amp;lt;!--Hat End--&amp;gt;



    &amp;lt;!--Left ear--&amp;gt;

    &amp;lt;ellipse cx=&amp;quot;55&amp;quot; cy=&amp;quot;70&amp;quot; rx=&amp;quot;25&amp;quot; ry=&amp;quot;25&amp;quot; stroke=&amp;quot;black&amp;quot; stroke-width=&amp;quot;2&amp;quot; fill=&amp;quot;gray&amp;quot;&amp;gt;&amp;lt;/ellipse&amp;gt;


    &amp;lt;!--Right ear--&amp;gt;

    &amp;lt;ellipse cx=&amp;quot;145&amp;quot; cy=&amp;quot;70&amp;quot; rx=&amp;quot;25&amp;quot; ry=&amp;quot;25&amp;quot; stroke=&amp;quot;black&amp;quot; stroke-width=&amp;quot;2&amp;quot; fill=&amp;quot;gray&amp;quot;&amp;gt;&amp;lt;/ellipse&amp;gt;


    &amp;lt;!--Face--&amp;gt;

    &amp;lt;circle cx=&amp;quot;100&amp;quot; cy=&amp;quot;105&amp;quot; r=&amp;quot;50&amp;quot; stroke=&amp;quot;black&amp;quot; stroke-width=&amp;quot;2&amp;quot; fill=&amp;quot;rgb(230, 231, 194)&amp;quot; /&amp;gt;


    &amp;lt;!--Left Eye--&amp;gt;

    &amp;lt;ellipse cx=&amp;quot;75&amp;quot; cy=&amp;quot;95&amp;quot; rx=&amp;quot;10&amp;quot; ry=&amp;quot;20&amp;quot;

                style=&amp;quot;fill:white;stroke:black;stroke-width:1&amp;quot; /&amp;gt;

    &amp;lt;!--Left Eye ball--&amp;gt;

    &amp;lt;ellipse cx=&amp;quot;80&amp;quot; cy=&amp;quot;95&amp;quot; rx=&amp;quot;5&amp;quot; ry=&amp;quot;12&amp;quot;

                style=&amp;quot;fill:black;stroke:black;stroke-width:1&amp;quot; /&amp;gt;


    &amp;lt;!--Right Eye--&amp;gt;

    &amp;lt;ellipse cx=&amp;quot;125&amp;quot; cy=&amp;quot;95&amp;quot; rx=&amp;quot;10&amp;quot; ry=&amp;quot;20&amp;quot;

                style=&amp;quot;fill:white;stroke:black;stroke-width:1&amp;quot; /&amp;gt;

    &amp;lt;!--Right Eye ball--&amp;gt;

    &amp;lt;ellipse cx=&amp;quot;120&amp;quot; cy=&amp;quot;95&amp;quot; rx=&amp;quot;5&amp;quot; ry=&amp;quot;12&amp;quot;

                style=&amp;quot;fill:black;stroke:black;stroke-width:1&amp;quot; /&amp;gt;


    &amp;lt;!--Mouth start--&amp;gt;

    &amp;lt;clipPath id=&amp;quot;cut-off-bottom&amp;quot;&amp;gt;

        &amp;lt;rect x=&amp;quot;70&amp;quot; y=&amp;quot;135&amp;quot; width=&amp;quot;60&amp;quot; height=&amp;quot;30&amp;quot; /&amp;gt;

    &amp;lt;/clipPath&amp;gt;

    &amp;lt;ellipse cx=&amp;quot;100&amp;quot; cy=&amp;quot;125&amp;quot; rx=&amp;quot;30&amp;quot; ry=&amp;quot;20&amp;quot; clip-path=&amp;quot;url(#cut-off-bottom)&amp;quot;

                style=&amp;quot;fill:rgb(230, 231, 194);stroke:black;stroke-width:2&amp;quot; /&amp;gt;

    &amp;lt;!--Mouth End--&amp;gt;


    &amp;lt;!--Nose--&amp;gt;

    &amp;lt;polygon points=&amp;quot;100,115 85,125 115,125&amp;quot;

                style=&amp;quot;fill: brown;

            stroke-width: 1&amp;quot; /&amp;gt;


    &amp;lt;!--Divider--&amp;gt;

    &amp;lt;line x1=&amp;quot;0&amp;quot; y1=&amp;quot;165&amp;quot; x2=&amp;quot;205&amp;quot; y2=&amp;quot;165&amp;quot; style=&amp;quot;stroke:brown;

stroke-width:2&amp;quot; /&amp;gt;

    &amp;lt;text x=&amp;quot;25&amp;quot; y=&amp;quot;185&amp;quot; font-family=&amp;quot;Comic Sans MS&amp;apos;&amp;quot; fill=&amp;quot;Blue&amp;quot; &amp;gt;A coder can be creative&amp;lt;/text&amp;gt;

&amp;lt;/svg&amp;gt;&lt;/pre&gt;
  &lt;p&gt;输出：&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/u.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;h3&gt;Lab 2.2SVG 动画&lt;/h3&gt;
  &lt;p&gt;SVG 使得动画制作变得简单：&lt;/p&gt;
  &lt;p&gt;初始化设置：&lt;/p&gt;
  &lt;pre&gt;&amp;lt;svg width=&amp;quot;205&amp;quot; height=&amp;quot;220&amp;quot;&amp;gt;

        &amp;lt;rect x=&amp;quot;0&amp;quot; y=&amp;quot;0&amp;quot; width=&amp;quot;205&amp;quot; height=&amp;quot;220&amp;quot; style=&amp;quot;fill: rgb(199, 240, 185);&amp;quot;&amp;gt;
        &amp;lt;/rect&amp;gt;

....
&amp;lt;/svg&amp;gt;&lt;/pre&gt;
  &lt;p&gt;眨眼动画：&lt;/p&gt;
  &lt;pre&gt;&amp;lt;!--Left Eye--&amp;gt;

        &amp;lt;ellipse cx=&amp;quot;75&amp;quot; cy=&amp;quot;95&amp;quot; rx=&amp;quot;15&amp;quot; ry=&amp;quot;15&amp;quot;

                    style=&amp;quot;fill:white;stroke:black;stroke-width:1&amp;quot; /&amp;gt;

        &amp;lt;!--Left Eye ball--&amp;gt;

        &amp;lt;ellipse cx=&amp;quot;75&amp;quot; cy=&amp;quot;95&amp;quot; rx=&amp;quot;5&amp;quot; ry=&amp;quot;5&amp;quot;

                    style=&amp;quot;fill:black;stroke:black;stroke-width:1&amp;quot;&amp;gt;

            &amp;lt;animate attributeName=&amp;quot;cx&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                        from=&amp;quot;75&amp;quot; to=&amp;quot;85&amp;quot; id=&amp;quot;Left1&amp;quot; repeatCount=&amp;quot;1&amp;quot;

                        begin=&amp;quot;0s;Left5.end&amp;quot; dur=&amp;quot;0.5s&amp;quot; /&amp;gt;

            &amp;lt;set attributeName=&amp;quot;cx&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                    to=&amp;quot;85&amp;quot;

                    begin=&amp;quot;Left1.end&amp;quot; /&amp;gt;


            &amp;lt;animateTransform attributeName=&amp;quot;transform&amp;quot;

                                type=&amp;quot;rotate&amp;quot; id=&amp;quot;Left2&amp;quot;

                                from=&amp;quot;0 75 95&amp;quot; to=&amp;quot;360 75 95&amp;quot;

                                begin=&amp;quot;Left1.end&amp;quot; dur=&amp;quot;1s&amp;quot;

                                repeatCount=&amp;quot;3&amp;quot;&amp;gt;

            &amp;lt;/animateTransform&amp;gt;

            &amp;lt;animate attributeName=&amp;quot;cx&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                        from=&amp;quot;85&amp;quot; to=&amp;quot;65&amp;quot; id=&amp;quot;Left3&amp;quot;

                        begin=&amp;quot;Left2.end&amp;quot; dur=&amp;quot;0.5s&amp;quot; /&amp;gt;

            &amp;lt;set attributeName=&amp;quot;cx&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                    to=&amp;quot;65&amp;quot;

                    begin=&amp;quot;Left3.end&amp;quot; /&amp;gt;


            &amp;lt;animateTransform attributeName=&amp;quot;transform&amp;quot;

                                type=&amp;quot;rotate&amp;quot; id=&amp;quot;Left4&amp;quot;

                                from=&amp;quot;360 75 95&amp;quot; to=&amp;quot;0 75 95&amp;quot;

                                begin=&amp;quot;Left3.end&amp;quot; dur=&amp;quot;1s&amp;quot;

                                repeatCount=&amp;quot;3&amp;quot;&amp;gt;

            &amp;lt;/animateTransform&amp;gt;

            &amp;lt;animate attributeName=&amp;quot;cx&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                        from=&amp;quot;65&amp;quot; to=&amp;quot;75&amp;quot; id=&amp;quot;Left5&amp;quot;

                        begin=&amp;quot;Left4.end&amp;quot; dur=&amp;quot;0.5s&amp;quot; /&amp;gt;

            &amp;lt;set attributeName=&amp;quot;cx&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                    to=&amp;quot;75&amp;quot;

                    begin=&amp;quot;Left4.end&amp;quot; &amp;gt;

            &amp;lt;/set&amp;gt;

        &amp;lt;/ellipse&amp;gt;&lt;/pre&gt;
  &lt;pre&gt;&amp;lt;!--Right Eye--&amp;gt;

        &amp;lt;ellipse cx=&amp;quot;125&amp;quot; cy=&amp;quot;95&amp;quot; rx=&amp;quot;15&amp;quot; ry=&amp;quot;15&amp;quot;

                    style=&amp;quot;fill:white;stroke:black;stroke-width:1&amp;quot; /&amp;gt;

        &amp;lt;!--Right Eye ball--&amp;gt;

        &amp;lt;ellipse cx=&amp;quot;125&amp;quot; cy=&amp;quot;95&amp;quot; rx=&amp;quot;5&amp;quot; ry=&amp;quot;5&amp;quot; style=&amp;quot;fill:black;stroke:black;stroke-width:1&amp;quot;&amp;gt;

            &amp;lt;animate attributeName=&amp;quot;cx&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                        from=&amp;quot;125&amp;quot; to=&amp;quot;135&amp;quot; id=&amp;quot;Right1&amp;quot; repeatCount=&amp;quot;1&amp;quot;

                        begin=&amp;quot;0s;Right5.end&amp;quot; dur=&amp;quot;0.5s&amp;quot; /&amp;gt;

            &amp;lt;set attributeName=&amp;quot;cx&amp;quot; attributeType=&amp;quot;XML&amp;quot; to=&amp;quot;135&amp;quot; begin=&amp;quot;Right1.end&amp;quot; /&amp;gt;


            &amp;lt;animateTransform attributeName=&amp;quot;transform&amp;quot;

                                type=&amp;quot;rotate&amp;quot; id=&amp;quot;Right2&amp;quot;

                                from=&amp;quot;0 125 95&amp;quot; to=&amp;quot;360 125 95&amp;quot;

                                begin=&amp;quot;Right1.end&amp;quot; dur=&amp;quot;1s&amp;quot;

                                repeatCount=&amp;quot;3&amp;quot;&amp;gt;

            &amp;lt;/animateTransform&amp;gt;

            &amp;lt;animate attributeName=&amp;quot;cx&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                        from=&amp;quot;135&amp;quot; to=&amp;quot;115&amp;quot; id=&amp;quot;Right3&amp;quot;

                        begin=&amp;quot;Right2.end&amp;quot; dur=&amp;quot;0.5s&amp;quot; /&amp;gt;

            &amp;lt;set attributeName=&amp;quot;cx&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                    to=&amp;quot;115&amp;quot;

                    begin=&amp;quot;Right3.end&amp;quot; /&amp;gt;


            &amp;lt;animateTransform attributeName=&amp;quot;transform&amp;quot;

                                type=&amp;quot;rotate&amp;quot; id=&amp;quot;Right4&amp;quot;

                                from=&amp;quot;360 125 95&amp;quot; to=&amp;quot;0 125 95&amp;quot;

                                begin=&amp;quot;Right3.end&amp;quot; dur=&amp;quot;1s&amp;quot;

                                repeatCount=&amp;quot;3&amp;quot;&amp;gt;

            &amp;lt;/animateTransform&amp;gt;

            &amp;lt;animate attributeName=&amp;quot;cx&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                        from=&amp;quot;115&amp;quot; to=&amp;quot;125&amp;quot; id=&amp;quot;Right5&amp;quot;

                        begin=&amp;quot;Right4.end&amp;quot; dur=&amp;quot;0.5s&amp;quot; /&amp;gt;

            &amp;lt;set attributeName=&amp;quot;cx&amp;quot; attributeType=&amp;quot;XML&amp;quot; to=&amp;quot;125&amp;quot; begin=&amp;quot;Right4.end&amp;quot; /&amp;gt;

        &amp;lt;/ellipse&amp;gt;&lt;/pre&gt;
  &lt;p&gt;张嘴动画：&lt;/p&gt;
  &lt;pre&gt;&amp;lt;clipPath id=&amp;quot;cut-off-bottom&amp;quot;&amp;gt;

    &amp;lt;rect x=&amp;quot;70&amp;quot; y=&amp;quot;135&amp;quot; width=&amp;quot;60&amp;quot; height=&amp;quot;11&amp;quot;&amp;gt;


        &amp;lt;animate attributeName=&amp;quot;y&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                    from=&amp;quot;135&amp;quot; to=&amp;quot;125&amp;quot; id=&amp;quot;MouthClipAnimation1&amp;quot;

                    begin=&amp;quot;0;MouthClipAnimation3.end+3&amp;quot; dur=&amp;quot;1s&amp;quot; /&amp;gt;

        &amp;lt;animate attributeName=&amp;quot;height&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                    from=&amp;quot;11&amp;quot; to=&amp;quot;22&amp;quot; id=&amp;quot;MouthClipAnimation2&amp;quot;

                    begin=&amp;quot;0;MouthClipAnimation4.end+3&amp;quot; dur=&amp;quot;1s&amp;quot; /&amp;gt;


        &amp;lt;set attributeName=&amp;quot;y&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                to=&amp;quot;125&amp;quot;

                begin=&amp;quot;MouthClipAnimation1.end-0.1&amp;quot; /&amp;gt;

        &amp;lt;set attributeName=&amp;quot;height&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                to=&amp;quot;22&amp;quot;

                begin=&amp;quot;MouthClipAnimation2.end-0.1&amp;quot; /&amp;gt;


        &amp;lt;animate attributeName=&amp;quot;y&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                    from=&amp;quot;125&amp;quot; to=&amp;quot;135&amp;quot; id=&amp;quot;MouthClipAnimation3&amp;quot;

                    begin=&amp;quot;MouthClipAnimation1.end+3&amp;quot; dur=&amp;quot;1s&amp;quot; /&amp;gt;

        &amp;lt;animate attributeName=&amp;quot;height&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                    from=&amp;quot;22&amp;quot; to=&amp;quot;11&amp;quot; id=&amp;quot;MouthClipAnimation4&amp;quot;

                    begin=&amp;quot;MouthClipAnimation2.end+3&amp;quot; dur=&amp;quot;1s&amp;quot; /&amp;gt;


        &amp;lt;set attributeName=&amp;quot;y&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                to=&amp;quot;135&amp;quot;

                begin=&amp;quot;MouthClipAnimation3.end-0.1&amp;quot; /&amp;gt;

        &amp;lt;set attributeName=&amp;quot;height&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                to=&amp;quot;11&amp;quot;

                begin=&amp;quot;MouthClipAnimation4.end-0.1&amp;quot; /&amp;gt;

    &amp;lt;/rect&amp;gt;

&amp;lt;/clipPath&amp;gt;

&amp;lt;ellipse cx=&amp;quot;100&amp;quot; cy=&amp;quot;125&amp;quot; rx=&amp;quot;30&amp;quot; ry=&amp;quot;20&amp;quot; clip-path=&amp;quot;url(#cut-off-bottom)&amp;quot;

            style=&amp;quot;fill:rgb(230, 231, 194);stroke:black;stroke-width:2&amp;quot;&amp;gt;


    &amp;lt;animate attributeName=&amp;quot;cy&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                from=&amp;quot;125&amp;quot; to=&amp;quot;135&amp;quot; id=&amp;quot;MouthEllipseAnimation1&amp;quot;

                begin=&amp;quot;0;MouthEllipseAnimation4.end+3&amp;quot; dur=&amp;quot;1s&amp;quot; /&amp;gt;

    &amp;lt;animate attributeName=&amp;quot;rx&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                from=&amp;quot;30&amp;quot; to=&amp;quot;8&amp;quot; id=&amp;quot;MouthEllipseAnimation2&amp;quot;

                begin=&amp;quot;0;MouthEllipseAnimation5.end+3&amp;quot; dur=&amp;quot;1s&amp;quot; /&amp;gt;

    &amp;lt;animate attributeName=&amp;quot;ry&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                from=&amp;quot;20&amp;quot; to=&amp;quot;8&amp;quot; id=&amp;quot;MouthEllipseAnimation3&amp;quot;

                begin=&amp;quot;0;MouthEllipseAnimation6.end+3&amp;quot; dur=&amp;quot;1s&amp;quot; /&amp;gt;

    &amp;lt;set attributeName=&amp;quot;cy&amp;quot; attributeType=&amp;quot;XML&amp;quot;

            to=&amp;quot;135&amp;quot;

            begin=&amp;quot;MouthEllipseAnimation1.end-0.1&amp;quot; /&amp;gt;

    &amp;lt;set attributeName=&amp;quot;rx&amp;quot; attributeType=&amp;quot;XML&amp;quot;

            to=&amp;quot;8&amp;quot;

            begin=&amp;quot;MouthEllipseAnimation2.end-0.1&amp;quot; /&amp;gt;

    &amp;lt;set attributeName=&amp;quot;ry&amp;quot; attributeType=&amp;quot;XML&amp;quot;

            to=&amp;quot;8&amp;quot;

            begin=&amp;quot;MouthEllipseAnimation3.end-0.1&amp;quot; /&amp;gt;


    &amp;lt;animate attributeName=&amp;quot;cy&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                from=&amp;quot;135&amp;quot; to=&amp;quot;125&amp;quot; id=&amp;quot;MouthEllipseAnimation4&amp;quot;

                begin=&amp;quot;MouthEllipseAnimation1.end+3&amp;quot; dur=&amp;quot;1s&amp;quot; /&amp;gt;

    &amp;lt;animate attributeName=&amp;quot;rx&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                from=&amp;quot;8&amp;quot; to=&amp;quot;30&amp;quot; id=&amp;quot;MouthEllipseAnimation5&amp;quot;

                begin=&amp;quot;MouthEllipseAnimation2.end+3&amp;quot; dur=&amp;quot;1s&amp;quot; /&amp;gt;

    &amp;lt;animate attributeName=&amp;quot;ry&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                from=&amp;quot;8&amp;quot; to=&amp;quot;20&amp;quot; id=&amp;quot;MouthEllipseAnimation6&amp;quot;

                begin=&amp;quot;MouthEllipseAnimation3.end+3&amp;quot; dur=&amp;quot;1s&amp;quot; /&amp;gt;

    &amp;lt;set attributeName=&amp;quot;cy&amp;quot; attributeType=&amp;quot;XML&amp;quot;

            to=&amp;quot;125&amp;quot;

            begin=&amp;quot;MouthEllipseAnimation4.end-0.1&amp;quot; /&amp;gt;

    &amp;lt;set attributeName=&amp;quot;rx&amp;quot; attributeType=&amp;quot;XML&amp;quot;

            to=&amp;quot;30&amp;quot;

            begin=&amp;quot;MouthEllipseAnimation5.end-0.1&amp;quot; /&amp;gt;

    &amp;lt;set attributeName=&amp;quot;ry&amp;quot; attributeType=&amp;quot;XML&amp;quot;

            to=&amp;quot;20&amp;quot;

            begin=&amp;quot;MouthEllipseAnimation6.end-0.1&amp;quot; /&amp;gt;

&amp;lt;/ellipse&amp;gt;&lt;/pre&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;盒子动画效果：&lt;/p&gt;
  &lt;pre&gt;&amp;lt;!--Box Anmation--&amp;gt;

        &amp;lt;rect x=&amp;quot;0&amp;quot; y=&amp;quot;165&amp;quot; width=&amp;quot;14&amp;quot; height=&amp;quot;14&amp;quot;

              stroke-width=&amp;quot;2&amp;quot; fill=&amp;quot;brown&amp;quot;&amp;gt;

            &amp;lt;animate attributeName=&amp;quot;width&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                     from=&amp;quot;0&amp;quot; to=&amp;quot;210&amp;quot; id=&amp;quot;leftToRight&amp;quot;

                     begin=&amp;quot;0;bottomToTop.end&amp;quot; dur=&amp;quot;1s&amp;quot; /&amp;gt;

            &amp;lt;set attributeName=&amp;quot;width&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                 to=&amp;quot;14&amp;quot;

                 begin=&amp;quot;leftToRight.end-0.2&amp;quot; /&amp;gt;

            &amp;lt;set attributeName=&amp;quot;x&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                 to=&amp;quot;191&amp;quot;

                 begin=&amp;quot;leftToRight.end-0.2&amp;quot; /&amp;gt;


            &amp;lt;animate attributeName=&amp;quot;height&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                     from=&amp;quot;14&amp;quot; to=&amp;quot;55&amp;quot; id=&amp;quot;topToBottom&amp;quot;

                     begin=&amp;quot;leftToRight.end&amp;quot; dur=&amp;quot;1s&amp;quot; /&amp;gt;

            &amp;lt;set attributeName=&amp;quot;height&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                 to=&amp;quot;14&amp;quot;

                 begin=&amp;quot;topToBottom.end-0.2&amp;quot; /&amp;gt;

            &amp;lt;set attributeName=&amp;quot;y&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                 to=&amp;quot;206&amp;quot;

                 begin=&amp;quot;topToBottom.end-0.2&amp;quot; /&amp;gt;


            &amp;lt;animate attributeName=&amp;quot;width&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                     from=&amp;quot;0&amp;quot; to=&amp;quot;210&amp;quot; id=&amp;quot;rightToLeft&amp;quot;

                     begin=&amp;quot;topToBottom.end&amp;quot; dur=&amp;quot;1s&amp;quot; /&amp;gt;

            &amp;lt;animate attributeName=&amp;quot;x&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                     from=&amp;quot;206&amp;quot; to=&amp;quot;0&amp;quot; id=&amp;quot;rightToLeft&amp;quot;

                     begin=&amp;quot;topToBottom.end&amp;quot; dur=&amp;quot;1s&amp;quot; /&amp;gt;

            &amp;lt;set attributeName=&amp;quot;width&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                 to=&amp;quot;14&amp;quot;

                 begin=&amp;quot;rightToLeft.end-0.2&amp;quot; /&amp;gt;

            &amp;lt;set attributeName=&amp;quot;x&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                 to=&amp;quot;0&amp;quot;

                 begin=&amp;quot;rightToLeft.end-0.2&amp;quot; /&amp;gt;


            &amp;lt;animate attributeName=&amp;quot;height&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                     from=&amp;quot;14&amp;quot; to=&amp;quot;55&amp;quot; id=&amp;quot;bottomToTop&amp;quot;

                     begin=&amp;quot;rightToLeft.end&amp;quot; dur=&amp;quot;1s&amp;quot; /&amp;gt;

            &amp;lt;animate attributeName=&amp;quot;y&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                     from=&amp;quot;206&amp;quot; to=&amp;quot;165&amp;quot; id=&amp;quot;bottomToTop&amp;quot;

                     begin=&amp;quot;rightToLeft.end&amp;quot; dur=&amp;quot;1s&amp;quot; /&amp;gt;

            &amp;lt;set attributeName=&amp;quot;height&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                 to=&amp;quot;14&amp;quot;

                 begin=&amp;quot;bottomToTop.end-0.2&amp;quot; /&amp;gt;

            &amp;lt;set attributeName=&amp;quot;y&amp;quot; attributeType=&amp;quot;XML&amp;quot;

                 to=&amp;quot;165&amp;quot;

                 begin=&amp;quot;bottomToTop.end-0.2&amp;quot; /&amp;gt;

        &amp;lt;/rect&amp;gt;


        &amp;lt;line x1=&amp;quot;0&amp;quot; y1=&amp;quot;165&amp;quot; x2=&amp;quot;205&amp;quot; y2=&amp;quot;165&amp;quot; style=&amp;quot;stroke:brown;

stroke-width:2&amp;quot; /&amp;gt;

        &amp;lt;text x=&amp;quot;14&amp;quot; y=&amp;quot;200&amp;quot; font-family=&amp;quot;Comic Sans MS&amp;apos;&amp;quot; fill=&amp;quot;Blue&amp;quot;&amp;gt;A coder can be creative&amp;lt;/text&amp;gt;&lt;/pre&gt;
  &lt;p&gt;输出&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/v.gif"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;h2&gt;SVG VS Canvas&lt;/h2&gt;
  &lt;p&gt;   &lt;br /&gt;SVG 和Canvas 区别：&lt;/p&gt;
  &lt;ul&gt;
   &lt;li&gt;Vector VS Pixel&lt;/li&gt;
&lt;/ul&gt;
  &lt;p&gt;Canvas 是基于Pixel 而SVG 是基于Vector&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/w.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" height="459" src="http://www.codeproject.com/KB/aspnet/889679/x.png" width="670"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;简单来说SVG图片是与屏幕分辨率无关的，而Canvas 不是。&lt;/p&gt;
  &lt;ul&gt;
   &lt;li&gt;XML VS JavaScript&lt;/li&gt;
&lt;/ul&gt;
  &lt;p&gt;SVG使用语义标记可绘出图形，然而Canvas就只能使用JS脚本代码。&lt;/p&gt;
  &lt;ul&gt;
   &lt;li&gt;支持事件处理&lt;/li&gt;
&lt;/ul&gt;
  &lt;p&gt;Canvas 不支持事件处理，SVG 支持。&lt;/p&gt;
  &lt;p&gt;HTML&lt;/p&gt;
  &lt;pre&gt;  &amp;lt;svg width=&amp;quot;120&amp;quot; height=&amp;quot;120&amp;quot;&amp;gt;

        &amp;lt;circle cx=&amp;quot;60&amp;quot; cy=&amp;quot;60&amp;quot; r=&amp;quot;25&amp;quot; stroke=&amp;quot;green&amp;quot;  id=&amp;quot;MyCircle&amp;quot;

            stroke-width=&amp;quot;8&amp;quot; fill=&amp;quot;yellow&amp;quot; onmouseover=&amp;quot;IncreaseSize();&amp;quot; onmouseout=&amp;quot;DecreaseSize();&amp;quot; /&amp;gt;

    &amp;lt;/svg&amp;gt;

&amp;lt;input type=&amp;quot;button&amp;quot; value=&amp;quot;+&amp;quot; onclick=&amp;quot;ChangeSize();&amp;quot;&amp;gt;&lt;/pre&gt;
  &lt;p&gt;JavaScript&lt;/p&gt;
  &lt;pre&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;

    function IncreaseSize ()

    {

                    document.getElementById(&amp;quot;MyCircle&amp;quot;).r.baseVal.value=50;

    }

    function DecreaseSize()

    {

        document.getElementById(&amp;quot;MyCircle&amp;quot;).r.baseVal.value = 25;

    }

&amp;lt;/script&amp;gt;&lt;/pre&gt;
  &lt;pre&gt;输出&lt;/pre&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/y.gif"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;ul&gt;
   &lt;li&gt;
    &lt;pre&gt;支持图片保存&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
  &lt;pre&gt;Canvas 最后可输出为图像，可使用浏览器默认的选项将图像保存。而SVG 不支持。&lt;/pre&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeproject.com/KB/aspnet/889679/z.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;pre&gt; &lt;/pre&gt;
  &lt;pre&gt;下一章将要学习什么？&lt;/pre&gt;
&lt;/div&gt;
          
           &lt;br /&gt; &lt;br /&gt;
          
             &lt;a href="http://powertoolsteam.iteye.com/blog/2275777#comments"&gt;已有   &lt;strong&gt;0&lt;/strong&gt; 人发表留言，猛击-&amp;gt;&amp;gt;  &lt;strong&gt;这里&lt;/strong&gt;&amp;lt;&amp;lt;-参与讨论&lt;/a&gt;
          
           &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;
ITeye推荐
 &lt;br /&gt;
 &lt;ul&gt;  &lt;li&gt;   &lt;a href="http://www.iteye.com/clicks/433" target="_blank"&gt;—软件人才免语言低担保 赴美带薪读研！— &lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
 &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;
          
        &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/55165-%E5%A4%A9%E5%AD%A6-html5-svg</guid>
      <pubDate>Thu, 04 Feb 2016 09:26:53 CST</pubDate>
    </item>
    <item>
      <title>HTML5数据可视化第二弹：打造最美3D机房</title>
      <link>https://itindex.net/detail/53567-html5-%E6%95%B0%E6%8D%AE-%E5%8F%AF%E8%A7%86%E5%8C%96</link>
      <description>&lt;div&gt;
  &lt;p&gt;最近项目开发任务告一段落，刚好有时间整理这大半年的一些成果。使用html5时间还不久，对js的认识还不够深入。没办法，以前一直搞java，对js的一些语言特性和概念一时还转换不过来。&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;上一篇   &lt;a href="http://www.iteye.com/admin/blogs/2215863/%20http:/twaver.iteye.com/blog/2212512" target="_blank" title="&amp;#24425;&amp;#34425;&amp;#29190;&amp;#28856;&amp;#22270;"&gt;第一弹&lt;/a&gt;介绍了项目中做的一个彩虹爆炸图，主要用了 html5的canvas的2d绘制技术。这一回我想介绍一下项目中的一个亮点技术：html5的3D，以及如何用它打造精美的3D机房监控系统。&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;h2&gt;目标效果图&lt;/h2&gt;
  &lt;p&gt;下图是领导给找的一张的效果参考图，客户希望机房至少能达到下面的3D效果。懂的人都知道，这可是一张设计公司出的装修效果图啊，就算是用max建模，也需要大量的工作，何况咱可是程序员在做数据中心的可视化项目啊。。。强忍心中奔腾的万千头**马，静下心来思考，那就先从搭建一个webGL的场景开始把。&lt;/p&gt;
  &lt;p&gt;  &lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1131/648ec24e-4151-3ba9-a902-fb8f0b84c8b6.png"&gt;&lt;/img&gt;   &lt;br /&gt;&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;h2&gt;WebGL基本场景搭建&lt;/h2&gt;
  &lt;p&gt;在html5里面使用3D已经不是什么高深技术，它的基础是WebGL，一个openGL的浏览器子集，支持大部分主要3D功能接口。目前最新的浏览器都有比较好的支持，IE需要到11（是的，你没有看错）。&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;要检测你的浏览器是否支持webGL，直接访问网页   &lt;a href="http://get.webgl.org/"&gt;http://get.webgl.org/&lt;/a&gt; 看是否能看到一个旋转的立方体。如果能看到，说明你的浏览器支持webgGL，否则，可以下一个最新的chrome试试吧。相对来说chrome对webGL的支持最好，效率也很优秀。&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;要在浏览器里面使用webGL，就要研究webGL相关的技术和用法。做3D应用并不是一件轻松的事。就算最简单的搭建一下webGL场景，也需要下面这些代码：&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;&amp;lt;script&amp;gt;    
    var width = window.innerWidth;  
    var height= window.innerHeight;  
    var container = document.createElement( &amp;apos;div&amp;apos; );  
    document.body.appendChild( container );  
    var webglcanvas = document.createElement(&amp;apos;canvas&amp;apos;);               
    container.appendChild(webglcanvas);   
    var gl = webglcanvas.getContext(&amp;quot;experimental-webgl&amp;quot;);                
    
    function updateFrame () {             
      gl.viewport ( 0, 0, width, height );  
            gl.clearColor(0.4, 0.4, 0.7, 1);  
            gl.clear ( gl.COLOR_BUFFER_BIT );       
             setTimeout(   
        function(){updateFrame()},  
                20);  
         }  

    setTimeout(   
      function(){
        updateFrame();
      },  
    20);  
&amp;lt;/script&amp;gt;   
&lt;/pre&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;和html一样，需要先创建一个canvas元素，并获得其webgl上下文：&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;var gl = webglcanvas.getContext(&amp;quot;experimental-webgl&amp;quot;);&lt;/pre&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;然后在一个updateFrame的函数中，像html5的2d context一样，去绘制3D的内容。另外，要再起一个死循环，每隔**毫秒调用一次这个updateFrame函数来重绘场景。和2D不同，3D场景里面的变化是随时随地的，所以需要不停刷新，就像播放电影或视频，静止不动的画面基本没有，所以死循环刷新基本是必要的。不过实际项目使用中会有很多优化，尽量做到“按需刷新”，节省cpu和移动设备电量。这一点也是很重要的，有感兴趣的同学，可以单独写文章介绍。这段程序基本上什么也没做，就画了一个静止不动的区域，如下图：&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1127/cca9aaec-e1c2-373b-baa1-4764f132dc53.png"&gt;&lt;/img&gt;   &lt;br /&gt;   &lt;br /&gt;&lt;/p&gt;
  &lt;p&gt;虽然看不见任何3D的内容，不过它已经是一个最简单的webgl程序了。我们的精美的3D机房，也是要在这上面不断丰富而已。&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;h2&gt;对象封装&lt;/h2&gt;
  &lt;p&gt;要做项目，搭建下去工作量太大了，时间周期也不允许。使用第三方辅助工具是不可避免的，像Three.js、twaver.js都是选择。这些工具都可以提供3D的基本对象和各种特效。当然这都不是最主要的，主要是如何利用它做出我想要的效果：好看。为了避免大量修改代码，在项目里做了一些封装，把原始3D的立方体等对象进行进一步封装，让一个json数据就可以提供这些对象的定义。这样使用起来就比较方便了。Json大致结构如下：&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;var json={	
	objects: [{
		name: &amp;apos;地板&amp;apos;,
		…
	},{
	…
	}],
}
&lt;/pre&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;下面我们逐一来看这些3D对象是怎么进行美化的，过程可能稍显啰嗦，但实际工作就是这么繁琐的有木有？&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;h2&gt;地板和斜坡&lt;/h2&gt;
  &lt;p&gt;第一个要做，也是应该比较简单的，就是地板。这个地板应该是一个有点厚度、有格子贴图的薄薄立方体平面。还好经过封装，就写一段json对象就能定义了：&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;{
		name: &amp;apos;地板&amp;apos;,
		type: &amp;apos;cube&amp;apos;,
		width: 1600,
		height: 10,
		depth: 1300,
			
		style: {
			&amp;apos;m.color&amp;apos;: &amp;apos;#BEC9BE&amp;apos;,
			&amp;apos;m.ambient&amp;apos;: &amp;apos;#BEC9BE&amp;apos;,
		}
}
&lt;/pre&gt;
  &lt;p&gt;    &lt;br /&gt;&lt;/p&gt;
  &lt;p&gt;通过定义，创建一个13米*16米的地板块：&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1137/faa47e03-69a5-3dcb-941c-6c84ffcad9fb.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;p&gt;只有颜色还不够，找一个地板砖纹理图。需要注意的是，纹理图的尺寸都需要是宽和高都是2的幂，例如128x128、256*256等，这样出来效果才会好。这也是3D软件一般所要求的。另外纹理要能连续拼接不露破绽，这样才好。例如下面我google出来的图：&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1141/3442440a-7a36-396d-90aa-c767ef774d31.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;p&gt;在style里面添加：&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;   &amp;apos;top.m.texture.image&amp;apos;: &amp;apos;images/floor.png&amp;apos;,
   &amp;apos;top.m.texture.repeat&amp;apos;: new mono.Vec2(10,10),&lt;/pre&gt;
  &lt;p&gt;    &lt;br /&gt;&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;效果如下：&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1145/f4fde2bd-d04d-34e8-bb19-b35c9d103218.png"&gt;&lt;/img&gt;   &lt;br /&gt;有图片材质纹理，效果果然好多了。不过客户说他们这里底面有一个方便运送设备的斜坡，要画出来。这……&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1147/bfd26506-318e-3a66-a3ff-aea426872a5b.png"&gt;&lt;/img&gt;   &lt;br /&gt; 后来想到twaver里面的对象可以支持运算。可以定义一个斜的立方体，让地板剪掉立方体，应该可以做到。于是继续定义json：&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;{
		name: &amp;apos;地板切坡&amp;apos;,
		type: &amp;apos;cube&amp;apos;,
		width: 200,
		height: 20,
		depth: 260,
		translate: [-348,0,530],
		rotate: [Math.PI/180*3, 0, 0],
		op: &amp;apos;-&amp;apos;,
		style: {
			…,
		}
	}
&lt;/pre&gt;
  &lt;p&gt; 这里定义的一个倾斜的立方体，通过translate定义位置，通过rotate定义旋转角度，然后再通过op定义运算符，这里是“减去”，就用“-”。被剪掉的立方体也可以设置材质、纹理、贴图、颜色….等等。看看效果：&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1149/f151c19b-a74a-3e9c-a370-0cf289773304.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;h2&gt;走廊桌&lt;/h2&gt;
  &lt;p&gt;按要求走廊要放一个接待桌。为了简单就偷懒做一个立方体表示吧！这个简单，继续使用上述办法：&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;{
		name: &amp;apos;走廊板凳&amp;apos;,
		type: &amp;apos;cube&amp;apos;,
		width: 300,
		height: 50,
		depth: 100,
		translate: [350, 0, -500],
	}&lt;/pre&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;效果如下：&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1152/41db7d6e-ea43-3a99-989c-8b6e54ac926b.png"&gt;&lt;/img&gt;   &lt;br /&gt; 再增加一点配色并启动阴影效果后，看着就好多了。尽管只是个简单的立方体，但只要和整体风格一致，并不显得简陋。很3D里面最重视的就是效率，千万不要放一些很复杂的模型，尤其是这些非业务对象。&lt;/p&gt;
  &lt;h2&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1158/d4e19350-c36d-3d54-ace9-ba2018065bb4.png"&gt;&lt;/img&gt; 墙体&lt;/h2&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;墙体是机房里很重要的一个部分，有好的光照、阴影的效果才能看起来更加逼真。由于墙体是不规则的路径，一段一段去生成还真挺麻烦的，还好引擎支持这种物体，甚至曲线路径都可以。这里只要在json里面定义一组数字的坐标，让这些数字依次连接，组成一个墙体，最后生成3D对象放入场景中就行啦。&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;json定义如下：&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;{
		name: &amp;apos;主墙体&amp;apos;,
		type: &amp;apos;path&amp;apos;,
		width: 20,
		height: 200,
		translate: [-500, 0, -500],
		data:[
			[0, 0],
			[1000, 0],
			[1000, 500],
			[500, 500],
			[500, 1000],
			[0, 1000],
			[0,0],
		],
}&lt;/pre&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;注意这里的类型变成了path，data中定义了一个二维坐标数组来描述墙体。由于墙都是从底面开始的，所以只定义它的平面的x、y坐标就行了。看看效果：&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1160/bc1f5e12-20b5-3528-a7fe-7aa40aee5097.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;p&gt;不如前文所说，还是需要上色、上阴影，才能有更好的效果。这里我们启用阴影并咨询设计师美眉几个颜色值，加上去，再看下效果：&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1162/ac4936e9-0106-3d6b-82ca-9608d88cd9d9.png"&gt;&lt;/img&gt;   &lt;br /&gt; 还有细节：&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1164/e0bb7304-1ad9-3cb2-8909-f67998867145.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;h2&gt;   &lt;br /&gt;门&lt;/h2&gt;
  &lt;p&gt;看着雪白的墙，是不是觉得少了点什么？对，就是门。在3D机房的监控系统里，门禁是很重要的一块，客户要求门应该与实际位置相对应，并且要有开门关门的动画效果。这样，实际的门禁信息采集上来后，就能在界面实时看到门的状态了。&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;这里，考虑到门如果直接放上去，会被墙盖住；如果比墙厚，又难看不符合实际。还是应该先定义一个门洞立方体，把门所在的位置挖掉：&lt;/p&gt;
  &lt;pre&gt;{
		name: &amp;apos;门洞&amp;apos;,
		type: &amp;apos;cube&amp;apos;,
		width: 195,
		height: 170,
		depth: 30,
		op: &amp;apos;-&amp;apos;,
		translate:[-350,2,500],
}
&lt;/pre&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;刚好挖在斜坡的位置，这样设备进屋就方便了：&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1174/07816a0b-0f9d-3fda-be45-4ea6e23369a6.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;p&gt;不过这门没有一个门框，感觉不太生动。多一个门框会感觉立体感强一些。门框可以是一个比门洞略大的立方体，在挖门洞之前添加：&lt;/p&gt;
  &lt;pre&gt;{
		name: &amp;apos;门框&amp;apos;,
		type: &amp;apos;cube&amp;apos;,
		width: 205,
		height: 180,
		depth: 26,
		translate: [-350, 0, 500],
		op: &amp;apos;+&amp;apos;,
	}&lt;/pre&gt;
  &lt;p&gt; 加上阴影和光线等综合效果，还不错，挺有档次的。&lt;/p&gt;
  &lt;p&gt;    &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1176/f79ad9df-d7cb-359c-9443-053879715792.png"&gt;&lt;/img&gt;   &lt;br /&gt; 来张全景图看看：&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1178/c3089957-2002-32f2-a26f-586cf05601ab.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;p&gt;接着，只要把门安上去就行了。门的定义比较简单，就是一个薄的立方体。不过为了做到玻璃效果，需要设置透明度，让它看上去更像一个玻璃，再让设计师美眉弄一张好看一点的门的图，贴上去。尽管有了webGL，复杂的建模工作可以省略了，不过设计师美眉的配合仍然很重要。&lt;/p&gt;
  &lt;p&gt;先做左边的门：&lt;/p&gt;
  &lt;pre&gt;{
		name: &amp;apos;左门&amp;apos;,
		type: &amp;apos;cube&amp;apos;,
		width: 93,
		height: 165,
		depth: 2,
		translate:[-397,4,500],
		style:{
			&amp;apos;m.transparent&amp;apos;: true,
			&amp;apos;m.texture.image&amp;apos;: &amp;apos;images/door_left.png&amp;apos;,					
		}&lt;/pre&gt;
  &lt;p&gt; 上面增加的style主要透明和贴图两项。看看效果：&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1180/9f3eeb7a-0a09-3e9d-b070-446bd50a496f.png"&gt;&lt;/img&gt;   &lt;br /&gt;同样的方法，再把右侧门贴上就搞定了。为了增加体验，也是用户的要求，门上面设置了动画：双击可以自动打开，再双击可以直接关闭。动画功能引擎做好了封装，在json中直接指定动画类型就行了。不过要注意左右门的动画旋转方向要相反，要不然一个向里开一个向外开感觉比较怪异。&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1182/ff25e19d-28dd-3a8d-a943-2b537f66ea67.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;h2&gt;窗&lt;/h2&gt;
  &lt;p&gt;项目中，窗本身不需要有任何业务属性，但是美观度的要求可一点都不能少。方法和门类似，先放窗框后挖窗体。不过为了有点变化，这里不做窗框了，做一个窗台，方法和道理与门相同。&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;{
		name: &amp;apos;主窗户洞&amp;apos;,
		type: &amp;apos;cube&amp;apos;,
		width: 420,
		height: 150,
		depth: 50, 
		translate: [200, 30, 500],
		op: &amp;apos;-&amp;apos;,
	},{
		name: &amp;apos;主窗户台&amp;apos;,
		type: &amp;apos;cube&amp;apos;,
		width: 420,
		height: 10,
		depth: 40, 
		translate: [200, 30, 510],
		op: &amp;apos;+&amp;apos;,
	}&lt;/pre&gt;
 
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;定义了一个窗洞（挖掉）、一个窗台（添加）。一个大窗户就做好了：&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1190/980fdbb7-a6c9-3b9f-8d69-b79e14f472f7.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;p&gt;再添加一个略带颜色的透明玻璃。玻璃设置点高光和反射，增加“玻璃”感觉：&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;{
		name: &amp;apos;主窗户玻璃&amp;apos;,
		type: &amp;apos;cube&amp;apos;,
		width: 420,
		height: 150,
		depth: 2,
		translate: [200, 30, 500],
		op: &amp;apos;+&amp;apos;,
		style: {
			&amp;apos;m.transparent&amp;apos;: true,
			&amp;apos;m.opacity&amp;apos;:0.4,
			&amp;apos;m.color&amp;apos;:&amp;apos;#58ACFA&amp;apos;,
		},			
	}&lt;/pre&gt;
 Json中玻璃设置了透明度和颜色。这样一个半透明的茶色玻璃就好了：
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1192/ce8a0948-d46a-3814-bd79-4c298e9525d0.png"&gt;&lt;/img&gt;   &lt;br /&gt;到这里突然在想：盖房子如果像写程序一样简单就好了，所有的程序猿就不会是无房一族单身狗了。当然写程序和盖房子一样：该封装好的要封装好，最后就是搭积木组装就行了。如果盖房子都是从挖土活泥巴开始，那就杯具了。写程序也是一样，如果从webGL的main开始写……这3D机房的系统要几个月甚至几年才能做出来呢？&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;h2&gt;外侧墙&lt;/h2&gt;
  &lt;p&gt;按照项目实际要求，继续增加更多建筑物墙体。主要是房间外侧有两道走廊隔墙。这是一个中间有大片透明玻璃的走廊隔墙，需要做的好看一点。由于是直线墙，没有复杂走向，直接用立方体定义得了：&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;{
		name: &amp;apos;左外墙&amp;apos;,
		type: &amp;apos;cube&amp;apos;,
		width: 20,
		height: 200,
		depth: 1300,
		translate: [-790, 0, 0],
		op: &amp;apos;+&amp;apos;,
}&lt;/pre&gt;
   &lt;br /&gt;  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;效果如下：   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1196/8de1d375-0394-3663-8cda-19e0511b29b2.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;p&gt;再继续挖掉中间的窗户部分：&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;{
		name: &amp;apos;左外墙洞&amp;apos;,
		type: &amp;apos;cube&amp;apos;,
		width: 30,
		height: 110,
		depth: 1300,
		translate: [-790, 60, 0],
		op: &amp;apos;-&amp;apos;,
}&lt;/pre&gt;
 
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1198/005e1b6c-8f9d-3050-aaef-b9b25b83d5d3.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;p&gt;空白显得很奇怪，加上玻璃试试：&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;{
		name: &amp;apos;左外墙玻璃&amp;apos;,
		type: &amp;apos;cube&amp;apos;,
		width: 4,
		height: 110,
		depth: 1300,
		translate: [-790, 60, 0],
		op: &amp;apos;+&amp;apos;,
		style: {
			&amp;apos;m.transparent&amp;apos;: true,
			&amp;apos;m.opacity&amp;apos;:0.6,
		},
}&lt;/pre&gt;
 
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;有了半透明和高光的效果，看起来就有质感了，右边也如法炮制：&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1202/60269052-367e-3651-bf87-0b2c6f8a2b0e.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;这样，整个建筑的外观就基本完成了。最后，放一些绿植，增加些生气吧。&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;h2&gt;植物&lt;/h2&gt;
  &lt;p&gt;做一盆植物，需要有一个空的花盆，花盆里面有泥土，上面有一株植物。这些东西用3D做起来都有点啰嗦。不过也不难。花盆用一个大圆柱剪掉中间的小圆柱，做成空心花盆；植物用贴图+透明模拟一下就行，不用真的去做植物的3D模型，否则要累死了。&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;根据上面的思路，在项目中通过仔细调整，把创建花盆的代码封装好，然后在json中定义花盆位置就行了。下面定义一个：&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;{
		name: &amp;apos;花1&amp;apos;,
		type: &amp;apos;plant&amp;apos;,
		translate: [560, 0, 400],
}
&lt;/pre&gt;
 程序中解析如果type是plant则创建植物对象并添加场景。
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1204/359b46c5-6bfb-37d8-a96a-a4d50e74c33c.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;p&gt;在房间、走廊、甚至窗台上都可以放几盆，窗台上的可以通过设置scale缩小一些，并提升其高度到窗台位置即可。&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1208/bc0052c6-be0e-317f-b229-69677f8e0217.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;p&gt;看看下整体效果，还不赖吧。&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1206/7de05bf6-77b7-352b-b72d-dff5b62f1b44.png"&gt;&lt;/img&gt;   &lt;br /&gt; 写了那么一大篇，才终于把3D机房的外观装修完成，咱也算是个设计师程序员的混合型人才了呢。其实机房最核心的资源——机柜，还没找落呢，没办法，形象工程也是项目建设的一大亮点。&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;h2&gt;机柜&lt;/h2&gt;
  &lt;p&gt;机柜，以及其中的服务器设备。这才是3D机房里面最终要管理的内容。在我们的实际项目中，这些资产都是在数据库中存储，并通过json接口加载到浏览器中显示。这里为了演示方便，直接写几个机柜的片段，看一下显示效果。&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;   &lt;strong&gt;机柜对象在项目中是这样封装的：用一个立方体来表示机柜，并加上贴图。项目中，为了提高显示速度，机柜一开始并不加载内部服务器内容，而是只显示自身一个立方体。当用户双击后，会触发一个延迟加载器，从服务器端加载机柜内部服务器，并加载到对应的位置上。此时，机柜会被挖空成一个空心的立方体，以便视觉上更像一个机柜。&lt;/strong&gt;&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;定义机柜的json如下：&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;{
		name: &amp;apos;机柜&amp;apos;,
		type: &amp;apos;rack&amp;apos;,
		lazy: true,
		width: 70,
		depth: 100,
		height: 220,
		translate: [-370, 0, -250],
		severity: CRITICAL,
	}&lt;/pre&gt;
上面的机柜定义中，有一个lazy标记，标记它是否延迟加载其内容。如果延迟加载，则双击触发，否则程序显示时直接加载其内容。Severity是定义了机柜的告警信息，它是否有业务告警。如果有告警，会用一个气泡显示在机柜的上方，同时机柜也会被染色成告警对应的颜色。
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1210/1b864267-2545-3d2b-a6da-cc0df2651bf7.png"&gt;&lt;/img&gt;   &lt;br /&gt;加入更多的机柜看看效果： &lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1212/703a20c3-0401-34a1-bea0-e9f6c6ac4bd0.png"&gt;&lt;/img&gt;   &lt;br /&gt;    &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1214/bd017fda-98cd-317f-8c5d-50c07b80dd20.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;h2&gt;设备&lt;/h2&gt;
  &lt;p&gt;简单起见，这里管理的设备假设都是机架设备，尺寸规格比较规整，因此比较容易在机柜中组织。一个设备的外观确定后，在数据库中定义好模板，加载时根据其所在机柜的位置放置即可。&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;这里只是随机生成了几个服务器设备，并按位置摆放。在实际应用中，可以通过手工录入或者智能机架报送的信息来确定服务器的类型和位置。&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1216/eb1c085f-8b86-3c88-944e-14f3e58ab982.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;p&gt;   &lt;strong&gt;如果需要监控到端口级别，还可以在服务器弹出后，再进一步延迟加载设备商的板卡、端口对象，并点击后进一步进行配置、监控等操作。&lt;/strong&gt;当然加载的数据越细，对3D引擎和浏览器的压力会越大。可以通过动态延迟加载/卸载策略，获取一些平衡折中。&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;h2&gt;电视机&lt;/h2&gt;
  &lt;p&gt;纯属无聊，再做一个电视机挂在墙上。依旧，定义一个立方体、挖空屏幕，放上透明玻璃，再贴上我们喜欢的电视节目画面，就ok了。&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;{
		name: &amp;apos;电视机体&amp;apos;,
		type: &amp;apos;cube&amp;apos;,
		width: 150,
		height: 80,
		depth: 5,
		translate: [80, 100, 13],
		op: &amp;apos;+&amp;apos;,		
	},{
		name: &amp;apos;电视机挖空&amp;apos;,
		type: &amp;apos;cube&amp;apos;,
		width: 130,
		height: 75,
		depth: 5,
		translate: [80, 102.5, 17],
		op: &amp;apos;-&amp;apos;,
	},{
		name: &amp;apos;电视机屏幕&amp;apos;,
		type: &amp;apos;cube&amp;apos;,
		width: 130,
		height: 75,
		depth: 1,
		translate: [80, 102.5, 14.6],
		op: &amp;apos;+&amp;apos;,
		style: {
			&amp;apos;front.m.texture.image&amp;apos;: &amp;apos;images/screen.jpg&amp;apos;,
		},
	}
&lt;/pre&gt;
  &lt;p&gt; 当然，实际项目中，也可以换上监控大屏幕的效果：&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1219/3ea26db6-a7b8-3dd9-8e96-4cf939422415.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;h2&gt;总结&lt;/h2&gt;
  &lt;p&gt;整个场景写到最后，我也已经脑洞大开游刃有余了。3D场景，尤其是这类业务系统，并不一定要死抠模型的仿真度，才能做到“好看”的效果。先来一张全景看一下：&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1223/c83da05f-4a31-333a-bef1-f2fe094c6193.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;怎么样，还算精美吧？基本不输前面看到的广告公司的效果图。但和效果图一张死图片不一样，我们这是一个能操作、能漫游、能缩放、有动画、显示流畅、浏览器无需插件就能直接打开的3D机房小程序，就一个json文件和一百多行代码和一天的时间就搞定了，还是让人有点惊讶的。&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1227/6108ce5f-f9e1-3660-b582-4563ac3c15d2.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;p&gt;不用插件、不用3Dmax，不用模型库，干干净净纯粹的小程序，手机和平板也能用哦，而且还很流畅！上一张我的Nexus5截图瞅瞅：&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;   &lt;img alt="" src="http://dl2.iteye.com/upload/attachment/0109/1229/099ce225-e222-3c82-8c18-8dba17af7f46.png"&gt;&lt;/img&gt;   &lt;br /&gt; &lt;/p&gt;
  &lt;p&gt;经过优化，场景加载已经控制在600毫秒以内，缩放漫游也很流畅。当然技术和美化永无止境，用户的需求也千变万化精益求精。但只要我们选择好了技术和工具，就能事半功倍。Html5就是极佳的一个选择。&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;Html5，也许它还不是银弹，但它确实是很好的一个炮弹。本文这一弹，你还喜欢吗？欢迎来信留言索取代码、技术交流：   &lt;a href="mailto:tw-service@servasoftware.com" target="_blank"&gt;tw-service@servasoftware.com&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
&lt;/div&gt;
          
           &lt;br /&gt; &lt;br /&gt;
          
             &lt;a href="http://twaver.iteye.com/blog/2215863#comments"&gt;已有   &lt;strong&gt;0&lt;/strong&gt; 人发表留言，猛击-&amp;gt;&amp;gt;  &lt;strong&gt;这里&lt;/strong&gt;&amp;lt;&amp;lt;-参与讨论&lt;/a&gt;
          
           &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;
ITeye推荐
 &lt;br /&gt;
 &lt;ul&gt;  &lt;li&gt;   &lt;a href="http://www.iteye.com/clicks/433" target="_blank"&gt;—软件人才免语言低担保 赴美带薪读研！— &lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
 &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;
          
        &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/53567-html5-%E6%95%B0%E6%8D%AE-%E5%8F%AF%E8%A7%86%E5%8C%96</guid>
      <pubDate>Mon, 01 Jun 2015 14:25:33 CST</pubDate>
    </item>
    <item>
      <title>HTML5游戏——只是趋势 未到爆点</title>
      <link>https://itindex.net/detail/53566-html5-%E6%B8%B8%E6%88%8F-%E8%B6%8B%E5%8A%BF</link>
      <description>&lt;p&gt;  &lt;img alt="" src="http://images0.cnblogs.com/news/66372/201506/011531116132687.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;HTML5 游戏是一个趋势，对现状而言，这仅是一个趋势。规则简单、进程快、时间短，成为 HTML5 游戏被迅速认可的主要原因。通过社交网络的分享，获取更广泛的传播，产品变成商业的逻辑正源于此。在资本市场的推波助澜后，留下的只有 HTML5 游戏从业者的迷惑——何时才是爆发点。&lt;/p&gt;
 &lt;p&gt;基于 HTML5 技术开发的《围住神经猫》在微信朋友圈疯狂转发的时候，从业者似乎看到了已故苹果 CEO 乔布斯所指引的方向已经到来——“没有人愿意使用 Flash，全球已经开始步入 HTML5 时代”。&lt;/p&gt;
 &lt;p&gt;作为生态链上的一环，HTML5 游戏引擎公司白鹭时代市场营销中心副总裁张翔最近在向外讲述这样一个利好消息：经纬创投王华东说非常看好 HTML5 游戏，这两年至少三五家公司能上市，300 亿的市场；程天总他说顺为也可能会拿出几亿美元投资 H5 领域。然而他同样明白，这个市场并非平稳发展。“从 2012 年开始就有很多人进入 H5 游戏行业，不过由于各方面的原因，HTML5 的发展受到很多阻碍。”&lt;/p&gt;
 &lt;p&gt;HTML5 的数据在一场行业会后被公开,HTML5 的游戏规模经过短短一年的发展，现在已有 1.2 亿左右的用户规模，据预测，今年用户将突破 1.71 亿。但这仍原远低于手机游戏用户的整体规模，腾讯互娱运营部总经理崔晓春在华为 2015 年分析师大会上表示，2015 年中国手机游戏用户超过 6 亿。此外，另一组数据也可以证实 HTML5 的虚火。日前一场行业会议上从业者披露，《愚公移山》月流水刚突破 200 万，《古龙群侠传》用户刚突破 200 万。这与动辄过千万，甚至过亿原生 App 手游相距甚远。&lt;/p&gt;
 &lt;p&gt;与 App 手游相比，HTML5 游戏更加依赖渠道，但却难以寻找到新的出路。南京泥巴怪创始人秦川表示，HTML5 可能接触到一些手游没有覆盖的人群，比如朋友圈的分享，工具类 APP 的游戏频道，或者浏览器的推荐，但已经形成规范运营和实际收入的渠道还是占少数。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;HTML5 游戏难以从趋势转为产业的四点原因：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;缺少明星产品带动产业健康发展&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;在朋友圈等社交网络迅速传播的 HTML5 游戏，能够称之为明星产品的少之又少。缺乏成功产品的带动，开发者的信心被打击，进而难以使得这类游戏产品迅速上量。&lt;/p&gt;
 &lt;p&gt;2014 年 7 月末一夜爆红的《围住神经猫》，因为设计符合移动端传播的规律，而游戏规则简化到只需用户点击，使得其迅速得以传播。然而同样是一夜之间，产品已经消失在用户的视野。在这之后虽然仍有一些小游戏在社交网络病毒式传播，但是难以被人记住，甚至更多有着浓厚的商业广告痕迹。即使有产品获得较好的成绩，如《寻找房祖名》2 日点击超 6000 万次、《愚公移山》月流水已达 100 万左右，但整个行业的最大问题仍是变现能力有限，这决定了 HTLM5 游戏市场的发展速度。&lt;/p&gt;
 &lt;p&gt;触控科技高级技术总监林顺表示，手游可以通过设置付费点，增值道具等一系列手段完成付费形成闭环，且通过日常运营来提高用户粘性和留存率，但 HTML5 游戏寿命短，用户利用碎片化时间进行即时游戏，热度通常不超过 7 天，一旦兴趣点转移，无需卸载变直接流失。&lt;/p&gt;
 &lt;p&gt;事实上，HTML5 游戏可以理解为移动端的网页游戏，这使得另一个影响产业健康发展的因素出现。类比 PC 端网页游戏即可发现，由于开发技术门槛较低，这使得山寨品开始出现。“神经猫”热度尚未衰减时，各类“围住 XXX”的山寨也开始出现在社交网络。神经猫的创造者秦川就估计：山寨神经猫大约分走了 500 万的访问量。同样为点击类操作的休闲游戏，开发类似《疯狂猜图》这样的 App 游戏尚需要 10 万元左右的成本，而《围住神经猫》的开发仅需要一个程序员、一个工程师合力开发一天的时间。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;硬件和网络发展并未推动 HTML5 爆发&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;早在 2010 年，Zynga 收购了 HTML5 游戏引擎开发商 Dextrose，随后发布了第一款 HTML 游戏《Mafia Wars Atlantic City》，这带动了 Facebook、EA，甚至是迪士尼的跟进。然而，仅用了不到一年时间，这些崛起的 HTML5 游戏公司就开始纷纷宣告失败、倒闭。彼时失败的原因被归结于网络上无法支持、渲染技术本身不够成熟、没有合适的分发渠道等多种因素。《围住神经猫》制作人秦川日前向媒体表示，“归结起来就是天时地利人和。”&lt;/p&gt;
 &lt;p&gt;经历两年的基础设施积累，2014 年 10 月，W3C HTML 工作组正式发布了 HTML5 的推荐标准。与之同步的是，智能手机的性能升级，以及网络进入 4G 带来的高速带宽。但从现实来看，HTML5 却并未如预期的那样迅速爆发，甚至连 Web App 取代原生 App 的呼声也日渐稀薄。&lt;/p&gt;
 &lt;p&gt;秦川表示，“我头疼的问题，确实手机首先性能参层不齐，其次 H5 在原生基础上性能再差一层。”游戏发展从轻度游戏到重度游戏，这是技术发展，“我们可以做重度游戏，但是重度只能少数机器上跑，其实投产比低，所以我们尽可能适配大量的游戏，让很多人都可以玩这一款游戏。”&lt;/p&gt;
 &lt;p&gt;事实上，更有游戏开发者表示，目前 HTML5 的坑很多，比如在适配的过程中，不仅要满足高配置系统的运行，而且要满足低端智能手机使用者的体验。这样的问题在网络方面同样出现，因为并非所有用户都在使用 4G 网络，甚至在一些地区用户仍使用 2G 网络进行。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;收入低导致行业普遍观望&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;尽管整个产业并不成熟，但对开发者来说，HTML5 游戏的快速开发和迅速发布，比起原生 App 要更容易切入市场，尤其是巨头林立的手游市场。DataEye《2014 年 Q4HTML5 游戏数据报告》显示，目前六成从业者已经投入或准备投入 HTML5 游戏，近 7 成 HTML5 游戏的用户集中在微信平台。不过，“HTML5 游戏的未来很美，但现在很苦。”掌趣科技联席 CEO 胡斌说，很多公司由于收入低的问题在观望。在他看来，如果能有三个月流水达 180 万的游戏出现，会吸引更多的 CP 切入尝试。&lt;/p&gt;
 &lt;p&gt;收入低的主要原因是 HTML5 游戏本身的特性。其主要以轻度游戏为主，虽然有一些厂商希望类似页游一样打造中重度游戏实现亿元级产品，但是后者的通道暂时没有打通，用户的碎片时间短暂，市场难以培育相应玩家。&lt;/p&gt;
 &lt;p&gt;但值得注意的是，一些轻度 HTML5 游戏正在朋友圈瞬间兴起，其本身并不具备更多游戏本身的特性，而是帮助企业营销而获取广告和开发收入。这类产品的出现，使得开发者可以通过流量实现广告变现，但其出现正在摧毁原本就很脆弱的 HTML5 良型生态。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;资本关注技术多过游戏本身&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;市场应该看空 HTML5 游戏，原因是这只是资本在旺盛的手游热后，正在需找新的出路，真正吸引资本的实际上技术，而非游戏开发者。正如张翔所讲述的，资本正在关注这以市场。顺为已经计划支持至少 10 个以上 HTML5 团队，而王华东认为在两三年内有多家 HTML5 技术公司在国内外上市。但显然这些团队并非是单纯的游戏 CP。HTML5 游戏的开发者似乎也意识到问题的现状，《愚公移山》制作人陈陈表示，资本对 HTML5 CP 的关注度很高，但是钱不多。“一大波很汹涌把你淹没掉，但是你们公司没有做好准备。”&lt;/p&gt; &lt;p&gt;  &lt;a href="http://news.cnblogs.com/n/522239/" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt; &lt;img alt="" height="1" src="http://news.cnblogs.com/news/rssclick.aspx?id=522239" width="1"&gt;&lt;/img&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/53566-html5-%E6%B8%B8%E6%88%8F-%E8%B6%8B%E5%8A%BF</guid>
      <pubDate>Mon, 01 Jun 2015 15:30:51 CST</pubDate>
    </item>
    <item>
      <title>自己的HTML5 播放器 - __constructor</title>
      <link>https://itindex.net/detail/53501-html5-%E6%92%AD%E6%94%BE%E5%99%A8-constructor</link>
      <description>&lt;p&gt;不知道写什么，主要也是自己水平实在是有限，想想自己会的东西都太基本，网上一搜往后不知道能数多少页，自己表达的也没有别人好。我希望自己写的东西要么是网上没有(可能性就是零……)，要么是带着自己的见解。所以没有素材，还是自己踏踏实实学习比较靠谱，看的书越多，发现自己不会的也越多，但是太长时间不发东西出来又害怕自己丢失了写文章的习惯，所以凑数也要凑一篇！&lt;/p&gt; &lt;p&gt;开头讲了这么多，就是做了铺垫，这个HTML5播放器很水……就是为了凑一篇博文素材加上这是我第一个上传到github上的项目……&lt;/p&gt; &lt;p&gt;github地址：https://github.com/westAnHui/HTML5-Player&lt;/p&gt; &lt;p&gt;功能很普遍，这玩意又不难，先看截图，如果觉得丑就不用看了0.0&lt;/p&gt; &lt;p&gt;本文不包含介绍HTML5播放器这方面的API，那个网上一搜一大摞……&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;注意：上一个(左箭头)，下一个(右箭头)、全屏还没写，未完成版……原谅我偷懒先放出来了，其他功能基本上都实现了&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;  &lt;img alt="" src="http://images0.cnblogs.com/blog2015/740327/201505/251551392091710.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;  &lt;img alt="" src="http://images0.cnblogs.com/blog2015/740327/201505/251551499438588.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;  &lt;img alt="" src="http://images0.cnblogs.com/blog2015/740327/201505/251552425682899.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;——————————————————————————————————————————————————————————————&lt;/p&gt; &lt;p&gt;很简单，几个基本的按钮，悬停按钮时发光用了border-radius和box-shadow配合，总进度条和音量进度条使用自定义拖拽&lt;/p&gt; &lt;p&gt;也有几点收获&lt;/p&gt; &lt;p&gt;比如：&lt;/p&gt; &lt;p&gt;box-sizing:border-box是真心的好用啊，特别对于有些在父级宽高未知，子元素需要填满，不过子元素自身有border和padding，这样无脑width或height设置为100%，那就超了~但是加上box-sizing:border-box世界就清静了~&lt;/p&gt; &lt;p&gt;transform:translate(-50%, -50%)，这个也是棒的不行，偏移的50%是针对子元素本身的，不需要知道自己的宽高数值就可以。配合top:50%，left:50%，position:absolute立马达到垂直居中！，相比较margin:-(需要知道自己本身宽高再除2)%，方便了很多！&lt;/p&gt; &lt;p&gt;js是写在window.onload里面的&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;注意：如果不用window.onload，在DOM加载完毕之后直接跑的话，是读不到总视频时间的&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;video.duration的结果是undefined&lt;/p&gt; &lt;p&gt;视频和图片是一个性质嘛~无聊测试了一下本机环境下延迟40ms就可以读了，不过这毫无用处……&lt;/p&gt; &lt;p&gt;最后给个GIF&lt;/p&gt; &lt;p&gt;  &lt;img alt="" src="http://images0.cnblogs.com/blog2015/740327/201505/251621437408936.gif"&gt;&lt;/img&gt;&lt;/p&gt; &lt;img alt="" height="1" src="http://counter.cnblogs.com/blog/rss/4528184" width="1"&gt;&lt;/img&gt; &lt;br /&gt; &lt;p&gt;本文链接：  &lt;a href="http://www.cnblogs.com/constructor/p/4528184.html" target="_blank"&gt;自己的HTML5 播放器&lt;/a&gt;，转载请注明。&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/53501-html5-%E6%92%AD%E6%94%BE%E5%99%A8-constructor</guid>
      <pubDate>Mon, 25 May 2015 16:23:00 CST</pubDate>
    </item>
    <item>
      <title>技术干货分享：如何选择 HTML5 游戏引擎</title>
      <link>https://itindex.net/detail/55510-%E6%8A%80%E6%9C%AF-%E5%B9%B2%E8%B4%A7-%E5%88%86%E4%BA%AB</link>
      <description>&lt;p&gt;原生手游市场已是红海，腾讯、网易等寡头独霸天下，H5游戏市场或将成为下一个风口。据笔者所知，很多H5游戏开发团队由于选择引擎不慎导致项目甚至团队夭折。如何选择适合团队和项目的引擎，笔者通过学习和项目实践，总结微薄经验，供大家参考，非技术人员也可以将本篇内容作为引擎选择的重要关注点。&lt;/p&gt; &lt;p&gt;选择H5游戏引擎的思考维度  &lt;br /&gt;1、开发语言的支持  &lt;br /&gt;2、2D、3D、VR的支持  &lt;br /&gt;3、性能  &lt;br /&gt;4、引擎的应用广度  &lt;br /&gt;5、设计理念  &lt;br /&gt;6、工作流支持力度  &lt;br /&gt;7、商业化成熟案例  &lt;br /&gt;8、学习资源与技术支持能力&lt;/p&gt; &lt;p&gt;首先，我们要知道，当前主流的游戏引擎有哪些。由于H5引擎有很多，笔者在这里进行了精心的筛选，过滤掉不支持webGL的引擎，以及封装了第三方渲染内核的JS框架，和不能直接在浏览器中运行的JS引擎。&lt;/p&gt; &lt;p&gt;为什么要过滤掉这几种呢，首先，没有自己的渲染内核，仅仅是基于第三方的内核作的API封装，笔者很担心可持续的性能优化和维护能力。另外，不能在浏览器中直接运行的JS引擎，将限制H5游戏跨平台的交互能力。还有， 笔者非常看好webGL模式，认为webGL模式才是H5引擎的未来。原因有几点：&lt;/p&gt; &lt;blockquote&gt;  &lt;p&gt;第一、性能，webGL模式远超Canvas数倍。DOM模式就不适合用于真正的游戏开发，更不用提。   &lt;br /&gt;第二、3D方向，webGL模式理论上可以制作2D和3D游戏，Canvas和DOM模式下只能制作2D游戏。   &lt;br /&gt;第三、普及率，webGL的普及率已经非常高了，尤其是支持webGL的腾讯TBS-Blink内核已在4月19日发布，并逐步在微信、QQ空间、QQ浏览器、手机QQ等APP中采用静默安装方式全面升级。这个普及率在国内带来的影响，;你懂的……&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;  &lt;strong&gt;1、选择H5游戏开发语言&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;拥有广泛开发者的H5游戏开发语言共有三种，分别为Flash AS3、TypeScript、JavaScript。其中Flash AS3、TypeScript均属于面向对象的高级脚本语言，通过编译器将原项目代码编译成JavaScript代码文件运行于浏览器之中，面向对象的高级语言无论是项目开发管理，还是项目开发的工具环境的成熟度都明显优于JavaScript脚本语言，尤其是中大型项目方面，AS3等高级语言的效率会更高。&lt;/p&gt; &lt;p&gt;  &lt;img alt="s1" src="http://www.gamelook.com.cn/wp-content/uploads/2016/04/s115.jpg" width="550"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;从上图看出，支持JavaScript语言的引擎更多，由于AS3语言的编译器为Layabox引擎推出的，因此采用AS3作为开发语言的仅有Layabox引擎。笔者建议在开发中大型游戏项目的时候，采用TypeScript或者是Flash AS3语言进行开发。如果是小型游戏，任选其一即可。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;2、引擎的未来延续能力&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;选择一个引擎，并不是简单的认为，满足眼前够用就可以了，引擎的未来延续能力也是很重要的，这个项目是2D，下个项目想开发3D，如果引擎不支持怎么办？去换个引擎？如果VR的机会来了，再想发布VR版本，这个引擎不支持，需要重新开发吗？等等问题，作为开发者尽可能要提前想好。&lt;/p&gt; &lt;p&gt;  &lt;img alt="s2" src="http://www.gamelook.com.cn/wp-content/uploads/2016/04/s29.jpg" width="550"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;通过上图，可以看出，即便是在支持webGL的H5引擎里，有只面向2D游戏的，也有只面向3D游戏的，同时支持2D、3D、VR的H5引擎，从目前看只有Layabox与Egret引擎。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;3、性能是核心需求&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;性能是H5游戏面临的核心门槛，也是很多H5游戏不被专业玩家认可的重要原因之一。游戏卡顿，不流畅，这样的产品体验很难在激烈竞争中生存下来。&lt;/p&gt; &lt;p&gt;H5产业早期的普及阶段即将过去，游戏品质在迅速提高，品质中包括精细的美术和炫酷的动画等。在复杂的游戏项目面前，上述种种元素，其流畅体验度对游戏引擎是极大的考验。所以选择性能优秀的引擎是保证品质的最重要基础，一定要谨慎。&lt;/p&gt; &lt;p&gt;在游戏项目研发开始时，一定要先对复杂的模块做DEMO测试，特别是带背景滚动的游戏。比如横屏卷轴游戏，对帧数稳定性要求极高，如果满足不了性能上的需求，可能会带来眩晕、眼花、疲倦等不良体验。&lt;/p&gt; &lt;p&gt;  &lt;img alt="s3" src="http://www.gamelook.com.cn/wp-content/uploads/2016/04/s38.jpg" width="550"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;在webGL的2D渲染性能方面，pixi.js的性能处于当前的顶级。在webGL的3D渲染性能方面，Three.js非常优秀。在runtime方面Cocos2d-js也有着原生级的表现，经过对比，笔者认为Layabox性能的综合实力最强，在各个渲染领域都保持在HTML5引擎的顶级水平。当然，上图仅作为参考，对于任何号称某个引擎性能最牛的论调，一定要亲自进行性能DEMO的测试对比，而不要轻易采信。&lt;/p&gt; &lt;p&gt;由于性能是游戏最核心的需求，笔者这里再多说一句，大型项目在系统复杂度、UI复杂度、动画显示数量和种类等方面与小型游戏项目完全不在一个量级。会涉及到比小游戏更复杂的性能优化、内存管理、资源管理等需求，如果选择了小马拉大车的低性能引擎，项目夭折可能性非常大，除非最后项目开发者花大量时间自己优化引擎。所以性能差一点，就会导致结果差很多，不可主观想象。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;4、与引擎的应用广度&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;随着H5游戏品质提升，在其他领域也具备一定的竞争力和价值，一次开发可发行各个领域版本，已成为日渐明确的需求，这里面包括发行原生APP手游和PC的flash页游需求，大统一的引擎时代即将来领。目前最火爆的H5游戏《传奇世界H5》据说有40%的收入来自PC网页。&lt;/p&gt; &lt;p&gt;发布PC页游时，由于PC浏览器目前对HTML5兼容性不足70%，用户损耗很大，页游联运平台可能会拒绝或放量很少，只有采用能同时发布Flash版本的引擎，才能解决这个问题。&lt;/p&gt; &lt;p&gt;  &lt;img alt="s4" src="http://www.gamelook.com.cn/wp-content/uploads/2016/04/s43.jpg" width="550"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;5、设计理念与定位&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;设计理念是个比较大的话题，也是个很重要的引擎选择因素，比如引擎是要专注移动端，还是要面向全平台多端游戏市场。是注重性能，还是注重工具链等等。深入了解不同引擎的理念与定位，才能更好的与游戏产品进行结合。&lt;/p&gt; &lt;p&gt;  &lt;img alt="s5" src="http://www.gamelook.com.cn/wp-content/uploads/2016/04/s52.jpg" width="550"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;上图内容仅作参考，详情建议去各引擎官网深入了解。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;6、工作流支持力度&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;作为商业级开源引擎，工具链的提供与支持也是一种选择考量要素，比如UI编辑器、粒子编辑器、骨骼编辑器、场景编辑器等等，如果引擎方直接提供或支持，那么将会较大的提升研发效率。  &lt;br /&gt;本文中提到的7个引擎，只有Egret、Layabox、Cocos2d-JS这三个引擎，在工具链方面提供足够全面的支撑。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;7、是否有成熟的商业案例&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;怎么证明引擎是成熟的？一定要有成熟的商业案例，一般引擎的官网上都会有游戏案例介绍，我们在选择引擎之前要进行深入体验，包括：商业案例的数量、商业案例的种类、稳定性、流畅度（要在低端机里体验）、项目复杂度、项目相似度等。如果有一些大型成功案例背书会相对安全可靠些。  &lt;br /&gt;从目前的行业案例来看，Layabox引擎的MMORPG《醉西游》、重度动作游戏《猎刃2》、大型模拟经营游戏《梦幻家园》等无疑是H5引擎技术的最高水准代表作。但是从卡牌、挂机等类型的付费游戏总体数量来看，Egret引擎明显占优，充分说明该引擎的市场宣传力度更胜一筹。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;8、学习资源与技术支持能力&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;能提供什么样的学习资源，以及技术支持，对于开发者也是重要因素，如果你是技术大牛，只想使用轻量的第三方渲染内核。那么2D游戏，pixi.js无疑是首选。3D游戏，笔者推荐Three.js。但是这两种引擎的学习资料都比较稀少。笔者认为学习资料的完善，以及在学习过程中的技术支持力度，将会很大的帮助你解决引擎使用中的问题。所以，API完善，DEMO完善，文档完善，社区的响应速度，交流氛围，以及QQ技术支持等，都可以作为你选择引擎的因素考量之一。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;9、页游移植产品的引擎选择&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;目前像《醉西游》等优秀H5产品是Flash页游或手游移植而成，移植类的产品在选用引擎时要注意，代码是否可以直接移植？如果可以，那将节省大量的开发成本。比如Flash AS3开发的2D或3D页游或手游，可以把逻辑与算法代码直接拷贝移植到Layabox引擎项目中，开发速度提高数倍。&lt;/p&gt; &lt;p&gt;写在最后：最后提醒一下，千万不要相信某些引擎的单方宣传，一定要花一点时间去研究实践，亲自制作DEMO去作一作对比，动手体验到的才是真理。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;针对DEMO测试笔者有几点建议：&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;        1、采用一个复杂的UI，特别是复杂列表，比如说没有分页的背包列表，背包里放上不同的道具图片，测试滑动时的流畅度，这块比较考验性能，元素越复杂，数据越多，尤其能对比出来性能上的差异。&lt;/p&gt; &lt;p&gt;        2、包含最复杂战斗部分，不要写战斗逻辑代码，不然会花的时间太长，只需要把战斗相关的动画和复杂的元素放在场景中模拟即可，因为H5游戏性能瓶颈通常在于画面的显示。&lt;/p&gt; &lt;p&gt;        3、 测试主要目的是看项目在引擎中性能，这是最至关重要的，所以，硬件上，我们要选择低端安卓手机（比如红米）进行测试。软件环境建议使用微信环境测试，首先，因为微信公众号是H5的主要渠道之一，其次，微信当前的H5性能低于chrome浏览器，在恶劣的环境下更能测试引擎的优劣。&lt;/p&gt; &lt;p&gt;文章来源：  &lt;a href="http://www.gamelook.com.cn/2016/04/251421" target="_blank"&gt;游戏大观&lt;/a&gt;  &lt;br /&gt;&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>综合新闻</category>
      <guid isPermaLink="true">https://itindex.net/detail/55510-%E6%8A%80%E6%9C%AF-%E5%B9%B2%E8%B4%A7-%E5%88%86%E4%BA%AB</guid>
      <pubDate>Wed, 27 Apr 2016 11:33:46 CST</pubDate>
    </item>
    <item>
      <title>玩转HTML5移动页面（动效篇）</title>
      <link>https://itindex.net/detail/53313-html5-%E7%A7%BB%E5%8A%A8-%E9%A1%B5%E9%9D%A2</link>
      <description>&lt;p&gt;作为一名前端，在拿到设计稿时你有两种选择：&lt;/p&gt;
 &lt;div&gt;1.快速输出静态页面&lt;/div&gt;
 &lt;div&gt;2.加上高级大气上档次狂拽炫酷屌炸天的动画让页面动起来&lt;/div&gt;
 &lt;div&gt;作为一个有志向的前端，当然是选2啦！可是需求时间又很短很短，怎么办呢？&lt;/div&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;div&gt;这次就来谈谈一些动画设计的小技巧，能在你时间不多又没有动画想法的时候瞬间让页面增色不少。&lt;/div&gt;
 &lt;div&gt;同时也会谈及移动端H5页面的优化细节与关键点，因此本文章将分为  &lt;strong&gt;动效篇&lt;/strong&gt;和  &lt;a href="http://isux.tencent.com/play-with-html5-optimize.html" target="_blank" title="&amp;#29609;&amp;#36716;HTML5&amp;#31227;&amp;#21160;&amp;#39029;&amp;#38754;&amp;#65288;&amp;#20248;&amp;#21270;&amp;#31687;&amp;#65289;"&gt;   &lt;strong&gt;优化篇&lt;/strong&gt;&lt;/a&gt;。&lt;/div&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;div&gt;====前方高能====&lt;/div&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;div&gt;（1）  CSS3时序错开渐显动画&lt;/div&gt;
 &lt;div&gt;这是一种比较常用的动画，它的优点是节奏感强，做法就是先让每个元素隐藏，然后当页面呈现后每个元素错开时间出现。&lt;/div&gt;
 &lt;div&gt;例子（忽略兼容前缀和无关属性）：&lt;/div&gt;
 &lt;div&gt;  &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326235946454.png" target="_blank"&gt;   &lt;img alt="code1" height="49" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326235946454-590x49.png" width="590"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/div&gt;
 &lt;div&gt;  &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/2015032623594763.png" target="_blank"&gt;   &lt;img alt="code2" height="257" src="http://isux.tencent.com/wp-content/uploads/2015/03/2015032623594763-590x257.png" width="590"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/div&gt;
 &lt;div&gt;
  &lt;p&gt;效果就是两个元素分别从上面掉下来，这里有个小细节（keyframes），为了让掉下来的动画生动点，应该是在90%的时候先掉下一点点，然后瞬间在100%时回跳5px。&lt;/p&gt;
  &lt;p&gt;还有个细节，安卓2.3.*不能良好支持-webkit-animation-fill-mode，也就是渐变动画不能停止在最后一帧。有这样一个解决方案：&lt;/p&gt;
  &lt;p&gt;1.用   &lt;a href="http://modernizr.com/" target="_blank"&gt;Modernizr&lt;/a&gt;去检测是否支持这个属性，加上识别类.no-animation-fill-mode；&lt;/p&gt;
  &lt;p&gt;2.根据识别类采取以下措施：   &lt;br /&gt;
（1）用js模拟同样效果；   &lt;br /&gt;
（2）用css屏蔽掉动画；   &lt;br /&gt;
（3）或者直接全部都用transition来做（不要keyframes）。&lt;/p&gt;
  &lt;p&gt;示例页面如下（   &lt;a href="http://m.isux.us/qz-act/vip/20140903-qzonev5/m-index.html" target="_blank"&gt;查看DEMO&lt;/a&gt;）：&lt;/p&gt;
  &lt;p&gt;   &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222456182.gif" target="_blank"&gt;    &lt;img alt="qzone5_1" height="561" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222456182.gif" width="316"&gt;&lt;/img&gt;&lt;/a&gt;     &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/2015032622245783.png" target="_blank"&gt;    &lt;img alt="qzone5_1_qrcode" height="168" src="http://isux.tencent.com/wp-content/uploads/2015/03/2015032622245783.png" width="169"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
  &lt;div&gt;
   &lt;div&gt;（2） CSS3细节强调动画&lt;/div&gt;
   &lt;div&gt;一些局部细节如果还是渐现显示，会枯燥没什么感觉，例如标题、按钮等，需要一种强调。&lt;/div&gt;
   &lt;p&gt; &lt;/p&gt;
   &lt;div&gt;分两种情况：&lt;/div&gt;
   &lt;div&gt;1.如果时间允许的话，基本做法是先把一个元素切成不同的块状，例如小人的手脚都切成不同图片，然后让它们重新组合，再通过赋予不同的CSS动画来让它生动起来，这里引用个webank的例子：&lt;/div&gt;
   &lt;div&gt;    &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222500244.gif" target="_blank"&gt;     &lt;img alt="webank" height="561" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222500244.gif" width="316"&gt;&lt;/img&gt;&lt;/a&gt;      &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222500772.png" target="_blank"&gt;     &lt;img alt="webank_qrcode" height="174" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222500772.png" width="173"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/div&gt;
   &lt;div&gt;（    &lt;a href="http://sunnyzhen.github.io/course/demo/motorcycle/index.html" target="_blank"&gt;查看DEMO&lt;/a&gt;）&lt;/div&gt;
   &lt;p&gt; &lt;/p&gt;
   &lt;div&gt;
    &lt;div&gt;2.如果时间紧凑，又不像桑尼一样擅长于动画细节，可以使用一些辅助工具：&lt;/div&gt;
    &lt;div&gt;     &lt;a href="http://daneden.github.io/animate.css/" target="_blank"&gt;Animate.css&lt;/a&gt;，通过直接预览选择想要的动效，然后下载它的CSS把对应的keyframe扒下来就好了（引用整个CSS是资源浪费）。&lt;/div&gt;
    &lt;p&gt; &lt;/p&gt;
    &lt;div&gt;
     &lt;div&gt;（3）SVG动画&lt;/div&gt;
     &lt;div&gt;SVG技术越来越不陌生，使用门槛也渐渐降低，而且SVG动画还可以使用CSS控制。&lt;/div&gt;
     &lt;div&gt;先看个生日页面，是个SVG的蛋糕：&lt;/div&gt;
     &lt;div&gt;      &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222454666.gif" target="_blank"&gt;       &lt;img alt="cyy" height="561" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222454666.gif" width="316"&gt;&lt;/img&gt;&lt;/a&gt;        &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222455593.png" target="_blank"&gt;       &lt;img alt="cyy_qrcode" height="158" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222455593.png" width="164"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/div&gt;
     &lt;div&gt;
      &lt;div&gt;（       &lt;a href="http://cyyis.me/" target="_blank"&gt;查看DEMO&lt;/a&gt;）&lt;/div&gt;
      &lt;p&gt; &lt;/p&gt;
      &lt;div&gt;可见SVG是很强大的！弥补了CSS3的不足。&lt;/div&gt;
      &lt;div&gt;
       &lt;div&gt;然而这种动画也是略耗时，但有一种比较常用的，就是线条的描绘动画，CSS3比较难实现，这里可以用SVG，看图：&lt;/div&gt;
       &lt;div&gt;&lt;/div&gt;
       &lt;div&gt;        &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222821628.gif" target="_blank"&gt;         &lt;img alt="linkline" height="561" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222821628.gif" width="316"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/div&gt;
       &lt;p&gt; &lt;/p&gt;
       &lt;div&gt;
        &lt;div&gt;介绍一个PS插件         &lt;a href="http://share.weiyun.com/d82e75215ed601986a63e16c6b6fc56a?g_f=&amp;srctype=&amp;ticket=" target="_blank"&gt;svgArtisan&lt;/a&gt;（目前还未有主页），这个工具可以直接根据PSD的路径图层生成SVG图形。&lt;/div&gt;
        &lt;div&gt;接下来就简单了，将设计稿上的路径图形用插件生成对应的SVG，例如是这样的：&lt;/div&gt;
        &lt;div&gt;（注意，其中的foreignObject标签内是不支持svg的浏览器会看到一张.m3-svg-nosupport标签下的图片。）&lt;/div&gt;
        &lt;p&gt;         &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326231605887.png" target="_blank"&gt;          &lt;img alt="svg1" height="192" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326231605887-590x192.png" width="590"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
        &lt;p&gt;再使用CSS3的animation控制stroke-dashoffset：&lt;/p&gt;
        &lt;p&gt;         &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326231606519.png" target="_blank"&gt;          &lt;img alt="svg2" height="96" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326231606519-590x96.png" width="590"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
        &lt;p&gt;效果不难吧！SVG还有各种用途，例如制作ICONFONT等，可以深入挖掘。&lt;/p&gt;
        &lt;div&gt;（4） 重力陀螺仪&lt;/div&gt;
        &lt;div&gt;想让页面更有层次感，不妨让设计提供一些碎片元素，例如彩花，星星之类，然后把它们单独切出来放画面前景，使用陀螺仪伴随着手机运动碎片也跟着运动，多么好玩！&lt;/div&gt;
        &lt;div&gt;这里提供一个工具可以轻松实现陀螺仪重力效果的：         &lt;a href="http://matthew.wagerfield.com/parallax/" target="_blank"&gt;parallax.js&lt;/a&gt;&lt;/div&gt;
        &lt;div&gt;用法简单，定义一个parallax-obj的父类，把需要动的元素加上layer的类，然后设置动的范围data-depth：&lt;/div&gt;
        &lt;div&gt;         &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326232342992.png" target="_blank"&gt;          &lt;img alt="parallax" height="130" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326232342992-590x130.png" width="590"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/div&gt;
        &lt;p&gt; &lt;/p&gt;
        &lt;div&gt;
         &lt;div&gt;（5） 背景音乐&amp;amp;音效&lt;/div&gt;
         &lt;div&gt;H5页面要炫酷，画面生动还是不够的，一定要配合生动的音乐。因此可以主动跟设计或产品沟通，让他们可以提供音乐资源，分分钟导致UV猛涨有木有！&lt;/div&gt;
         &lt;p&gt; &lt;/p&gt;
         &lt;div&gt;当然，有了音乐，前端也不是直接引用的，还是有点要求：&lt;/div&gt;
         &lt;div&gt;1.音乐不宜过长，30s为佳，而且音乐要加上渐现渐隐效果，方便循环播放；&lt;/div&gt;
         &lt;div&gt;2.音乐体积要小，音质和流量，在手机上还是优先考虑流量吧。&lt;/div&gt;
         &lt;div&gt;一般背景音乐体积可以接受的范围是200K以下，若太大，可以使用格式工厂等软件，降低它的比特率和声道来改变体积。&lt;/div&gt;
         &lt;p&gt; &lt;/p&gt;
         &lt;div&gt;接着，只需要简单引用：&lt;/div&gt;
         &lt;div&gt;          &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326235947764.png" target="_blank"&gt;           &lt;img alt="code3" height="44" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326235947764-590x44.png" width="590"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/div&gt;
         &lt;div&gt;这里有个问题，IOS是不能自动播放音乐的，一定要触发一个用户交互事件，例如点击。&lt;/div&gt;
         &lt;div&gt;但是有一种hack的方法可以让IOS微信侧页面自动播放（SAFARI依旧无效）：&lt;/div&gt;
         &lt;div&gt;通过new一张图片，监听一张图片的onload事件，结束后回调执行音频播放audio.play()即可，原理估计是动了dom结构，相当于执行了一次交互。（有人也用过createEvent模拟，原理也是动了dom。）&lt;/div&gt;
         &lt;div&gt;因此，记得暴露一个音乐关闭/打开的按钮，不然肯定被用户骂死。&lt;/div&gt;
         &lt;p&gt; &lt;/p&gt;
         &lt;div&gt;（6）有趣的loading&lt;/div&gt;
         &lt;div&gt;Loading页还是要有的，万一用户网速慢呢？&lt;/div&gt;
         &lt;div&gt;以上做了那么多事，如果没有资源加载都是玩不来的，因此还需要一个loading的支持。一般情况下页面体积大于3m则要加上loading页。&lt;/div&gt;
         &lt;p&gt; &lt;/p&gt;
         &lt;div&gt;然而loading还是可以做得很有趣的，一般的做法是：&lt;/div&gt;
         &lt;div&gt;1.引入品牌，例如APP宣传页；&lt;/div&gt;
         &lt;div&gt;2.引入有趣动画，放一个贱贱的人物跳舞给你看；&lt;/div&gt;
         &lt;div&gt;3.一切从简，用CSS3简单动画。&lt;/div&gt;
         &lt;p&gt;====最后总结====&lt;/p&gt;
         &lt;div&gt;最后，给一个例子结尾吧。&lt;/div&gt;
         &lt;div&gt;
          &lt;div&gt;这是空间5.0预约页第二版，使用了以上的若干方法论，例如loading动画，CSS3动画，SVG星空连线，首屏星球重力感应，音乐（这里使用开启按钮后播放）等等。&lt;/div&gt;
          &lt;div&gt;（由于活动已结束，很多运营处都被删掉从简了，忽略那些细节）&lt;/div&gt;
          &lt;div&gt;&lt;/div&gt;
          &lt;div&gt;           &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222457610.gif" target="_blank"&gt;            &lt;img alt="qzone5_2" height="561" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222457610.gif" width="316"&gt;&lt;/img&gt;&lt;/a&gt;             &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222458446.png" target="_blank"&gt;            &lt;img alt="qzone5_2_qrcode" height="171" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222458446.png" width="173"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div&gt;（           &lt;a href="http://qzs.qq.com/qzone/qzact/act/qzapp/qzone5.0/mobile/index.html" target="_blank"&gt;查看DEMO&lt;/a&gt;）&lt;/div&gt;
          &lt;p&gt; &lt;/p&gt;
          &lt;div&gt;当然，真正要做到高效制作动态H5页面，还是靠积累，因此平时做好的细节动画自己都积累起来，下次分分钟就能用得上。&lt;/div&gt;
          &lt;div&gt;&lt;/div&gt;
          &lt;div&gt;请继续阅读《           &lt;a href="http://isux.tencent.com/play-with-html5-optimize.html" target="_blank" title="&amp;#29609;&amp;#36716;HTML5&amp;#31227;&amp;#21160;&amp;#39029;&amp;#38754;&amp;#65288;&amp;#20248;&amp;#21270;&amp;#31687;&amp;#65289;"&gt;玩转HTML5移动页面（优化篇）&lt;/a&gt;》。&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>前端技术 html5 动画 效果 移动端</category>
      <guid isPermaLink="true">https://itindex.net/detail/53313-html5-%E7%A7%BB%E5%8A%A8-%E9%A1%B5%E9%9D%A2</guid>
      <pubDate>Tue, 28 Apr 2015 10:32:55 CST</pubDate>
    </item>
    <item>
      <title>玩转HTML5移动APP页面（优化篇）</title>
      <link>https://itindex.net/detail/53307-html5-%E7%A7%BB%E5%8A%A8-app</link>
      <description>&lt;p&gt;承接上文《  &lt;a href="http://www.shejidaren.com/html5-animate-page.html"&gt;玩转HTML5移动APP页面（动效篇）&lt;/a&gt;》，上次说的是让页面动起来的一些小技巧。  &lt;br /&gt;
而页面动起来的根基是功能可用的页面，因此有必要分享一些优化细节的技巧和方向，熟悉掌握一些方法论还是会对页面开发大大提高效率的，并且也能防止疏忽缺漏。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="cover-01" height="360" src="http://images.shejidaren.com/wp-content/uploads/2015/04/034816e5f.jpg" width="630"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;====前方高能====&lt;/p&gt;
 &lt;h3&gt;（1） 动画雪碧图&lt;/h3&gt;
 &lt;p&gt;涉及的动画十分多，用的元素也十分多，请务必使用雪碧图（Sprite）！  &lt;br /&gt;
网上的工具有一些可以帮助你生成雪碧图的工具，例如  &lt;a href="http://www.99css.com/tag/cssgaga/" target="_blank"&gt;CssGaga&lt;/a&gt;，  &lt;a href="http://isux.tencent.com/alloyteam.github.io/gopng" target="_blank"&gt;GoPng&lt;/a&gt;等等，自动化构建工具Grunt和Gulp也提供了相应插件。  &lt;br /&gt;
特别地，如果单张雪碧图面积实在太大，可以拆分雪碧图，例如拆分成2-4张，因为现代浏览器都支持4-6个同源请求下载，若资源实在太多，也可以考虑把静态资源放在不同源域名下去请求，这里牺牲多几个请求换来图片同时加载比一张图片慢慢加载要好，当然，这需要具体情况去衡量。&lt;/p&gt;
 &lt;p&gt;顺便提一下，我写动画的一个小技巧是把每一页的动画分在一个import.css里面，然后最后在主样式中import进去，这样方便调试动画，也容易维护，例如：&lt;/p&gt;
 &lt;pre&gt;//style.css
@import url(&amp;quot;reset.import.css&amp;quot;);
@import url(&amp;quot;loading.import.css&amp;quot;);
@import url(&amp;quot;m-animate-1.import.css&amp;quot;);
@import url(&amp;quot;m-animate-2.import.css&amp;quot;);
@import url(&amp;quot;m-animate-3.import.css&amp;quot;);&lt;/pre&gt;
 &lt;p&gt;当然，import不是原生支持的，这里需要一些流程化工具让import的页面在输出之前经过组装-压缩的步骤。&lt;/p&gt;
 &lt;h3&gt;（2）图片压缩&lt;/h3&gt;
 &lt;p&gt;图片压缩是老生常谈，但是仍然有不少人忘记压缩，那可是活生生的带宽和流量的浪费啊…&lt;/p&gt;
 &lt;p&gt;压缩图片需要有好工具，有  &lt;a href="http://zhitu.tencent.com/" target="_blank"&gt;智图&lt;/a&gt;，  &lt;a href="https://tinypng.com/" target="_blank"&gt;TinyPNG&lt;/a&gt;，  &lt;a href="http://www.jpegmini.com/" target="_blank"&gt;JPEGmini&lt;/a&gt;等等。&lt;/p&gt;
 &lt;p&gt;依靠工具外，还有以下方式可以优化图片：&lt;/p&gt;
 &lt;p&gt;1.尽量避免用PNG24。如果图片色彩要求不高，请使用PNG8；  &lt;br /&gt;
2.使用新格式，WEBP和BPG等新格式的到来，在不用考虑兼容的情况下请大胆尝试；  &lt;br /&gt;
3.用SVG和ICONFONT代替简单的图标；  &lt;br /&gt;
4.用FUFU的  &lt;a href="http://isux.tencent.com/font-spider.html" target="_blank"&gt;字蛛&lt;/a&gt;来代替艺术字体切图。&lt;/p&gt;
 &lt;h3&gt;（3）多终端兼容&lt;/h3&gt;
 &lt;p&gt;多终端兼容是一切的根基，要知道有人拿着肾6+，有人拿着肾4，大则414×736，小则320×416（IPHONE4在SAFARI保留上下端导航），因此多终端兼容是十分必要的。  &lt;br /&gt;
曾经有一种派系为320派系，就是大部分页面都是320宽度，因此干脆直接用320的容器来包一切页面，那样也简单，然而IPHOEN6和IPHONE6+的出现简直是灭了这个派系。&lt;/p&gt;
 &lt;p&gt;那么到底要如何兼容呢？  &lt;br /&gt;
这里我分了三个时期来说说：  &lt;br /&gt;
A.设计初期。先审视设计稿，因为320派系的原因，大部分设计稿只考虑到IPHONE5来设计，因此很多背景元素是只有320px宽度（页面实际渲染宽度），例如下图。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#29609;&amp;#36716;HTML5&amp;#31227;&amp;#21160;&amp;#39029;&amp;#38754;&amp;#65288;&amp;#20248;&amp;#21270;&amp;#31687;&amp;#65289;" height="521" src="http://images.shejidaren.com/wp-content/uploads/2015/04/034816MQF.jpg" width="439"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;那么，这时候就需要设计提供一个较长的延伸背景了，最好是可以重复的，用background-repeat可以减少图片大小。&lt;/p&gt;
 &lt;p&gt;B.设计中期。也就是具体的兼容方法，可以使用CSS3 Media Query和类覆盖。&lt;/p&gt;
 &lt;p&gt;1.CSS3 Media Query，按范围兼容机型。&lt;/p&gt;
 &lt;pre&gt;/*iphone6*/
@media only screen
and (min-device-width : 375px)
and (max-device-width : 667px)
and (orientation : portrait)
and (-webkit-min-device-pixel-ratio : 2)
{
.page6 .ele-building{top: 69px;}
.page6 .ele-runner{top: 100px;}
.page6 .ele-pophome{top: 16px;}
}&lt;/pre&gt;
 &lt;p&gt;2.类覆盖，这种方式适合直接为小屏或大屏做整体兼容。  &lt;br /&gt;
首先，为小屏（大屏）加一个识别类，这里小于420表示为小屏幕（IPHONE4有上下导航栏）：&lt;/p&gt;
 &lt;pre&gt;var bh = $(window).height();
// 480 - 64 = 416 iphone4
if(bh&amp;amp;lt;420){
$(&amp;apos;body&amp;apos;).addClass(&amp;apos;low-screen&amp;apos;);
}&lt;/pre&gt;
 &lt;p&gt;然后，对应识别类加上要变动的元素覆盖，例如：&lt;/p&gt;
 &lt;pre&gt;.page6 .ele-bg{top: 10px;}
.low-screen .page6 .ele-bg{top: 0px;}&lt;/pre&gt;
 &lt;p&gt;C.设计后期。这是最后一步，整体检查和体验，这里面会暴露一些问题，例如元素在IPHONE6P显得小了或者元素在IPHONE4挤不下了，可以来最后大招解决：&lt;/p&gt;
 &lt;p&gt;1.大屏适当用zoom:(倍率)或者transform:scale(倍率)来增大元素，实测失真根本看不出来，设计师也满意（毕竟不用多做一张图！）；  &lt;br /&gt;
2.小屏适当去掉一些元素，例如一些翻页提示，一些多余图标，可以让优雅降级，把它们 display:none掉。&lt;/p&gt;
 &lt;p&gt;有以上几步，基本就能兼容大部分机器了。兼容一直是个苦活，但是这是前端必修课，多练就会发觉其实也没有那么难嘛。&lt;/p&gt;
 &lt;h3&gt;（4）交互提示&lt;/h3&gt;
 &lt;p&gt;前面说了，加了音效就要加上音乐切换开关的按钮，不然会被用户骂死。还有其他，例如如果你的页面不能兼容横屏，请监听横屏状态，然后加上适当的横屏提示。&lt;/p&gt;
 &lt;p&gt;例如：&lt;/p&gt;
 &lt;pre&gt;// 横屏监听
var updateOrientation = function(){
if(window.orientation==&amp;apos;-90&amp;apos; || window.orientation==&amp;apos;90&amp;apos;){
$(&amp;apos;.landscape-wrap&amp;apos;).removeClass(&amp;apos;hide&amp;apos;);
console.log(&amp;apos;为了更好的体验，请将手机/平板竖过来！&amp;apos;);
}else{
$(&amp;apos;.landscape-wrap&amp;apos;).addClass(&amp;apos;hide&amp;apos;);
console.log(&amp;apos;竖屏状态&amp;apos;);
}
};
window.onorientationchange = updateOrientation;&lt;/pre&gt;
 &lt;p&gt;提示越多，界面越友好，有时候设计师会漏掉一些可能出现的页面情况。  &lt;br /&gt;
作为有态度的前端，请好好把关，让用户有好的体验。&lt;/p&gt;
 &lt;h3&gt;（5）分享接口&lt;/h3&gt;
 &lt;p&gt;H5做好了，要传播分享才能展示你的牛逼轰轰。  &lt;br /&gt;
然而分享其实是个坑，分享到微信、手Q等都有各种问题。&lt;/p&gt;
 &lt;p&gt;A.微信&lt;/p&gt;
 &lt;p&gt;旧微信会使用WeixinJSBridge来声明分享的缩略图、标题、正文等，比较方便。例如：  &lt;br /&gt;
  &lt;img alt="&amp;#29609;&amp;#36716;HTML5&amp;#31227;&amp;#21160;&amp;#39029;&amp;#38754;&amp;#65288;&amp;#20248;&amp;#21270;&amp;#31687;&amp;#65289;" height="287" src="http://images.shejidaren.com/wp-content/uploads/2015/04/0348166Q1.png" width="590"&gt;&lt;/img&gt;  &lt;br /&gt;
而最新的微信提供了新的微信SDK，需要在公众账号绑定所属域名之后调用SDK作分享，可以说分享功能会更加强大，坑也会更加少。&lt;/p&gt;
 &lt;p&gt;B.手Q&lt;/p&gt;
 &lt;p&gt;手Q支持声明meta标签的的分享方式，例如：  &lt;br /&gt;
  &lt;img alt="&amp;#29609;&amp;#36716;HTML5&amp;#31227;&amp;#21160;&amp;#39029;&amp;#38754;&amp;#65288;&amp;#20248;&amp;#21270;&amp;#31687;&amp;#65289;" height="96" src="http://images.shejidaren.com/wp-content/uploads/2015/04/034817fAl.png" width="590"&gt;&lt;/img&gt;  &lt;br /&gt;
而若在qq.com域名下也支持api的定义方式。&lt;/p&gt;
 &lt;p&gt;C.一般化分享&lt;/p&gt;
 &lt;p&gt;在默认兼容旧版微信、手Q或者各种浏览器，平台，可以用这样的方法：  &lt;br /&gt;
写h1做标题，p做内容，img做缩略图，只需要把h1隐藏掉就好，这里的缩略图最好要大于200x200px。&lt;/p&gt;
 &lt;p&gt;例如：  &lt;br /&gt;
  &lt;img alt="&amp;#29609;&amp;#36716;HTML5&amp;#31227;&amp;#21160;&amp;#39029;&amp;#38754;&amp;#65288;&amp;#20248;&amp;#21270;&amp;#31687;&amp;#65289;" height="120" src="http://images.shejidaren.com/wp-content/uploads/2015/04/034817G6h.png" width="590"&gt;&lt;/img&gt;  &lt;br /&gt;
当然，这样也有利于搜索引擎拉取信息。&lt;/p&gt;
 &lt;p&gt;分享的坑还有更多，例如不同浏览器例如QQ浏览器、Chrome也会有自己的默认拉取方式（部分截图作缩略图），需要多加测试优化。&lt;/p&gt;
 &lt;h3&gt;（5）SEO搜索引擎优化&lt;/h3&gt;
 &lt;p&gt;SEO（搜索引擎优化）的基本做法是把页面结构写好，这包括：&lt;/p&gt;
 &lt;p&gt;1.定义精确的网页标题。你的标题应该有概括性，能明确告知搜索引擎和用户你的网站大概内容和目的，可以是当前页面标题-所属类型-产品名，例如“全民来猜歌-年费黄钻-QQ空间”。&lt;/p&gt;
 &lt;p&gt;2.针对页面内容补充description和keywords的meta标签。你需要简短总结页面的主要目标，然后补充description，以及根据关键词补充keywords。&lt;/p&gt;
 &lt;p&gt;3.优化你的超链接和图片。包括优化超链接显示的文本，要具有语义性也要跟超链接的网页具有相关性，例如“空间主页”就不要链接到“www.qq.com”。同时，要补充”title”和”alt”属性，例如“&amp;lt;img src=’images/apple.jpg’ title=’苹果示例图’ alt=’苹果示例图’ /&amp;gt;”。&lt;/p&gt;
 &lt;p&gt;4.建立良好的网站导航和sitemap。网站需要有一个良好的导航，控制根目录和各子目录的关键，通过sitemap可以帮助网站主了解网站结构，也方便搜索引擎收录整个站点。&lt;/p&gt;
 &lt;p&gt;5.优化目录结构和URL。你的URL应该有语义性，简短易懂，例如http://www.apple.com/macbook-air/，而且每一层级都要有它对应的页面展示以及语义。&lt;/p&gt;
 &lt;p&gt;6.善用h1-h6的标题结构树。合理的标题可以强调文字，也能让搜索引擎更加了解到各标题的重要性，因此建立良好的标题树十分有意义。&lt;/p&gt;
 &lt;p&gt;7.不断致力于提供优质的内容。社交化分享是网站曝光最快的因素，因此不断提供了优质原创内容才能真正提高你的网站曝光权重。&lt;/p&gt;
 &lt;h3&gt;（6）无障碍&lt;/h3&gt;
 &lt;p&gt;无障碍的普及是一件好事，这让互联网真正地为所有人可用。因此我们也应该为之而努力，无障碍的根基是你页面强壮的语义性和结构性，具体可以参考《  &lt;a href="http://www.qq.com/demo/accessibility.htm" target="_blank"&gt;腾讯网无障碍说明&lt;/a&gt;》了解无障碍的优化手段。&lt;/p&gt;
 &lt;p&gt;最后，罗嗦了这么多，只是我自己的一些小经验，请轻拍砖，多交流。&lt;/p&gt;
 &lt;p&gt;腾讯ISUX (  &lt;a href="http://isux.tencent.com/play-with-html5-optimize.html" rel="nofollow" target="_blank"&gt;http://isux.tencent.com/play-with-html5-optimize.html&lt;/a&gt;)&lt;/p&gt;
 &lt;hr&gt;&lt;/hr&gt;Copyright ©2010-2014 ¦  &lt;a href="http://www.shejidaren.com/feed" target="_blank" title="RSS&amp;#35746;&amp;#38405;"&gt;RSS订阅&lt;/a&gt; ¦  &lt;a href="http://weibo.com/shejidaren888" target="_blank" title="&amp;#26032;&amp;#28010;&amp;#24494;&amp;#21338;"&gt;新浪微博&lt;/a&gt; ¦  &lt;a href="http://www.shejidaren.com/html5-app-page-optimize.html" target="_blank" title="&amp;#29609;&amp;#36716;HTML5&amp;#31227;&amp;#21160;APP&amp;#39029;&amp;#38754;&amp;#65288;&amp;#20248;&amp;#21270;&amp;#31687;&amp;#65289;"&gt;本文链接&lt;/a&gt; ¦  &lt;a href="http://www.shejidaren.com/html5-app-page-optimize.html#respond" target="_blank" title="&amp;#29609;&amp;#36716;HTML5&amp;#31227;&amp;#21160;APP&amp;#39029;&amp;#38754;&amp;#65288;&amp;#20248;&amp;#21270;&amp;#31687;&amp;#65289;&amp;#30340;&amp;#35780;&amp;#35770;"&gt;添加评论&lt;/a&gt;  &lt;br /&gt;交流：UI设计交流群：59300679，与500名设计师交流设计，分享素材。&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>HTML &amp; CSS 前端开发 HTML5</category>
      <guid isPermaLink="true">https://itindex.net/detail/53307-html5-%E7%A7%BB%E5%8A%A8-app</guid>
      <pubDate>Tue, 28 Apr 2015 12:10:42 CST</pubDate>
    </item>
    <item>
      <title>中国和美国的HTML5市场差距有多少？</title>
      <link>https://itindex.net/detail/54570-%E4%B8%AD%E5%9B%BD-%E5%92%8C%E7%BE%8E-html5</link>
      <description>&lt;p&gt;  &lt;strong&gt;【编者按】本文作者APICloud 创始人兼CEO刘鑫。&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;  &lt;img src="http://7te8bu.com1.z0.glb.clouddn.com/uploads/new/article/740_740/201510/5628ba39c7e6d.jpg"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;近日，我在旧金山和美国的HTML5开发者进行了一次近距离的接触，感受中美HTML5开发者的热度差别和不同市场阶段的中美表现巨大差异。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;中国和美国的HTML5市场差距有多少？&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;首先，从下面两张趋势图我们很容易发现美国的HTML5公众关注度是从2009年底出现第一次的快速上涨，而将近2年后2011年下半年，中国的HTML5市场才出现了第一次的集中关注。&lt;/p&gt; &lt;p&gt;美国HTML5市场经过5年的长期发展之后，早进入理性的状态，不是炒作概念或者单纯的市场宣讲活动，甚至关注度出现了下降，已经变成了在web技术各个独立领域深度探索和创新。而中国HTML5市场在2015年的此刻虽然关注度火热，但是可能比美国市场出现了更进一步的延后。&lt;/p&gt; &lt;p&gt;  &lt;img src="http://7te8bu.com1.z0.glb.clouddn.com/uploads/new/article/740_740/201510/5628b1743b1fe.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;图1:HTML5在美国的关注度数年的趋势&lt;/p&gt; &lt;p&gt;   &lt;img src="http://7te8bu.com1.z0.glb.clouddn.com/uploads/new/article/740_740/201510/5628b17c2e2e6.png"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt; 图2:HTML5在中国的关注度趋势&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;美国HTML5开发者和公司在做什么？&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;1、 先总结：从创新到实用&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;此次见到了很多很“cool”的公司，其中有一家公司利用WebGL和Websocket技术，将一个方程式赛车场搬到了互联网上。&lt;/p&gt; &lt;p&gt;他们是这样做的，首先赛车上被安装的上千个传感器可以实时数据回传，通过Websocket技术和HTML5的结合在PC上做实时的跟踪模拟展示，并且可以以3D的形式呈现。这种方式的实现，除了感觉震撼，也让我感受到一个真正的程序员在创新和技术深度使用上所下的功夫。并且通过这种努力让创新的想法得以变成现实。虚拟现实、IoT物联网、3D是美国HTML5开发者目前所关注的焦点。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;2、 美国的HTML5和移动&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;对于把Web App网页加壳直接打包成成一个iOS和Android App的模式，美国的开发者基本不再更多地提及。&lt;/p&gt; &lt;p&gt;通过和美国网页开发者的交流，我发现经过5、6年的发展，大家对于写一套代码可以直接在PC、手机浏览器、加壳成App（当然在中国还多了一个微信的发布渠道）这种模式的认识已经比较成熟，普遍认为这种理想主义状态下的模式并不能带来真正的用户体验。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;他们对于纯前端框架的使用也比较谨慎。&lt;/strong&gt;比如有一个开发者告诉我，因为Angular.js在重写 2.0并且会在1.0的版本上彻底重构，因此在很多美国开发者现在不会选择至少到新版本的发布。这段对话最重要的价值是让我明白美国HTML5开发者的成熟和理性。&lt;/p&gt; &lt;p&gt;因此，美国HTML5开发者在移动上也并不会抱着偷懒的心态写一套代码，希望在PC、手机等全部通用。这也能解释为什么Sencha等这种前端框架发展不愠不火的现状。&lt;/p&gt; &lt;p&gt;  &lt;strong&gt;3、 在美国开发者的眼中，React JS/Native是什么样的？&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;让我出乎意外的是，React Native在此次美国交流中并没有那么火热。&lt;/p&gt; &lt;p&gt;我原以为，Facebook刚刚发布React Native会让美国开发者热情高涨。大家都很关注，但是只能说没那么让人激动。我和一个开发者沟通了对于ReactJS和React Native的经验，他告诉我，React JS更多被用在了PC端，而移动端使用React Native对于一般的前端工程师来说也并不简单。很多大公司非常高级的前端程序员会追求新技术，并且尝试使用。&lt;/p&gt; &lt;p&gt;另外，他们也相信，有Facebook站在后面背书会持续发展，但是对于大多数前端HTML5开发者来说还是太复杂了。因为使用React Native对前端程序员的要求不是单纯的Web技术，同样需要原生的开发经验和能力，想作出真正好用的App，可能需要的不仅仅是尝新的兴趣，更需要有多种技术跨领域使用的能力，否则只能当成程序员的一种学习。并且关于React在美国HTML5开发者中也存在着巨大的Hype（争议）。我总结此次交流，发现React的发展仍旧任重道远。&lt;/p&gt; &lt;p&gt;美国开发者眼中，React Native很酷，使用React Native主要用来解决移动端App的UI界面布局和交互的问题，App其他功能的实现需要开发团队独立解决。&lt;/p&gt; &lt;blockquote&gt;  &lt;p&gt;但是，眼下存在的问题是，JavaScript开发者需要了解Native App技术，而Native App开发者需要精通JavaScript才能基于React Native开发App，这似乎有点矛盾。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;其次，iOS与Android有组件代码可以重用，但是部分会存在区别。&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;最后，React Native开发需要彻底的搭建原生App开发环境支持，这对于很多开发者来说尤其是网页开发者来说也过于复杂了。&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;  &lt;strong&gt;站在美国看中国HTML5市场&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;从概念到实用，这是和美国HTML5开发者交流最深刻的感受。反观中国HTML5开发者市场，我们需要的是沉淀而不是简单地追求热点。&lt;/p&gt; &lt;p&gt;对此我也进行了一些深入思考，结合此次的美国开发者交流活动，我发现很多思考和观点也得到了验证。&lt;/p&gt; &lt;p&gt;比如，响应式设计虽然能够带来一些在多终端开发的便利性，但是更多的还是被用在以PC网站为主体的业务上（也就是对于大部分用户仍旧使用PC端访问的服务），很多前端框架被用在改造老旧网站或者说遗产型网站上（Website as a legacy），这是为了保证这些老旧网站也可以被越来越多的移动端用户能访问（就好像云适配在中国所做的事情，一行代码将PC网站变成手机网站）。&lt;/p&gt; &lt;p&gt;但是，对于纯粹的移动端业务，PC和Mobile更多被独立地开发和认真对待。一套代码在手机浏览器、在微信公用号甚至变成App多个场景应用的模式在美国这个成熟的HTML5市场并不是主流。&lt;/p&gt; &lt;p&gt;这个观点，我想也能够很好地说明——&lt;/p&gt; &lt;blockquote&gt;  &lt;p&gt;   &lt;strong&gt;中国HTML5开发市场，还需要挤掉炒作的泡沫和市场的误导。&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;在这几天和美国开发者的深度交流中，我感受美国市场虽然也在不停地谈创新，但是并没有太多空的概念和炒作。这种氛围也造就了一批相当有实力的前端程序员，甚至full stack全栈程序员。&lt;/p&gt; &lt;p&gt;市场会发展，他相信中国的HTML5在未来2年也会进入理性成熟阶段，中国也会有更多有实力、有创新能力的HTML5甚至全栈程序员出现。当然这首先需要的还是中国HTML5前端程序员们深度的积累和踏实不盲目追逐热点的心态。&lt;/p&gt; &lt;p&gt;最后，附上我们在旧金山的现场：&lt;/p&gt; &lt;p&gt;  &lt;img src="http://7te8bu.com1.z0.glb.clouddn.com/uploads/new/article/740_740/201510/5628b8f200b7f.jpg"&gt;&lt;/img&gt;&lt;/p&gt; &lt;p&gt;【作者介绍】刘鑫，APICloud移动应用云服务创始人兼CEO。见证了中国移动互联网从SP梦网到智能机时代的全过程。专注于国内外移动应用开发平台领域的研究，系统的阐述过Web App的挑战与Hybrid App的发展。  &lt;br /&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>专栏</category>
      <guid isPermaLink="true">https://itindex.net/detail/54570-%E4%B8%AD%E5%9B%BD-%E5%92%8C%E7%BE%8E-html5</guid>
      <pubDate>Thu, 22 Oct 2015 18:47:00 CST</pubDate>
    </item>
    <item>
      <title>Html5 客户端存储安全</title>
      <link>https://itindex.net/detail/54842-html5-%E5%AE%A2%E6%88%B7%E7%AB%AF-%E5%AE%89%E5%85%A8</link>
      <description>HTML 5 在客户端存储上的内容更丰富，更强大了，比如cookie只能存4k的内容，而HTML5标准里，可以存数十M都没有问题。
 &lt;br /&gt;
 &lt;br /&gt;在未来可能很多隐私数据都会保存在客户端，这其实也提高了风险。
 &lt;br /&gt;
 &lt;br /&gt;在html5中的客户端存储有3个
 &lt;br /&gt;
 &lt;br /&gt;Session Storage
 &lt;br /&gt;Local Storage(ex Global Storage)
 &lt;br /&gt;Database Storage
 &lt;br /&gt;
 &lt;br /&gt;做了点小笔记。
 &lt;br /&gt;
 &lt;br /&gt;和cookie类似，在新的html 5中使用的是 Session Storage，不过它的生效时间不再由程序员指定了。
 &lt;br /&gt;
 &lt;br /&gt;Session Storage没有path字段，所以相对cookie能针对某个目录的设计而言，这种设计在安全上反而是削弱了。
 &lt;br /&gt;
 &lt;br /&gt;Global Storage 比较危险，属于全局保存的数据，能跨全域，不过目前ff2 ff3和ie8都严格限制了这一点。
 &lt;br /&gt;
 &lt;br /&gt;database storage目前还只有webkit支持，用的是sqlite。
 &lt;br /&gt;
 &lt;br /&gt;未来FF和IE肯定也会加入对它的支持，不知道会不会也用sqlite。
 &lt;br /&gt;
 &lt;br /&gt;如果使用了Database storage，那就还会存在客户端注射的风险。
 &lt;br /&gt;
 &lt;br /&gt;一般情况下，需要知道字段名才能去操作，不过paper的作者提出可以用遍历的方法来获取字段名，类似遍历：window.sessionStorage
 &lt;br /&gt;
          
           &lt;br /&gt; &lt;br /&gt;
          
             &lt;a href="http://q2768717191.iteye.com/blog/2263607#comments"&gt;已有   &lt;strong&gt;0&lt;/strong&gt; 人发表留言，猛击-&amp;gt;&amp;gt;  &lt;strong&gt;这里&lt;/strong&gt;&amp;lt;&amp;lt;-参与讨论&lt;/a&gt;
          
           &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;
ITeye推荐
 &lt;br /&gt;
 &lt;ul&gt;  &lt;li&gt;   &lt;a href="http://www.iteye.com/clicks/433" target="_blank"&gt;—软件人才免语言低担保 赴美带薪读研！— &lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
 &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;
          
        &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/54842-html5-%E5%AE%A2%E6%88%B7%E7%AB%AF-%E5%AE%89%E5%85%A8</guid>
      <pubDate>Sat, 12 Dec 2015 12:27:57 CST</pubDate>
    </item>
    <item>
      <title>【译文】Top 10：HTML5、JavaScript 3D游戏引擎和框架</title>
      <link>https://itindex.net/detail/53748-%E8%AF%91%E6%96%87-top-html5</link>
      <description>&lt;p&gt;  &lt;img alt="best-3d-javascript-game-engines-frameworks-webgl-html5" src="http://ido321.qiniudn.com/qiniu/1599/image/4056fbf291c8f7e871c3f62b1d87271b.png" title=""&gt;&lt;/img&gt;
&lt;/p&gt; &lt;p&gt;由于很多人都在用JavaScript、HTML5和WebGL技术创建基于浏览器的3D游戏，所有JavaScript 3D游戏引擎是一个人们主题。基于浏览器的游戏最棒的地方是平台独立，它们能在iOS、Android、Windows或其他任何平台上运行。&lt;/p&gt;
 &lt;p&gt;有很多的JavaScript能够用于创建基于浏览器、使用HTML5和WebGL的3D游戏。然后，选择一个合适的游戏引擎是一个不小的挑战，它有时能帮你完成项目或突破项目瓶颈。&lt;/p&gt;
 &lt;p&gt;为了让你的选择变的容易，我们已经通过分析大多数JavaScript 3D游戏引擎在今天的市场并列出了十大游戏引擎来帮助您用JavaScript创建非常棒的HTML5,WebGL游戏。&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="http://www.babylonjs.com/" target="_blank"&gt;1. Babylon.js&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;毫无疑问，Babylon.JS是最好的JavaScript3D游戏引擎，它能创建可以出售的专业级游戏。   &lt;br /&gt;Babylon.JS是David Catuhe对3D游戏引擎热爱的结果，他在用DirectX, OpenGL, 和Silverlight创建3D游戏引擎方面是经验丰富，并最终自己完成了一个游戏引擎。   &lt;br /&gt;Babylon.js的一些核心功能包含了场景图与灯光、摄像机、材料和网格、碰撞引擎、物理引擎、音频引擎和优化引擎。   &lt;br /&gt;这是一个  &lt;a href="http://www.babylonjs.com/playground" target="_blank"&gt;Babylon.js&lt;/a&gt;试验场，你可以拿你手边的游戏来试试这个游戏引擎。&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="http://threejs.org/" target="_blank"&gt;2.Three.js&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;Three.js是另一个广泛应用并且功能强大的JavaScript 3D库，从创建简单的3D动画到创建交互的3D游戏， 它都能实现。   &lt;br /&gt;Threejs带来的不仅是支持WebGL渲染，也支持SVG、Canvas和CSS3D渲染。然而，从游戏的角度来看，你可以只关注Threejs的WebGL渲染。   &lt;br /&gt;获取Three.js 3D引擎的源代码—  &lt;a href="https://github.com/mrdoob/three.js/" target="_blank"&gt;github&lt;/a&gt;&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="http://biz.turbulenz.com/developers" target="_blank"&gt;3. Turbulenz&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;Turbulenz是最好的游戏引擎之一，在2009年，当HTML5和WebGL还在酝酿时，它已经被推出。直到2013年，Turbulenz才基于MIT协议拥抱开源。   &lt;br /&gt;Turbulenz包含了很多功能，例如2d物理、3d物理、声音、视频和其他服务,如排行榜、multichat,支付和用户数据。   &lt;br /&gt;了解更多：  &lt;a href="http://biz.turbulenz.com/developers" target="_blank"&gt;biz.turbulenz.com&lt;/a&gt;   &lt;br /&gt;获取源代码：  &lt;a href="https://github.com/turbulenz/turbulenz_engine" target="_blank"&gt;turbulenz_engine&lt;/a&gt;&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="http://famo.us/" target="_blank"&gt;4. Famo.us&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;在HTML5 3D发展的市场中，Famo.us占据了非常重要的地位，并且它是最好的JavaScript 3D开源框架之一。对于famo.us，最好的事情就是包装了3D布局引擎，其完全继承了3D物理驱动的动画引擎。   &lt;br /&gt;了解更多—  &lt;a href="http://famo.us/docs/" target="_blank"&gt;famo.us/docs&lt;/a&gt;   &lt;br /&gt;获取源代码—  &lt;a href="https://github.com/Famous/famous" target="_blank"&gt;famous&lt;/a&gt;&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="https://playcanvas.com/" target="_blank"&gt;5. PlayCanvas.js&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;PlayCanvas是一个基于  &lt;strong&gt;WebGL游戏引擎&lt;/strong&gt;的企业级开源JavaScript框架，它有许多的开发工具能帮你快速创建3D游戏。PlayCanvas.js由一个专业社区创建，最初并不是开源的，但现在你可以在github上fork PlayCanvas.js，然后在你的下一个3D游戏项目中免费使用。   &lt;br /&gt;它还提供了能在浏览器中云心的云编辑器，开始使用PalyCanvas和导航到编辑器的URL一样容易。   &lt;br /&gt;了解更多—  &lt;a href="https://playcanvas.com/" target="_blank"&gt;playcanvas.com&lt;/a&gt;   &lt;br /&gt;获取源代码—  &lt;a href="https://github.com/playcanvas/engine" target="_blank"&gt;playcanvas/engine&lt;/a&gt;&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="http://www.goocreate.com/" target="_blank"&gt;6. Goo Engine&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;来自于GOO技术家族，Goo引擎有一组功能强大的JavaScript API，可通过使用HTML5和WebGL创建任何3D事物。有一个在线的编辑器goocreate，可以运行在Goo引擎上，并封装了一些功能，例如视觉三维编辑器,材质编辑器、脚本和容易发布选项等。   &lt;br /&gt;你可以通过支付一些相关的许可费用，在浏览器中使用在线编辑器。   &lt;br /&gt;尽管编辑器需要一些费用，但是Goo引擎是绝对免费的，你可以下载它并在你的3D项目中使用。   &lt;br /&gt;了解更多—-  &lt;a href="https://code.gooengine.com/" target="_blank"&gt;labs.gooengine.com&lt;/a&gt;   &lt;br /&gt;获取源代码—  &lt;a href="https://code.gooengine.com/" target="_blank"&gt;code.gooengine.com&lt;/a&gt;&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="http://www.ambiera.com/copperlicht/" target="_blank"&gt;7. CooperLicht&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;对于创建基于浏览器的游戏，CopperLIcht是最出色的3D引擎之一，也是CopperCube 3D游戏编辑器的后端引擎。   &lt;br /&gt;CopperCube是一个支持创建3D游戏和动画所需要的所有功能的编辑器，但是，它并不开源，需要一些相关的许可费用。   &lt;br /&gt;了解更多—  &lt;a href="http://www.ambiera.com/copperlicht/download.html" target="_blank"&gt;ambiera.com/copperlicht&lt;/a&gt;&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="http://voxeljs.com/" target="_blank"&gt;8. Voxel.JS&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;Voxel.Js是开源的，基于JavaScript的一个3D游戏引擎，自从它发布以来，社区成长非常快。如果你喜欢模块化方法，Voxel是一个不错的选择。   &lt;br /&gt;Voxel-engine是创建3D游戏的核心模块，其它模块可以根据需要插入。到目前为止，已经有超过200个扩展在npm上发布。   &lt;br /&gt;了解更多—  &lt;a href="https://github.com/maxogden/voxel-engine" target="_blank"&gt;maxogden/voxel-engine&lt;/a&gt;&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="https://www.blend4web.com/en/" target="_blank"&gt;9. Blend4Web&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;在2014年，Blend4Web作为开源的3D框架而发布，它高度集成了Triumph的3D内容创建工具“Blender”，并且本地支持Blender的节点材料、粒子系统、bullet物理引擎和其他功能。   &lt;br /&gt;获取源代码—  &lt;a href="https://www.blend4web.com/en/downloads/" target="_blank"&gt;blend4web.com/en/downloads&lt;/a&gt;&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="http://enchantjs.com/" target="_blank"&gt;10. Enchant.js&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;Enchant.js是一个模块化的、面向对象的JavaScript框架，可用HTML5创建简单的APP和游戏。它是基于MIT协议开源的，因此开源免费使用。3D动画和游戏开源使用额外的插件（基于WebGL）创建。   &lt;br /&gt;获取源代码–  &lt;a href="https://github.com/wise9/enchant.js" target="_blank"&gt;wise9/enchant.js&lt;/a&gt;&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;本文根据@Nicolas Bevacqua的   &lt;a href="http://noeticforce.com/best-3d-javascript-game-engines-frameworks-webgl-html5" target="_blank"&gt;《best-3d-javascript-game-engines-frameworks-webgl-html5》&lt;/a&gt;所译，整个译文带有我自己的理解与思想，如果译得不好或有不对之处还请同行朋友指点。如需转载此译文，需注明英文出处：   &lt;a href="http://noeticforce.com/best-3d-javascript-game-engines-frameworks-webgl-html5" target="_blank"&gt;http://noeticforce.com/best-3d-javascript-game-engines-frameworks-webgl-html5&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;table border="0" cellpadding="3" cellspacing="0"&gt;
    
      &lt;tr&gt;
           &lt;td colspan="5"&gt;    &lt;strong&gt;淡忘~浅思猜你喜欢&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    
          &lt;tr&gt;
                   &lt;td valign="top" width="102"&gt;
                        &lt;a href="http://app.wumii.com/ext/redirect?url=http%3A%2F%2Fwww.ido321.com%2F1116.html&amp;from=http%3A%2F%2Fwww.ido321.com%2F1599.html" target="_blank" title="&amp;#24590;&amp;#20040;&amp;#23545;HTML 5&amp;#30340;&amp;#29305;&amp;#24615;&amp;#20570;&amp;#26816;&amp;#27979;&amp;#65311;"&gt;
                             &lt;img height="96px" src="http://wumii-cc.wumii.cn/site_images/ti/7dT4Oij.jpg?i=15Yx6yXs7" width="96px"&gt;&lt;/img&gt;     &lt;br /&gt;
                        怎么对HTML 5的特性做检测？
                    &lt;/a&gt;
                &lt;/td&gt;
                   &lt;td valign="top" width="102"&gt;
                        &lt;a href="http://app.wumii.com/ext/redirect?url=http%3A%2F%2Fwww.ido321.com%2F1308.html&amp;from=http%3A%2F%2Fwww.ido321.com%2F1599.html" target="_blank" title="HTML 5&amp;#65306;&amp;#32472;&amp;#21046;&amp;#26059;&amp;#36716;&amp;#30340;&amp;#22826;&amp;#26497;&amp;#22270;"&gt;
                             &lt;img height="96px" src="http://wumii-cc.wumii.cn/site_images/ti/lFJYnCwM.jpg?i=9LXHq6jw" width="96px"&gt;&lt;/img&gt;     &lt;br /&gt;
                        HTML 5：绘制旋转的太极图
                    &lt;/a&gt;
                &lt;/td&gt;
                   &lt;td valign="top" width="102"&gt;
                        &lt;a href="http://app.wumii.com/ext/redirect?url=http%3A%2F%2Fwww.ido321.com%2F1293.html&amp;from=http%3A%2F%2Fwww.ido321.com%2F1599.html" target="_blank" title="&amp;#12304;&amp;#35793;&amp;#12305;&amp;#21033;&amp;#29992;HTML 5&amp;#20013;&amp;#30340;Menu&amp;#21644;Menuitem&amp;#20803;&amp;#32032;&amp;#24555;&amp;#36895;&amp;#21019;&amp;#24314;&amp;#33756;&amp;#21333;"&gt;
                             &lt;img height="96px" src="http://wumii-cc.wumii.cn/site_images/ti/5AlZA4D5.jpg?i=u78WlRr7" width="96px"&gt;&lt;/img&gt;     &lt;br /&gt;
                        【译】利用HTML 5中的Menu和Menuitem元素快速创建菜单
                    &lt;/a&gt;
                &lt;/td&gt;
                   &lt;td valign="top" width="102"&gt;
                        &lt;a href="http://app.wumii.com/ext/redirect?url=http%3A%2F%2Fwww.ido321.com%2F949.html&amp;from=http%3A%2F%2Fwww.ido321.com%2F1599.html" target="_blank" title="&amp;#21021;&amp;#35782;HTML 5&amp;#65306;&amp;#20851;&amp;#20110;&amp;#23427;&amp;#30340;&amp;#19977;&amp;#20010;&amp;#19977;"&gt;
                             &lt;img height="96px" src="http://wumii-cc.wumii.cn/site_images/ti/1dhvu1uY3.jpg?i=af7W8CRC" width="96px"&gt;&lt;/img&gt;     &lt;br /&gt;
                        初识HTML 5：关于它的三个三
                    &lt;/a&gt;
                &lt;/td&gt;
                   &lt;td valign="top" width="102"&gt;
                        &lt;a href="http://app.wumii.com/ext/redirect?url=http%3A%2F%2Fwww.ido321.com%2F1069.html&amp;from=http%3A%2F%2Fwww.ido321.com%2F1599.html" target="_blank" title="HTML 5 API&amp;#30340;&amp;#8221;&amp;#21069;&amp;#29983;&amp;#20170;&amp;#19990;&amp;#8221;"&gt;
                             &lt;img height="96px" src="http://wumii-cc.wumii.cn/site_images/ti/Zo7Qg2Fz.jpg?i=6ARMefIk" width="96px"&gt;&lt;/img&gt;     &lt;br /&gt;
                        HTML 5 API的”前生今世”
                    &lt;/a&gt;
                &lt;/td&gt;
        &lt;/tr&gt;
    
      &lt;tr&gt;
           &lt;td align="right" colspan="5"&gt;
                &lt;a href="http://www.wumii.com/widget/relatedItems" target="_blank" title="&amp;#26080;&amp;#35269;&amp;#20851;&amp;#32852;&amp;#25512;&amp;#33616;"&gt;
                无觅
            &lt;/a&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt; &lt;p&gt;转载请注明：  &lt;a href="http://www.ido321.com"&gt;淡忘~浅思&lt;/a&gt; »   &lt;a href="http://www.ido321.com/1599.html"&gt;【译文】Top 10：HTML5、JavaScript 3D游戏引擎和框架&lt;/a&gt;&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>HTML JavaScript HTML5 js 游戏</category>
      <guid isPermaLink="true">https://itindex.net/detail/53748-%E8%AF%91%E6%96%87-top-html5</guid>
      <pubDate>Wed, 24 Jun 2015 12:13:19 CST</pubDate>
    </item>
    <item>
      <title>一些有用的HTML5 pattern</title>
      <link>https://itindex.net/detail/53718-html5-pattern</link>
      <description>&lt;p&gt;最近在做手机页面时，遇到数字输入的键盘的问题，之前的做法只是一刀切的使用   &lt;code&gt;type=&amp;quot;tel&amp;quot;&lt;/code&gt;，不过一直觉得九宫格的电话号码键盘上的英文字母太碍事了。于是想要尝试其它的实现方案，最终的结论却令人沮丧。不过也趁机详细了解了下  &lt;code&gt;pattern&lt;/code&gt;这个属性。 &lt;/p&gt;

 &lt;h3&gt;type=&amp;quot;tel&amp;quot; 和 type=&amp;quot;number&amp;quot; 的区别&lt;/h3&gt;

 &lt;p&gt;这里还是先那么先交代一下最初遇到的问题。其实无论是  &lt;code&gt;tel&lt;/code&gt;还是  &lt;code&gt;number&lt;/code&gt;都不是完美的：&lt;/p&gt;

 &lt;h4&gt;type=&amp;quot;tel&amp;quot;&lt;/h4&gt;

 &lt;ul&gt;
  &lt;li&gt;优点是iOS和Android的键盘表现都差不多&lt;/li&gt;
  &lt;li&gt;缺点是那些字母好多余，虽然我没有强迫症但还是感觉怪怪的啊。
   &lt;img alt="" src="http://www.qianduan.net/content/images/2015/06/type_tel.jpg"&gt;&lt;/img&gt;&lt;/li&gt;
&lt;/ul&gt;

 &lt;h4&gt;type=&amp;quot;number&amp;quot;&lt;/h4&gt;

 &lt;ul&gt;
  &lt;li&gt;优点是Android下实现的一个真正的数字键盘&lt;/li&gt;
  &lt;li&gt;缺点一：iOS下不是九宫格键盘，输入不方便&lt;/li&gt;
  &lt;li&gt;缺点二：旧版Android（包括微信所用的X5内核）在输入框后面会有超级   &lt;strong&gt;鸡肋的小尾巴&lt;/strong&gt;，好在Android 4.4.4以后给去掉了。&lt;/li&gt;
&lt;/ul&gt;

 &lt;p&gt;  &lt;img alt="" src="http://www.qianduan.net/content/images/2015/06/type_number.jpg"&gt;&lt;/img&gt;
  &lt;img alt="" src="http://www.qianduan.net/content/images/2015/06/numberarrow.jpg"&gt;&lt;/img&gt;
不过对于缺点二，我们可以用webkit私有的伪元素给fix掉：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;input[type=number]::-webkit-inner-spin-button,  
    input[type=number]::-webkit-outer-spin-button { 
        -webkit-appearance: none; 
        appearance: none; 
        margin: 0; 
    }
&lt;/code&gt;&lt;/pre&gt;

 &lt;h3&gt;pattern属性&lt;/h3&gt;

 &lt;p&gt;  &lt;code&gt;pattern&lt;/code&gt;用于验证表单输入的内容，通常HTML5的  &lt;code&gt;type&lt;/code&gt;属性，比如  &lt;code&gt;email&lt;/code&gt;、  &lt;code&gt;tel&lt;/code&gt;、  &lt;code&gt;number&lt;/code&gt;、  &lt;code&gt;data&lt;/code&gt;类、  &lt;code&gt;url&lt;/code&gt;等，已经自带了简单的数据格式验证功能了，加上pattern后，前端部分的验证更加简单高效了。&lt;/p&gt;

 &lt;p&gt;显而易见，  &lt;code&gt;pattern&lt;/code&gt;的属性值要用正则表达式。&lt;/p&gt;

 &lt;h3&gt;实例&lt;/h3&gt;

 &lt;h4&gt;简单的数字验证&lt;/h4&gt;

 &lt;p&gt;数字的验证有两个：  &lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;&amp;lt;input type=&amp;quot;number&amp;quot; pattern=&amp;quot;\d&amp;quot;&amp;gt;  
&amp;lt;input type=&amp;quot;number&amp;quot; pattern=&amp;quot;[0-9]*&amp;quot;&amp;gt;  
&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;  &lt;br /&gt;
  &lt;img alt="" src="http://www.qianduan.net/content/images/2015/06/type_number-1.jpg"&gt;&lt;/img&gt;
对表单验证来说，这两个正则的作用是一样的，表现的话差异就很大：&lt;/p&gt;

 &lt;ul&gt;
  &lt;li&gt;iOS中，   &lt;strong&gt;只有    &lt;code&gt;[0-9]\*&lt;/code&gt;才可以调起九宫格数字键盘&lt;/strong&gt;，   &lt;code&gt;\d&lt;/code&gt; 无效&lt;/li&gt;
  &lt;li&gt;Android 4.4以下(包括X5内核)，两者都调起数字键盘；&lt;/li&gt;
  &lt;li&gt;Android 4.4.4以上，只认    &lt;code&gt;type&lt;/code&gt; 属性，也就是说，如果上面的代码将    &lt;code&gt;type=&amp;quot;number&amp;quot;&lt;/code&gt; 改为    &lt;code&gt;type=&amp;quot;text&amp;quot;&lt;/code&gt; ，将调起全键盘而不会是九宫格数字键盘。&lt;/li&gt;
&lt;/ul&gt;

 &lt;h4&gt;常用的正则表达式&lt;/h4&gt;

 &lt;p&gt;  &lt;code&gt;pattern&lt;/code&gt;的用法都一样，这里不再啰嗦各种详细写法了，只是列出来一些常用的正则就好了：&lt;/p&gt;

 &lt;ul&gt;
  &lt;li&gt;信用卡     &lt;code&gt;[0-9]{13,16}&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;银联卡     &lt;code&gt;^62[0-5]\d{13,16}$&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Visa:    &lt;code&gt;^4[0-9]{12}(?:[0-9]{3})?$&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;万事达：   &lt;code&gt;^5[1-5][0-9]{14}$&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;QQ号码：    &lt;code&gt;[1-9][0-9]{4,14}&lt;/code&gt;  &lt;/li&gt;
  &lt;li&gt;手机号码：   &lt;code&gt;^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;身份证：   &lt;code&gt;^([0-9]){7,18}(x|X)?$&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;密码：   &lt;code&gt;^[a-zA-Z]\w{5,17}$&lt;/code&gt; 字母开头，长度在6~18之间，只能包含字母、数字和下划线&lt;/li&gt;
  &lt;li&gt;强密码：   &lt;code&gt;^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$&lt;/code&gt; 包含大小写字母和数字的组合，不能使用特殊字符，长度在8-10之间&lt;/li&gt;
  &lt;li&gt;7个汉字或14个字符：   &lt;code&gt;^[\u4e00-\u9fa5]{1,7}$|^[\dA-Za-z_]{1,14}$&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

 &lt;h3&gt;浏览器支持&lt;/h3&gt;

 &lt;p&gt;很不幸，pattern的浏览器支持很惨：
  &lt;img alt="" src="http://www.qianduan.net/content/images/2015/06/patternsupport.jpg"&gt;&lt;/img&gt;
  &lt;em&gt;   &lt;a href="http://caniuse.com/#feat=input-pattern"&gt;via Can I Use&lt;/a&gt;&lt;/em&gt;   &lt;br /&gt;
但是如果只是如文章开头提到的改  &lt;strong&gt;数字键盘&lt;/strong&gt;的话，iOS和Android都是没有问题的。&lt;/p&gt; &lt;img alt="" height="1" src="http://feeds.feedburner.com/~r/qianduannet/~4/uQ9p308BqEc" width="1"&gt;&lt;/img&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>HTML5 表单 正则</category>
      <guid isPermaLink="true">https://itindex.net/detail/53718-html5-pattern</guid>
      <pubDate>Thu, 18 Jun 2015 21:42:17 CST</pubDate>
    </item>
    <item>
      <title>HTML5本地裁剪图片</title>
      <link>https://itindex.net/detail/53899-html5-%E5%9B%BE%E7%89%87</link>
      <description>&lt;h2&gt;先上效果图：&lt;/h2&gt;

 &lt;p&gt;  &lt;img alt="&amp;#26367;&amp;#20195;&amp;#25991;&amp;#23383;" src="https://wt-prj.oss.aliyuncs.com/0d06af79c49d4e08abb1ab3f7ab6e860/a08ff4d5-9228-4a31-b4d5-50b447f73b5e.gif"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;我们首先需要创建一个  &lt;code&gt;index.html&lt;/code&gt;文件，里面写上一些简单的  &lt;code&gt;html&lt;/code&gt;和  &lt;code&gt;css&lt;/code&gt;代码：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;HTML5 Crop Image&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;style type=&amp;quot;text/css&amp;quot;&amp;gt;
body{text-align:center;}
#label{border:1px solid #ccc;background-color:#fff;text-align:center;height:300px; width:300px;margin:20px auto;position:relative;}
#get_image{position:absolute;}
#edit_pic{position:absolute;display:none;background:#000;}
#cover_box{position: absolute;z-index: 9999;display:none;top:0px;left:0px;}
#show_edit{margin: 0 auto;display:inline-block;}
#show_pic{height:100px;width:100px;border:2px solid #000;overflow:hidden;margin:0 auto;display:inline-block; }
&amp;lt;/style&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;input type=&amp;quot;file&amp;quot; name=&amp;quot;file&amp;quot; id=&amp;quot;post_file&amp;quot;&amp;gt;
&amp;lt;button id=&amp;quot;save_button&amp;quot;&amp;gt;SAVE&amp;lt;/button&amp;gt;


&amp;lt;div id=&amp;quot;label&amp;quot;&amp;gt;
    &amp;lt;canvas id=&amp;quot;get_image&amp;quot;&amp;gt;&amp;lt;/canvas&amp;gt;
    &amp;lt;p&amp;gt;
        &amp;lt;canvas id=&amp;quot;cover_box&amp;quot;&amp;gt;&amp;lt;/canvas&amp;gt;
        &amp;lt;canvas id=&amp;quot;edit_pic&amp;quot;&amp;gt;&amp;lt;/canvas&amp;gt;
    &amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;




&amp;lt;p&amp;gt;
    &amp;lt;span id=&amp;quot;show_edit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;
    &amp;lt;span id=&amp;quot;show_pic&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/p&amp;gt;


&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;js/js.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;以上的三个  &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt;标签都是用来处理跟图片相关的内容的，详细的处理会在后续的js代码中给出。而  &lt;code&gt;id&lt;/code&gt;为  &lt;code&gt;show_edit&lt;/code&gt; 和  &lt;code&gt;id&lt;/code&gt;为  &lt;code&gt;show_pic&lt;/code&gt;这两个是为了图片的预览和查看最后的图片生成结果。做完html和css的布局之后，我们就可以进入js代码，实现本节课的图片裁剪功能。&lt;/p&gt;

 &lt;h2&gt;实现图片裁剪的init函数：&lt;/h2&gt;

 &lt;pre&gt;  &lt;code&gt;var postFile = { 
        init: function() {
        var t = this;
        t.regional = document.getElementById(&amp;apos;label&amp;apos;);
        t.getImage = document.getElementById(&amp;apos;get_image&amp;apos;);
        t.editPic = document.getElementById(&amp;apos;edit_pic&amp;apos;);
        t.editBox = document.getElementById(&amp;apos;cover_box&amp;apos;);
        t.px = 0;    //background image x
        t.py = 0;    //background image y
        t.sx = 15;    //crop area x
        t.sy = 15;    //crop area y
        t.sHeight = 150;    //crop area height
        t.sWidth = 150    //crop area width
        document.getElementById(&amp;apos;post_file&amp;apos;).addEventListener(&amp;quot;change&amp;quot;, t.handleFiles, false);
    },

}

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;我们将所有的函数和变量都是封装在  &lt;code&gt;postFile&lt;/code&gt;这个对象里面的，上面的  &lt;code&gt;init&lt;/code&gt;方法主要是设置一些初始值&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;t.px = 0;    
t.py = 0;    
t.sx = 15;   
t.sy = 15;   
t.sHeight = 150;    
t.sWidth = 150   

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;以上的  &lt;code&gt;t.px&lt;/code&gt;   &lt;code&gt;t.py&lt;/code&gt;分别表示在实时预览区域的背景图片的坐标；  &lt;code&gt;t.sx&lt;/code&gt;，  &lt;code&gt;t.sy&lt;/code&gt;，   &lt;code&gt;t.sHeight&lt;/code&gt;，   &lt;code&gt;t.sWidth&lt;/code&gt;分别表示图片的横纵坐标和宽高。&lt;/p&gt;

 &lt;p&gt;并且我们通过  &lt;code&gt;document.getElementById&lt;/code&gt;获取了多个稍后需要操作的元素，注意到：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;document.getElementById(&amp;apos;post_file&amp;apos;).addEventListener(&amp;quot;change&amp;quot;, t.handleFiles, false);

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;我们通过监听  &lt;code&gt;id&lt;/code&gt;为  &lt;code&gt;post_file&lt;/code&gt;的  &lt;code&gt;input&lt;/code&gt;表单的  &lt;code&gt;change&lt;/code&gt;事件来处理用户上传的文件，在这我们交给了  &lt;code&gt;handleFiles&lt;/code&gt;函数来处理，所以下面我们就来实现  &lt;code&gt;handleFiles&lt;/code&gt;函数。&lt;/p&gt;

 &lt;h2&gt;实现handleFiles，获取文件，读取文件并生成url&lt;/h2&gt;

 &lt;pre&gt;  &lt;code&gt; handleFiles: function() {
        var fileList = this.files[0];
        var oFReader = new FileReader();
        oFReader.readAsDataURL(fileList);
        oFReader.onload = function (oFREvent) { 
            postFile.paintImage(oFREvent.target.result);
        };
    },

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;上面这几行代码就可以基本实现  &lt;code&gt;handleFiles&lt;/code&gt;的处理功能，我们在这里就使用了HTML5的File API，首先通过  &lt;code&gt;new FileReader()&lt;/code&gt;来实例化一个  &lt;code&gt;FileReader&lt;/code&gt;对象  &lt;code&gt;oFReader&lt;/code&gt;，再调用其  &lt;code&gt;readAsDataURL()&lt;/code&gt;方法将文件的内容读取出来并处理成base64编码的格式。&lt;/p&gt;

 &lt;p&gt;如果你对  &lt;code&gt;var fileList = this.files[0];&lt;/code&gt;有疑问，不妨在在这里打印出来看看：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;console.log(this.files);

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;你将会看到类似于这样的打印输出：&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="&amp;#26367;&amp;#20195;&amp;#25991;&amp;#23383;" src="https://wt-prj.oss.aliyuncs.com/0d06af79c49d4e08abb1ab3f7ab6e860/c07413b1-bacb-408f-b4e3-b734bccedc90.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;最后，当文件读取完毕并完成加载的时候，我们通过  &lt;code&gt;postFile.paintImage(oFREvent.target.result)&lt;/code&gt;处理我们读取到的图片，说白了就是将读取到的图片数据重新绘画到浏览器上。&lt;/p&gt;

 &lt;p&gt;关于  &lt;code&gt;oFREvent&lt;/code&gt;究竟是什么东西，你可以通过  &lt;code&gt;console.log(oFREvent)&lt;/code&gt;来查看。你还可以查看这里的链接来获取更多的FileReader的知识：&lt;/p&gt;

 &lt;p&gt;  &lt;a href="https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader" rel="nofollow"&gt;https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader&lt;/a&gt;&lt;/p&gt;

 &lt;h2&gt;实现paintImage函数&lt;/h2&gt;

 &lt;pre&gt;  &lt;code&gt; paintImage: function(url) {
        var t = this;
        var createCanvas = t.getImage.getContext(&amp;quot;2d&amp;quot;);
        var img = new Image();
        img.src = url;
        img.onload = function(){

            if ( img.width &amp;lt; t.regional.offsetWidth &amp;amp;&amp;amp; img.height &amp;lt; t.regional.offsetHeight) {
                t.imgWidth = img.width;
                t.imgHeight = img.height;

            } else {
                var pWidth = img.width / (img.height / t.regional.offsetHeight);
                var pHeight = img.height / (img.width / t.regional.offsetWidth);
                t.imgWidth = img.width &amp;gt; img.height ? t.regional.offsetWidth : pWidth;
                t.imgHeight = img.height &amp;gt; img.width ? t.regional.offsetHeight : pHeight;
            }
            t.px = (t.regional.offsetWidth - t.imgWidth) / 2 + &amp;apos;px&amp;apos;;
            t.py = (t.regional.offsetHeight - t.imgHeight) / 2 + &amp;apos;px&amp;apos;;

            t.getImage.height = t.imgHeight;
            t.getImage.width = t.imgWidth;
            t.getImage.style.left = t.px;
            t.getImage.style.top = t.py;

            createCanvas.drawImage(img,0,0,t.imgWidth,t.imgHeight);
            t.imgUrl = t.getImage.toDataURL();
            t.cutImage(); 
            t.drag();
        };
    },


&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;以上最重要的就是根据容器的大小使用canvas绘制图片。在上一步使用File API的FileReader已经得到了需要上传图片的地址了(  &lt;code&gt;oFREvent.target.result&lt;/code&gt;这个值)，接下来需要使用canvas把这个图片绘制出来。我们首先使用到  &lt;code&gt;getImage.getContext&lt;/code&gt;来获取  &lt;code&gt;&amp;lt;canvas id=&amp;quot;get_image&amp;quot;&amp;gt;&amp;lt;/canvas&amp;gt;&lt;/code&gt;的2d内容，简单理解就是图像内容，然后利用  &lt;code&gt;new Image()&lt;/code&gt;来得到一个  &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;标签，设置  &lt;code&gt;src属&lt;/code&gt;性的值，如果你  &lt;code&gt;console.log(img)&lt;/code&gt;,得到的大概是这样的结果：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;&amp;lt;img src=&amp;quot;images/background.png&amp;quot; &amp;gt;

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;在  &lt;code&gt;img.onload&lt;/code&gt;函数里，我们的主要目的是为了将图片按照原大小等比例地重画出来，所以才有if条件判断，最后我们通过  &lt;code&gt;createCanvas.drawImage(img,0,0,t.imgWidth,t.imgHeight);&lt;/code&gt;这一行代码来实现真正的绘画图片，效果大概是这样的：&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="&amp;#26367;&amp;#20195;&amp;#25991;&amp;#23383;" src="https://wt-prj.oss.aliyuncs.com/0d06af79c49d4e08abb1ab3f7ab6e860/7c002e9b-1a79-421e-ad23-c333f56a56bf.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;这里为什么不直接插入img而用canvas重新绘制呢，这不是多此一举了吗？其实不然。如果用img直接插入页面，就无法自适应居中了，如果使用canvas绘制图片，不但能使图片自适应居中以及能等比例缩放，并且方便把图片的坐标，尺寸大小传给后来的遮罩层(  &lt;code&gt;id&lt;/code&gt;为  &lt;code&gt;label&lt;/code&gt;的div)，这样能根据图片的坐标以及图片的尺寸大小来绘制遮罩层。&lt;/p&gt;

 &lt;p&gt;如果你对drawImage()有任何疑问，点击下面的链接进行详细的了解：&lt;/p&gt;

 &lt;p&gt;  &lt;a href="https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/drawImage" rel="nofollow"&gt;https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContex...&lt;/a&gt;&lt;/p&gt;

 &lt;p&gt;到这里，前期的一小半工作其实已经完成了，我们按照上面的思路，接下来就把  &lt;code&gt;cutImage&lt;/code&gt;和  &lt;code&gt;drag&lt;/code&gt;这两个方法实现就可以了。&lt;/p&gt;

 &lt;h2&gt;实现cutImage方法&lt;/h2&gt;

 &lt;p&gt;在上一张图片中，我们其实很清楚地看到了两个明暗不一的层，这是因为我们根据背景图的坐标和尺寸来绘制遮罩层覆盖在背景上面，并且使用canvas的  &lt;code&gt;clearRect&lt;/code&gt;方法清空出一块裁剪区域，使之与不裁剪的地方做明暗对比，这样的目的一个是为了更好地看到对比，一个就是为了用户体验：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;cutImage: function() {
    var t = this;

    //绘制遮罩层：
    t.editBox.height = t.imgHeight;
    t.editBox.width = t.imgWidth;
    t.editBox.style.display = &amp;apos;block&amp;apos;;
    t.editBox.style.left = t.px;
    t.editBox.style.top = t.py;

    var cover = t.editBox.getContext(&amp;quot;2d&amp;quot;);
    cover.fillStyle = &amp;quot;rgba(0, 0, 0, 0.5)&amp;quot;;
    cover.fillRect (0,0, t.imgWidth, t.imgHeight);
    cover.clearRect(t.sx, t.sy, t.sHeight, t.sWidth);

    //预览图片

    document.getElementById(&amp;apos;show_edit&amp;apos;).style.background = &amp;apos;url(&amp;apos; + t.imgUrl + &amp;apos;)&amp;apos; + -t.sx + &amp;apos;px &amp;apos; + -t.sy + &amp;apos;px no-repeat&amp;apos;;
    document.getElementById(&amp;apos;show_edit&amp;apos;).style.height = t.sHeight + &amp;apos;px&amp;apos;;
    document.getElementById(&amp;apos;show_edit&amp;apos;).style.width = t.sWidth + &amp;apos;px&amp;apos;;
},

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;以上的  &lt;code&gt;cutImage&lt;/code&gt;方法主要是负责两个事情，一个是制造遮罩层，一个是利用css的  &lt;code&gt;background&lt;/code&gt;属性将选中的裁剪区域实时预览。&lt;/p&gt;

 &lt;p&gt;  &lt;code&gt;但是需要注意的是，这里的遮罩层仅仅是用来做显示效果，并没有做裁剪图片的工作。&lt;/code&gt;&lt;/p&gt;

 &lt;h2&gt;编写drag方法&lt;/h2&gt;

 &lt;p&gt;在很多web应用中，使用截图上传头像功能时我们希望能裁剪到满意的图片，所以裁剪框就需要不停的变动才得以裁剪出完美的图片。前几步已经把裁剪图片的基本功能做出来了，所以现在需要做的就是裁剪框跟进鼠标的移动来实时裁剪图片&lt;/p&gt;

 &lt;p&gt;先来一张预览图片：&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="&amp;#26367;&amp;#20195;&amp;#25991;&amp;#23383;" src="https://wt-prj.oss.aliyuncs.com/0d06af79c49d4e08abb1ab3f7ab6e860/5d81ad36-fea1-4c0d-bff2-e8b3d00378a4.gif"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;   &lt;br /&gt; drag: function() {
        var t = this;
        var draging = false;
        var startX = 0;
        var startY = 0;

        document.getElementById(&amp;apos;cover_box&amp;apos;).onmousemove = function(e) {
            var pageX = e.pageX - ( t.regional.offsetLeft + this.offsetLeft );
            var pageY = e.pageY - ( t.regional.offsetTop + this.offsetTop );

            if ( pageX &amp;gt; t.sx &amp;amp;&amp;amp; pageX &amp;lt; t.sx + t.sWidth &amp;amp;&amp;amp; pageY &amp;gt; t.sy &amp;amp;&amp;amp; pageY &amp;lt; t.sy + t.sHeight ) {
                this.style.cursor = &amp;apos;move&amp;apos;;

                this.onmousedown = function(){
                    draging = true;

                    t.ex = t.sx;
                    t.ey = t.sy;

                    startX = e.pageX - ( t.regional.offsetLeft + this.offsetLeft );
                    startY = e.pageY - ( t.regional.offsetTop + this.offsetTop );

                }
                window.onmouseup = function() {
                    draging = false;
                }

                if (draging) {

                    if ( t.ex + (pageX - startX) &amp;lt; 0 ) {
                        t.sx = 0;
                    } else if ( t.ex + (pageX - startX) + t.sWidth &amp;gt; t.imgWidth) {
                        t.sx = t.imgWidth - t.sWidth;
                    } else {
                        t.sx = t.ex + (pageX - startX);
                    };

                    if (t.ey + (pageY - startY) &amp;lt; 0) {
                        t.sy = 0;
                    } else if ( t.ey + (pageY - startY) + t.sHeight &amp;gt; t.imgHeight ) {
                        t.sy = t.imgHeight - t.sHeight;
                    } else {
                        t.sy = t.ey + (pageY - startY);
                    }

                    t.cutImage();
                }
            } else{
                this.style.cursor = &amp;apos;auto&amp;apos;;
            }
        };
    }


&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;这个方法里要理解一下几个主要的点：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;var pageX = e.pageX - ( t.regional.offsetLeft + this.offsetLeft );
var pageY = e.pageY - ( t.regional.offsetTop + this.offsetTop );

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;我们通过上面两行代码来获取  &lt;code&gt;鼠标距离背景图片的距离&lt;/code&gt;，  &lt;code&gt;e.pageX&lt;/code&gt;代表鼠标到浏览器左边缘的距离，  &lt;code&gt;t.regional.offsetLeft + this.offsetLeft&lt;/code&gt;可以计算出图片到浏览器的左边边缘的距离。上边的距离同理可得。&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;   &lt;br /&gt; if ( pageX &amp;gt; t.sx &amp;amp;&amp;amp; pageX &amp;lt; t.sx + t.sWidth &amp;amp;&amp;amp; pageY &amp;gt; t.sy &amp;amp;&amp;amp; pageY &amp;lt; t.sy + t.sHeight )

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;在理解了  &lt;code&gt;鼠标距离背景图片的距离&lt;/code&gt;距离之后，这个应该很容易理解：就是判断鼠标是否在图片的区域内部。&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;   &lt;br /&gt;t.ex = t.sx; 
t.ey = t.sy;

startX = e.pageX - ( t.regional.offsetLeft + this.offsetLeft );
startY = e.pageY - ( t.regional.offsetTop + this.offsetTop );


&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;这两段代码也是要拿出来说说的，头两行是为了记录上一次截图时候的坐标（没有上一次就是初始化的时候的坐标）；后两行记录鼠标按下时候的坐标。你都可以通过  &lt;code&gt;console.log()&lt;/code&gt;来分别查看这几个值。&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;   &lt;br /&gt;if (draging) {


    if ( t.ex + (pageX - startX) &amp;lt; 0 ) {
        t.sx = 0;
    } else if ( t.ex + (pageX - startX) + t.sWidth &amp;gt; t.imgWidth) {
        t.sx = t.imgWidth - t.sWidth;
    } else {
        t.sx = t.ex + (pageX - startX);
    };

    if (t.ey + (pageY - startY) &amp;lt; 0) {
        t.sy = 0;
    } else if ( t.ey + (pageY - startY) + t.sHeight &amp;gt; t.imgHeight ) {
        t.sy = t.imgHeight - t.sHeight;
    } else {
        t.sy = t.ey + (pageY - startY);
    }

    t.cutImage();
}


&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;上面这一行代码就是说：如果实在拖动的情况下，我们需要根据坐标的变化来实时更新  &lt;code&gt;t.sx&lt;/code&gt;和  &lt;code&gt;t.sy&lt;/code&gt;的值,并且实时调用  &lt;code&gt;cutImage&lt;/code&gt;方法实现预览。&lt;/p&gt;

 &lt;p&gt;  &lt;code&gt;移动时裁剪区域的坐标 = 上次记录的定位 + (当前鼠标的位置 - 按下鼠标的位置)&lt;/code&gt;&lt;/p&gt;

 &lt;h2&gt;最后，将裁剪的图片进行保存&lt;/h2&gt;

 &lt;p&gt;从一开始，我们就有一个save按钮在页面上，我们的目的就是在用户点击save按钮的时候，将裁剪出来的图片保存到预览右边的方框内，于是，我们在  &lt;code&gt;init&lt;/code&gt;方法里面添加下面的代码：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;   &lt;br /&gt;document.getElementById(&amp;apos;save_button&amp;apos;).onclick = function() {
    t.editPic.height = t.sHeight;
    t.editPic.width = t.sWidth;
    var ctx = t.editPic.getContext(&amp;apos;2d&amp;apos;);
    var images = new Image();
    images.src = t.imgUrl;

    images.onload = function(){
        ctx.drawImage(images,t.sx, t.sy, t.sHeight, t.sWidth, 0, 0, t.sHeight, t.sWidth); 
        document.getElementById(&amp;apos;show_pic&amp;apos;).getElementsByTagName(&amp;apos;img&amp;apos;)[0].src = t.editPic.toDataURL();
    }

}

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;跟实现  &lt;code&gt;painImage&lt;/code&gt;方法类似，首先监听save按钮的点击事件，然后我们将选中区域的图片利用  &lt;code&gt;drawImage&lt;/code&gt;方法绘制出来，最后利用  &lt;code&gt;toDataURL&lt;/code&gt;方法转换成base64编码格式并将该值赋予  &lt;code&gt;show_pic&lt;/code&gt;下  &lt;code&gt;img&lt;/code&gt;的  &lt;code&gt;src&lt;/code&gt;属性，这样就完成了图片的裁剪保存。效果如图：&lt;/p&gt;

 &lt;h2&gt;调用init方法&lt;/h2&gt;

 &lt;p&gt;最后别忘了在开始之前调用  &lt;code&gt;init&lt;/code&gt;方法，在js文件的最后一行加上：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;postFile.init();

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;最后的代码布局应该时这样的：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;var postFile = {

    init: function() {
        //codes
        },

    handleFiles: function() {
        //codes
        },

    //...methods
}
postFile.init();
&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;  &lt;strong&gt;Happy Hacking&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>html5 canvas 图片处理</category>
      <guid isPermaLink="true">https://itindex.net/detail/53899-html5-%E5%9B%BE%E7%89%87</guid>
      <pubDate>Wed, 15 Jul 2015 15:55:24 CST</pubDate>
    </item>
    <item>
      <title>Youtube网站正式全面使用HTML5&lt;video&gt;播放视频</title>
      <link>https://itindex.net/detail/52655-youtube-%E7%BD%91%E7%AB%99-html5</link>
      <description>&lt;p&gt;四年前，Youtube官方曾宣布在网站上  &lt;a href="http://apiblog.youtube.com/2010/06/flash-and-html5-tag.html"&gt;实验性的支持HTML5&amp;lt;video&amp;gt;标记&lt;/a&gt;，测试它跟使用Flash对比的效果。当时，由于诸多的限制，无法将这种技术广泛的运用到视频播放中。最重要的原因是，HTML5缺乏对Adaptive Bitrate (ABR)的支持，这种技术能让视频进行少量的缓冲就能播放。&lt;/p&gt;
 &lt;p&gt;经过最近的4年发展，浏览器的发展和各种广泛的交流促使HTML5技术和实际视频运用之间的差距越来越小。现在，在谷歌浏览器、IE11、苹果浏览器以及最新版的火狐浏览器中，使用HTML5&amp;lt;video&amp;gt;播放将成为缺省设置。&lt;/p&gt;
 &lt;p&gt;HTML5的优势并不是仅仅体现在web浏览器在，它还能运用到智能电视和其它流媒体设备中。下面是HTML5的一些关键技术指标：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;支持 ABR（Adaptive Bitrate，自适应比特率）：ABR 能够有效减少缓冲时间，能利用媒体源拓展（   &lt;a href="http://w3c.github.io/media-source/" target="_blank"&gt;MediaSourse Extensions&lt;/a&gt;）使视频 / 直播在 Chrome, IE11, Safari 8 还有 beta 版的 Firebox 等众多浏览器中流畅播放。HTML5 也能照顾到多种流媒体设备，包括目前主流的 Xbox One，Playstation 4 和 Chromecast 等。&lt;/li&gt;
  &lt;li&gt;支持VP9 codec：VP9 codec 能有效节省带宽、加载时间和文件的大小。YouTube 团队鼓励开发者使用   &lt;a href="https://developers.google.com/youtube/iframe_api_reference" target="_blank"&gt;iframe API&lt;/a&gt;代替 Flash，这样在很多不支持 Flash 的设备上也能进行视频的浏览。&lt;/li&gt;
  &lt;li&gt;加密媒体扩展 (   &lt;a href="https://w3c.github.io/encrypted-media/" target="_blank"&gt;Encrypted Media Extensions&lt;/a&gt;)：通过这个扩展和正常加密的措施的结合，YouTube 的视频能够通过简单的配置，在不同平台上对多种内容保护技术进行支撑。简化了视频传输中由于加密保护与内容高度整合带来的不便，可以减少视频播放中的卡顿。&lt;/li&gt;
  &lt;li&gt;WebRTC 和   &lt;a href="http://www.webhek.com/fullscreen"&gt;全屏幕 API 支持&lt;/a&gt;：YouTube 开发者可以通过 WebRTC 在浏览器内开发直播工具插件。有了 HTML5 的全屏 API，YouTube 在标准的 HTML UI 下，就可提供沉浸式的全屏观看体验。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;YouTube 将支持内嵌语法 &amp;lt;iframe&amp;gt;，放弃 Flash 时代惯用的 &amp;lt;object&amp;gt; 语法，全力支持 HTML5 video 标签。要内嵌影片的人，用 &amp;lt;iframe&amp;gt; API 内嵌影片，能够在所有平台顺利播放。&lt;/p&gt;
 &lt;p&gt;这种改进将不仅仅使YouTube收益，而是整个行业。其它的视频网站，比如 Netflix 和 Vimeo，甚至微软和苹果等公司，都在支持HTML5，并非常成功。基于开放的HTML5标准，像Chromebooks和Chremecast这样的新设备也成为了可能。同样，每个人都可以通过   &lt;a href="https://developers.google.com/youtube/iframe_api_reference"&gt;&amp;lt;iframe&amp;gt; API&lt;/a&gt;将YouTube视频嵌入到自己网站上。&lt;/p&gt;
 &lt;p&gt;参考英文：  &lt;a href="http://youtube-eng.blogspot.com/2015/01/youtube-now-defaults-to-html5_27.html" target="_blank"&gt;YouTube now defaults to HTML5&amp;lt;video&amp;gt;   &lt;br /&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>新闻资讯 html5 video 视频</category>
      <guid isPermaLink="true">https://itindex.net/detail/52655-youtube-%E7%BD%91%E7%AB%99-html5</guid>
      <pubDate>Fri, 30 Jan 2015 00:23:23 CST</pubDate>
    </item>
    <item>
      <title>谷歌开始自动将Flash广告转为HTML5</title>
      <link>https://itindex.net/detail/52798-%E8%B0%B7%E6%AD%8C-flash-%E5%B9%BF%E5%91%8A</link>
      <description>&lt;p&gt;  &lt;a href="http://madbrief.com/wp-content/uploads/2015/02/madbrief_google-now-automatically-converts-flash-ads-to-html5.jpg"&gt;   &lt;img alt="&amp;#35895;&amp;#27468;&amp;#24320;&amp;#22987;&amp;#33258;&amp;#21160;&amp;#23558;Flash&amp;#24191;&amp;#21578;&amp;#36716;&amp;#20026;HTML5" height="435" src="http://madbrief.com/wp-content/uploads/2015/02/madbrief_google-now-automatically-converts-flash-ads-to-html5.jpg" width="770"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;谷歌今天开始将Adobe Flash广告自动转换成HTML5格式，方便谷歌的广告主将广告送达更多用户——即使其使用的设备或浏览器不支持Flash。&lt;/p&gt;&lt;/blockquote&gt;
 &lt;p&gt;来源：  &lt;a href="http://tech.sina.com.cn/i/2015-02-26/doc-iawzuney0274782.shtml" target="_blank"&gt;新浪科技&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;谷歌从去年9月开始提供HTML5版的互动备份，同时放弃了对Flash的支持。谷歌显示广告网络和DoubleClick Campaign Manager提供的转换工具可以创建HTML5版的Flash广告，其效果与原先的广告相同，而不仅仅是一个静态的图像备份。&lt;/p&gt;
 &lt;p&gt;而现在，谷歌可以自动将合格的Flash广告系列转换成HTML5，包括现有广告和新广告。所有广告主都只要通过AdWords、AdWords Editor或其他与谷歌广告平台兼容的第三方工具上传其广告即可。&lt;/p&gt;
 &lt;p&gt;但谷歌所谓的“合格”值得进行一番详细解释：“并非所有Flash广告都可以转换成HTML5.要了解你的Flash广告能否转换，请先将其上传到Swiffy工具。如果这个工具能够转换你的广告，你上传到AdWords的广告就可以自动转换。”&lt;/p&gt;
 &lt;p&gt;换句话说，谷歌正在逐渐将所有的Flash广告都转换成HTML5格式。最终，绝大多数广告从一开始可能就会直接使用HTML5。&lt;/p&gt;
 &lt;p&gt;事实上，谷歌早就开始推动Flash向HTML5的转换趋势。例如，该公司旗下的YouTube曾在2010年1月发布测试版HTML5播放器，上月最终将默认格式由Flash调整为HTML5。&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>公司新闻 Google 科技趋势 网络广告</category>
      <guid isPermaLink="true">https://itindex.net/detail/52798-%E8%B0%B7%E6%AD%8C-flash-%E5%B9%BF%E5%91%8A</guid>
      <pubDate>Thu, 26 Feb 2015 16:46:28 CST</pubDate>
    </item>
    <item>
      <title>HTML5 实现橡皮擦的擦除效果</title>
      <link>https://itindex.net/detail/52796-html5-%E6%A9%A1%E7%9A%AE%E6%93%A6-%E6%95%88%E6%9E%9C</link>
      <description>&lt;div&gt;
  &lt;p&gt;体验效果：   &lt;br /&gt;   &lt;a href="http://keleyi.com/keleyi/phtml/html5/32.htm" target="_blank"&gt;http://keleyi.com/keleyi/phtml/html5/32.htm&lt;/a&gt;   &lt;br /&gt;   &lt;br /&gt;请使用   &lt;a href="http://keleyi.com/a/bjac/g039tue3.htm"&gt;支持HTML5的浏览器&lt;/a&gt;查看效果，请按住鼠标拖动。   &lt;br /&gt;   &lt;br /&gt;最近项目刚好用到这种效果，也就是有点像刮刮卡一样，在移动设备上，把某张图片刮掉显示出另一张图片。效果图如下：   &lt;br /&gt;   &lt;a href="http://keleyi.com/keleyi/phtml/html5/32.htm" target="_blank"&gt;    &lt;img alt="" src="http://keleyi.com/image/a/vo1xqa2t.jpg"&gt;&lt;/img&gt;&lt;/a&gt;   &lt;br /&gt;   &lt;br /&gt;这种在网上还是挺常见的，本来就想直接网上找个demo套用下他的方法就行了，套用了才发现，在android上卡出翔了，因为客户要求，在android不要求特别流畅，至少要能玩，但是网上找的那个demo实在太卡，根本就是没法玩的情况。于是就想自己写一个算了，本文也就权当记录一下研究过程。   &lt;br /&gt;   &lt;br /&gt;　　这种刮图的效果，首先想到就是用HTML5的canvas来实现，而canvas的API中，可以清除像素的就是clearRect方法，但是clearRect方法的清除区域矩形，毕竟大部分人的习惯中的橡皮擦都是圆形的，所以就引入了剪辑区域这个强大的功能，也就是clip方法。用法很简单：　&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;pre&gt;ctx.save()
ctx.beginPath()
ctx.arc(x2,y2,a,0,2*Math.PI);
ctx.clip()
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.restore();&lt;/pre&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;上面那段代码就实现了圆形区域的擦除，也就是先实现一个圆形路径，然后把这个路径作为剪辑区域，再清除像素就行了。有个注意点就是需要先保存绘图环境，清除完像素后要重置绘图环境，如果不重置的话以后的绘图都是会被限制在那个剪辑区域中。   &lt;br /&gt;   &lt;br /&gt;　　擦除效果有了，现在就是写鼠标移动擦除的效果了，下面我均用鼠标来描述，因为移动端也差不多，就是把mousedown换成touchstart，mousemove换成touchmove，mouseup换成touchend、以及获取坐标点由e.clientX换成e.targetTouches[0].pageX而已。   &lt;br /&gt;   &lt;br /&gt;　　实现鼠标移动擦除，刚开始就是想到鼠标移动时在触发的mousemove事件中对鼠标所在位置进行圆形区域擦除，写出来后发现，当鼠标移动速度很快的时候，擦除的区域就不连贯了，就会出现下面这种效果，这显然不是我们想要的橡皮擦擦除效果。   &lt;br /&gt;   &lt;br /&gt;   &lt;img alt="" src="http://keleyi.com/image/a/sgxcxmt4.jpg"&gt;&lt;/img&gt;   &lt;br /&gt;   &lt;br /&gt;既然所有点不连贯，那接下来要做的事就是把这些点连贯起来，如果是实现画图功能的话，就可以直接通过lineTo把两点之间连接起来再绘制，但是擦除效果中的剪辑区域要求要是闭合路径，如果是单纯的把两个点连起来就无法形成剪辑区域了。然后我就想到用计算的方法，算出两个擦除区域中的矩形四个端点坐标来实现，也就是下图中的红色矩形：   &lt;br /&gt;   &lt;br /&gt;   &lt;img alt="" src="http://keleyi.com/image/a/cyw81wyc.png"&gt;&lt;/img&gt;   &lt;br /&gt;   &lt;br /&gt;计算方法也很简单，因为可以知道两个剪辑区域连线两个端点的坐标，又知道我们要多宽的线条，矩形的四个端点坐标就变得容易求了，所以就有了下面的代码：&lt;/p&gt;
  &lt;pre&gt;var asin = a*Math.sin(Math.atan((y2-y1)/(x2-x1)));
var acos = a*Math.cos(Math.atan((y2-y1)/(x2-x1)))
var x3 = x1+asin;
var y3 = y1-acos;
var x4 = x1-asin;
var y4 = y1+acos;
var x5 = x2+asin;
var y5 = y2-acos;
var x6 = x2-asin;
var y6 = y2+acos;&lt;/pre&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;x1、y1和x2、y2就是两个端点，从而求出了四个端点的坐标。这样一来，剪辑区域就是圈加矩形，代码组织起来就是：&lt;/p&gt;
  &lt;pre&gt;var hastouch = &amp;quot;ontouchstart&amp;quot; in window?true:false,//判断是否为移动设备
tapstart = hastouch?&amp;quot;touchstart&amp;quot;:&amp;quot;mousedown&amp;quot;,
tapmove = hastouch?&amp;quot;touchmove&amp;quot;:&amp;quot;mousemove&amp;quot;,
tapend = hastouch?&amp;quot;touchend&amp;quot;:&amp;quot;mouseup&amp;quot;;

canvas.addEventListener(tapstart , function(e){
e.preventDefault();

x1 = hastouch?e.targetTouches[0].pageX:e.clientX-canvas.offsetLeft;
y1 = hastouch?e.targetTouches[0].pageY:e.clientY-canvas.offsetTop;

　　//鼠标第一次点下的时候擦除一个圆形区域，同时记录第一个坐标点
ctx.save()
ctx.beginPath()
ctx.arc(x1,y1,a,0,2*Math.PI);
ctx.clip()
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.restore();

canvas.addEventListener(tapmove , tapmoveHandler);
canvas.addEventListener(tapend , function(){
canvas.removeEventListener(tapmove , tapmoveHandler);
});
　　//鼠标移动时触发该事件
function tapmoveHandler(e){
e.preventDefault()
x2 = hastouch?e.targetTouches[0].pageX:e.clientX-canvas.offsetLeft;
y2 = hastouch?e.targetTouches[0].pageY:e.clientY-canvas.offsetTop;

　　　　//获取两个点之间的剪辑区域四个端点
var asin = a*Math.sin(Math.atan((y2-y1)/(x2-x1)));
var acos = a*Math.cos(Math.atan((y2-y1)/(x2-x1)))
var x3 = x1+asin;
var y3 = y1-acos;
var x4 = x1-asin;
var y4 = y1+acos;
var x5 = x2+asin;
var y5 = y2-acos;
var x6 = x2-asin;
var y6 = y2+acos;

　　　　//保证线条的连贯，所以在矩形一端画圆
ctx.save()
ctx.beginPath()
ctx.arc(x2,y2,a,0,2*Math.PI);
ctx.clip()
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.restore();

　　　　//清除矩形剪辑区域里的像素
ctx.save()
ctx.beginPath()
ctx.moveTo(x3,y3);
ctx.lineTo(x5,y5);
ctx.lineTo(x6,y6);
ctx.lineTo(x4,y4);
ctx.closePath();
ctx.clip()
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.restore();

　　　　//记录最后坐标
x1 = x2;
y1 = y2;
}
})
&lt;/pre&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;如此一来，鼠标擦除的效果就实现了，不过还有一个要实现的点，就是大部分擦除的效果，当你擦了一定数量的像素后，就会自动把所有图片内容呈现出来，这个效果，我是用imgData来实现的。代码如下：&lt;/p&gt;
  &lt;pre&gt;var imgData = ctx.getImageData(0,0,canvas.width,canvas.height);
var dd = 0;
for(var x=0;x&amp;lt;imgData.width;x+=1){
for(var y=0;y&amp;lt;imgData.height;y+=1){
var i = (y*imgData.width + x)*4;
if(imgData.data[i+3] &amp;gt; 0){
dd++
}
}
}
if(dd/(imgData.width*imgData.height)&amp;lt;0.4){
canvas.className = &amp;quot;noOp&amp;quot;;
}&lt;/pre&gt;
  &lt;p&gt; 获取到imgData，对imgData里的像素进行遍历，然后再对imgData的data数组里的rgba中的alpha进行分析，也就是分析透明度，如果像素被擦除了，那透明度就是0了，也就是把当前画布中透明度不为0的像素的数量跟画布总像素数进行比较，如果透明度不为0 的像素数比例低于40%，那说明当前画布上就以后有百分六十以上的区域被擦除了，就可以自动呈现图片了。&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;　　此处注意，我是把检查像素这段代码方法mouseup事件里面的，因为这个计算量相对来说还是不小，如果用户狂点鼠标，就会狂触发mouseup事件，也就是会疯狂的触发那个循环计算像素，计算量大到阻塞进程，导致界面卡住的情况，缓解办法如下：加个timeout，延迟执行像素计算，而在每一次点击的时候再清除timeout，也就是如果用户点击很快，这个计算也就触发不了了，还有一个提升的办法就是抽样检查，我上面的写法是逐个像素检查，逐个像素检查的话像素量太大，肯定会卡的，所以可以采用抽样检查，比如每隔30个像素检查一次，修改后的代码如下：&lt;/p&gt;
  &lt;pre&gt;timeout = setTimeout(function(){
var imgData = ctx.getImageData(0,0,canvas.width,canvas.height);
var dd = 0;
for(var x=0;x&amp;lt;imgData.width;x+=30){
for(var y=0;y&amp;lt;imgData.height;y+=30){
var i = (y*imgData.width + x)*4;
if(imgData.data[i+3] &amp;gt;0){
dd++
}
}
}
if(dd/(imgData.width*imgData.height/900)&amp;lt;0.4){
canvas.className = &amp;quot;noOp&amp;quot;;
}
},100)
&lt;/pre&gt;
  &lt;p&gt; 这样就可以较大限度的防止用户狂点击了，如果有其他更好的检查方法欢迎给出意见，谢谢。&lt;/p&gt;
  &lt;p&gt;   &lt;br /&gt;　　到了这一步就都写完了，然后就是测试的时候了，结果并不乐观，在android上还是卡啊卡啊，所以又得另想办法，最终发现了绘图环境中的globalCompositeOperation这个属性，这个属性的默认值是source-over，也就是，当你在已有像素上进行绘图时会叠加，但是还有一个属性是destination-out，官方解释就是：在源图像外显示目标图像。只有源图像外的目标图像部分才会被显示，源图像是透明的。好像不太好理解，但是其实自己测试一下就会发现很简单，也就是在已有像素的基础上进行绘图时，你绘制的区域里的已有像素都会被置为透明，直接看张图更容易理解：   &lt;br /&gt;   &lt;img alt="" src="http://keleyi.com/image/a/24pi9pbf.jpg"&gt;&lt;/img&gt;   &lt;br /&gt;   &lt;br /&gt;globalCompositeOperation属性效果图解。   &lt;br /&gt;   &lt;br /&gt;　　有了这个属性后，就意味着不需要用到clip，也就不需要用sin、cos什么的计算剪辑区域，直接用条粗线就行了，这样一来就能够很大限度的降低了计算量，同时减少了绘图环境API的调用，性能提升了，在android上运行应该也会流畅很多，下面是修改后的代码：&lt;/p&gt;
  &lt;pre&gt;//通过修改globalCompositeOperation来达到擦除的效果
function tapClip(){
var hastouch = &amp;quot;ontouchstart&amp;quot; in window?true:false,
tapstart = hastouch?&amp;quot;touchstart&amp;quot;:&amp;quot;mousedown&amp;quot;,
tapmove = hastouch?&amp;quot;touchmove&amp;quot;:&amp;quot;mousemove&amp;quot;,
tapend = hastouch?&amp;quot;touchend&amp;quot;:&amp;quot;mouseup&amp;quot;;

canvas.addEventListener(tapstart , function(e){
　　　　 clearTimeout(timeout)
e.preventDefault();

x1 = hastouch?e.targetTouches[0].pageX:e.clientX-canvas.offsetLeft;
y1 = hastouch?e.targetTouches[0].pageY:e.clientY-canvas.offsetTop;

ctx.lineCap = &amp;quot;round&amp;quot;;　　//设置线条两端为圆弧
ctx.lineJoin = &amp;quot;round&amp;quot;;　　//设置线条转折为圆弧
ctx.lineWidth = a*2;　　
ctx.globalCompositeOperation = &amp;quot;destination-out&amp;quot;;

ctx.save();
ctx.beginPath()
ctx.arc(x1,y1,1,0,2*Math.PI);
ctx.fill();
ctx.restore();

canvas.addEventListener(tapmove , tapmoveHandler);
canvas.addEventListener(tapend , function(){
canvas.removeEventListener(tapmove , tapmoveHandler);

　　　　　　　timeout = setTimeout(function(){
var imgData = ctx.getImageData(0,0,canvas.width,canvas.height);
var dd = 0;
for(var x=0;x&amp;lt;imgData.width;x+=30){
for(var y=0;y&amp;lt;imgData.height;y+=30){
var i = (y*imgData.width + x)*4;
if(imgData.data[i+3] &amp;gt; 0){
dd++
}
}
}
if(dd/(imgData.width*imgData.height/900)&amp;lt;0.4){
canvas.className = &amp;quot;noOp&amp;quot;;
}
　　　　　　　},100)
});
function tapmoveHandler(e){
e.preventDefault()
x2 = hastouch?e.targetTouches[0].pageX:e.clientX-canvas.offsetLeft;
y2 = hastouch?e.targetTouches[0].pageY:e.clientY-canvas.offsetTop;

ctx.save();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
ctx.restore()

x1 = x2;
y1 = y2;
}
})
}&lt;/pre&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;擦除那部分代码就这么一点，也就相当于画图功能，直接设置line属性后通过lineTo进行绘制线条，只要事前把globalCompositeOperation设成destination-out，你所进行的一切绘制，都变成了擦除效果。鼠标滑动触发的事件里面代码也少了很多，绘图对象的调用次数减少了，计算也减少了，性能提升大大滴。   &lt;br /&gt;   &lt;br /&gt;　　改好代码后就立即用自己的android机子测试了一下，果然如此，跟上一个相比，流畅了很多，至少达到了客户要求的能玩的地步了。&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
  &lt;p&gt;附完整HTML文件代码：&lt;/p&gt;
  &lt;pre&gt;&amp;lt;!doctype html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;meta charset=&amp;quot;UTF-8&amp;quot; /&amp;gt;
&amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0;&amp;quot;&amp;gt;
&amp;lt;title&amp;gt;HTML5橡皮檫-柯乐义&amp;lt;/title&amp;gt;
&amp;lt;style type=&amp;quot;text/css&amp;quot;&amp;gt;
body {
margin: 0;
padding: 0;
}

.box {
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
background: url(&amp;quot;http://keleyi.com/keleyi/phtml/html5/32/keleyi.jpg&amp;quot;) no-repeat;
background-size: 100% 100%;
backface-visibility: hidden;
overflow: hidden;
}

#cas_keleyi_com {
width: 100%;
height: 100%;
opacity: 1;
-webkit-transition: opacity .5s;
-ms-transition: opacity .5s;
-moz-transition: opacity .5s;
}

.noOp {
opacity: 0 !important;
}
&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;div class=&amp;quot;box&amp;quot; id=&amp;quot;bb&amp;quot;&amp;gt;
&amp;lt;canvas id=&amp;quot;cas_keleyi_com&amp;quot;&amp;gt;&amp;lt;/canvas&amp;gt;
&amp;lt;a href=&amp;quot;http://keleyi.com&amp;quot;&amp;gt;首页&amp;lt;/a&amp;gt; &amp;lt;a href=&amp;quot;http://keleyi.com/a/bjae/uvolnjek.htm&amp;quot;&amp;gt;原文&amp;lt;/a&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;script type=&amp;quot;text/javascript&amp;quot; charset=&amp;quot;utf-8&amp;quot;&amp;gt;
var canvas = document.getElementById(&amp;quot;cas_ke&amp;quot;+&amp;quot;leyi_com&amp;quot;),ctx = canvas.getContext(&amp;quot;2d&amp;quot;);
var x1,y1,a=30,timeout,totimes = 100,jiange = 30;
canvas.width = document.getElementById(&amp;quot;bb&amp;quot;).clientWidth;
canvas.height = document.getElementById(&amp;quot;bb&amp;quot;).clientHeight;
var img = new Image();
img.src = &amp;quot;http://keleyi.com/keleyi/phtml/html5/32/hovertree.jpg&amp;quot;;
img.onload = function(){
ctx.drawImage(img,0,0,canvas.width,canvas.height)
//ctx.fillRect(0,0,canvas.width,canvas)
tapClip()
}

//通过修改globalCompositeOperation来达到擦除的效果
function tapClip(){
var hastouch = &amp;quot;ontouchstart&amp;quot; in window?true:false,
tapstart = hastouch?&amp;quot;touchstart&amp;quot;:&amp;quot;mousedown&amp;quot;,
tapmove = hastouch?&amp;quot;touchmove&amp;quot;:&amp;quot;mousemove&amp;quot;,
tapend = hastouch?&amp;quot;touchend&amp;quot;:&amp;quot;mouseup&amp;quot;;

ctx.lineCap = &amp;quot;round&amp;quot;;
ctx.lineJoin = &amp;quot;round&amp;quot;;
ctx.lineWidth = a*2;
ctx.globalCompositeOperation = &amp;quot;destination-out&amp;quot;;

canvas.addEventListener(tapstart , function(e){
clearTimeout(timeout)
e.preventDefault();

x1 = hastouch?e.targetTouches[0].pageX:e.clientX-canvas.offsetLeft;
y1 = hastouch?e.targetTouches[0].pageY:e.clientY-canvas.offsetTop;

ctx.save();
ctx.beginPath()
ctx.arc(x1,y1,1,0,2*Math.PI);
ctx.fill();
ctx.restore();

canvas.addEventListener(tapmove , tapmoveHandler);
canvas.addEventListener(tapend , function(){
canvas.removeEventListener(tapmove , tapmoveHandler);

timeout = setTimeout(function(){
var imgData = ctx.getImageData(0,0,canvas.width,canvas.height);
var dd = 0;
for(var x=0;x&amp;lt;imgData.width;x+=jiange){
for(var y=0;y&amp;lt;imgData.height;y+=jiange){
var i = (y*imgData.width + x)*4;
if(imgData.data[i+3] &amp;gt;0){
dd++
}
}
}
if(dd/(imgData.width*imgData.height/(jiange*jiange))&amp;lt;0.4){
canvas.className = &amp;quot;noOp&amp;quot;;
}
},totimes)
});
function tapmoveHandler(e){
clearTimeout(timeout)
e.preventDefault()
x2 = hastouch?e.targetTouches[0].pageX:e.clientX-canvas.offsetLeft;
y2 = hastouch?e.targetTouches[0].pageY:e.clientY-canvas.offsetTop;

ctx.save();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
ctx.restore()

x1 = x2;
y1 = y2;
}
})
}

//使用clip来达到擦除效果
function otherClip(){
var hastouch = &amp;quot;ontouchstart&amp;quot; in window?true:false,
tapstart = hastouch?&amp;quot;touchstart&amp;quot;:&amp;quot;mousedown&amp;quot;,
tapmove = hastouch?&amp;quot;touchmove&amp;quot;:&amp;quot;mousemove&amp;quot;,
tapend = hastouch?&amp;quot;touchend&amp;quot;:&amp;quot;mouseup&amp;quot;;

canvas.addEventListener(tapstart , function(e){
clearTimeout(timeout)
e.preventDefault();

x1 = hastouch?e.targetTouches[0].pageX:e.clientX-canvas.offsetLeft;
y1 = hastouch?e.targetTouches[0].pageY:e.clientY-canvas.offsetTop;

ctx.save()
ctx.beginPath()
ctx.arc(x1,y1,a,0,2*Math.PI);
ctx.clip()
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.restore();

canvas.addEventListener(tapmove , tapmoveHandler);
canvas.addEventListener(tapend , function(){
canvas.removeEventListener(tapmove , tapmoveHandler);

timeout = setTimeout(function(){
var imgData = ctx.getImageData(0,0,canvas.width,canvas.height);
var dd = 0;
for(var x=0;x&amp;lt;imgData.width;x+=jiange){
for(var y=0;y&amp;lt;imgData.height;y+=jiange){
var i = (y*imgData.width + x)*4;
if(imgData.data[i+3] &amp;gt;0){
dd++
}
}
}
if(dd/(imgData.width*imgData.height/(jiange*jiange))&amp;lt;0.4){
canvas.className = &amp;quot;noOp&amp;quot;;
}
},totimes)

});

function tapmoveHandler(e){
e.preventDefault()
x2 = hastouch?e.targetTouches[0].pageX:e.clientX-canvas.offsetLeft;
y2 = hastouch?e.targetTouches[0].pageY:e.clientY-canvas.offsetTop;

var asin = a*Math.sin(Math.atan((y2-y1)/(x2-x1)));
var acos = a*Math.cos(Math.atan((y2-y1)/(x2-x1)));
var x3 = x1+asin;
var y3 = y1-acos;
var x4 = x1-asin;
var y4 = y1+acos;
var x5 = x2+asin;
var y5 = y2-acos;
var x6 = x2-asin;
var y6 = y2+acos;

ctx.save()
ctx.beginPath()
ctx.arc(x2,y2,a,0,2*Math.PI);
ctx.clip()
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.restore();

ctx.save()
ctx.beginPath()
ctx.moveTo(x3,y3);
ctx.lineTo(x5,y5);
ctx.lineTo(x6,y6);
ctx.lineTo(x4,y4);
ctx.closePath();
ctx.clip()
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.restore();

x1 = x2;
y1 = y2;
}
})
}
&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;
  &lt;p&gt;    &lt;a href="http://keleyi.com/a/bjae/uvolnjek.htm"&gt;http://keleyi.com/a/bjae/uvolnjek.htm&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;http://www.cnblogs.com/axes/&lt;/p&gt;
  &lt;p&gt;特效集合：&lt;/p&gt;
  &lt;p&gt;   &lt;a href="http://www.iteye.com/blog/2165698" target="_blank"&gt;http://ini.iteye.com/blog/2165698&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;   &lt;a href="http://www.iteye.com/blog/2163592" target="_blank"&gt;http://ini.iteye.com/blog/2163592&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt; &lt;/p&gt;
&lt;/div&gt;
          
           &lt;br /&gt; &lt;br /&gt;
          
             &lt;a href="http://ini.iteye.com/blog/2186716#comments"&gt;已有   &lt;strong&gt;0&lt;/strong&gt; 人发表留言，猛击-&amp;gt;&amp;gt;  &lt;strong&gt;这里&lt;/strong&gt;&amp;lt;&amp;lt;-参与讨论&lt;/a&gt;
          
           &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;
ITeye推荐
 &lt;br /&gt;
 &lt;ul&gt;  &lt;li&gt;   &lt;a href="http://www.iteye.com/clicks/433" target="_blank"&gt;—软件人才免语言低担保 赴美带薪读研！— &lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;
 &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;
          
        &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/52796-html5-%E6%A9%A1%E7%9A%AE%E6%93%A6-%E6%95%88%E6%9E%9C</guid>
      <pubDate>Wed, 25 Feb 2015 21:23:38 CST</pubDate>
    </item>
    <item>
      <title>别不信！App三年内将被HTML5顶替彻底消失？</title>
      <link>https://itindex.net/detail/52723-%E4%B8%8D%E4%BF%A1-app-html5</link>
      <description>&lt;p&gt;2007年W3C(万维网联盟)立项HTML5，直至2014年10月底，这个长达八年的规范终于正式封稿。&lt;/p&gt;
 &lt;p&gt;过去这些年，HTML5颠覆了PC互联网的格局，优化了移动互联网的体验，接下来，HTML5将颠覆原生App世界。这听起来有点危言耸听，但若认真分析HTML5的发展史，你会发现，这个世界的发展趋势确实就是这样。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="320" src="http://www.codeceo.com/wp-content/uploads/2015/02/78c0d79bdf0c76b89fb985859c2ad04f.jpg" width="585"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;HTML5对开发者的7大优势&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;跨平台：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;在多屏年代，开发者的痛苦指数非常高，人人都期盼HTML5能扮演救星。多套代码、不同技术工种、业务逻辑同步，这是折磨人的过程。有点类似个人电脑早期世界，那个时候的每家电脑都有自己的操作系统和编程语言，开发者疲于做不同版本，其实DOS的盛行也很大程度是因为开发者实在没精力给其他电脑写程序。跨平台技术在早期大多因为性能问题夭折，但中后期硬件能力增强后又会占据主流，因为跨平台确实是刚需。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;快速迭代：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;移动互联网是一个快鱼吃慢鱼的时代，谁对用户的需求满足的更快，谁的试错成本更低，谁就拥有巨大的优势。互联网产品大多免费、且有网络效应，后入者抢夺用户的难度非常大。使用原生开发，从招聘、开发、上线各个环节的效率都慢一倍以上，而且参与的人越多，沟通效率往往拖慢不止一倍。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;持续交付：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;很多人有这样的体会，一个原生应用上线Appstore，突然有一个大bug，只好连夜加班修复，然后静静等待2周或更长时间的Apple审核，这2个星期被用户的涂抹淹死，市场上一片差评，用户大量流失。等新应用被审核上线了，用户已经卸载了。但是，HTML5没有这些问题，你可以实时更新，有问题立即响应。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;大幅下降成本：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;创业者融资并不容易，如何花钱更高效非常重要。如果你使用原生开发的App和竞争对手使用HTML5开发的App没什么区别，但你的开发成本高出一倍，我相信没有投资人会喜欢给你投钱。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;开源生态系统发达：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;HTML5前端是开放的正反馈循环生态系统，大量的开源库可以使用，开发应用变得更轻松、更敏捷，当然这也体现在了快速迭代和成本下降上。不过更重要的是，这种开放的正反馈循环生态系统未来的生命力是比原生生态系统更强劲的。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;开放的数据交换：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;HTML是以page为单元开放代码的，它无需专门开发SDK，只要不混淆，就能与其他应用交互数据。开发者可以让手机搜索引擎很容易检索到自己的数据， 也更容易通过跨应用协作来满足最终用户需求。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;更容易推广、更容易爆发：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;导流入口多：HTML5应用导流非常容易，超级App(如微信朋友圈)、搜索引擎、应用市场、浏览器，到处都是HTML5的流量入口。而原生App的流量入口只有应用市场。聪明的HTML5开发者当然会玩转各种流量入口从而取得更强的优势。&lt;/p&gt;
 &lt;p&gt;流量大：前段时间微信朋友圈风靡一时《神经猫》，这个游戏如果放到Appstore，绝对没有那么多流量，超级App带来的流量，远大于原生应用市场。假如微信允许游戏在桌面创建快捷方式、假如游戏后续升级解决持续娱乐问题，未来不可想象。&lt;/p&gt;
 &lt;p&gt;导流效率高：除了入口多、流量大，导流效率高也不可忽视，谁都知道：页游和端游打同样的广告，广告变用户的转化率，页游远远高于端游。&lt;/p&gt;
 &lt;h2&gt;HTML5对最终用户的3大优势&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;大幅降低使用门槛&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;为什么流媒体会替代下载视频成为主流?为什么页游会如此火爆?只因用户太“懒”。让用户更方便的满足需求，有时效果好于更多的满足需求。&lt;/p&gt;
 &lt;p&gt;用户眼睛看到一个兴趣点，点击后，就应该立即开始满足用户需求。比如流媒体可以立即看，页游可以立即玩。而目前的原生应用市场，用户需要这样操作：选一个应用、等待下载、确认权限、等待安装，然后点击打开。这样糟糕的体验迟早要被颠覆。&lt;/p&gt;
 &lt;p&gt;不管是App、游戏还是音视频，未来都将即点即用。谁先满足用户这个需求，谁就制胜。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;实时更新、差量更新的优秀体验&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;HTML5应用可以绕开应用市场的限制进行自主实时更新，用户可以快速享受新服务。&lt;/p&gt;
 &lt;p&gt;而且这种更新完全可以是差量更新，比如某个HTML页面或某个js文件有问题，只更新这个几k的小文件就可以了，这比原生应用的更新体验好太多。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;跨应用的使用体验&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;目前手机应用切换是以桌面或任务管理器为中心的，但事实上这些中心很影响效率和体验。用户想出差三亚，先打开去哪App订票，然后切回桌面，再找到并打开天气App，搜索输入三亚，再切到桌面，找到并打开航旅纵横App，输入航班号值机，哦对了，航班号多少来着，再切到桌面，找到并打开去哪App看航班号，最后找到并打开租车App，输入租车地点，然后再切回桌面。&lt;/p&gt;
 &lt;p&gt;在原生应用体系下，用户只能这样。但在HTML5体系下，他不需要切回桌面，他可以在App间方便的直接跳来跳去，而不是使用一个一个孤岛App;他更不用重复录入数据，应用间可以方便的互相传递数据。&lt;/p&gt;
 &lt;p&gt;这种模式需要一点想象力，但未来迟早会来。&lt;/p&gt;
 &lt;p&gt;分析至此，我们可以明显的看出，不管是站在最终用户角度、还是站在开发者角度，HTML5必将取代原生应用当前的位置。并由此引发一系列颠覆。&lt;/p&gt;
 &lt;h2&gt;原生App的颠覆&lt;/h2&gt;
 &lt;p&gt;HTML5的“性工能”障碍得到解决，可以接近原生App的效果，所以它就可以替代原生App吗?很多人认为，即使HTML5会发展的比现在好，也将是与原生App各占一部分市场的格局，要求不高的长尾应用会使用HTML5，而主流应用仍是原生App的天下。&lt;/p&gt;
 &lt;p&gt;但这样的想法很危险，就像Apple成立前，HP的高层告诉沃兹：谁会在家里摆一台电脑呢?未来HTML5肯定会颠覆原生App。&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>资讯 HTML5</category>
      <guid isPermaLink="true">https://itindex.net/detail/52723-%E4%B8%8D%E4%BF%A1-app-html5</guid>
      <pubDate>Sun, 08 Feb 2015 21:37:29 CST</pubDate>
    </item>
    <item>
      <title>HTML5 Web Speech API，让网站更有趣</title>
      <link>https://itindex.net/detail/52703-html5-web-speech</link>
      <description>&lt;p&gt;Web API 变得越来越丰富，其中一个值得注意的是  &lt;code&gt;Web Speech&lt;/code&gt; API。传统的网站只能“说”，这个API的出现，让网站能“倾听”用户。这个功能已经开放了一系列的用法，非常棒。&lt;/p&gt;

 &lt;p&gt;在这篇文章中，我们将看一下这项技术和建议的用法，以及如何用它来增强用户体验的一些好例子。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="clipboard.png" src="http://segmentfault.com/img/bVkOoy"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;blockquote&gt;
    &lt;p&gt;声明：本技术比较前沿，目前该规范是W3C的“非官方编辑器的征求意见稿”（截至2014年6月6日）。它的使用方法可能和本文中的代码片有所不同。查看代码规范和发布前的测试是很有必要的。&lt;/p&gt;
&lt;/blockquote&gt;

 &lt;h2&gt;语音合成 Speech Synthesis&lt;/h2&gt;

 &lt;p&gt;该API分为两部分。首先，让我们来看看语音的合成部分——说话。如果你的网站有一些文字内容——文章主体、表单、输入框、标签等——你可以运行一些有趣的功能，设备就会把文字读给用户听。&lt;/p&gt;

 &lt;p&gt;来看看做到这一点所需要的代码。首先创建  &lt;code&gt;SpeechSynthesisUtterance&lt;/code&gt;接口的新实例。然后指定要阅读的文本。再把这个实例添加到队列中，告诉浏览器什么时候说话。&lt;/p&gt;

 &lt;p&gt;下面的speak函数里完成了上面所述的功能 ，把想要朗读的内容作为参数。&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;function speak(textToSpeak) {
   //创建一个 SpeechSynthesisUtterance的实例
   var newUtterance = new SpeechSynthesisUtterance();

   // 设置文本
   newUtterance.text = textToSpeak;

   // 添加到队列
   window.speechSynthesis.speak(newUtterance);
}
&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;现在我们需要做的就是调用这个函数，并传入我们想要朗读的内容：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;speak(&amp;apos;Welcome to Smashing Magazine&amp;apos;);
&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;  &lt;code&gt;SpeechSynthesisUtterance&lt;/code&gt;还有开始、暂停、停止功能，还能设置语言、速度、声音。停止、启动或暂停都触发一个事件，开发者可以编写这个事件来完成很多有趣的事情。&lt;/p&gt;

 &lt;p&gt;目前，语音合成只有Chrome和Safari（包括桌面和移动设备版）支持。此外，通过API提供给用户的声音在很大程度上取决于操作系统。谷歌有自己的一套给Chrome的默认声音，可以在Mac OS X，Windows和Ubuntu上使用。Mac OS X的声音也可用，所以和OSX的Safari的声音一样。你可以通过开发者工具的控制台看有哪种声音可用。&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;window.speechSynthesis.getVoices();
&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;  &lt;strong&gt;如果你使用OS X，可以用“Zarvox”声音&lt;/strong&gt;&lt;/p&gt;

 &lt;h2&gt;语音识别 Speech Recognition&lt;/h2&gt;

 &lt;p&gt;Web Speech API另一部分是语音识别，它能够识别用过从麦克风或网站应用获取的语音。&lt;/p&gt;

 &lt;p&gt;让我们通过一些代码运行。这一次，我们将创建  &lt;code&gt;SpeechRecognition&lt;/code&gt;的新实例。因为这部分只得到了Chrome的支持，所以要添加WebKit的前缀。&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;var newRecognition = webkitSpeechRecognition();
&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;  &lt;code&gt;peechRecognition&lt;/code&gt;有相当多的属性。比如状态是可连续的，浏览器在没有接收到声音的一段时间后默认把状态设为  &lt;code&gt;false&lt;/code&gt;，如果你想继续听，可以设为  &lt;code&gt;true&lt;/code&gt;。&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;newRecognition.continuous = true;
&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;开启和停止语音识别，使用  &lt;code&gt;start()&lt;/code&gt; 、   &lt;code&gt;stop()&lt;/code&gt;：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;// 开始
newRecognition.start();

// 停止
newRecognition.stop();
&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;还可以绑定很多事件，例如：  &lt;code&gt;soundstart&lt;/code&gt;、  &lt;code&gt;speechstart&lt;/code&gt;、  &lt;code&gt;result&lt;/code&gt; 、   &lt;code&gt;error&lt;/code&gt;。  &lt;a href="http://codepen.io/Rumyra/pen/bCphe" rel="nofollow"&gt;看看这个demo&lt;/a&gt;。&lt;/p&gt;

 &lt;h2&gt;使用场景举例&lt;/h2&gt;

 &lt;h3&gt;听写&lt;/h3&gt;

 &lt;p&gt;目前，Speech API最常见的用法是听写和读取。也就是用户通过麦克风说话，设备把语音翻译成文字（看看  &lt;a href="https://www.google.com/intl/en/chrome/demos/speech.html" rel="nofollow"&gt;Chrome开发团队做的demo&lt;/a&gt;），或者设备读取文字转化成语音。&lt;/p&gt;

 &lt;p&gt;设备能说话这是非常有用的功能。设想一下，当你早上起床的时候，镜子告诉你今天的天气，这多么神奇。&lt;/p&gt;

 &lt;p&gt;很多汽车都有语音系统，在你开车的时候给你导航。设想一下，当你在开车的时候，浏览器把你想要的内容读给你听，多么方便。&lt;/p&gt;

 &lt;h3&gt;声音控制&lt;/h3&gt;

 &lt;p&gt;听写可以很容易地变成语音控制。正如上面的例子，我们可以通过语音导航。如果把这个功能加入到网络电视的浏览器中，将会有更多有意思的实现。&lt;/p&gt;

 &lt;p&gt;我的同事做了个网球应用，在他打球的时候，它的应用会把他的分数读出来。&lt;/p&gt;

 &lt;h3&gt;翻译&lt;/h3&gt;

 &lt;p&gt;未来翻译会变得很不一样。一个人说了一段话，设备就翻译成对方的语言并读出。&lt;/p&gt;

 &lt;h2&gt;限制&lt;/h2&gt;

 &lt;p&gt;离线是需要注意的问题。目前API的实现是浏览器把数据发送到远端服务器，再把处理好的数据返回。没有网络就无法实现功能。&lt;/p&gt;

 &lt;hr&gt;&lt;/hr&gt;
 &lt;p&gt;英文原文：   &lt;a href="http://www.smashingmagazine.com/2014/12/05/enhancing-ux-with-the-web-speech-api/" rel="nofollow"&gt;Enhancing User Experience With The Web Speech API&lt;/a&gt;  &lt;br /&gt;
由SegmentFault整理翻译&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>html5</category>
      <guid isPermaLink="true">https://itindex.net/detail/52703-html5-web-speech</guid>
      <pubDate>Thu, 05 Feb 2015 15:39:02 CST</pubDate>
    </item>
    <item>
      <title>HTML5的页面资源预加载技术(Link prefetch)加速页面加载</title>
      <link>https://itindex.net/detail/49441-html5-%E9%A1%B5%E9%9D%A2-%E8%B5%84%E6%BA%90</link>
      <description>&lt;p&gt;不管是浏览器的开发者还是普通web应用的开发者，他们都在做一个共同的努力：让Web浏览有更快的速度感觉。有很多已知的技术都可以让你的网站速度变得更快：使用CSS sprites，使用图片优化工具，使用.htaccess设置页面头信息和缓存时间，JavaScript压缩，使用CDN等。我曾经介绍过本站上使用的一些速度优化技术。而在  &lt;a href="http://www.html5tricks.com/" target="_blank" title="HTML5"&gt;HTML5&lt;/a&gt;里，出现了一个新的用来优化网站速度的新功能：页面资源预加载/预读取(Link prefetch)。&lt;/p&gt;
 &lt;p&gt;页面资源预加载/预读取(Link prefetch)是什么？来自  &lt;a href="https://developer.mozilla.org/en/link_prefetching_faq" rel="nofollow"&gt;MDN&lt;/a&gt;的解释:&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;页面资源预加载(Link prefetch)是浏览器提供的一个技巧，目的是让浏览器在空闲时间下载或预读取一些文档资源，用户在将来将会访问这些资源。一个Web页面可以对浏览器设置一系列的预加载指示，当浏览器加载完当前页面后，它会在后台静悄悄的加载指定的文档，并把它们存储在缓存里。当用户访问到这些预加载的文档后，浏览器能快速的从缓存里提取给用户。&lt;/p&gt;&lt;/blockquote&gt;
 &lt;p&gt;简单说来就是：让浏览器预先加载用户访问当前页后极有可能访问的其他资源(页面，图片，视频等)。而且方法超级的简单！&lt;/p&gt;
 &lt;h2&gt;HTML5页面资源预加载(Link prefetch)写法&lt;/h2&gt;
 &lt;pre&gt;&amp;lt;!-- 预加载整个页面 --&amp;gt;
&amp;lt;link rel=&amp;quot;prefetch&amp;quot; href=&amp;quot;http://www.webhek.com/misc/3d-album/&amp;quot; /&amp;gt;

&amp;lt;!-- 预加载一个图片 --&amp;gt;
&amp;lt;link rel=&amp;quot;prefetch&amp;quot; href=&amp;quot; http://www.webhek.com/wordpress/
wp-content/uploads/2014/04/b-334x193.jpg &amp;quot; /&amp;gt;&lt;/pre&gt;
 &lt;p&gt;HTML5页面资源预加载/预读取(Link prefetch)功能是通过  &lt;code&gt;Link&lt;/code&gt;标记实现的，将  &lt;code&gt;rel属性&lt;/code&gt;指定为“prefetch”，在  &lt;code&gt;href属性&lt;/code&gt;里指定要加载资源的地址。火狐浏览器里还提供了一种额外的属性支持：&lt;/p&gt;
 &lt;pre&gt;&amp;lt;link rel=&amp;quot;prefetch alternate stylesheet&amp;quot; 
title=&amp;quot;Designed for Mozilla&amp;quot; href=&amp;quot;mozspecific.css&amp;quot; /&amp;gt;
&amp;lt;link rel=&amp;quot;next&amp;quot; href=&amp;quot;2.html&amp;quot; /&amp;gt;&lt;/pre&gt;
 &lt;p&gt;HTTPS协议资源下也可以使用prefetch。&lt;/p&gt;
 &lt;h2&gt;什么情况下应该预加载页面资源&lt;/h2&gt;
 &lt;p&gt;在你的页面里加载什么样的资源，什么时候加载，这完全取决于你。下面是一些建议：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;当页面有幻灯片类似的服务时，预加载/预读取接下来的1-3页和之前的1-3页。&lt;/li&gt;
  &lt;li&gt;预加载那些整个网站通用的图片。&lt;/li&gt;
  &lt;li&gt;预加载网站上搜索结果的下一页。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h2&gt;禁止页面资源预加载(Link prefetch)&lt;/h2&gt;
 &lt;p&gt;火狐浏览器里有一个选项可以禁止任何的页面资源预加载(Link prefetch)功能，你可以这样设置：&lt;/p&gt;
 &lt;pre&gt;user_pref(&amp;quot;network.prefetch-next&amp;quot;, false);&lt;/pre&gt;
 &lt;h2&gt;页面资源预加载(Link prefetch)注意事项&lt;/h2&gt;
 &lt;p&gt;下面是一些关于页面资源预加载(Link prefetch)的注意事项：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;预加载(Link prefetch)不能跨域工作，包括跨域拉取cookies。&lt;/li&gt;
  &lt;li&gt;预加载(Link prefetch)会污染你的网站访问量统计，因为有些预加载到浏览器的页面用户可能并未真正访问。&lt;/li&gt;
  &lt;li&gt;火狐浏览器从2003年开始就已经提供了对这项预加载(Link prefetch)技术的支持。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;利用浏览器空闲时间加载一些额外的资源文件，看起来是既刺激又危险，你想试试这些技术吗？&lt;/p&gt;
 &lt;p&gt;原文来自：  &lt;a href="http://www.webhek.com/link-prefetch/" target="_blank"&gt;webhek&lt;/a&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>HTML5教程 Link prefetch 预加载</category>
      <guid isPermaLink="true">https://itindex.net/detail/49441-html5-%E9%A1%B5%E9%9D%A2-%E8%B5%84%E6%BA%90</guid>
      <pubDate>Sun, 04 May 2014 09:25:58 CST</pubDate>
    </item>
    <item>
      <title>使用HTML5技术控制电脑或手机上的摄像头</title>
      <link>https://itindex.net/detail/49404-html5-%E6%8A%80%E6%9C%AF-%E6%8E%A7%E5%88%B6</link>
      <description>&lt;p&gt;移动设备和桌面电脑上的客户端API起初并不是同步的。最初总是移动设备上先拥有某些功能和相应的API，但慢慢的，这些API会出现在桌面电脑上。其中一个应用接口技术就是  &lt;code&gt;getUserMedia&lt;/code&gt; API，它能让应用开发者访问用户的摄像头或内置相机。下面就让我展示一下如何通过浏览器来访问你的摄像头，并提取截屏图形。&lt;/p&gt;
 &lt;div&gt;  &lt;a href="http://www.webhek.com/demo/browser-camera/" target="_blank"&gt;观看演示&lt;/a&gt;&lt;/div&gt;
 &lt;h2&gt;HTML代码&lt;/h2&gt;
 &lt;p&gt;下面的代码里我写了一部分注释，请阅读：&lt;/p&gt;
 &lt;pre&gt;&amp;lt;!--
	理想情况下我们应该先判断你的设备上是否
	有摄像头或相机，但简单起见，我们在这里直接
	写出了HTML标记，而不是用JavaScript先判断
	然后动态生成这些标记
--&amp;gt;
&amp;lt;video id=&amp;quot;video&amp;quot; width=&amp;quot;640&amp;quot; height=&amp;quot;480&amp;quot; autoplay&amp;gt;&amp;lt;/video&amp;gt;
&amp;lt;button id=&amp;quot;snap&amp;quot;&amp;gt;Snap Photo&amp;lt;/button&amp;gt;
&amp;lt;canvas id=&amp;quot;canvas&amp;quot; width=&amp;quot;640&amp;quot; height=&amp;quot;480&amp;quot;&amp;gt;&amp;lt;/canvas&amp;gt;&lt;/pre&gt;
 &lt;p&gt;在写出上面这些标记前应该判断用户的客户端是否有摄像头支持，但这里为了不那么麻烦，这里直接写出了这些HTML标记，需要注意的是我们这里使用的长宽是640×480。&lt;/p&gt;
 &lt;h2&gt;JavaScript代码&lt;/h2&gt;
 &lt;p&gt;因为我们是手工写出的HTML，所以下面的js代码会比你想象的要简单了很多。&lt;/p&gt;
 &lt;pre&gt;// Put event listeners into place
window.addEventListener(&amp;quot;DOMContentLoaded&amp;quot;, function() {
	// Grab elements, create settings, etc.
	var canvas = document.getElementById(&amp;quot;canvas&amp;quot;),
		context = canvas.getContext(&amp;quot;2d&amp;quot;),
		video = document.getElementById(&amp;quot;video&amp;quot;),
		videoObj = { &amp;quot;video&amp;quot;: true },
		errBack = function(error) {
			console.log(&amp;quot;Video capture error: &amp;quot;, error.code); 
		};

	// Put video listeners into place
	if(navigator.getUserMedia) { // Standard
		navigator.getUserMedia(videoObj, function(stream) {
			video.src = stream;
			video.play();
		}, errBack);
	} else if(navigator.webkitGetUserMedia) { // WebKit-prefixed
		navigator.webkitGetUserMedia(videoObj, function(stream){
			video.src = window.webkitURL.createObjectURL(stream);
			video.play();
		}, errBack);
	}
	else if(navigator.mozGetUserMedia) { // Firefox-prefixed
		navigator.mozGetUserMedia(videoObj, function(stream){
			video.src = window.URL.createObjectURL(stream);
			video.play();
		}, errBack);
	}
}, false);&lt;/pre&gt;
 &lt;p&gt;一旦判断出用户浏览器支持  &lt;code&gt;getUserMedia&lt;/code&gt; ，下面就非常简单了，只需要将那个  &lt;code&gt;video&lt;/code&gt;元素的  &lt;code&gt;src&lt;/code&gt;设置为用户的摄像头视频直播连接。这就是用浏览器访问摄像头需要做的所有的事情！&lt;/p&gt;
 &lt;p&gt;拍照的功能只能说是稍微复杂一点点。我们在按钮上加入一个监听器，将视频画面画到画布上。&lt;/p&gt;
 &lt;pre&gt;// 触发拍照动作
document.getElementById(&amp;quot;snap&amp;quot;)
       .addEventListener(&amp;quot;click&amp;quot;, function() {
	context.drawImage(video, 0, 0, 640, 480);
});&lt;/pre&gt;
 &lt;p&gt;当然，你还可以在图片上加一些滤镜效果….我还是把这些技术放到以后的文章里再说吧。但至少你可以将这个  &lt;a href="http://www.webhek.com/convert-canvas-image/"&gt;画布图像转换成一张图片&lt;/a&gt;。&lt;/p&gt;
 &lt;div&gt;  &lt;a href="http://www.webhek.com/demo/browser-camera/" target="_blank"&gt;观看演示&lt;/a&gt;&lt;/div&gt;
 &lt;p&gt;以前我们需要使用第三方的插件才能从浏览器里访问用户的摄像头，这不免有些复杂。现在只需要HTML5的画布技术和javaScript，我们就能简单快速的操作用户的摄像头。不仅仅还是访问摄像头，而且是因为HTML5的画布技术及其强大，我们可以给图片上加入各种迷人的滤镜效果。现在，在浏览器里用自己的摄像头给自己拍张照片吧！&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>技术技巧 html5 摄像头</category>
      <guid isPermaLink="true">https://itindex.net/detail/49404-html5-%E6%8A%80%E6%9C%AF-%E6%8E%A7%E5%88%B6</guid>
      <pubDate>Fri, 02 May 2014 00:37:39 CST</pubDate>
    </item>
    <item>
      <title>HTML5 视频直播（一）</title>
      <link>https://itindex.net/detail/53238-html5-%E8%A7%86%E9%A2%91-%E7%9B%B4%E6%92%AD</link>
      <description>&lt;p&gt;前不久工作中遇到了在移动 WEB 端直播视频的需求，研究了一下相关技术，记录一下。&lt;/p&gt;
 &lt;p&gt;目前 WEB 上主流的视频直播方案有 HLS 和 RTMP，移动 WEB 端目前就只有 HLS 能用，我们重点介绍它。&lt;/p&gt;
 &lt;h3&gt;HTTP Live Streaming&lt;/h3&gt;
 &lt;p&gt;HTTP Live Streaming（简称 HLS）是一个基于 HTTP 的视频流协议，由 Apple 公司实现，Mac OS 上的 QuickTime、Safari 以及 iOS 上的 Safari 都能很好的支持 HLS，高版本 Android 也增加了对 HLS 的支持。一些常见的客户端如：MPlayerX、VLC 也都支持 HLS 协议。&lt;/p&gt;
 &lt;p&gt;HLS 协议基于 HTTP，非常简单。一个提供 HLS 的服务器需要做两件事：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;编码：以 H.263 格式对图像进行编码，以 MP3 或者 HE-AAC 对声音进行编码，最终打包到 MPEG-2 TS（Transport Stream）容器之中；&lt;/li&gt;
  &lt;li&gt;分割：把编码好的 TS 文件等长切分成后缀为 ts 的小文件，并生成一个 .m3u8 的纯文本索引文件；&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;浏览器使用的是 m3u8 文件。m3u8 跟音频列表格式 m3u 很像，可以简单的认为 m3u8 就是包含多个 ts 文件的播放列表。播放器按顺序逐个播放，全部放完再请求一下 m3u8 文件，获得包含最新 ts 文件的播放列表继续播，周而复始。整个直播过程就是依靠一个不断更新的 m3u8 和一堆小的 ts 文件组成，m3u8 必须动态更新，ts 可以走 CDN。&lt;/p&gt;
 &lt;p&gt;可以看到 HLS 协议本质还是一个个的 HTTP 请求 / 响应，所以适应性很好，不会受到防火墙影响。但它也有一个致命的弱点：延迟现象非常明显。如果每个 ts 按照 5 秒来切分，一个 m3u8 放 6 个 ts 索引，那么至少就会带来 30 秒的延迟。如果减少每个 ts 的长度，减少 m3u8 中的索引数，延时确实会减少，但会带来更频繁的缓冲，对服务端的请求压力也会成倍增加。所以只能需要根据实际情况找到一个折中的点。&lt;/p&gt;
 &lt;p&gt;对于支持 HLS 的浏览器来说，直接这样写就能播放了：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;video src=&amp;quot;http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8&amp;quot;
height=&amp;quot;300&amp;quot; width=&amp;quot;400&amp;quot;&amp;gt;&amp;lt;/video&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;对于不支持 m3u8 的浏览器，比如 PC / Mac 上的 Chrome，需要借助 Flash 来实现了。网上有一些较为成熟的方案可以直接用，如：  &lt;a href="https://github.com/jackzhang1204/sewise-player"&gt;Sewise Player&lt;/a&gt;（免费）、  &lt;a href="http://www.jwplayer.com/html5/hls/"&gt;JW Player&lt;/a&gt;（收费）。&lt;/p&gt;
 &lt;h3&gt;Real Time Messaging Protocol&lt;/h3&gt;
 &lt;p&gt;Real Time Messaging Protocol（简称 RTMP）是 Macromedia 开发的一套视频直播协议，现在属于 Adobe。这套方案需要搭建专门的 RTMP 流媒体服务如 Adobe Media Server，并且在浏览器中只能使用 Flash 实现播放器。它的实时性非常好，延迟很小。但是无法支持移动端 WEB 播放是它的硬伤。&lt;/p&gt;
 &lt;p&gt;前面提到的 JW Player 能很好的播放采用 RTMP 协议的直播服务。&lt;/p&gt;
 &lt;p&gt;这次先写这么多，下一篇写一个另类的直播方案。&lt;/p&gt;
 &lt;p&gt;本文链接：  &lt;a href="https://www.imququ.com/post/html5-live-player-1.html"&gt;https://www.imququ.com/post/html5-live-player-1.html&lt;/a&gt;&lt;/p&gt; &lt;p&gt;--EOF--&lt;/p&gt; &lt;p&gt;推荐：  &lt;a href="http://www.75team.com/weekly/" target="_blank"&gt;领略前端技术 阅读奇舞周刊&lt;/a&gt;&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/53238-html5-%E8%A7%86%E9%A2%91-%E7%9B%B4%E6%92%AD</guid>
      <pubDate>Fri, 24 Apr 2015 09:35:11 CST</pubDate>
    </item>
    <item>
      <title>在HTML5移动应用中挖掘XSS漏洞</title>
      <link>https://itindex.net/detail/53049-html5-%E7%A7%BB%E5%8A%A8%E5%BA%94%E7%94%A8-xss</link>
      <description>&lt;p&gt;  &lt;img src="http://image.3001.net/images/20150325/1427292070110.gif!small" title="Zoho.gif"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;Linus  &lt;strong&gt;(&lt;/strong&gt;  &lt;a href="https://twitter.com/_zulln" target="_blank" title=""&gt;   &lt;strong&gt;@_zulln&lt;/strong&gt;&lt;/a&gt;  &lt;strong&gt;)是一位有着15年漏洞挖掘经验的瑞士黑客，本文就是他写的。&lt;/strong&gt;  &lt;br /&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;现在使用HTML5开发移动APP越来越受欢迎。HTML5不仅开发效率高，而且可以跨平台，代码重用性也很高。Zoho（全球第一大在线软件提供商，总部位于美国）是一个有着1300万用户的HTML5邮件系统，我打算挖挖他们的漏洞。&lt;/strong&gt;  &lt;br /&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;寻找Html和Javascript代码&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;首先我从Google Play上下载了APK，用解压软件打开。&lt;/p&gt;
 &lt;p&gt;  &lt;img src="http://image.3001.net/images/20150325/14272851363383.png!small" title="1.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;assets文件夹中有很多html文件，html文件和javascript文件要比java文件读起来易懂很多。&lt;/p&gt;
 &lt;p&gt;  &lt;img src="http://image.3001.net/images/20150325/14272851893117.png!small" title="2.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;翻了几下之后我发现mailDetail.html是用来显示邮件内容的，这里有一个漏洞非常有趣。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;读了代码，懂了代码结构之后，发现它调用了setContent方法：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;function setContent(contentToSet,margin){
    document.body.style.marginTop = margin + &amp;quot;px&amp;quot;;
    document.body.style.marginBottom = &amp;quot;10px&amp;quot;;
    setBaseURL();
    document.getElementById(&amp;apos;mailcontentid&amp;apos;).innerHTML = &amp;quot;&amp;quot;;
    handleContentForMailThread($(&amp;apos;mailcontentid&amp;apos;), contentToSet);
    androidResponse();
    }
function handleContentForMailThread(contentEl,value) {
    var ind = value.indexOf(&amp;quot;&amp;lt;blockquote&amp;quot;);// NO I18N
    if(ind &amp;lt; 0) {
    	addContentToElement(contentEl,value);
        return;
    }
    else
    {
        // removed 54 lines here for readability
    }
    }
function addContentToElement(contentEl,value){
	contentEl.innerHTML = value;
	addListener();
	}&lt;/pre&gt;
 &lt;p&gt;如果你跟踪contentToSet变量(应该是邮件内容)，你会发现javascript代码中没有对数据做任何转义操作，所以，如果有任何转义或者安全操作，都只能是在服务端做的，或者在java代码中做的。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;确定邮件内容是否做过安全处理&lt;/strong&gt;  &lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;最简单的办法就是在setContent函数的开始未知加入payload代码，比如alert(contentToSet),然后打包重签名。&lt;/p&gt;
 &lt;p&gt;我在apk 包中加入了如下几个payload：&lt;/p&gt;
 &lt;pre&gt;test&amp;lt;jukk

http://test&amp;lt;jukk

http://test%3Cjukk&lt;/pre&gt;
 &lt;p&gt;结果如下：&lt;/p&gt;
 &lt;p&gt;  &lt;img src="http://image.3001.net/images/20150325/14272853269111.png!small" title="3.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;前两个payload被正确处理了，但是第三个payload(我事先对数据做了url编码)中显示了一个&amp;lt;尖括号。&lt;/p&gt;
 &lt;p&gt;貌似后台有一个黑名单，如果时间足够，这些黑名单肯定可以被绕过，但是我对手工fuzzing已经无感了，所以我走了另外一条路。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;逆向APK&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;我没有写过apk，所以我决定寻找webview相关的代码来读，当我找到从java传递数据到html的代码的时候，我被webView.loadUrl绊倒了，这明显可以执行javascript代码呀：&lt;/p&gt;
 &lt;pre&gt;webView.loadUrl(&amp;quot;javascript:initialize(&amp;quot; + myNumber + &amp;quot;);&amp;quot;);&lt;/pre&gt;
 &lt;p&gt;很明显zoho使用了跟上面类似的代码，才使得前面用url编码过得数据正确地显示出来。&lt;/p&gt;
 &lt;p&gt;通过使用dex2jar将apk逆向为.jar文件，我使用JD-GUI阅读这些jar文件，我搜索了setContent函数(之前提到的javascript函数)，&lt;/p&gt;
 &lt;pre&gt;this.webView.loadUrl(&amp;quot;javascript:setContent(&amp;quot; + JSONObject.quote(this.content) + &amp;quot;,&amp;quot; + i + &amp;quot;)&amp;quot;);&lt;/pre&gt;
 &lt;p&gt;正如你看到的，zoho使用了类似的代码。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;总结&lt;/strong&gt;  &lt;br /&gt;&lt;/p&gt;
 &lt;p&gt;zoho使用了webview.loadurl方法来调用setContent方法，这告诉我们什么？用这种方式打开uri，里面的 javascript就会被执行，任何pct-encode ugo的代码都会被当做正常代码来执行。&lt;/p&gt;
 &lt;p&gt;下面这些代码很容易理解&lt;/p&gt;
 &lt;pre&gt;// this line of code:location.href = &amp;apos;javascript:setContent(&amp;quot;%22-alert%281%29-%22&amp;quot;)&amp;apos;;// is the same as this:location.href = &amp;apos;javascript:setContent(&amp;quot;&amp;quot;-alert(1)-&amp;quot;&amp;quot;)&amp;apos;;&lt;/pre&gt;
 &lt;p&gt;问题很明显，通过在邮件中的任意地方包含如下的payload，就可以在邮件客户端中执行任意javascript代码：&lt;/p&gt;
 &lt;pre&gt;%22-alert%281%29-%22&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;总结&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;在我将这个漏洞报告给zoho几天过后，他们在Google Play上发布了新版，并且我收到邮件被告知已经有其他人给zoho报告了这个漏洞。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;我觉得这个漏洞非常有趣，其他很多APP可能会有很多相似的漏洞。不过在使用HTML开发的应用中寻找漏洞比在web中寻找漏洞要难一些。让我们一起挖洞拯救世界，让互联网更安全吧！&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;[消息来源  &lt;a href="http://labs.detectify.com/post/111566617371/finding-an-xss-in-an-html-based" target="_blank" title=""&gt;detectify.com&lt;/a&gt;，翻译/Conermx，转载请注明来自FreeBuf黑客与极客（FreeBuf.COM）]&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>WEB安全</category>
      <guid isPermaLink="true">https://itindex.net/detail/53049-html5-%E7%A7%BB%E5%8A%A8%E5%BA%94%E7%94%A8-xss</guid>
      <pubDate>Thu, 26 Mar 2015 06:00:50 CST</pubDate>
    </item>
    <item>
      <title>Sewise Player 2.5.2 发布，HTML5 视频播放器</title>
      <link>https://itindex.net/detail/52320-sewise-player-html5</link>
      <description>&lt;p&gt;Sewise Player 发布了 2.5.2 版本，更新内容如下：&lt;/p&gt;
 &lt;p&gt;1、增加primary参数，用于确定html5与flash播放的优先级。  &lt;br /&gt;2、HTML5模块加入draggable参数。  &lt;br /&gt;3、修复了在bootstrap框架中弹窗进度条错误的问题。  &lt;br /&gt;4、修复了Flash模块无法播放相对路径视频地址的问题。  &lt;br /&gt;5、修复了一此小问题。  &lt;br /&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://git.oschina.net/jackzhang1204/sewise-player" target="_blank"&gt;http://git.oschina.net/jackzhang1204/sewise-player&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://github.com/jackzhang1204/sewise-player" target="_blank"&gt;https://github.com/jackzhang1204/sewise-player&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;Sewise Player是一款专业的免费网页HTML5视频、流播放器，它功能强大，体积小，跨平台，兼容性好，使用方便简洁。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://static.oschina.net/uploads/space/2014/1227/155709_0hbn_1864350.jpg"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>软件更新新闻</category>
      <guid isPermaLink="true">https://itindex.net/detail/52320-sewise-player-html5</guid>
      <pubDate>Sat, 27 Dec 2014 15:58:00 CST</pubDate>
    </item>
    <item>
      <title>微信圈养下，国内的HTML5生态有可能成为下一个Zynga</title>
      <link>https://itindex.net/detail/52301-%E5%BE%AE%E4%BF%A1-%E5%9C%88%E5%85%BB-%E5%9B%BD%E5%86%85</link>
      <description>&lt;p&gt;  &lt;img alt="" src="http://a.36krcnd.com/photo/2014/610fb7d2b1087966c842ac6059b1679b.jpg"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;本文的前作《  &lt;a href="http://www.36kr.com/p/216973.html"&gt;HTML 5定稿了？背后还是那场闹剧&lt;/a&gt;》和《  &lt;a href="http://www.36kr.com/p/217260.html"&gt;反思HTML5惨痛的500天和四个谎言&lt;/a&gt;》分别讲了HTML5所谓“定稿”背后的商业利益博弈和反思两年前那场“Web App和Native App”的大争论，本文将继续阐述HTML5的未来，  &lt;strong&gt;那就是旧敌未消，新敌又起&lt;/strong&gt;。&lt;/p&gt;

 &lt;p&gt;HTML5如果颠覆了原生APP，不会是简单的Web App崛起，而是意味着“大生态”系统的构建，包括新的操作系统、新的玩家、新的商业模式、新的产品逻辑等等。但没有几个人真的相信这种颠覆会很快出现。&lt;/p&gt;

 &lt;p&gt;  &lt;strong&gt;微信的地盘他做主&lt;/strong&gt;&lt;/p&gt;

 &lt;p&gt;抛开“HTML5颠覆APP”这种骇人听闻的说辞，业界已经看到一些构建HTML5 “小生态”机会的存在，例如微信已经融入原生生态并且构建了自己的HTML5小生态。但是融入生态意味着顺从，微信亦要看更高等生态系统如Apple的脸色，遵循玩家规则。同样微信“小生态”体系下的玩家亦要学会做个乖乖的顺从者，上周张小龙的发言给HTML5游戏重燃的热情浇了一盆冰水，不知是有意或是失言，谈话中对HTML5游戏的明确拒绝让业界好不容易重燃的希望再次受到打击。&lt;/p&gt;

 &lt;p&gt;回顾互联网开放平台，Facebook曾造就了Zynga也毁灭了Zynga，中国互联网开放平台打击合作商出手的力度只会“有过之而无不及”，美国市场数年前诞生过Zynga这样的公司，中国出现过类似机会只是从来没有真正实现过。微信马力十足的一步步掌控电商和游戏的流量、收编媒体，如果HTML5从业者剔除更多的野心，作个乖乖的顺从者从微信的小生态内分得一杯羹还是十分现实，只是这里没有构建“大生态”和“颠覆原生APP”的机会。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="" src="http://a.36krcnd.com/photo/2014/c433a206ff43d006990a2dfb51da12a4.png"&gt;&lt;/img&gt; &lt;/p&gt;

 &lt;p&gt;国内移动浏览器眼下已呈现日落西山之势，微信这样的“小生态”系统更是无法承载过大的野心，那么HTML5和当下生态系统到底如何共处并且获得发展？“融入”正在发生！市场不是不需要HTML5技术，只是不需要HTML5从业者的野心。&lt;/p&gt;

 &lt;p&gt;相比PC主导的web互联网，APP主导的移动互联网缺少了“流量促进规模化”的有效手段，“流量产生流量”即倒流的模式艰难的存在着。积分墙和广告推荐APP有效果，但是相比web时代一个链接跳转的高效模式效果又不那么理想。&lt;/p&gt;

 &lt;p&gt;  &lt;strong&gt;HTML5只是App的血管&lt;/strong&gt;&lt;/p&gt;

 &lt;p&gt;因此HTML5正在快速融入iOS与Android主导的原生生态系统！原生APP内嵌入webview访问web页面已经成为通行做法，用HTML5开发原生APP也早不是新鲜事。并且HTML5技术的进一步发展解决了原生APP生态的一些痼疾，例如APP的“孤岛效应”。&lt;/p&gt;

 &lt;p&gt;微信朋友圈分享让HTML5产生了盘活移动互联网流量的巨大价值，“将内容从一个APP快速、完整、高效的传输到另外一个APP”是HTML5最擅长的部分。在去中心化的用户设备桌面上，HTML5像血管一样连接了一个个的独立的APP器官并且输送血液到不同的APP中。这就是HTML5快速融入生态的表现之一，并且发挥自由流量的价值加速和逐步改造原生生态。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="" src="http://a.36krcnd.com/photo/2014/dda0f376a08f0b409dbaef6bcff2ecbd.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;但是说了很久的，“HTML5颠覆APP”这种假大空的结论，就是另外一回事了。不能说HTML5颠覆APP的可能性不存在，但是就算颠覆也不会以我们目前可以轻易预期的形式出现，不会是移动浏览器也不会是APP内访问Web App。&lt;/p&gt;

 &lt;p&gt;所谓的颠覆，往往就是在我们不可预期的情况下以一种未知的形态扑面而来。最新的美国移动互联网报告显示，所有联网设备中PC份额已经被严重挤压到不足1/4并且呈现进一步萎缩的趋势，移动支付手段也推陈出新，基于“云端”架构的移动购物、商业等行为正在重塑各个传统领域，例如星巴克2013年移动交易额超过60亿元。&lt;/p&gt;

 &lt;p&gt;只有欧美HTML5市场催生了足够规模的成功案例情况下，中国的HTML5大生态领域才可能出现类似的机会。颠覆意味着革命、革命意味着创新，只有行业积聚了足够的创新人才、创新动力以及创新资源的时候，才会推动变革，只是目前这些创新的条件几乎无一具备。因此完全下赌注在基于HTML5技术的纯Web模式下，机会渺茫。&lt;/p&gt;

 &lt;p&gt;  &lt;strong&gt;HTML已经遭遇了下一个对手&lt;/strong&gt;&lt;/p&gt;

 &lt;p&gt;在残酷的互联网竞争环境下，3年可以造就一个公司更可以消灭一个公司，中国互联网更像“快餐经济”，把发展的指望放在5年后才可能出现的机会就等于自取灭亡。当下用HTML5远比赌HTML5更现实。&lt;/p&gt;

 &lt;p&gt;HTML的优势时技术简单，迭代快，渗透能力强。把一个HTML5的内容嵌入到任何APP中，技术工作量都很小，启动webview就可以实现应用嵌套，这些都是HTML5渗透力强的表现，透过HTML5将服务轻松落地到APP中。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="" src="http://a.36krcnd.com/photo/2014/e90ec95cf744da293c4b8cdd3281a916.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;但是纵观欧美市场，一种全新的融入形式正在崛起——“API嵌套”。&lt;/p&gt;

 &lt;p&gt;前一段时间一则新闻让人耳目一新，“Uber开放API实现在星巴克的APP叫车”，这种不同APP之间通过API的方式融入和开放，让“跨APP的流量”成为可能，并且结合开放API开发者可以随意定制使用流程、甚至用户UI界面，增强了用户的体验，也提升了流量的价值。&lt;/p&gt;

 &lt;p&gt;在一个宽松的体系下，开放API成为移动互联网的一种商业主流诉求，API经济一说由此崛起。并且API也存在技术简单、传播力好和渗透力强的优势，HTML5又生不逢时的遇到另外一个强劲的竞争者。&lt;/p&gt;

 &lt;p&gt;  &lt;em&gt;本文作者刘鑫，移动云服务APICloud创始人兼CEO，从SP梦网时代就开始持续关注移动Web开发，个人邮箱hi.seanliu@yahoo.com&lt;/em&gt;&lt;/p&gt;除非注明，本站文章均为原创或编译，转载请注明： 文章来自  &lt;a href="http://www.36kr.com/"&gt;36氪&lt;/a&gt; &lt;hr&gt;&lt;/hr&gt;
 &lt;p&gt;  &lt;a href="http://www.36kr.com/p/201073.html?ref=kr_post_feed"&gt;36氪官方iOS应用正式上线，支持『一键下载36氪报道的移动App』和『离线阅读』&lt;/a&gt;   &lt;a href="https://itunes.apple.com/cn/app/36ke/id593394038?l=en&amp;mt=8" target="_blank"&gt;立即下载！&lt;/a&gt;&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/52301-%E5%BE%AE%E4%BF%A1-%E5%9C%88%E5%85%BB-%E5%9B%BD%E5%86%85</guid>
      <pubDate>Wed, 24 Dec 2014 03:37:17 CST</pubDate>
    </item>
    <item>
      <title>Html5会成为页游厂商的强心针吗？</title>
      <link>https://itindex.net/detail/51050-html5-%E9%A1%B5%E6%B8%B8-%E5%8E%82%E5%95%86</link>
      <description>&lt;p&gt;  &lt;img alt="" border="0" hspace="0" src="http://images.cnitblog.com/news/66372/201409/141203203403396.jpg" title="w.jpg" vspace="0"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;自从神经猫之后，Html5 游戏开始攻占我们的朋友圈，类似神经猫这样快速传播又快速消失的 Html5 游戏数不胜数。&lt;/p&gt;
 &lt;p&gt;而就在最近有两则与 Html5 的消息相信是牵动了许多希望进入这个领域的游戏从业者的神经。&lt;/p&gt;
 &lt;p&gt;1、据游戏陀螺报道，基于微信的 HTML5 的一些小游戏的分享接口被微信封杀，主要是像 7K7K 这类型大战。腾讯欢迎开发小游戏团队和腾讯合作。&lt;/p&gt;
 &lt;p&gt;2、腾讯的广点通项目正在准备在除公众号、微店等项目之外进入游戏，Html5 成为首选，因为 Html5 目前而言只能依靠广告获得营收，同时这类小游戏的流量十分可观，难点在于 Html5 的流量都是瞬间爆发型，何时接入至今还没有解决办法。&lt;/p&gt;
 &lt;p&gt;Html5 手游从本质上来说是手机端的页游，但与在 PC 端相比，这类游戏的生命周期更短，且营收模式暂且单一，同时由于现在的移联网入口的分散导致只有类似微信、UC 这样超大流量的入口才能承载起一个平台。&lt;/p&gt;
 &lt;p&gt;但问题多不代表 Html5 游戏的未来就应该被唱衰，我们以前也从没想过在智能手机上，没有按键控制的手游会发展的这么迅猛。&lt;/p&gt;
 &lt;p&gt;Html5 的将成为手机游戏中一个尚未被开发的金矿，这一点毫无疑问。&lt;/p&gt;
 &lt;p&gt;那么在这下一波热点当中，会成为当年在 PC 端的叱咤风云的页游厂商的止血药吗?因为我们需要知道的是，在 2012 年的 CJ 上还在大放异彩的页游现在已经逐渐成为了游戏行业当中逐渐被遗忘的角色。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;手游刚热电视游戏又来抢风口&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;微软似乎已经不再满足于自己游戏平台的定位，而是全面的打算打造游戏的全产业链，根据《华尔街日报》的最新报道，微软正在打算以 20 亿美元的价格来收购瑞典游戏开发商 Mojang AB。&lt;/p&gt;
 &lt;p&gt;自从 2009 年发布以来，Mojang 已售出逾 5000 万份《我的世界》，去年从该游戏和商品中获利逾 1 亿美元。这款游戏在 2012 年登陆了 Xbox 平台，去年来自 Xbox 版《我的世界》的营收占据了 Mojang 总营收的近三分之一。&lt;/p&gt;
 &lt;p&gt;微软对于电视游戏的加大投入无疑将在全球范围给给这个产业带来利好，而自从去年年中开始，新的一波电视游戏热正在中国慢慢衍生。&lt;/p&gt;
 &lt;p&gt;以 Xbox 入华为契机，国内的游戏厂商以及电视厂商均开始将目光纷纷投向电视游戏产业，无论是借 Xbox 生蛋，还是自主打造游戏终端设备，亦或是无差别式打造平台，中国的电视游戏产业正经历他最好的年代。&lt;/p&gt;
 &lt;p&gt;完美接连收购游戏资讯网站试图从内容口切入;百视通坐拥 Xbox 平台，竖起大旗招揽了一帮企业打造“家庭游戏产业联盟”;TCL、海信等电视厂商号称在智能电视上的广告、大数据、游戏、应用商店等领域达成战略联盟;其他诸如乐视、小米、中兴九城、360、阿里等亦在积极布局。&lt;/p&gt;
 &lt;p&gt;此前在手游领域没有获得成功的游戏创业团队也正在快速的调转方向，投入电视游戏的开发。&lt;/p&gt;
 &lt;p&gt;中国的游戏市场继手游之后开始出现第四股的力量，它承载了新的一波游戏致富梦。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;徘徊的页游&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;9 月 9 日，巨人与 37 游戏宣布在页游领域合作，双方合作的首款产品也即将上市。&lt;/p&gt;
 &lt;p&gt;巨人副总裁吴盟表示，页游行业经过多年发展，仍在坚守的公司已不多，37 游戏在页游领域取得的巨大成绩有目共睹。各方拿出互补优势，持开放共赢心态，定能创造更好成绩。&lt;/p&gt;
 &lt;p&gt;这两家的合作表面看上去是一次简单的战略合作，资源共享，但在背后却影射了更多不一样的东西。&lt;/p&gt;
 &lt;p&gt;我们先来看看 37 游戏，在被顺荣股份收购时，顺荣股份给出的价格是 19.2 亿元占股 60%，整体估值约 33 亿元。&lt;/p&gt;
 &lt;p&gt;根据财务数据显示，37wan 在去年 1 月至 7 月之间，营收超过 8 亿元，净利润达 1.146 亿元，月均充值收入 1.05 亿元，月均付费用户 22 万，月均 ARPU476.48 元。&lt;/p&gt;
 &lt;p&gt;而艾瑞给出的《2013-2014 年中国网页游戏行业研究报告》显示，“2013 年 37 游戏营收 17.0 亿元，是除去腾讯系页游平台以外的最大网页游戏运营平台，37 游戏同比增长率为 188.1%，是整个网页游戏市场增长率的 2 倍”。&lt;/p&gt;
 &lt;p&gt;毫无疑问 37 游戏在页游领域占据着领先的地位，就在与巨人合作之前，发布的页游《大天使之剑》在 60 天的时间内流水突破 3.2 亿元。&lt;/p&gt;
 &lt;p&gt;37 游戏在页游领域的数据足够漂亮，但是领头羊的数据并不足以代表整个页游产业的问题。&lt;/p&gt;
 &lt;p&gt;目前游戏产业最大的明星是手游。巨人在 2012 年初发力页游，为此挖来动网先锋总裁吴盟负责页游，吴盟也是巨人首位 85 后副总裁。可时过进迁，页游可能早已不再是巨人战略当中最核心的部分。&lt;/p&gt;
 &lt;p&gt;在今年 CJ 期间，巨人总裁刘伟表示，巨人网络将以私有化为契机，正式进入二次创业阶段，而手游将是二次创业的主战场，目标是做出《征途》级别有影响力的手游产品。&lt;/p&gt;
 &lt;p&gt;即使是上述的 37 游戏也在今年起宣布将投入 15 亿资金发力手游市场，用于产品代理、开发团队扶持及推广资源购买等，预计有3~4 款自研游戏会在今年上半年推出。&lt;/p&gt;
 &lt;p&gt;反观页游，在 2010-2013 年是页游的黄金发展期，但到 2012 年底，页游的整体盘子依然没有突破百亿元大关，直到 2013 年营收才突破百亿达到 127 亿，可只有短短 3 年发展时间的手游也在去年达到了 112 亿元，2014 年手游的营收全面超越页游以成为既定的事实。&lt;/p&gt;
 &lt;p&gt;而再从市场份额去看，2013 年的页游市场份额为 15.4%，仅仅比 2012 年增长了 1.9 个百分点，页游的未来基本被锁死。&lt;/p&gt;
 &lt;p&gt;所以，巨人与 37 游戏的结盟表面去看是一次简单的合作，但背后显示的却是一次对于游戏新模式的探索，这种探索在页游整体增长缓慢的情况下显得尤为重要。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Html5 会成为强心针吗?&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;37 游戏与巨人的合作或许可以在一定程度上帮助这两家公司在页游领域获得进步，但这仅仅是在“打封闭”，面对页游下滑的趋势，页游厂商所需要的是开拓一条完整的道路，需要找到止血药。&lt;/p&gt;
 &lt;p&gt;目前来看 Html5 很可能将成为止血药。&lt;/p&gt;
 &lt;p&gt;一个很有趣的现象是，37 游戏在手游方面的布局其实很早，比如有一款产品去年就签了，直到今年 5 月份才发布。&lt;/p&gt;
 &lt;p&gt;“这半年以来，我们工作的重点在于建立完整的数据分析体系、锻炼服务团队，同时签约更多的产品，在这其间，最好的产品在网上的销量排名第九。”37 游戏的李逸飞说&lt;/p&gt;
 &lt;p&gt;但是 Html5 的手游与 PC 页游其实在很多方面有着契合程度，比如即开即玩、互动性、病毒式传播、玩家的进入门槛低等等。&lt;/p&gt;
 &lt;p&gt;当前一个新游戏动辄几百兆，即使游戏非常好，但是很多人可能连尝试的勇气都没有，大部分玩家还是喜欢轻松易上手的游戏。&lt;/p&gt;
 &lt;p&gt;多盟总裁张鹤说，“基于 HTML5 的即开即玩游戏符合手游的本质，将成为未来的主流。”&lt;/p&gt;
 &lt;p&gt;而根据板邓得到的消息，已经有很多有实力的页游厂商其实已经在秘密的在探索这个方向，页游厂商进入 Html5 的优势在于有一整套如何快速传播游戏的营销，以及对于即开即玩需求玩家的数据分析，接入 Html5 页游厂商可以实现无缝链接，甚至是简单的移植。&lt;/p&gt;
 &lt;p&gt;前段时间 Html5 手游的早期公司 Moblyng 倒闭了，但他的倒闭并不能说明它的失败，创始人 Putney 称“我们在业务的货币化上没有产生足够重视。”&lt;/p&gt;
 &lt;p&gt;Moblyng 成功地制作了一些游戏，可以让 facebook 上用户和手机上的用户一起玩同一个游戏，该公司称曾有超过 1000 万下载。&lt;/p&gt;
 &lt;p&gt;另外，在今年彻底引爆 Html5 的神经猫的游戏引擎为 Egret，二据 Egret 联合创始人马鉴介绍，Egret 团队成员都是页游出身。Egret 基于微软的 TypeScipt 语言编写，与 Flash 的 ActionScript 语言结构相似。&lt;/p&gt;
 &lt;p&gt;“中国有 40~45 万的 FLASH 开发者，即页游开发者，他们从 PC 端的页游生态系统向新一代的移动互联网的过渡中，不得不放弃已经掌握的知识资源，重新去学习 C  做原生。Egret 在 Visual Studio 上的插件工具 EgretVS，把所有 ActionScript、JavaScript、TypeScript 开发者，带入到移动游戏的开发领域，这也是我们选择 TypeScript 的原因。” 马鉴说。&lt;/p&gt;
 &lt;p&gt;综合这些来看，虽然 Html5 现在的产业链还不成熟，但这仅仅是早期，对于页游厂商来说，Html5 手游与 PC 页游有共存性，很有可能成为他们的一剂强心针。&lt;/p&gt; &lt;p&gt;  &lt;a href="http://news.cnblogs.com/n/503660/" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt; &lt;img alt="" height="1" src="http://news.cnblogs.com/news/rssclick.aspx?id=503660" width="1"&gt;&lt;/img&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category />
      <guid isPermaLink="true">https://itindex.net/detail/51050-html5-%E9%A1%B5%E6%B8%B8-%E5%8E%82%E5%95%86</guid>
      <pubDate>Sun, 14 Sep 2014 12:03:50 CST</pubDate>
    </item>
    <item>
      <title>代码检测HTML5/CSS3新特性的浏览器支持情况</title>
      <link>https://itindex.net/detail/52061-%E4%BB%A3%E7%A0%81-html5-css3</link>
      <description>&lt;div&gt;
  &lt;p&gt;伴随着今年10月底HTML5标准版的发布，未来使用HTML5的场景会越来越多，这是令web开发者欢欣鼓舞的事情。然而有一个现实我们不得不看清，那就是IE系列浏览器还占有一大部分市场份额，以IE8、9为主，windows8.1的用户已经用上了IE10/11，而考虑我国的国情，IE6、7依然存留不少。在我们放手用HTML5开发的时候，新特性支持度检测就是必不可少的了。一种方式是用navigator.userAgent或navigator.appName来检测浏览器类型和版本，不过这种方式不是很可靠，浏览器对于一些新特性也是在逐渐支持，不能肯定说某个浏览器100%支持了HTML5。而且，IE11做了一个恶心的举动：在UA中去掉了“MSIE”标志，把appName改为了“Netspace”，并且开始支持-webkit-前缀的css属性，这是活生生要伪装成chrome的节奏。所以，HTML5/CSS3支持性的检测，还是靠特征检测（figure detection）或者说能力检测更好些。本篇就来介绍一下常用的检测方式都有哪些。&lt;/p&gt;
  &lt;h2&gt;HTML5部分&lt;/h2&gt;
  &lt;p&gt;检测HTML5新特性的方法主要有以下几种：&lt;/p&gt;
  &lt;p&gt;1. 检查全局对象（window或navigator）上有没有相应的属性名&lt;/p&gt;
  &lt;p&gt;2. 创建一个元素，检查元素上有没有相应的属性&lt;/p&gt;
  &lt;p&gt;3. 创建一个元素，检测元素上有没有方法名称，然后调用该方法，看能否正确执行&lt;/p&gt;
  &lt;p&gt;4. 创建一个元素，为元素的相应属性赋一个值，然后再获取此属性的值，看看赋值是否生效&lt;/p&gt;
  &lt;p&gt;由于不同浏览器的不同行为，检测一些特性的时候，可能会用到上述几个方法的组合，接下来用上面的方法做一下常用特性的检测：&lt;/p&gt;
  &lt;h3&gt;canvas&lt;/h3&gt;
  &lt;div&gt;
   &lt;pre&gt;function support_canvas(){
    var elem = document.createElement(’canvas’);
    return !!(elem.getContext &amp;amp;&amp;amp; elem.getContext(’2d’));
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;p&gt;一般来讲，创建canvas元素并检查getContext属性即可，但是在一些浏览器下不够准确，所以再检测一下elem.getContext(’2d’)的执行结果，就可以完全确定。以上代码摘自Modernizr：   &lt;a href="http://github.com/Modernizr/Modernizr/issues/issue/97/"&gt;http://github.com/Modernizr/Modernizr/issues/issue/97/&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;关于canvas，有一点要补充的，那就是fillText方法，尽管浏览器支持canvas，我们并不能确切的确定它支持fillText方法，因为canvas API经历了各种修改，有一些历史原因，检测支持fillText的方法如下：&lt;/p&gt;
  &lt;div&gt;
   &lt;pre&gt;function support_canvas_text(){
    var elem = document.createElement(’canvas’);
    var context = elem.getContext(’2d’);
    return typeof context.fillText === ’function’;
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;h3&gt;video/audio&lt;/h3&gt;
  &lt;div&gt;
   &lt;pre&gt;function support_video(){
    return !!document.createElement(’video’).canPlayType;
}

function support_audio(){
    return !!document.createElement(’audio’).canPlayType;
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;p&gt;video和audio的写法相似。&lt;/p&gt;
  &lt;p&gt;要检测video/audio支持的资源格式，可以调用canPlayType方法来进行检查，具体如下：&lt;/p&gt;
  &lt;div&gt;
   &lt;pre&gt;unction support_video_ogg(){
    var elem = document.createElement(’video’);
    return elem.canPlayType(’video/ogg; codecs=&amp;quot;theora&amp;quot;’);
}
function support_video_h264(){
    var elem = document.createElement(’video’);
    return elem.canPlayType(’video/mp4; codecs=&amp;quot;avc1.42E01E&amp;quot;’);
}
function support_video_webm(){
    var elem = document.createElement(’video’);
    return elem.canPlayType(’video/webm; codecs=&amp;quot;vp8, vorbis&amp;quot;’);
}

function support_audio_ogg(){
    var elem = document.createElement(’audio’);
    return elem.canPlayType(’audio/ogg; codecs=&amp;quot;vorbis&amp;quot;’);
}
function support_audio_mp3(){
    var elem = document.createElement(’audio’);
    return elem.canPlayType(’audio/mpeg;’);
}
function support_audio_wav(){
    var elem = document.createElement(’wav’);
    return elem.canPlayType(’audio/wav; codecs=&amp;quot;1&amp;quot;’);
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;p&gt;要注意的是，canPlayType的返回值并不是布尔类型，而是字符串，取值有以下几种：&lt;/p&gt;
  &lt;ul&gt;
   &lt;li&gt;“probably”：浏览器完全支持此格式&lt;/li&gt;
   &lt;li&gt;“maybe”：浏览器可能支持此格式&lt;/li&gt;
   &lt;li&gt;“”：空串，表示不支持&lt;/li&gt;
&lt;/ul&gt;
  &lt;h3&gt;localStorage&lt;/h3&gt;
  &lt;p&gt;一般来讲，检查全局对象是否有localStorage属性即可，如下：&lt;/p&gt;
  &lt;div&gt;
   &lt;pre&gt;function support_localStorage(){
    try {
        return ’localStorage’ in window &amp;amp;&amp;amp; window[’localStorage’] !== null;
      } 
    catch(e){
        return false;
    }
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;p&gt;在一些浏览器禁用cookie，或者设置了隐私模式什么的情况，检查属性或报错，所以加在try语句中，如果报错了认为不支持。&lt;/p&gt;
  &lt;p&gt;另外，还有一种更严格的检查方法，检查相应方法是否支持，如下：&lt;/p&gt;
  &lt;div&gt;
   &lt;pre&gt;function support_localStorage(){
    try {
        if(’localStorage’ in window &amp;amp;&amp;amp; window[’localStorage’] !== null){
            localStorage.setItem(’test_str’, ’test_str’);
            localStorage.removeItem(’test_str’);
            return true;
        }
        return false;
    } 
    catch(e){
        return false;
    }
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;h3&gt;webWorker&lt;/h3&gt;
  &lt;div&gt;
   &lt;pre&gt;function support_webWorker(){
    return !!window.Worker;
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;h3&gt;applicationCache&lt;/h3&gt;
  &lt;div&gt;
   &lt;pre&gt;function support_applicationCache(){
    return !!window.applicationCache;
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;h3&gt;geolocation&lt;/h3&gt;
  &lt;div&gt;
   &lt;pre&gt;function support_geolocation(){
    return ’geolocation’ in navigator;
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;h3&gt;input标签新属性&lt;/h3&gt;
  &lt;p&gt;input标签新增的属性包括：autocomplete、autofocus、list、placeholder、max、min、multiple、pattern、required、step，检测是否支持用上面提到的方法2即可，新建一个input标签，看是否有这些属性，以autocomplete为例：&lt;/p&gt;
  &lt;div&gt;
   &lt;pre&gt;function support_input_autocomplete(){
    var elem = document.createElement(’input’);
    return ’autocomplete’ in elem;
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;p&gt;另外要特别注意list属性，因为它是与datalist标签连用的，所以检查的时候要一并检测datalist标签是否支持：&lt;/p&gt;
  &lt;div&gt;
   &lt;pre&gt;function support_input_list(){
    var elem = document.createElement(’input’);
    return !!(’list’ in elem &amp;amp;&amp;amp; document.createElement(’datalist’) &amp;amp;&amp;amp; window.HTMLDataListElement);
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;h3&gt;input标签新类型&lt;/h3&gt;
  &lt;p&gt;这里的类型就是指type的取值，input新增的type值包括：search、tel、url、email、datetime、date、month、week、time、datetime-local、number、range、color。检测这些值需要用上面提到的方法4，以number为例：&lt;/p&gt;
  &lt;div&gt;
   &lt;pre&gt;function support_input_type_number(){
    var elem = document.createElement(’input’);
    elem.setAttribute(’type’, ’number’);
    return elem.type !== ’text’;
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;p&gt;这是一种较为简单的检查方法，因为严格来讲，浏览器会为不同的类型提供不同的外观或实现，例如chrome中range类型会长这样：&lt;/p&gt;
  &lt;p&gt;   &lt;img alt="" src="http://www.codeceo.com/wp-content/uploads/2014/12/0c992bfe66695ef648fcd2a568a956f5.png"&gt;&lt;/img&gt;&lt;/p&gt;
  &lt;p&gt;我们要确切的知道浏览器为该类型提供了对应的实现，才可以认为是“支持的”，要从这个方面检测是有难度的，各浏览器实现都不一。下面贴出Modernizr中的一个实现，供参考：检测email类型的实现：&lt;/p&gt;
  &lt;div&gt;
   &lt;pre&gt;function support_input_type_email(){
    var elem = document.createElement(’input’);
    elem.setAttribute(’type’, ’email’);
    elem.value = ’:)’;
    return elem.checkValidity &amp;amp;&amp;amp; elem.checkValidity() === false;
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;p&gt;为email类型设置了一个非法的value，然后手动调用校验方法，如果返回false，说明浏览器提供了该类型的实现，认为是支持的。&lt;/p&gt;
  &lt;h3&gt;history&lt;/h3&gt;
  &lt;p&gt;history虽说是HTML4就有的，但HTML5提供了新的方法，检测方法如下：&lt;/p&gt;
  &lt;div&gt;
   &lt;pre&gt;function support_history(){
    return !!(window.history &amp;amp;&amp;amp; history.pushState);
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;h3&gt;webgl&lt;/h3&gt;
  &lt;div&gt;
   &lt;pre&gt;function support_webgl(){
    return !!window.WebGLRenderingContext;
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;h3&gt;postMessage&lt;/h3&gt;
  &lt;div&gt;
   &lt;pre&gt;function support_postMessage(){
    return !!window.postMessage;
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;h3&gt;draggable&lt;/h3&gt;
  &lt;p&gt;HTML5的拖拽特性：&lt;/p&gt;
  &lt;div&gt;
   &lt;pre&gt;function support_draggable(){
    var div = document.createElement(’div’);
    return (’draggable’ in div) || (’ondragstart’ in div &amp;amp;&amp;amp; ’ondrop’ in div);
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;h3&gt;webSocket&lt;/h3&gt;
  &lt;div&gt;
   &lt;pre&gt;unction support_webSocket(){
    return ’WebSocket’ in window || ’MozWebSocket’ in window;
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;h3&gt;svg&lt;/h3&gt;
  &lt;div&gt;
   &lt;pre&gt;function support_svg(){
    return !!document.createElementNS &amp;amp;&amp;amp; !!document.createElementNS(’http://www.w3.org/2000/svg’, ’svg’).createSVGRect;
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;h2&gt;事件的支持性判断&lt;/h2&gt;
  &lt;h2&gt;通用方法：&lt;/h2&gt;
  &lt;p&gt;检查事件的支持性，用上面提到的方法2就可以，创建一个元素，看元素上有没有对应的事件名称，下面是摘自Modernizr的实现：&lt;/p&gt;
  &lt;pre&gt;isEventSupported = (function() {

      var TAGNAMES = {
        ’select’: ’input’, ’change’: ’input’,
        ’submit’: ’form’, ’reset’: ’form’,
        ’error’: ’img’, ’load’: ’img’, ’abort’: ’img’
      };

      function isEventSupported( eventName, element ) {

        element = element || document.createElement(TAGNAMES[eventName] || ’div’);
        eventName = ’on’ + eventName;

        // When using `setAttribute`, IE skips &amp;quot;unload&amp;quot;, WebKit skips &amp;quot;unload&amp;quot; and &amp;quot;resize&amp;quot;, whereas `in` &amp;quot;catches&amp;quot; those
        var isSupported = eventName in element;

        if ( !isSupported ) {
          // If it has no `setAttribute` (i.e. doesn’t implement Node interface), try generic element
          if ( !element.setAttribute ) {
            element = document.createElement(’div’);
          }
          if ( element.setAttribute &amp;amp;&amp;amp; element.removeAttribute ) {
            element.setAttribute(eventName, ’’);
            isSupported = is(element[eventName], ’function’);

            // If property was created, &amp;quot;remove it&amp;quot; (by setting value to `undefined`)
            if ( !is(element[eventName], ’undefined’) ) {
              element[eventName] = undefined;
            }
            element.removeAttribute(eventName);
          }
        }

        element = null;
        return isSupported;
      }
      return isEventSupported;
    })()&lt;/pre&gt;
  &lt;h3&gt;touch事件&lt;/h3&gt;
  &lt;p&gt;如果仅仅是检查touch事件是否支持，就没必要写上面那么多东西了，可以简单书写如下：&lt;/p&gt;
  &lt;div&gt;
   &lt;pre&gt;function support_touch_event(){
    return !!((’ontouchstart’ in window) || window.DocumentTouch &amp;amp;&amp;amp; document instanceof DocumentTouch);
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;p&gt;Mozilla还提供了一个媒体查询的语句用来检测touch的支持性：touch-enabled，可以在页面上插入一个带有此媒体查询的元素来判断是否支持touch事件。参考：   &lt;a href="http://www.quirksmode.org/css/mediaqueries/touch.html"&gt;http://www.quirksmode.org/css/mediaqueries/touch.html&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;不过我们做移动开发一般都只考虑webkit内核了，Mozilla的方式就不写了，如果需要请参考Modernizr源码。&lt;/p&gt;
  &lt;h2&gt;css3部分&lt;/h2&gt;
  &lt;h2&gt;通用方法&lt;/h2&gt;
  &lt;p&gt;css3属性支持度的检测，主要通过上面方法提到的2和4来检查，不过我们要检查的是元素的style属性。另外一个要提的就是浏览器私有前缀，在现阶段我们用css3属性大部分是要写前缀的，因为各浏览器还未完全支持。我们用到的前缀有：-webkit-、-ms-、-o-、-moz-，至于前缀-khtml-，这是Safari早期使用的，现在基本也没有人再用它了，所以进行检测的时候就把它省去了。Modernizr移除了此前缀的检测，详见：   &lt;a href="https://github.com/Modernizr/Modernizr/issues/454"&gt;https://github.com/Modernizr/Modernizr/issues/454&lt;/a&gt;&lt;/p&gt;
  &lt;p&gt;通用代码如下：&lt;/p&gt;
  &lt;pre&gt;var support_css3 = (function() {
   var div = document.createElement(’div’),
      vendors = ’Ms O Moz Webkit’.split(’ ’),
      len = vendors.length;

   return function(prop) {
      if ( prop in div.style ) return true;

      prop = prop.replace(/^[a-z]/, function(val) {
         return val.toUpperCase();
      });

      while(len--) {
         if ( vendors[len] + prop in div.style ) {
            return true;
         } 
      }
      return false;
   };
})();&lt;/pre&gt;
  &lt;h3&gt;3D变形&lt;/h3&gt;
  &lt;p&gt;css3 3D变形的检测稍微复杂些，首先要支持perspective属性，其次要支持transform-style的值为preserve-3d。用方法4的方式无法检测出来，需要借助媒体查询的方式，代码如下：&lt;/p&gt;
  &lt;div&gt;
   &lt;pre&gt;function support_css3_3d(){
    var docElement = document.documentElement;
    var support = support_css3(’perspective’);
    var body = document.body;
    if(support &amp;amp;&amp;amp; ’webkitPerspective’ in docElement.style){
        var style = document.createElement(’style’);
        style.type = ’text/css’;
        style.innerHTML = ’@media (transform-3d),(-webkit-transform-3d){#css3_3d_test{left:9px;position:absolute;height:3px;}}’;
        body.appendChild(style);
        var div = document.createElement(’div’);
        div.id = ’css3_3d_test’;
        body.appendChild(div);

        support = div.offsetLeft === 9 &amp;amp;&amp;amp; div.offsetHeight === 3;

    }
    return support;
}&lt;/pre&gt;
&lt;/div&gt;
  &lt;p&gt;需要借助上面定义好的support_css3方法来检测perspective。&lt;/p&gt;
  &lt;p&gt;基本常用检测的就这些了，本文中一部分代码是网上搜来的，还有一部分是从Modernizr源码中抽离出来的。如文中叙述有误，欢迎指正。&lt;/p&gt;
  &lt;p&gt;在实际开发中，推荐直接使用Modernizr进行检测，它已经封装的非常漂亮了。但是如果你仅仅检测几个属性，或者不想因加载额外的库而浪费性能，就可以使用上述代码进行单个检测。&lt;/p&gt;
  &lt;p&gt;   &lt;a name="soft-link"&gt;&lt;/a&gt;
&lt;/p&gt;&lt;/div&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>General</category>
      <guid isPermaLink="true">https://itindex.net/detail/52061-%E4%BB%A3%E7%A0%81-html5-css3</guid>
      <pubDate>Sat, 06 Dec 2014 00:00:02 CST</pubDate>
    </item>
  </channel>
</rss>

