{"hotArticleList":[{"content":"<h1><br></h1><p>可以像FIS一样，具有模块化的前端目录结构。</p><p>基于gulp，简单、灵活，容易扩展和修改，懂点gulp的童鞋都可以自己修改、使用、组合。</p><p>不需要任何服务端的整合工作，这个与FIS有很大不同，不需要修改服务端代码来适配，就像正常的html一样，去引用你的js、css、img、fonts等资源，无侵入。</p><p>整合SCSS ES6 Browserify|cssnano|uglify|imagmein|rev等前端常用套件，同时有监视文件变动功能(watch)，可配置的发布目录、资源目录、CDN等，方便开发，简单易用，一站式搞定。</p><p><br></p><p><br>更新说明：</p><p><br></p><pre><code class=\"lang-bash\">gulpman 1.4.6版本更新：\n新增支持cdn_prefix的数组/函数/字符串传参方式，更灵活和强大\n新增支持内联嵌入CSS/JS到html。 只需要再url后面添加 ?_gm_inline\n完善内联资源嵌入后的自动更新引用文件(html和CSS)\n完善文档\n</code></pre><pre><code>gulpman 1.3.6版本更新：\n\n新增对React/jsx支持，可以直接写ReactJS了</code></pre><pre><code>gulpman 1.3.3版本更新：\n\n1、新增对复杂目录和多级目录设定支持:\n比如下面这种模板、静态文件复杂的、多级的路径：\ngulpman.config({\n&nbsp; &nbsp; 'components': 'components/cc',\n&nbsp; &nbsp; 'runtime_views': 'runtime_views/rv',\n&nbsp; &nbsp; 'dist_views': 'dist_views/dv/dv',\n&nbsp; &nbsp; 'runtime_assets': 'runtime_assets/ra/ra',\n&nbsp; &nbsp; 'dist_assets': 'dist_assets/da'\n&nbsp; &nbsp;&nbsp;\n})\n\n2、增加彩色log\n\n3、增加base64关联的资源文件的自动关联编译，比如跟这个base64图片有关的html、css都会自动编译(监视模式下)\n</code></pre><p><br></p><p><br></p><p>先来个大致的介绍：</p><ul><li>使用gulpman按照模块划分后，模块根目录可以是<code>./components</code>(默认，可配置)，如果你有个模块是foo，那么应该有如下目录：<code>./components/foo</code>，然后跟foo模块相关的<code>html|js|css|fonts|image</code>等资源文件都放到<code>foo</code>下，这个结构下，做开发时非常清晰、高效，便于模块组织、资源定位等。</li><li>通过<code>gm:publish</code>命令构建后，会自动生成模板<code>views</code>目录，和静态资源<code>assets</code>目录。</li></ul><p><span style=\"color: rgb(51, 51, 51);\"><br></span></p><p><span style=\"color: rgb(51, 51, 51);\"><br></span></p><p><span style=\"color: rgb(51, 51, 51);\">Github源码： <a href=\"https://github.com/xunuoi/gulpman\">https://github.com/xunuoi/gulpman</a></span></p><p><br></p><p><br></p><h3><a href=\"https://github.com/xunuoi/gulpman#introduction-说明\"></a>Introduction 说明</h3><ul><li>支持Mac、Linux环境下安装、使用</li><li>Windows环境未做测试，由于安装脚本使用到shell，windows不支持sh，可能需要手动安装gulp-sass等模块。</li></ul><h3><br></h3><h3><a href=\"https://github.com/xunuoi/gulpman#install-安装\"></a>Install 安装</h3><p>cd into your project dir and install:</p><pre><code class=\"lang-bash\">npm install gulpman --save-dev</code></pre><h3><br></h3><h3><a href=\"https://github.com/xunuoi/gulpman#usage-使用\"></a>Usage 使用说明</h3><h4><br></h4><h4><a href=\"https://github.com/xunuoi/gulpman#in-your-gulpfile\"></a>一、In Your gulpfile:</h4><p>只需要require gulpman模块，就会自动加载gm:publish、gm:develop（开发监视模式）等预置的task，使用时在命令行直接输入gulp gm:publish即可执行</p><p><br></p><pre><code class=\"lang-js\"><span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">/**</span>\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"> * Gulpfile.js</span>\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"> */</span>\n\n\n<span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">var</span> gulp <span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">=</span> <span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">require</span>(<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>gulp<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>),\n    gman <span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">=</span> <span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">require</span>(<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>gulpman<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>)\n\n\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// your other tasks ...你的其他task\n\n</span>\n\n\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 设置路径、CDN、资源URL前缀等，API超级简单。\n// 你也可以不设置，全部采用默认值!</span>\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// if you want to set the dir, you can use config API:</span>\n\n<span class=\"pl-smi\" style=\"box-sizing: border-box;\">gman</span>.<span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">config</span>({\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 是否使用绝对路径，默认true,推荐使用，方便服务器配置。比如`/static/home/main.js`这种风格。</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 如果is_absolute是false, 那么可能是`../../assets/static/home/main.js`这种风格。</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 具体取决于项目情况、服务端配置等。</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// if set the assets url prefix as absolute or relative, default: true</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>is_absolute<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">true</span>,\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// cdn prefix 配置CDN</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>cdn_prefix<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>, \n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 配置资源URL前缀，建议 /xxx这种</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// usually set as /static, this involves the server config ,such as the static path of nginx</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>url_prefix<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>/static<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span> \n\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 模块COMPONENTS目录，同一个模块的html和资源文件在一起。默认 'components'即可</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>components<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>components<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>,\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// develop和publish下的views目录，跟服务端框架的views目录配置一致，比如express</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>runtime_views<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>views<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>,\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>dist_views<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>views_dist<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>,\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// develop和publish下的assets静态目录，跟服务器配置有关，比如nginx的static目录指向</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>runtime_assets<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>assets<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>,\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>dist_assets<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>assets_dist<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>,\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 第三方JS类库、模块的目录，推荐设置为`lib`或`bower_components`（这样bower可以直接安装到这个目录）</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 这个目录默认打包时为全局模块目录，可以直接`require('xxx')`，而不用加相对路径</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// the js library dir, set as a global module. Also you can set as bower_components</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>lib<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>lib<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>, \n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 可以添加一个自定的全局模块目录，该目录下的js模块，也作为全局模块来require，不需要相对路径。</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// the global module dir</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>global<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>common<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span> \n})\n\n</code></pre><h4><br></h4><h4><br></h4><h4>二、全局模块介绍：</h4><p><br></p><p>1. config的配置中，lib和global都是全局模块目录。举个例子说明：你的components/lib目录下有一个模块 foo.js，就是： components/lib/foo.js，那么你在你的es6文件中，就可以这样使用：` import foo from 'foo' `，不需要写成 ` import foo from '../lib/foo' `。&nbsp;</p><p>2. 同理global那个配置也是这样的，推荐将lib目录设置成跟bower一致的，全部来存放第三方类库，而global设置的目录，比如common，可以存放自己的 公用模块。</p><p>3. 这样开发会更加灵活、方便。注意全局模块不要用同名冲突。</p><p><br></p><h4><br></h4><h4><a href=\"https://github.com/xunuoi/gulpman#in-your-cli\"></a>三、In Your CLI 命令行中调用:</h4><p>就是普通的调用gulp 的task</p><pre><code class=\"lang-bash\"><span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># 初始化目录，建立components目录并添加一份html的demo文件</span>\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># init components dir and a html demo</span>\ngulp gm:init\n\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># publish 发布资源，包括合并、压缩资源、rev产生MD5等</span>\ngulp gm:publish\n\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># develop and watch 开发模式，监视相关文件变动，增量更新</span>\ngulp gm:develop\n\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># clean 清理构建输出的目录和文件</span>\ngulp gm:clean\n\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># 编译输出一份运行时资源文件，但是不进入监视状态</span>\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"># compile for develop, not watch</span>\ngulp gm:compile\n</code></pre>","excerpt":"可以像FIS一样，具有模块化的前端目录结构。基于gulp，简单、灵活，容易扩展和修改，懂点gulp的童鞋都可以自己修改、使用、组合。不需要任何服务端的整合工作，这个与FIS有很大不同，不需要修改服务端代码来适配，就像正常的html一样，去引用你的js、css、img、fonts等资源，无侵入。整合SCSS ES6 Browserify|cssnano|uglify|imagmein|rev等前端常用套件，同时有监视文件变动功能(watch)，可配置的发布目录、资源目录、CDN等，方便开发，简单易用，一站式搞定。更新说明：gulpman 1.4.6版本更新","title":"Gulpan-简单灵活的模块化前端解决方案!","author":"Cloud","type":"tech","en_gallery":false,"enable":true,"tag":["前端"],"img":[],"thumb":[],"mid":[],"raw":[],"createdAt":"2016-01-23T10:11:15.235Z","updatedAt":"2016-02-05T08:19:47.223Z","pv_count":3625,"article_id":"56a351c3e48d2d05682aa0ac","id":"56a351c3e48d2d05682aa0ac"},{"content":"<p style=\"margin-left: 0px;\">Karat克拉这个网站，就是基于sails开发的，前后端都启用了es6+es7特性的开发。</p><p style=\"margin-left: 0px;\">我在github上传了部署代码和文档：<a href=\"https://github.com/xunuoi/sails-babel\">https://github.com/xunuoi/sails-babel</a>&nbsp;</p><p style=\"margin-left: 0px;\">修改变动比较多，github上可能不是最新的代码和文档。</p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\">主要是用了一个支持babel的hook和babel的gulp组件，来支援es6~</p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\">新建一个空sails项目，不包含前端：</p><pre><code class=\"lang-bash\">sails new withu.cc --no-frontend --template=swig</code></pre><p>修改.sailssrc</p><p>1、添加如下，否则启动sails lift会有找不到grunt的warn</p><pre><code>{\n  \"generators\": {\n    \"modules\": {}\n  },\n  \"hooks\": {\n    \"grunt\": false\n  },\n  \"paths\": {\n    \"views\": \"views\"\n  }\n\n}</code></pre><p>2、修改模板引擎配置<br></p><p>安装swig： 目录下，npm install swig</p><p>config/views文件：</p><pre><code>engine: {\n&nbsp; &nbsp; 'name': 'swig',\n&nbsp; &nbsp; 'ext': 'html',\n&nbsp; &nbsp; fn: function (pathName, locals, cb) {\n&nbsp; &nbsp; &nbsp; var swig = require('swig')\n&nbsp; &nbsp; &nbsp; swig.setDefaults({&nbsp;\n&nbsp; &nbsp; &nbsp; &nbsp; loader: swig.loaders.fs('./views')&nbsp;\n&nbsp; &nbsp; &nbsp; })\n&nbsp; &nbsp; &nbsp; return swig.renderFile(pathName, locals, cb);\n&nbsp; &nbsp; }\n&nbsp; },</code></pre><p>3、简历 views和assets目录</p><p>assets目录：&nbsp;</p><p>js</p><p>lib： for bower</p><p>img</p><p>font</p><p>css</p><p>&nbsp;scss 或者less</p><p>==================================</p><p>4、安装bower</p><p>assets目录下 bower init</p><p>assets下目录static</p><p>.bowerrc:</p><pre><code>{\n&nbsp; \"directory\": \"./static/lib/\",\n&nbsp; \"analytics\": false,\n&nbsp; \"timeout\": 120000\n}\n</code></pre><p>5、配置nginx静态目录和upstream</p><p>vhost&nbsp;</p><h2><span style=\"color: rgb(227, 55, 55);\">6、配置安装gulp来适配当前view模式</span></h2><p>assets目录下，设置bower和gulpfile.js</p><p>npm install安装时可能会有问题：</p><blockquote><p>Error: pngquant failed to build, make sure that libpng-dev is installed</p></blockquote><p>This error means that the system is lacking&nbsp;<code>libpng</code>&nbsp;development library, which is needed to install<code>imagemin</code>&nbsp;Node.JS module. To install it on CentOS 6, you need to issue this command:</p><pre><code>yum install libpng-devel</code></pre><p><br></p><p>另外简单介绍下assets/gulpfile.js中的babel配置，完整文件请戳到github上：&nbsp;<a href=\"https://github.com/xunuoi/sails-babel/blob/master/assets/gulpfile.js\" rel=\"nofollow\">https://github.com/xunuoi/sails-babel/blob/master/assets/gulpfile.js</a></p><p>通过配置来启用你想要的es6、7特性：</p><pre><code class=\"lang-js\">var babelOptional = [\n&nbsp; &nbsp; \"es7.asyncFunctions\",\n&nbsp; &nbsp; \"es7.objectRestSpread\",\n&nbsp; &nbsp; \"es7.functionBind\",\n&nbsp; &nbsp; \"es7.comprehensions\",\n]\n</code></pre><p>在gulp task中引用这个option：</p><pre><code class=\"lang-js\">gulp.task('es6', function() {\n&nbsp; return gulp.src([\n&nbsp; &nbsp; &nbsp; j(ASSETS_ROOT, 'es6/**/*.es6'),&nbsp;\n&nbsp; &nbsp; ])\n&nbsp; &nbsp; .pipe(p.babel({\n&nbsp; &nbsp; &nbsp; optional: babelOptional,\n&nbsp; &nbsp; }))\n&nbsp; &nbsp; .pipe(gulp.dest(\n&nbsp; &nbsp; &nbsp; j(ASSETS_ROOT, '.tmp')\n&nbsp; &nbsp; ))\n})</code></pre><p><br></p><p><br></p><p>==========================================================================</p><p>前端构建中，涉及到配合es6中的import 语句（相当于烂大街的require等）来打包构建（browserify来构建），并且增加md5防止缓存问题，需要对一个gulp插件修改一下，这个插件是gulp-md5-plus，但是本身不支持文件搜索定位，所以修改下来支持，详细如下：</p><p>修改gulp-md5-plus ，增加root选项</p><pre><code>module.exports = function (size, ifile, rootpath) {\nsize = size | 0;\nrootpath = rootpath || '\nxxx\n})</code></pre><pre><code>&nbsp; &nbsp; &nbsp; &nbsp; var match_file_path = path.join(rootpath, relativepath)\n&nbsp; &nbsp; &nbsp; &nbsp; var md5_filename = filename.split('.').map(function(item, i, arr){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return i == arr.length-2 ? item + '_'+ d : item;\n&nbsp; &nbsp; &nbsp; &nbsp; }).join('.');\n&nbsp; &nbsp; &nbsp; &nbsp; var relative_dir = path.relative(file.base, dir)\n&nbsp; &nbsp; &nbsp; &nbsp; var md5_file_path = path.join(rootpath,relative_dir, md5_filename)\n&nbsp; &nbsp; &nbsp; &nbsp; console.log('debug: gulp-md5-plus: \\n', md5_file_path)\n&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;\n</code></pre><p>然后替换replace：</p><pre><code>replace(new RegExp(match_file_path), md5_file_path);</code></pre><p><br></p><p>修改后的完整代码（安装完gulp-md5-plus，他的目录下index.js的代码）：</p><p><br></p><pre><code>var path = require('path')\n, gutil = require('gulp-util')\n, through = require('through2')\n, crypto = require('crypto')\n, fs = require('fs')\n, glob = require('glob');\nmodule.exports = function (size, ifile, rootpath) {\n&nbsp; &nbsp; size = size | 0;\n&nbsp; &nbsp; rootpath = rootpath || ''\n&nbsp; &nbsp; return through.obj(function (file, enc, cb) {\n&nbsp; &nbsp; &nbsp; &nbsp; if (file.isStream()) {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.emit('error', new gutil.PluginError('gulp-debug', 'Streaming not supported'));\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return cb();\n&nbsp; &nbsp; &nbsp; &nbsp; }\n&nbsp; &nbsp; &nbsp; &nbsp; if(!file.contents){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return cb();\n&nbsp; &nbsp; &nbsp; &nbsp; }\n&nbsp; &nbsp; &nbsp; &nbsp; var d = calcMd5(file, size)\n&nbsp; &nbsp; &nbsp; &nbsp; , filename = path.basename(file.path)\n&nbsp; &nbsp; &nbsp; &nbsp; , relativepath = path.relative(file.base ,file.path)\n&nbsp; &nbsp; &nbsp; &nbsp; , sub_namepath = relativepath\n&nbsp; &nbsp; &nbsp; &nbsp; .replace(new RegExp(filename) , \"\").split(path.sep).join('/')\n&nbsp; &nbsp; &nbsp; &nbsp; , dir;\n&nbsp; &nbsp; &nbsp; &nbsp; if(file.path[0] == '.'){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dir = path.join(file.base, file.path);\n&nbsp; &nbsp; &nbsp; &nbsp; } else {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dir = file.path;\n&nbsp; &nbsp; &nbsp; &nbsp; }\n&nbsp; &nbsp; &nbsp; &nbsp; dir = path.dirname(dir);\n&nbsp; &nbsp; &nbsp; &nbsp; var match_file_path = path.join(rootpath, relativepath)\n&nbsp; &nbsp; &nbsp; &nbsp; var md5_filename = filename.split('.').map(function(item, i, arr){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return i == arr.length-2 ? item + '_'+ d : item;\n&nbsp; &nbsp; &nbsp; &nbsp; }).join('.');\n&nbsp; &nbsp; &nbsp; &nbsp; var relative_dir = path.relative(file.base, dir)\n&nbsp; &nbsp; &nbsp; &nbsp; var md5_file_path = path.join(rootpath,relative_dir, md5_filename)\n&nbsp; &nbsp; &nbsp; &nbsp; console.log('debug: gulp-md5-plus: \\n', match_file_path)\n&nbsp; &nbsp; &nbsp; &nbsp; console.log('debug: gulp-md5-plus: \\n', md5_file_path)\n&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;\n&nbsp; &nbsp; &nbsp; &nbsp; if(Object.prototype.toString.call(ifile) == \"[object Array]\"){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ifile.forEach(function(i_ifile){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i_ifile &amp;&amp; glob(i_ifile,function(err, i_files){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(err) return console.log(err);\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i_files.forEach(function(i_ilist){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var result = fs.readFileSync(i_ilist,'utf8').replace(new RegExp(match_file_path), md5_file_path);\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fs.writeFileSync(i_ilist, result, 'utf8');\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })\n&nbsp; &nbsp; &nbsp; &nbsp; }else{\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ifile &amp;&amp; glob(ifile,function(err, files){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(err) return console.log(err);\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; files.forEach(function(ilist){\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var result = fs.readFileSync(ilist,'utf8').replace(new RegExp(match_file_path), md5_file_path);\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fs.writeFileSync(ilist, result, 'utf8');\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })\n&nbsp; &nbsp; &nbsp; &nbsp; }\n&nbsp; &nbsp; &nbsp; &nbsp; file.path = path.join(dir, md5_filename);\n&nbsp; &nbsp; &nbsp; &nbsp; this.push(file);\n&nbsp; &nbsp; &nbsp; &nbsp; cb();\n&nbsp; &nbsp; }, function (cb) {\n&nbsp; &nbsp; &nbsp; &nbsp; cb();\n&nbsp; &nbsp; });\n};\nfunction calcMd5(file, slice){\n&nbsp; &nbsp; var md5 = crypto.createHash('md5');\n&nbsp; &nbsp; md5.update(file.contents, 'utf8');\n&nbsp; &nbsp; return slice &gt;0 ? md5.digest('hex').slice(0, slice) : md5.digest('hex');\n}\n</code></pre><p><br></p><p>==========================================================================</p><p><br></p><p>关于 gulpfile.js</p><p>两个gulpfile。assets和根目录下各一个</p><p>browserify只能打包js，也就是转化成es5的js文件。通过添加paths这个函数，可以设置全局模块的路径，注意此时paths必须是转成js的模块，不是es6的路径。</p><p>部分打包代码：</p><pre><code>function browserifyOne(fpath){\n    return browserify({\n          entries: fpath,\n          debug: true,\n          sourceMaps: false,\n          extensions: ['.es6', '.jsx', '.js'],\n          paths: [\n            j(ASSETS_ROOT, 'lib'),\n            j(ASSETS_ROOT, '.tmp/common')\n          ]\n      })\n      /*.transform(babelify.configure({\n        optional: babelOptional\n      }))*/\n      /*.require(require.resolve('babel/polyfill'),{expose: 'babel/polyfill'} )*/ // use regenerators\n      .bundle()\n      .pipe(source(fpath))\n      .pipe(buffer())\n      .pipe(p.rename(function(path) {\n        path['dirname'] = path['dirname'].replace('.tmp', 'js').replace(j(ASSETS_ROOT,'/'), '')\n      }))\n      /*.on('error', function(err){\n        throw Error(err)\n      })*/\n}<br></code></pre><h2><span style=\"color: rgb(227, 55, 55);\">7、sails服务端启用es6</span></h2><p>安装sails-babel-hook的钩子，自动调用babel转化，不需要再手工写gulp来转了</p><p>8、配置js和lib</p><p>让jquery能打包进入js中正常使用</p><pre><code>//main.js\n\nimport 'jquery/dist/jquery'\n$('body').html('i am jquery googog')\nexport { foo, bar }</code></pre><p>修改jquery源代码</p><pre><code>(function( global, factory ) {\n\tif (false &amp;&amp; typeof module === \"object\" &amp;&amp; typeof module.exports === \"object\" ) {</code></pre><p>9、适配mongodb</p><p>npm install --save-dev sails-mongo</p><p>创建对应model</p>","excerpt":"Karat克拉这个网站，就是基于sails开发的，前后端都启用了es6+es7特性的开发。我在github上传了部署代码和文档：https://github.com/xunuoi/sails-babel 修改变动比较多，github上可能不是最新的代码和文档。主要是用了一个支持babel的hook和babel的gulp组件，来支援es6~新建一个空sails项目，不包含前端：sails new withu.cc --no-frontend --template=swig修改.sailssrc1、添加如下，否则启动sails lift会有找不到grunt的","img":[],"title":"全栈es6、7的js开发－基于Sails","author":"Cloud","type":"tech","en_gallery":false,"enable":true,"tag":["前端","Web","Sails","Express"],"thumb":[],"mid":[],"createdAt":"2015-10-27T12:34:27.378Z","updatedAt":"2015-11-18T10:04:36.053Z","pv_count":3560,"article_id":"562f6f53d6db69011de1bbe0","id":"562f6f53d6db69011de1bbe0"},{"content":"<p>什么Ajax、Pjax、Njax。。。神马玩意？ 有Njax吗？ 木有。。。不过真有Pjax！！</p><p>其实pjax就是用到了html5的新history api： pushState和replaceState。<b>如果浏览器不支持，会自动降级为普通http访问，跟正常a链接一样</b></p><p><span style=\"color: rgb(51, 51, 51);\">具体啥区别？</span>先视觉通感感受下！！上图：</p><p><br></p><p>1、普通的http切换页面的请求方式，闪烁、白屏、卡顿、加载等，就是完整加载一坨页面嘛<img src=\"/static/lib/simditor-emoji/images/emoji/joy.png\" width=\"20\" height=\"20\" alt=\"joy\" data-emoji=\"true\" data-non-image=\"true\">，又慢又挫的，就像如花姑娘：</p><p><img alt=\"1.jpg\" src=\"/img/large/559038a7-2d21-4123-a03c-f1a3970a56ff.jpg\" width=\"500\" height=\"248\"><br></p><p><br></p><p>2、通过Ajax来开发页面，只加在部分数据，没有切换和闪烁，清新宜人哦，就像街上MM、邻家小妹<img src=\"/static/lib/simditor-emoji/images/emoji/stuck_out_tongue_winking_eye.png\" width=\"20\" height=\"20\" alt=\"stuck_out_tongue_winking_eye\" data-emoji=\"true\" data-non-image=\"true\"></p><p>如果只是ajax的话，不能保存页面状态！一刷新就没了啊！！转瞬即逝啊！！</p><p>街上的MM都走远了，童鞋别看了，找不到了！！</p><p>如果要保存的话，结合hash#，其实很坑爹啊！</p><p>很多时候引入hash,导致开发复杂不说，关键是影响SEO，百度不认识 #! 啊 只有谷歌认识有毛线用啊被墙了!<img src=\"/static/lib/simditor-emoji/images/emoji/sob.png\" width=\"20\" height=\"20\" alt=\"sob\" data-emoji=\"true\" data-non-image=\"true\"></p><p><img alt=\"2.JPG\" src=\"/img/large/031ecc7d-3564-4884-abfa-bbfea938d786.JPG\" width=\"400\" height=\"600\"><br></p><p><br></p><p>3、Pjax来了啊，喜大普奔！既能无切换、高性能加载显示html，又能跟普通url兼容，前后端开发逻辑也简单！</p><p>就像下面的女神吉田沙世和摄影模特啊！关键是你还能抱回家，轻松hold住，各种调戏啊！卧槽。。说漏嘴了。。咳说正事！</p><p><img alt=\"3.jpg\" src=\"/img/large/2394c653-c8dc-43d9-9861-5e9be3035e2d.jpg\" width=\"480\" height=\"319.6363636363636\"><br></p><p><img alt=\"4.jpg\" src=\"/img/large/091ea772-e6c9-41c7-8740-883003bf1253.jpg\" width=\"480\" height=\"312.8\"><br></p><p><br></p><p><br></p><p>说完了视觉上的通感感受，我们再看一眼开发的区别，是不是开发很麻烦啊 ！！！上代码:</p><p><br></p><pre><code>MO.go('.ctn a', '#ttt')</code></pre><p>然后呢？&nbsp;</p><p>木有了啊！只要后台再根据请求头区分下是否是pjax来返回片段html代码就可以了！</p><p>浏览器不支持pjax怎么办？ 自动将极为普通http啊！！不用担心的！</p><p>艾玛、这么happy！真幸福！</p><p>简直就是修炼<b>玉女心经</b>的节奏啊！ 耶，操练起来！</p><p><br></p><p><br></p><h2><a href=\"https://github.com/xunuoi/MO.Pjax/blob/master/README.md#usage\"></a>\b玉女心经使用指南:</h2><h4><br></h4><h4><a href=\"https://github.com/xunuoi/MO.Pjax/blob/master/README.md#install\"></a>\b安装:</h4><blockquote><ol><li>首先需要jQuery这个基础库~其实可以用纯js写这个pjax类库的，但是，我懒。。。</li><li>引入编译es5后到dist目录下的 <b>mo.pjax.es5.js </b>脚本文件到html文件，如果使用es6，请import并配置编译</li></ol></blockquote><pre><code class=\"lang-js\"><span class=\"pl-e\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">src</span>=<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span>./dist/mo.pjax.es5.js<span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span></span></code></pre><p><b>可以去github上下载：&nbsp;<a href=\"https://github.com/xunuoi/MO.Pjax\">https://github.com/xunuoi/MO.Pjax</a></b></p><p><span style=\"color: rgb(0, 0, 0);\"><br></span></p><p><span style=\"color: rgb(0, 0, 0);\"><br></span></p><p><span style=\"color: rgb(0, 0, 0);\"><b>用法:</b></span></p><p><br></p><p>Api Params Desc 参数注释:</p><p><br></p><blockquote><p><b><i>_fetch : &nbsp;</i></b> 是否请求网络，比如这次pjax的url参数是/about ,如果_fetch为false，那么不发送http 请求或读取缓存，只执行回调。</p><p>多用在复杂web/app设计中，比如当前内容已存在于html中，不想更新和获取.</p><p>* MO.state默认值是false，因为只是重新定义本页面状态，不需要更新已有数据和HTML&nbsp;</p><p>* MO.touch中默认值是true，因为要从http或缓存中 更新数据、html</p></blockquote><p><br></p><blockquote><p><b>_fire：</b>是否立刻触发onpopfn ，立刻执行回调函数。false表示popstate 事件触发后才执行</p><p>* MO.state中默认值是false, 只有popstate事件触发后才执行</p><p><span style=\"color: rgb(51, 51, 51);\">* MO.go中调用了MO.state，并传参_fire值为false.</span><br></p><p>* MO.define中调用了MO.state，并传参_fire值为true.</p></blockquote><h4><br></h4><h4><br></h4><h4><b>配置:</b><br></h4><p>调教一下，再美的女神也不是天生就符合你的口味，来这定制下啊！</p><pre><code><span class=\"pl-smi\" style=\"box-sizing: border-box;\">MO</span>.<span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">config</span>({\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>type<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>POST<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>,\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// this can be used for you back-end ,to detect if it is a pjax request</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>pjaxHeader<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> {\n        <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>X-Http-Pjax<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>Pjax<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>\n    }\n})</code></pre><p><br></p><p>详细配置和注解:</p><pre><code class=\"lang-js\">{\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>type<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>POST<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>,<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// post is default http请求方式</span>\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// if cache data， 是否缓存</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>cache<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">true</span>,\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 'cacheExpires': 10000, // 0 means always avaliable, default none 缓存时间</span>\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// if store data in localStorage , default true </span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>storage<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">true</span>, <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">//是否启用localStorage</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">//如果storageExpires设置为0或false，永不过期</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>storageExpires<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">43200000</span>, <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 12 hours ,default 12 </span>\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// the res data type, default html</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>dataType<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>html<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>, <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">//返回数据类型，默认html</span>\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// you can set your own header ,just use `pjaxHeader` opts, </span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// which you can detect if it is an pjax request in back-end </span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 你可以自己定义请求头，方便后端判断是否是pjax请求，如果是pjax, 返回部分html， fragment</span>\n    <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>pjaxHeader<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> {\n        <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>Http-Request-Pjax<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span><span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">:</span> <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>Fragment<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>\n    },\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// you can set the fn which will triggered before MO.touch and popstate event happened</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// 触发pjax操作前和 出现popstate的事件时的事件函数, 参数是state，包含url、title等信息</span>\n    <span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">before</span> (<span class=\"pl-smi\" style=\"box-sizing: border-box;\">state</span>) { ... } <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">//默认无</span>\n\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// you can set the beforeSend fn , before ajax request send.</span>\n    <span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\">// jquery的ajax方法调用，请求前设置请求头，可以覆盖</span>\n    <span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">beforeSend</span> (<span class=\"pl-smi\" style=\"box-sizing: border-box;\">req</span>){\n        <span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">let</span> ph <span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">=</span> <span class=\"pl-v\" style=\"box-sizing: border-box; color: rgb(237, 106, 67);\">this</span>[<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>pjaxHeader<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>]\n        <span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">for</span> (<span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">let</span> h <span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">in</span> ph ){\n            <span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">let</span> v <span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">=</span> ph[h]\n            <span class=\"pl-smi\" style=\"box-sizing: border-box;\">req</span>.<span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">setRequestHeader</span>(h, v)\n        }\n    }\n}</code></pre><h4><b><br></b></h4><h4><b><br></b></h4><h4><b>Api说明:</b><br></h4><p>看看美女哪里长得最漂亮啊<img src=\"/static/lib/simditor-emoji/images/emoji/heart_eyes.png\" width=\"20\" height=\"20\" alt=\"heart_eyes\" data-emoji=\"true\" data-non-image=\"true\"><img src=\"/static/lib/simditor-emoji/images/emoji/heart_eyes.png\" width=\"20\" height=\"20\" alt=\"heart_eyes\" data-emoji=\"true\" data-non-image=\"true\"></p><p><br></p><p>一、MO.go 最简单！</p><pre><code class=\"lang-js\">MO.go(aSelector, ctnSelector, onSuccess)</code></pre><p>这个是最简单和常用的api， 只需要go一下，传入2个参数即可，一个是点击后触发pjax的元素选择器，一般是a，第二个是更新返回内容的html 。第三个是回调函数，可选。</p><p><br></p><p></p><p>MO.go添加处理错误的函数，比如出现网络请求错误，比如404，会在此处捕获</p><pre><code class=\"lang-js\"><span class=\"pl-smi\" style=\"box-sizing: border-box;\">MO</span>.<span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">go</span>(<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>.ctn a<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>, <span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>#ttt<span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>, \n<span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">function</span> <span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">onSuccess</span>(<span class=\"pl-smi\" style=\"box-sizing: border-box;\">res</span>, <span class=\"pl-smi\" style=\"box-sizing: border-box;\">$aEle</span>){\n    <span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">console</span>.<span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">log</span>(res, $aEle)\n}, \n<span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">function</span> <span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">onError</span>(<span class=\"pl-smi\" style=\"box-sizing: border-box;\">err</span>, <span class=\"pl-smi\" style=\"box-sizing: border-box;\">$aEle</span>){\n    <span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">console</span>.<span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">log</span>(err, $aEle)\n})</code></pre><p><br></p><p><span style=\"color: rgb(51, 51, 51);\">二、MO.define 不常用</span><br></p><p>定义当前页面的state状态，不常用</p><pre><code class=\"lang-js\">MO.define(ctn, htmlData)</code></pre><p></p><p><br></p><p>三、MO.state 适合复杂开发</p><p>* <span style=\"color: rgb(51, 51, 51);\">MO.state和MO.go</span>两者经常配合使用，比较灵活</p><blockquote><p>详细定义当前页面state状态，以及是否请求次url, 和是否立刻触发onpopFn_fire<br></p><p></p></blockquote><pre><code class=\"lang-js\">MO.state(url, title, onpopFn, _data=null, _fetch=false, _fire=false)\n</code></pre><p><br></p><p>四、<span style=\"color: rgb(51, 51, 51);\">MO.go 复杂开发，很好用啊！！！</span></p><p>做复杂交互和逻辑时，比较常用</p><blockquote><p>* 更强大和灵活的使用pjax， 可以定义 pjax的操作的url、回调、是否发起此url的网络请求等，同样可以添加fail的错误处理函数</p></blockquote><p></p><pre><code class=\"lang-js\">MO.touch(apiUrl, title, onpopFn, _fetch=true)</code></pre><p></p><p>给touch添加fail处理网络请求错误，添加方式如下<br></p><pre><code class=\"lang-js\"><span class=\"pl-smi\" style=\"box-sizing: border-box;\">MO</span>.<span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">touch</span>(apiUrl, title, onpopFn, _fetch<span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">=</span><span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">true</span>)\n.<span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">fail</span>(<span class=\"pl-k\" style=\"box-sizing: border-box; color: rgb(167, 29, 93);\">function</span>(<span class=\"pl-smi\" style=\"box-sizing: border-box;\">err</span>) {\n    <span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">console</span>.<span class=\"pl-c1\" style=\"box-sizing: border-box; color: rgb(0, 134, 179);\">log</span>(<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span>There is an error <span class=\"pl-pds\" style=\"box-sizing: border-box;\">'</span></span>, err)\n})\n</code></pre><p><br></p><p><br></p><p><br></p><p><b>服务端处理：</b></p><blockquote><p>服务端只需要判断是普通请求(完整html)还是pjax请求（fragment html）</p><p>可以通过MO.config({'pjaxHeader': {xxx: yyy}})来设置请求头，或者修改type为POST\\GET等，只要让服务端能判断即可！</p></blockquote><p><br></p><p><br></p><p><b>说明：</b></p><blockquote><ul><li>通过MO.touch和MO.state，可以做非常复杂的pjax 应用，自定义事件\\UI等</li><li>如果要简单使用，就是直接 MO.go(), 传入你想要pjax的a元素的selector即可</li><li>配合启用cache/localStorage(默认都启用), 给用户更好操作体验，减少等待、卡顿</li></ul></blockquote><p><br></p><p><br></p><p><br></p><p><br></p><p><b>本地存储：store/removeStore</b></p><p>原来还有这么个福利！！！</p><p>可以在引入MO.Pjax的任何页面，来store数据，当其他页面pjax到此页面的时候，数据直接从storage获取就可以啦！这个在做多重请求方式的web开发时，经常用到哦！</p><p><br></p><blockquote><ul><li>提供本地存储和自动过期机制，</li><li>过期时间通过MO.config({'storageExpires': xxx})来设定</li><li>自动创建一个item来跟踪这条数据的时间: &nbsp;{ k+'createdAt': (new Date).getTime() },</li></ul></blockquote><p><br></p><p><b>Store的Api</b></p><p></p><pre><code><span class=\"pl-smi\" style=\"box-sizing: border-box;\">\nMO</span>.<span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">store</span>(k, v)\n<span class=\"pl-smi\" style=\"box-sizing: border-box;\">MO</span>.<span class=\"pl-en\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">removeStore</span>(k, v)</code></pre><h4><br></h4><h4><br></h4><h4><br></h4><h4><br></h4><h4><b>MO.pjax 使用 MO.go 举例</b></h4><h4>女神跳个舞吧！！<br></h4><p><a href=\"https://github.com/xunuoi/MO.Pjax/blob/master/README.md#html\"></a>html代码</p><pre><code><span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"><!-- Index.html 这个是index.html文件 --></span>\n\n&lt;<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\">div</span> <span class=\"pl-e\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">class</span>=<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span>ctn<span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span></span>&gt;\n    &lt;<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\">h3</span>&gt;Test Mo.pjax<!--<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\"-->h3&gt;\n    &lt;<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\">p</span>&gt;\n       &lt;<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\">a</span> <span class=\"pl-e\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">href</span>=<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span>/about.html<span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span></span>&gt;About<!--<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\"-->a&gt;\n        &lt;<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\">a</span> <span class=\"pl-e\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">href</span>=<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span>/toxic.html<span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span></span>&gt;Toxic<!--<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\"-->a&gt; \n    <!--<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\"-->p&gt;\n<!--<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\"-->div&gt;\n&lt;<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\">div</span> <span class=\"pl-e\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">id</span>=<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span>ttt<span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span></span> <span class=\"pl-e\" style=\"box-sizing: border-box; color: rgb(121, 93, 163);\">style</span>=<span class=\"pl-s\" style=\"box-sizing: border-box; color: rgb(24, 54, 145);\"><span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span>margin-top: 30px;<span class=\"pl-pds\" style=\"box-sizing: border-box;\">\"</span></span>&gt;\n    &lt;<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\">p</span>&gt;This is index html<!--<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\"-->p&gt;\n<!--<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\"-->div&gt;\n\n\n\n------------------------------------------------------------------\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"><!-- about.html  这个是about.html文件 --></span>\n\n&lt;<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\">div</span>&gt;This is about html<!--<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\"-->div&gt;\n\n\n\n------------------------------------------------------------------\n<span class=\"pl-c\" style=\"box-sizing: border-box; color: rgb(150, 152, 150);\"><!-- toxic.html  这个是toxic.html文件  --></span>\n\n&lt;<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\">div</span>&gt;This is toxic html<!--<span class=\"pl-ent\" style=\"box-sizing: border-box; color: rgb(99, 163, 92);\"-->div&gt;\n</code></pre><p><br></p><p><a href=\"https://github.com/xunuoi/MO.Pjax/blob/master/README.md#js-代码\"></a>JS 代码</p><pre><code class=\"lang-js\">MO.go('.ctn a', '#ttt')</code></pre><p></p><p><br></p><p><br></p><p><b>So easy! 搞定收工！</b></p><p>就似这么简单！就似这么任性！</p><p>我娘再也不用担心我无刷新更新页面内容了！Pjax大法\b好！</p><p>赶紧把pjax女神抱回家！！！<img src=\"/static/lib/simditor-emoji/images/emoji/heart_eyes.png\" width=\"20\" height=\"20\" alt=\"heart_eyes\" data-emoji=\"true\" data-non-image=\"true\"><img src=\"/static/lib/simditor-emoji/images/emoji/smile.png\" width=\"20\" height=\"20\" alt=\"smile\" data-emoji=\"true\" data-non-image=\"true\"></p>","excerpt":"什么Ajax、Pjax、Njax。。。神马玩意？ 有Njax吗？ 木有。。。不过真有Pjax！！其实pjax就是用到了html5的新history api： pushState和replaceState。如果浏览器不支持，会自动降级为普通http访问，跟正常a链接一样具体啥区别？先视觉通感感受下！！上图：1、普通的http切换页面的请求方式，闪烁、白屏、卡顿、加载等，就是完整加载一坨页面嘛，又慢又挫的，就像如花姑娘：2、通过Ajax来开发页面，只加在部分数据，没有切换和闪烁，清新宜人哦，就像街上MM、邻家小妹如果只是ajax的话，不能保存页面状态！一刷新","title":"Pjax 无刷新开发web，更好用户体验","author":"Cloud","type":"tech","en_gallery":true,"enable":true,"tag":["前端","Web","html5"],"img":["/img/large/559038a7-2d21-4123-a03c-f1a3970a56ff.jpg","/img/large/031ecc7d-3564-4884-abfa-bbfea938d786.JPG","/img/large/2394c653-c8dc-43d9-9861-5e9be3035e2d.jpg","/img/large/091ea772-e6c9-41c7-8740-883003bf1253.jpg"],"thumb":["/img/thumb/559038a7-2d21-4123-a03c-f1a3970a56ff.jpg","/img/thumb/031ecc7d-3564-4884-abfa-bbfea938d786.JPG","/img/thumb/2394c653-c8dc-43d9-9861-5e9be3035e2d.jpg","/img/thumb/091ea772-e6c9-41c7-8740-883003bf1253.jpg"],"mid":["/img/mid/559038a7-2d21-4123-a03c-f1a3970a56ff.jpg","/img/mid/031ecc7d-3564-4884-abfa-bbfea938d786.JPG","/img/mid/2394c653-c8dc-43d9-9861-5e9be3035e2d.jpg","/img/mid/091ea772-e6c9-41c7-8740-883003bf1253.jpg"],"raw":["/img/559038a7-2d21-4123-a03c-f1a3970a56ff.jpg","/img/031ecc7d-3564-4884-abfa-bbfea938d786.JPG","/img/2394c653-c8dc-43d9-9861-5e9be3035e2d.jpg","/img/091ea772-e6c9-41c7-8740-883003bf1253.jpg"],"createdAt":"2015-11-25T13:51:24.441Z","updatedAt":"2015-12-15T11:14:19.629Z","article_id":"5655bcdce6fecb6c65eded27","pv_count":3105,"id":"5655bcdce6fecb6c65eded27"},{"content":"<p style=\"margin-left: 0px;\">SVG动画，结合了CSS3的transition， 先看下效果图&nbsp;<img alt=\"屏幕快照 2015-10-27 下午8.25.00.png\" src=\"/img/081b72c0-8ffa-429a-a643-fa44adc6d3a3.png\" width=\"134\" height=\"51\"><br></p><p style=\"margin-left: 0px;\">动画效果： 直接参见本页面的导航菜单<img src=\"http://karat.cc/static/lib/simditor-emoji/images/emoji/laughing.png\" width=\"20\" height=\"20\" alt=\"laughing\" data-emoji=\"true\" data-non-image=\"true\"></p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\">鼠标一上去，会有border变长，通过border的dashoffset的变化，包围住整个菜单矩形。</p><p style=\"margin-left: 0px;\">用到了css3的animation，详细用法大家可以看下：&nbsp;<a href=\"http://www.ruanyifeng.com/blog/2014/02/css_transition_and_animation.html\">http://www.ruanyifeng.com/blog/2014/02/css_transition_and_animation.html</a> 讲的比较好</p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\">注意，Firefox中跟webkit计算dash-offset方法有不同，需要fix一下：</p><pre><code class=\"lang-css\">/**\n&nbsp;* FIX Firefox bugs: anti-direcion，\n&nbsp;* and dashoffset is different with Chrome\n&nbsp;*/\n@keyframes moz_draw {\n&nbsp; 0% {\n&nbsp; &nbsp; stroke-dasharray: $dash_len $dash_space_len;\n&nbsp; &nbsp; stroke-dashoffset: $dash_offset;\n&nbsp; &nbsp; stroke-width: $stroke_max_width;\n&nbsp; }\n&nbsp; 100% {\n&nbsp; &nbsp; stroke-dasharray: $dash_full_len+$dash_space_len;\n&nbsp; &nbsp; stroke-dashoffset: -$dash_offset;\n&nbsp; &nbsp; stroke-width: $stroke_min_width;\n&nbsp; }\n}\n</code></pre><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\">然后单独对Firefox进行CSS Hack：</p><pre><code class=\"lang-css\">&amp;:hover .shape {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -webkit-animation: 0.5s linear 0s normal forwards 1 draw;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; animation: 0.5s linear 0s normal forwards 1 draw;\n\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //fix Firefox :stroke-dashoffset not 0 ??\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @-moz-document url-prefix() {\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; animation: 0.5s linear 0s normal forwards 1 moz_draw;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }\n}</code></pre><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\">Firefox的差异，稍后有时间我再研究下。这种东西比较坑爹~</p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\">其他不多说，上代码，算法代码总有注释：</p><p style=\"margin-left: 0px;\">1. &nbsp;先上html结构参考：</p><p style=\"margin-left: 0px;\"><br></p><pre><code class=\"lang-html\">&lt;header&gt;\n&nbsp; &nbsp; &lt;nav&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &lt;div class=\"menu active\"&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"180px\" height=\"48px\"&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;rect width=\"180px\" height=\"48px\" class=\"shape\"&gt;&lt;/rect&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/svg&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;a href=\"/\" class=\"text\"&gt;HOME&lt;/a&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &lt;/div&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &lt;div class=\"menu\"&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"180px\" height=\"48px\"&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;rect width=\"180px\" height=\"48px\" class=\"shape\"&gt;&lt;/rect&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/svg&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;a href=\"/toxic\" class=\"text\"&gt;TOXIC&lt;/a&gt;&nbsp;\n&nbsp; &nbsp; &nbsp; &nbsp; &lt;/div&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &lt;div class=\"menu\"&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"180px\" height=\"48px\"&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;rect width=\"180px\" height=\"48px\" class=\"shape\"&gt;&lt;/rect&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/svg&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;a href=\"/gallery\" class=\"text\"&gt;GALLERY&lt;/a&gt;\n&nbsp; &nbsp; &nbsp; &nbsp; &lt;/div&gt;\n&nbsp; &nbsp; &lt;/nav&gt;\n&lt;/header&gt;</code></pre><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\">2. 这块是定义变量和动画， \b注意下stroke和dash、dash offset的值的定义：</p><pre><code class=\"lang-css\">@import 'define';\n@import 'util';\n\n/**\n&nbsp;* Stroke Calculator =====================\n&nbsp;* @type {[type]}\n&nbsp;* @description: stroke-dashoffset ,\n&nbsp;* 是起点偏移量，在svg的rect中，从左上角开始，\n&nbsp;* 如果offset为负值，那么线段向右偏移移动。\n&nbsp;* dasharray第一个是线段长度，\n&nbsp;* 第二个是空白间隔长度，\n&nbsp;* 当空白间隔小于 offset的时候，\n&nbsp;* 起点处会进入一部分线段（起点之前的线段）。\n&nbsp;* 线段是无穷循环的，\n&nbsp;* 但是都会没入结点中，超过结点后，被覆盖。\n&nbsp;*/\n$stroke_color: #19f6e8;\n$menu_w: 180px;\n$menu_h: 48px;\n$stroke_max_width: 6px;\n$stroke_min_width: 2px;\n$dash_len: 120px;\n$dash_space_len: $menu_w + $menu_h + ($menu_w - $dash_len)/2;\n$dash_offset: - $dash_space_len;\n&nbsp;\n$dash_full_len: 2*($menu_w + $menu_h);\n//======================================\n/**\n&nbsp;* A text center size\n&nbsp;*/\n$text_size: 18px;\n$text_bottom: $text_size + ($menu_h - $text_size)/2 + $stroke_min_width;\n@keyframes draw {\n&nbsp; 0% {\n&nbsp; &nbsp; stroke-dasharray: $dash_len $dash_space_len;\n&nbsp; &nbsp; stroke-dashoffset: $dash_offset;\n&nbsp; &nbsp; stroke-width: $stroke_max_width;\n&nbsp; }\n&nbsp; 100% {\n&nbsp; &nbsp; stroke-dasharray: $dash_full_len;\n&nbsp; &nbsp; stroke-dashoffset: 0;\n&nbsp; &nbsp; stroke-width: $stroke_min_width;\n&nbsp; }\n}\n/**\n&nbsp;* FIX Firefox bugs: anti-direcion，\n&nbsp;* and dashoffset is different with Chrome\n&nbsp;*/\n@keyframes moz_draw {\n&nbsp; 0% {\n&nbsp; &nbsp; stroke-dasharray: $dash_len $dash_space_len;\n&nbsp; &nbsp; stroke-dashoffset: $dash_offset;\n&nbsp; &nbsp; stroke-width: $stroke_max_width;\n&nbsp; }\n&nbsp; 100% {\n&nbsp; &nbsp; stroke-dasharray: $dash_full_len+$dash_space_len;\n&nbsp; &nbsp; stroke-dashoffset: -$dash_offset;\n&nbsp; &nbsp; stroke-width: $stroke_min_width;\n&nbsp; }\n}\n</code></pre><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\">3. 这块是CSS样式</p><pre><code>\n\n      .menu {  \n        width: $menu_w;\n        height: $menu_h;\n        display: inline-block;\n        margin: 2px;\n        // margin: 0 auto;\n        text-align: center;\n        position: relative;\n\n        /**\n         * @debug Firefox和一些safair版本中，不识别CSS中的width和height\n         * 必须将width写在svg代码中\n         */\n        svg{\n          width: $menu_w;\n          height: $menu_h;\n          .shape {\n            \n            // @extend .hardware;\n\n            width: $menu_w;\n            height: $menu_h;\n\n            fill: transparent;\n            stroke-dasharray: $dash_len $dash_space_len;\n            stroke-dashoffset: $dash_offset;\n            stroke-width: 0;\n            stroke: $stroke_color;\n  \n            // 选中状态的\n            @at-root nav .menu.active svg .shape {\n              stroke-width: $stroke_max_width;\n            }\n\n          }\n        }\n\n        &amp;:hover .shape {\n          -webkit-animation: 0.5s linear 0s normal forwards 1 draw;\n          animation: 0.5s linear 0s normal forwards 1 draw;\n\n          //fix Firefox :stroke-dashoffset not 0 ??\n          @-moz-document url-prefix() {\n            animation: 0.5s linear 0s normal forwards 1 moz_draw;\n          }\n        }\n\n        .text {\n          // 具有子菜单的一级菜单，具有交互模糊效果\n          @at-root .menu.on .text{\n            @include blur(2px);\n          }\n          @include trans-all(); \n          \n          color: $nav_a_color;\n          font-size: $text_size;\n          letter-spacing: 3px;\n          line-height: $text_size;\n          position: relative;\n          bottom: $text_bottom;\n          // font-family: 'roboto';\n          text-decoration: none;          \n          \n          &amp;:hover {\n            color: $nav_a_color;\n            letter-spacing: 4px;\n          }\n        }\n      }\n\n\n</code></pre>","excerpt":"SVG动画，结合了CSS3的transition， 先看下效果图 动画效果： 直接参见本页面的导航菜单鼠标一上去，会有border变长，通过border的dashoffset的变化，包围住整个菜单矩形。用到了css3的animation，详细用法大家可以看下： http://www.ruanyifeng.com/blog/2014/02/css_transition_and_animation.html 讲的比较好注意，Firefox中跟webkit计算dash-offset方法有不同，需要fix一下：/** * FIX Firefox bugs: an","img":["/img/081b72c0-8ffa-429a-a643-fa44adc6d3a3.png"],"title":"酷酷的SVG动画菜单","author":"Cloud","type":"tech","en_gallery":false,"enable":true,"tag":["前端","UI","SVG"],"thumb":["/img/081b72c0-8ffa-429a-a643-fa44adc6d3a3.png"],"mid":["/img/081b72c0-8ffa-429a-a643-fa44adc6d3a3.png"],"createdAt":"2015-10-27T12:26:35.881Z","updatedAt":"2015-11-27T01:45:00.281Z","pv_count":2987,"article_id":"562f6d7bd6db69011de1bbdc","raw":["/img/081b72c0-8ffa-429a-a643-fa44adc6d3a3.png"],"id":"562f6d7bd6db69011de1bbdc"},{"content":"<p>　　黑白摄影从古至今一直很流行，景观摄影是一大流派，许多摄影师选择拍摄单色照片。但黑色和白色在每张照片里的效果是不一样的。它需要时间和实践，提高你对黑色白色的理解。下面这些技巧将有助于你更好的拍摄黑白风景照片。</p><p><strong>　　1.了解什么场景拍摄黑白照片更好</strong></p><p>　　有了彩色景观照片，可以依靠色彩的力量来创造内容和兴趣。良好的色彩景观摄影的关键是找到一个值得拍摄的场景，并有最美丽的光作支撑。这就是为什么这么多的彩色景观照片是在黄金时段或日落后拍摄的。</p><p>　　黑白是不同的。没有颜色，你就必须更加努力地创造出强大的作品。你需要学习寻找摄影构图的技巧，如引线，形状，图案，色调对比度和纹理。真的，你要将你看到的色彩在脑中转换成黑白，所剩下的图案就是你要学习的。</p><p>　　例如，这张黑色摄影作品，用的是双瀑布和黑暗的岩石之间的对比。</p><p style=\"text-align: center;\"><img alt=\"ceSjMjJG6580w.jpg\" src=\"/img/large/31ad11c8-debb-4f61-973d-4bd892c69520.jpg\" width=\"700\" height=\"560\"><br></p><p><strong>　　2.寻找文理和色调的对比</strong></p><p>　　色调对比度是用来描述图像的不同部分之间的亮度变化的术语。以下面的照片为例。码头，映衬着傍晚的天空，码头是黑暗的，天空则更浅。这是色调对比。海中的灰色比天空暗一点，但又亮于码头。</p><p style=\"text-align: center;\"><img alt=\"ceOCnQh07Q7cw.jpg\" src=\"/img/large/f3eaf83c-9515-49e3-a550-2b42e216acd7.jpg\" width=\"600\" height=\"600\"><br></p><p>　　如果你想在拍摄悬崖，岩石，草，树，山上出现的东西，海和人造的物体，如码头和码头他们都有不同的纹理。</p><p>　　在下面的照片中，石拱，远处的悬崖，和岩石在前景都是沉重的纹理。大海和天空都更光滑。这是岩石的粗糙度与触感和平静的海面和天空之间的强烈对比。</p><p style=\"text-align: center;\"><img alt=\"ceny4bjWodmw.jpg\" src=\"/img/large/f7c6c9d6-9da4-4d9a-b655-3c4bddec20fc.jpg\" width=\"700\" height=\"395\"><br></p><p><strong>　　3.黑白模式拍摄</strong></p><p>　　用码相机拍摄的好处是，他们可以帮助你理解黑白颜色下的世界。你所要做的就是把你的相机设置为黑白（单色）模式。然后在相机的取景器上查看当前现场的黑白效果。</p><p style=\"text-align: center;\"><img alt=\"ceZuAsO1EStIg.jpg\" src=\"/img/large/b276c816-562d-4a1a-b5e9-24b415d63926.jpg\" width=\"600\" height=\"460\"><br></p><p>　　这有助于你只看到黑色和白色，不会被其他杂乱的颜色分心。这个方法是有用的，因为它使你更容易看到色调的对比度，纹理，线条，形状，图案和光。</p><p><br></p><p><strong>　4.学习使用中灰密度滤光镜</strong></p><p>　　中灰密度滤光镜是景观摄影师的秘密武器，要了解为什么他们是如此有用，让我们思考一下景观照片的典型设置。首先，您设置您ISO尽可能低来保证最佳的图像质量。下一步，你设置一个光圈，大多数的景观照片都是在F / 11或F / 16。</p><p>　　有了这些变量，快门速度取决于环境光的水平。在明亮的阳光下，它可能是约1 / 125s。在低光，它可以低至1 / 2s。但是，如果你想使用一个较慢的快门速度创意效果呢？如果ISO和光圈是固定的，你得到更长快门速度的唯一的方式就是通过使用中灰密度滤光镜。</p><p>　　下面是一个例子。这张照片是在黄昏的光圈的F / 11在ISO 200和快门速度的1 /5th下。这是慢到水面模糊，你甚至可以看到前景的岩石。</p><p style=\"text-align: center;\"><img alt=\"1.jpg\" src=\"/img/large/b1e561be-ab30-4d91-978b-62e47492538e.jpg\" width=\"700\" height=\"395\"><br></p><p>　　然后我添加了一个中灰密度滤光镜，并使这张照片（下面）的快门速度为180秒（3分钟）。水是完全平静的，云在空中移动形成了一个条纹。</p><p style=\"text-align: center;\"><img alt=\"2.jpg\" src=\"/img/large/0e9ffe97-0abc-4176-86d8-ac9e27e699fa.jpg\" width=\"700\" height=\"395\"><br></p><p><strong>　　5.不要被其他摄影作品影响</strong></p><p>　　摄影师Cole Thompson有一个有趣的想法。他练习他所谓的摄影禁欲，不看其他摄影师的作品。该理论是，他能够通过自己的眼睛看到的景观绝不受其他人的照片的影响。</p><p style=\"text-align: center;\"><img alt=\"3.jpg\" src=\"/img/large/34cc3b0f-bd43-4091-8e58-416fc9eed2cd.jpg\" width=\"600\" height=\"600\"><br></p><p>　　我不是很相信这个极端的方法，因为当你缺乏灵感的时候，其他摄影师的作品或许会给你新的想法。但问题是，你在研究过程中看到的最优秀的摄影作品往往会印在你的脑海中。之后你的大脑自然趋势就是要创建类似的图像。这样做的结果就会导致你最后的照片看起来像其他人的。</p><p style=\"text-align: center;\"><img alt=\"4.jpg\" src=\"/img/large/4b77b067-647a-4076-8446-3950627e23bd.jpg\" width=\"700\" height=\"284\"><br></p><p><strong>　　6.旅行</strong></p><p>　　所有的照片，我已经展示给你的都是在西班牙北部拍的。除非你也足够的幸运的生活在这样一个地区，否则你需要旅行来找到类似鼓舞人心的风景照片。</p><p>　　即使你住在一个风景优美的地方，你也需要旅行来扩大你的经验，并增加你照片的深度。我最喜欢的风景照片是在旅行时拍摄的，这两个活动很好地结合在一起，当它背后有一个目的时，旅行更有趣，更令人兴奋。风景摄影是种可以给你的目的感的东西之一。</p><p style=\"text-align: center;\"><img alt=\"5.jpg\" src=\"/img/large/6e0b277c-d3aa-4c04-b255-2157cfb3d99d.jpg\" width=\"700\" height=\"467\"><br></p><p>　　没有旅行，我永远不会有经验和这么优秀的作品。</p><p>[From: <a href=\"http://www.andrewsgibson.com/blog/2016/01/the-power-of-the-black-white-landscape/\">http://www.andrewsgibson.com/blog/2016/01/the-power-of-the-black-white-landscape/</a>]</p>","excerpt":"黑白摄影从古至今一直很流行，景观摄影是一大流派，许多摄影师选择拍摄单色照片。但黑色和白色在每张照片里的效果是不一样的。它需要时间和实践，提高你对黑色白色的理解。下面这些技巧将有助于你更好的拍摄黑白风景照片。　　1.了解什么场景拍摄黑白照片更好　　有了彩色景观照片，可以依靠色彩的力量来创造内容和兴趣。良好的色彩景观摄影的关键是找到一个值得拍摄的场景，并有最美丽的光作支撑。这就是为什么这么多的彩色景观照片是在黄金时段或日落后拍摄的。　　黑白是不同的。没有颜色，你就必须更加努力地创造出强大的作品。你需要学习寻找摄影构图的技巧，如引线，形状，图案，色调对比度和纹","img":["/img/large/31ad11c8-debb-4f61-973d-4bd892c69520.jpg","/img/large/f3eaf83c-9515-49e3-a550-2b42e216acd7.jpg","/img/large/f7c6c9d6-9da4-4d9a-b655-3c4bddec20fc.jpg","/img/large/b276c816-562d-4a1a-b5e9-24b415d63926.jpg","/img/large/b1e561be-ab30-4d91-978b-62e47492538e.jpg","/img/large/0e9ffe97-0abc-4176-86d8-ac9e27e699fa.jpg","/img/large/34cc3b0f-bd43-4091-8e58-416fc9eed2cd.jpg","/img/large/4b77b067-647a-4076-8446-3950627e23bd.jpg","/img/large/6e0b277c-d3aa-4c04-b255-2157cfb3d99d.jpg"],"title":"黑白摄影技巧","author":"Andrew S. Gibson","type":"essay","en_gallery":true,"enable":true,"tag":["摄影"],"thumb":["/img/thumb/31ad11c8-debb-4f61-973d-4bd892c69520.jpg","/img/thumb/f3eaf83c-9515-49e3-a550-2b42e216acd7.jpg","/img/thumb/f7c6c9d6-9da4-4d9a-b655-3c4bddec20fc.jpg","/img/thumb/b276c816-562d-4a1a-b5e9-24b415d63926.jpg","/img/thumb/b1e561be-ab30-4d91-978b-62e47492538e.jpg","/img/thumb/0e9ffe97-0abc-4176-86d8-ac9e27e699fa.jpg","/img/thumb/34cc3b0f-bd43-4091-8e58-416fc9eed2cd.jpg","/img/thumb/4b77b067-647a-4076-8446-3950627e23bd.jpg","/img/thumb/6e0b277c-d3aa-4c04-b255-2157cfb3d99d.jpg"],"mid":["/img/mid/31ad11c8-debb-4f61-973d-4bd892c69520.jpg","/img/mid/f3eaf83c-9515-49e3-a550-2b42e216acd7.jpg","/img/mid/f7c6c9d6-9da4-4d9a-b655-3c4bddec20fc.jpg","/img/mid/b276c816-562d-4a1a-b5e9-24b415d63926.jpg","/img/mid/b1e561be-ab30-4d91-978b-62e47492538e.jpg","/img/mid/0e9ffe97-0abc-4176-86d8-ac9e27e699fa.jpg","/img/mid/34cc3b0f-bd43-4091-8e58-416fc9eed2cd.jpg","/img/mid/4b77b067-647a-4076-8446-3950627e23bd.jpg","/img/mid/6e0b277c-d3aa-4c04-b255-2157cfb3d99d.jpg"],"raw":["/img/31ad11c8-debb-4f61-973d-4bd892c69520.jpg","/img/f3eaf83c-9515-49e3-a550-2b42e216acd7.jpg","/img/f7c6c9d6-9da4-4d9a-b655-3c4bddec20fc.jpg","/img/b276c816-562d-4a1a-b5e9-24b415d63926.jpg","/img/b1e561be-ab30-4d91-978b-62e47492538e.jpg","/img/0e9ffe97-0abc-4176-86d8-ac9e27e699fa.jpg","/img/34cc3b0f-bd43-4091-8e58-416fc9eed2cd.jpg","/img/4b77b067-647a-4076-8446-3950627e23bd.jpg","/img/6e0b277c-d3aa-4c04-b255-2157cfb3d99d.jpg"],"createdAt":"2020-05-07T06:41:30.975Z","updatedAt":"2020-05-07T06:41:30.975Z","pv_count":2310,"id":"5eb3ad9a82b94de52f13b5ff"},{"content":"<blockquote><p>Русское слово</p></blockquote><p><br></p><p>2015-7-20</p><p>1. Июль : July</p><p>2. Аигуст : Autumn</p><p>3. фотография : photograph&nbsp;</p><p>4. вода : water</p><p>5. адрес : address</p><p>6. автобус : bus</p><p>7. английски : English</p><p>8. без : not exist, have not [thing]</p><p>9. воздух : the air</p><p>10. ветер : wind, breeze</p><p>11. На свете : On the world,&nbsp;</p><p>12. На : on the ...&nbsp;</p><p>13. фильмов : movie，film</p><p>2015-7-21</p><p>14. Элегантные девушка ： elegant girl</p><p>15. девушка ：girl</p><p>16. дурак :【阳】 fool ,stupid guy； дура： 【阴】; дурацкий &nbsp;【形容词】</p><p>17. очень красивый : very nice ,beautiful&nbsp;</p><p>18. самая ： the most xxx</p><p>19. сексуальная женщина ： sexy women</p><p>20. мира ： the world</p><p>2015-7-24</p><p>21. жаркая погода : hot weather</p><p>22. В моей комнате : in my room</p><p>23. большой : big, large</p><p>24. магазин ： shop, store</p><p>25. жаркая ： hot</p><p>2015-7-26</p><p>26. Я учусь ： I‘m studying</p><p>2015-7-27</p><p>27. Доброе утро : good morning</p><p>28. Привет : hi, hello</p><p>29. &nbsp;Спасибо : thanks&nbsp;</p><p>30. Нормально : fine , I am fine &nbsp;</p><p>31. восхитительна : happy, pleasure</p><p>32. добрый день : good afternoon</p><p>33. где учил русский язык ? 在哪儿学的俄语吗？</p><p>34. Я могу говорить простой русский&nbsp;</p><p>eg.</p><p>ах, русский язык ? Я могу говорить простой русский )) &nbsp; Я больше знаю с английского и китайский .</p><p>啊，俄语吗？我能说简单的俄语））我更知道英语和中文</p><p>35. Ты в пекин? &nbsp;: &nbsp;Are you in Beijing ？</p><p>36. русский язык очень интересно ： Russian is interesting</p><p>37. Да, &nbsp;я живу Пекине &nbsp;: Yes, I live in Beijing.</p><p>38. в минувшие выходные я пошел плавать ： I went swimming on last weekend</p><p>39. Ты где работаешь ? ： where do you work ?</p><p>40. работаешь ： work, do jobs</p><p>41. Какие метро станция ты живешь рядом? : which subway station do you live near?</p><p>42. &nbsp;Я только пришел домой с работы ： 我刚下班回家</p><p>43. кушай и отдыхай : eating and reset&nbsp;</p><p>44. Шел дождь . &nbsp;: It is raining.</p><p>45. Я чувствую себя очень комфортно : &nbsp;I feel very comfortable .</p><p>46. ты был в России ? : 你曾经在俄罗斯吗？&nbsp;</p><p>47. Сейчас на улице очень хорошо 😌 не жарко ： 现在大街上是很不错的😌不热</p><p>48. Почему ？： &nbsp;why？&nbsp;</p><p>49. когда вы пришли в Пекин?</p><p>50. Ты где учил русский язык ?</p><p>51. Ты умеешь разговаривать по русски ? : Can you speak in Russian?</p><p>52. больше общайся с русскими друзьями : 更多的沟通与俄罗斯朋友</p><p>53. Хорошо ： OK</p><p>54. Я хочу поехать в Москву : &nbsp;I want to go to Moscow</p><p>55. Приятного аппетита : 好好享受吃好</p><p>56. Спасибо, вы очень добры : thanks, you are so kind</p><p>57. место дая тебя : the place gives to you</p><p>58. любят ： like， like to do, love&nbsp;</p><p>59. нравлюсь ： like some one， love some one</p><p>60. то что ваш любимый китайской кушанье? ： what is your favorite Chinese dish?</p><p>61. познакомиться &nbsp;: &nbsp;认识，熟悉</p><p>2015-7-30</p><p>62. &nbsp;Мне очень нравится китайская кухня &nbsp;： I really like Chinese food</p><p>63. Мне все нравися &nbsp;： &nbsp;I like everything</p><p>64. Я люблю фотографию : I love photograph</p><p>65. Отобразить некоторые фотографию : show some photograph</p><p>2015-8-2</p><p>66. Привет, друг. Я найду тебя в VK : Hi， friend. I find you on VK</p><p>67. Я люблю тебя ： I love you&nbsp;</p><p>68. Извините： sorry</p><p>==================================</p><p>2015-9-4</p><p>69. Сегодня день рождения &nbsp;у Tom : Today is Tom's birthday.</p><p>2015-9-10&nbsp;</p><p>70. Добрый вечер： good evening</p><p>71. доброй ночи: good night</p><p>2015-9-14</p><p>72. До свидания： good bye</p><p><br></p><p><br></p><p><br></p><p>2015 - 10 -28</p><blockquote><ol><li>Это дом. :This is room</li><li>Это он. this is him</li></ol></blockquote><p><br></p><p>2015-10-31</p><p><br></p><p>как поживаете эти дни ？: how are these days ?<br></p><p><br></p><p>2015-11-30</p><p>прекрасный 非常好看的，漂亮的 &nbsp;<span style=\"color: rgb(102, 102, 102);\">~а</span><span style=\"color: rgb(255, 120, 0);\">я</span><span style=\"color: rgb(102, 102, 102);\">&nbsp;ж</span><span style=\"color: rgb(255, 120, 0);\">е</span><span style=\"color: rgb(102, 102, 102);\">нщина非常漂亮的女人.</span><br></p>","excerpt":"Русское слово2015-7-201. Июль : July2. Аигуст : Autumn3. фотография : photograph 4. вода : water5. адрес : address6. автобус : bus7. английски : English8. без : not exist, have not [thing]9. воздух : the air10. ветер : wind, breeze11. На свете : On the world, 12. На : on the ... ","title":"常用俄语","author":"Cloud","type":"essay","en_gallery":false,"enable":true,"tag":["生活","俄语"],"img":[],"thumb":[],"mid":[],"createdAt":"2015-10-27T16:25:01.790Z","updatedAt":"2015-11-30T08:58:14.778Z","pv_count":2101,"article_id":"562fa55d031ba6331fb06be7","raw":[],"id":"562fa55d031ba6331fb06be7"},{"content":"<p>去年公司在三元桥远洋新干线的时候，在楼下溜达时看到的，可爱的萝莉和正太，老爸领着在下面玩</p><p><br></p><p>1. 奔跑</p><p><img alt=\"1.jpg\" src=\"/img/large/b12bc630-59e1-4c7f-a696-2585b47471d9.jpg\" width=\"1200\" height=\"800\"><br></p><p><br></p><p>2. 看</p><p><img alt=\"2.jpg\" src=\"/img/large/9d8bc092-3dc9-4d14-8628-4897bb8afe4f.jpg\" width=\"1200\" height=\"800\"><br></p><p><br></p><p>3. 害羞</p><p><br></p><p><img alt=\"3.jpg\" src=\"/img/large/82901e1e-e2a8-4ed3-b6b6-e3446a7be949.jpg\" width=\"598\" height=\"800\"><br></p>","excerpt":"去年公司在三元桥远洋新干线的时候，在楼下溜达时看到的，可爱的萝莉和正太，老爸领着在下面玩1. 奔跑2. 看3. 害羞","img":["/img/large/b12bc630-59e1-4c7f-a696-2585b47471d9.jpg","/img/large/9d8bc092-3dc9-4d14-8628-4897bb8afe4f.jpg","/img/large/82901e1e-e2a8-4ed3-b6b6-e3446a7be949.jpg"],"title":"马思德一家","author":"Cloud","type":"essay","en_gallery":true,"enable":true,"tag":["生活","摄影","人像"],"thumb":["/img/thumb/b12bc630-59e1-4c7f-a696-2585b47471d9.jpg","/img/thumb/9d8bc092-3dc9-4d14-8628-4897bb8afe4f.jpg","/img/thumb/82901e1e-e2a8-4ed3-b6b6-e3446a7be949.jpg"],"mid":["/img/mid/b12bc630-59e1-4c7f-a696-2585b47471d9.jpg","/img/mid/9d8bc092-3dc9-4d14-8628-4897bb8afe4f.jpg","/img/mid/82901e1e-e2a8-4ed3-b6b6-e3446a7be949.jpg"],"createdAt":"2015-10-27T12:45:23.350Z","updatedAt":"2015-11-25T10:48:31.495Z","pv_count":2041,"article_id":"562f71e3c114ada21d3b866d","raw":["/img/b12bc630-59e1-4c7f-a696-2585b47471d9.jpg","/img/9d8bc092-3dc9-4d14-8628-4897bb8afe4f.jpg","/img/82901e1e-e2a8-4ed3-b6b6-e3446a7be949.jpg"],"id":"562f71e3c114ada21d3b866d"},{"content":"<p>1. 选择一个焦点</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 自动对焦时，相机会选取最近镜头的物体来对焦，容易造成对焦不准的情况，所以把自动对焦模式抛弃使用吧。选择一个对焦点，这是摄影人必须要学会的。</p><p><br></p><p style=\"margin-left: 0px;\"><img alt=\"793d5ac1-4f4d-4d76-9448-d68bd0fb0077.jpg\" src=\"http://karat.cc/img/575957eb-a1ab-4b89-ae27-89c4ef6c549d.jpg\" width=\"800\" height=\"521\"><br></p><p><br></p><p>2. 把焦点放在眼睛</p><p>&nbsp; &nbsp; &nbsp; &nbsp; 眼睛是心灵的窗口。眼睛是脸上最敏锐的一个点，也是好照片最重要的部分。当光圈全开时，把焦点堆在眼睛，连皮肤都会模糊起来，这时候你也可以为磨皮省事了。</p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\"><img alt=\"9015eee1-e203-45c2-9cc3-734c6c17d412.jpg\" src=\"http://karat.cc/img/4534a01f-c07d-4e87-bcb1-8f518bb8f6b5.jpg\" width=\"800\" height=\"533\"><br></p><p style=\"margin-left: 0px;\"><br></p><p>3. 全开光圈，小景深</p><p>　　有相当多理由的理由给你去买一个大光圈的镜头。最能引起共识的就是为了拍摄小景深效果。令人惊讶的光线效果和迷人的背景模糊，都能从大光圈里获得。</p><p><br></p><p style=\"margin-left: 0px;\"><img alt=\"5a3abbc2-fbce-4daa-9d35-b8f067dc456d.jpg\" src=\"/img/a2edeffb-e0c7-49fe-ac80-f7548c1182f9.jpg\" width=\"665\" height=\"600\"></p><p style=\"margin-left: 0px;\"><br></p><p>4. 尝试用70mm或以上的镜头拍摄</p><p>　　很多mm 看完照片后都会有这样的疑问：“为什么我的脸看上去肿了?” 。任何70mm以下的镜头拍摄都会引起不同程度的变形。长焦会产生压缩空间的效果，也能加深背景的模糊。</p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\"><img alt=\"4}@T`@G_D[%9)Z6BRVFA85Y.jpg\" src=\"/img/abc16db5-4327-4601-bb37-fc2bd921ce8e.jpg\" width=\"1600\" height=\"1067\"><br></p><p style=\"margin-left: 0px;\"><br></p><p><img alt=\"bd4daef1cf63f6d5a020f34684183336.jpg\" src=\"http://karat.cc/img/7111514a-71ca-42c7-afa2-faba79675a66.jpg\" width=\"683\" height=\"1024\"><br></p><p><br></p><p><img alt=\"2cb92c03-8314-499b-b082-bb78427134c7.jpg\" src=\"http://karat.cc/img/e6a4dba5-6827-49a7-ad06-c7e3302302ae.jpg\" width=\"800\" height=\"531\"></p><p><img alt=\"M$(7VI~KNRG6_8{Y3BLJOON.jpg\" src=\"/img/e2385c65-ffb1-4a03-ad91-1d7f5d74da35.jpg\" width=\"1800\" height=\"1201\"><br></p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\"><img alt=\"4692dcc7-63c2-44dd-9ebd-ad4cf5de4c46.jpg\" src=\"/img/fd44f342-df03-4ff5-a22d-199f61bf027c.jpg\" width=\"800\" height=\"533\"><br></p><p style=\"margin-left: 0px;\"><img alt=\"`7OB7BBP@1UK]6`[T[~_`C6.jpg\" src=\"/img/641f6b22-5e55-49dc-83f5-7122a2784aa1.jpg\" width=\"1280\" height=\"1920\"><br></p><p style=\"margin-left: 0px;\"><img alt=\"222.jpg\" src=\"http://karat.cc/img/4c7233aa-39be-49b9-9a55-8dddb8413541.jpg\" width=\"652\" height=\"460\"><br></p><p style=\"margin-left: 0px;\"><br></p><p style=\"margin-left: 0px;\"><img alt=\"bf07033e-f6e0-4098-84a9-7a0bca2ba959.jpg\" src=\"/img/747244bc-6d45-4862-850a-c669772d6d19.jpg\" width=\"800\" height=\"553\"></p>","excerpt":"1. 选择一个焦点        自动对焦时，相机会选取最近镜头的物体来对焦，容易造成对焦不准的情况，所以把自动对焦模式抛弃使用吧。选择一个对焦点，这是摄影人必须要学会的。2. 把焦点放在眼睛        眼睛是心灵的窗口。眼睛是脸上最敏锐的一个点，也是好照片最重要的部分。当光圈全开时，把焦点堆在眼睛，连皮肤都会模糊起来，这时候你也可以为磨皮省事了。3. 全开光圈，小景深　　有相当多理由的理由给你去买一个大光圈的镜头。最能引起共识的就是为了拍摄小景深效果。令人惊讶的光线效果和迷人的背景模糊，都能从大光圈里获得。4. 尝试用70mm或以上的镜头拍摄　　很","img":["http://karat.cc/img/575957eb-a1ab-4b89-ae27-89c4ef6c549d.jpg","http://karat.cc/img/4534a01f-c07d-4e87-bcb1-8f518bb8f6b5.jpg","/img/a2edeffb-e0c7-49fe-ac80-f7548c1182f9.jpg","/img/abc16db5-4327-4601-bb37-fc2bd921ce8e.jpg","http://karat.cc/img/7111514a-71ca-42c7-afa2-faba79675a66.jpg","http://karat.cc/img/e6a4dba5-6827-49a7-ad06-c7e3302302ae.jpg","/img/e2385c65-ffb1-4a03-ad91-1d7f5d74da35.jpg","/img/fd44f342-df03-4ff5-a22d-199f61bf027c.jpg","/img/641f6b22-5e55-49dc-83f5-7122a2784aa1.jpg","http://karat.cc/img/4c7233aa-39be-49b9-9a55-8dddb8413541.jpg","/img/747244bc-6d45-4862-850a-c669772d6d19.jpg"],"title":"几组街拍和人像摄影","author":"Cloud","type":"essay","en_gallery":true,"enable":true,"tag":["摄影","人像"],"thumb":["http://karat.cc/img/thumb/575957eb-a1ab-4b89-ae27-89c4ef6c549d.jpg","http://karat.cc/img/thumb/4534a01f-c07d-4e87-bcb1-8f518bb8f6b5.jpg","/img/thumb/a2edeffb-e0c7-49fe-ac80-f7548c1182f9.jpg","/img/thumb/abc16db5-4327-4601-bb37-fc2bd921ce8e.jpg","http://karat.cc/img/thumb/7111514a-71ca-42c7-afa2-faba79675a66.jpg","http://karat.cc/img/thumb/e6a4dba5-6827-49a7-ad06-c7e3302302ae.jpg","/img/thumb/e2385c65-ffb1-4a03-ad91-1d7f5d74da35.jpg","/img/thumb/fd44f342-df03-4ff5-a22d-199f61bf027c.jpg","/img/thumb/641f6b22-5e55-49dc-83f5-7122a2784aa1.jpg","http://karat.cc/img/thumb/4c7233aa-39be-49b9-9a55-8dddb8413541.jpg","/img/thumb/747244bc-6d45-4862-850a-c669772d6d19.jpg"],"mid":["http://karat.cc/img/mid/575957eb-a1ab-4b89-ae27-89c4ef6c549d.jpg","http://karat.cc/img/mid/4534a01f-c07d-4e87-bcb1-8f518bb8f6b5.jpg","/img/mid/a2edeffb-e0c7-49fe-ac80-f7548c1182f9.jpg","/img/mid/abc16db5-4327-4601-bb37-fc2bd921ce8e.jpg","http://karat.cc/img/mid/7111514a-71ca-42c7-afa2-faba79675a66.jpg","http://karat.cc/img/mid/e6a4dba5-6827-49a7-ad06-c7e3302302ae.jpg","/img/mid/e2385c65-ffb1-4a03-ad91-1d7f5d74da35.jpg","/img/mid/fd44f342-df03-4ff5-a22d-199f61bf027c.jpg","/img/mid/641f6b22-5e55-49dc-83f5-7122a2784aa1.jpg","http://karat.cc/img/mid/4c7233aa-39be-49b9-9a55-8dddb8413541.jpg","/img/mid/747244bc-6d45-4862-850a-c669772d6d19.jpg"],"createdAt":"2015-10-27T11:16:38.727Z","updatedAt":"2015-10-30T08:42:01.429Z","pv_count":2025,"article_id":"562f5d16aab8c5ee1a16005c","id":"562f5d16aab8c5ee1a16005c"},{"content":"<p><img alt=\"4a7f6fdbd58b4b29a783b9530e83d99c.jpg\" src=\"/img/large/6f868e96-67e7-4da0-b92a-56f5dc73ae56.jpg\" width=\"640\" height=\"406\"><br></p><p><br></p><p>所谓人像摄影，就是以人物为主要创作对象的摄影形式。人像摄影与一般的人物摄影不同：人像摄影以刻画与表现被摄者的具体相貌和神态为自身的首要创作任务，虽然有些人像摄影作品也包含一定的情节，但它仍以表现被照者的相貌为主。那么，我们今天来讨论下人像的相机参数吧！</p><p>标准的人像摄影镜头，一般是指在镜头1.5m—2m的距离上照人的镜头，也就是70mm-135mm的镜头。按照一般的美学观点，在1.5至2米外看一个人的五官是最漂亮的。比方说如果想要拍摄带环境的人像，建议选择 50mm 以下的镜头，而如果想要拍半身以上的肖像照并且有很明显的虚化将主体和背景分离，那么 85mm 以上的中长焦镜头可能是更好的选择。</p><p><br></p><p><img alt=\"2954a9b0c96f4a458cb1b6d2ddfd12a6.jpg\" src=\"/img/large/173b8f80-20ea-408f-b160-6ca917f5aa51.jpg\" width=\"640\" height=\"459\"><br></p><p>好用的头就是又容易与被拍摄人沟通，又不发生明显的变形的镜头。</p><p>对于135相机来说，70mm-135mm镜头是公认的人像镜头。</p><p>而对于APS-C相机来说，因为同样的镜头能得到的像场比135相机小，所以50mm-90mm焦距的135相机镜头才是APS-C相机的人像镜头。</p><p>那如果是拍儿童呢？按理说我们要用比普通人像镜头焦距更大（放大倍数更大）的镜头才能使小孩的头肩充满整个像场，但是由于儿童的五官没有成人那么突出，我们可以在更近的距离拍摄而不影响审美，所以我们用普通人像镜头在1米外拍就行了。</p><p><br></p><p><img alt=\"8f2174d3f3e54c35b98d36479b006b60.jpg\" src=\"/img/large/6e6aa160-73e0-4d32-a354-b66e55cb5a1a.jpg\" width=\"500\" height=\"700\"><br></p><p>想要背景虚化，仅仅靠开大光圈是不够的，它需要满足三个要素，一是光圈，还有就是镜头的焦段和主体的位置。</p><p>简单来说，在其他两个元素不变的前提下，光圈越大，景深越浅，虚化效果就越明显。</p><p>同样的，镜头的焦段越长，虚化效果也就越明显，比方说，在人像在画面中的大小不变的前提下，85mm f/2.8 的虚化效果肯定要比 50mm f/2.8 的虚化效果要好，而就算是 35mm f/2 的虚化效果，可能都不如 85mm f/4 的虚化效果来的好。</p><p><br></p><p><img alt=\"47ecb8adf9004a6cbd67cdda7d7932ea.jpg\" src=\"/img/large/66db5f18-6bdb-4fd4-b761-26bdda06fd44.jpg\" width=\"826\" height=\"526\"><br></p><p>而想要拍出更明显的虚化效果，还需要第三个要素作用，就是被摄主体的位置，同样，也是在其他两个要素相同的前提下，主体距离拍摄者（相机）越近，或者主体距离背景越远，虚化效果就越明显。</p><p>但是要明确的一个观点是，并不是景深越浅越好，就拿肖像照来说，太浅的景深也会导致面部部分失去焦点，同时也并不是所有镜头都是最大光圈可用的，大部分镜头开足光圈会不可避免的带来锐度的损失，让画面模糊，一切都还是要以合适为主，不能一味的追求极端。</p><p><img alt=\"4e657d161c5e487aa6f33ba7a42f232f.jpg\" src=\"/img/large/93fcfcc0-e796-4a80-9688-b201f72d30a8.jpg\" width=\"500\" height=\"751\"><br></p><p>在光线充足的环境下，快门并不是一个很重要的问题，拍摄静止人像的时候，在安全快门以上就可以，但是如果想要拍摄运动中的人像，就得提高快门速度，如果是弱光环境，会比较难办，只能通过开大光圈或者增加感光度来解决。但是有的时候即使光圈开到最大也不足以满足快门，感光度拉的太高又会影响画质，因此在弱光环境下拍摄还是要多试验，根据现场光线来选择最合适的设置以免拍出自己并不满意的照片。</p><p>虽然在弱光环境下并不容易捕捉高速运动中的人，但是我们也可以利用慢快门来捕捉人物运动的轨迹。思想是活的，就看你能想到什么样的画面，然后用技术去实现它。</p><p><img alt=\"26b20b950f034f488dece6488043af96.jpg\" src=\"/img/large/3e7fc3d0-4b5e-45d4-895e-ecc6a96005df.jpg\" width=\"1080\" height=\"716\"><br></p><p>而感光度则是一个更加单纯的因素，每一台相机的高感的处理能力都不同，有些相机可以使用高达 6400 的感光度也能够拍出让自己满意的画面，而有些相机感光度超过 1600 可能就难以接受。拉高感光度所产生的噪点不同于胶片产生的颗粒，胶片颗粒的规则性会带来一定的美感，而杂乱的噪点只会让人想到古老电视机屏幕上的雪花点，看起来很不舒服。因此，高感的选择取决于你对你自己的相机的理解，在你认为可以接受的高感范围内，选择合适的感光度。</p><p><br></p><p><img alt=\"0905ef1735004c7190e2c1e26cd833ca.jpg\" src=\"/img/large/ef528c18-2546-4936-b267-293c9a6b6628.jpg\" width=\"605\" height=\"800\"><br></p><p><br></p><p><br></p><p><br></p><p>[转自：<a href=\"https://www.sohu.com/a/255093120_99931854\">https://www.sohu.com/a/255093120_99931854</a> ]</p>","excerpt":"所谓人像摄影，就是以人物为主要创作对象的摄影形式。人像摄影与一般的人物摄影不同：人像摄影以刻画与表现被摄者的具体相貌和神态为自身的首要创作任务，虽然有些人像摄影作品也包含一定的情节，但它仍以表现被照者的相貌为主。那么，我们今天来讨论下人像的相机参数吧！标准的人像摄影镜头，一般是指在镜头1.5m—2m的距离上照人的镜头，也就是70mm-135mm的镜头。按照一般的美学观点，在1.5至2米外看一个人的五官是最漂亮的。比方说如果想要拍摄带环境的人像，建议选择 50mm 以下的镜头，而如果想要拍半身以上的肖像照并且有很明显的虚化将主体和背景分离，那么 85mm ","img":["/img/large/6f868e96-67e7-4da0-b92a-56f5dc73ae56.jpg","/img/large/173b8f80-20ea-408f-b160-6ca917f5aa51.jpg","/img/large/6e6aa160-73e0-4d32-a354-b66e55cb5a1a.jpg","/img/large/66db5f18-6bdb-4fd4-b761-26bdda06fd44.jpg","/img/large/93fcfcc0-e796-4a80-9688-b201f72d30a8.jpg","/img/large/3e7fc3d0-4b5e-45d4-895e-ecc6a96005df.jpg","/img/large/ef528c18-2546-4936-b267-293c9a6b6628.jpg"],"title":"单反人像摄影技巧","author":"Sohu","type":"essay","en_gallery":true,"enable":true,"tag":["摄影","人像"],"thumb":["/img/thumb/6f868e96-67e7-4da0-b92a-56f5dc73ae56.jpg","/img/thumb/173b8f80-20ea-408f-b160-6ca917f5aa51.jpg","/img/thumb/6e6aa160-73e0-4d32-a354-b66e55cb5a1a.jpg","/img/thumb/66db5f18-6bdb-4fd4-b761-26bdda06fd44.jpg","/img/thumb/93fcfcc0-e796-4a80-9688-b201f72d30a8.jpg","/img/thumb/3e7fc3d0-4b5e-45d4-895e-ecc6a96005df.jpg","/img/thumb/ef528c18-2546-4936-b267-293c9a6b6628.jpg"],"mid":["/img/mid/6f868e96-67e7-4da0-b92a-56f5dc73ae56.jpg","/img/mid/173b8f80-20ea-408f-b160-6ca917f5aa51.jpg","/img/mid/6e6aa160-73e0-4d32-a354-b66e55cb5a1a.jpg","/img/mid/66db5f18-6bdb-4fd4-b761-26bdda06fd44.jpg","/img/mid/93fcfcc0-e796-4a80-9688-b201f72d30a8.jpg","/img/mid/3e7fc3d0-4b5e-45d4-895e-ecc6a96005df.jpg","/img/mid/ef528c18-2546-4936-b267-293c9a6b6628.jpg"],"raw":["/img/6f868e96-67e7-4da0-b92a-56f5dc73ae56.jpg","/img/173b8f80-20ea-408f-b160-6ca917f5aa51.jpg","/img/6e6aa160-73e0-4d32-a354-b66e55cb5a1a.jpg","/img/66db5f18-6bdb-4fd4-b761-26bdda06fd44.jpg","/img/93fcfcc0-e796-4a80-9688-b201f72d30a8.jpg","/img/3e7fc3d0-4b5e-45d4-895e-ecc6a96005df.jpg","/img/ef528c18-2546-4936-b267-293c9a6b6628.jpg"],"createdAt":"2020-05-07T06:25:49.545Z","updatedAt":"2020-05-07T06:25:49.545Z","pv_count":2017,"id":"5eb3a9ed82b94de52f13b5fd"},{"content":"<h1><span style=\"color: rgb(51, 51, 51);\"><br></span></h1><h1><span style=\"color: rgb(51, 51, 51);\">转自：<a taget=\"_blank\" href=\"http://www.ruanyifeng.com/blog/2015/09/web-page-performance-in-depth.html\" rel=\"nofollow\">http://www.ruanyifeng.com/blog/2015/09/web-page-performance-in-depth.html</a></span><br></h1><p>作者： 阮一峰&nbsp;<br></p><p><br></p><p><br></p><p>你遇到过性能很差的网页吗？</p><p>这种网页响应非常缓慢，占用大量的CPU和内存，浏览起来常常有卡顿，页面的动画效果也不流畅。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091508.jpg\" alt=\"\"></p><p>你会有什么反应？我猜想，大多数用户会关闭这个页面，改为访问其他网站。作为一个开发者，肯定不愿意看到这种情况，那么怎样才能提高性能呢？</p><p>本文将详细介绍性能问题的出现原因，以及解决方法。</p><h2>一、网页生成的过程</h2><p>要理解网页性能为什么不好，就要了解网页是怎么生成的。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091501.png\" alt=\"\"></p><p>网页的生成过程，大致可以分成五步。</p><blockquote><ol><li>HTML代码转化成DOM</li><li>CSS代码转化成CSSOM（CSS Object Model）</li><li>结合DOM和CSSOM，生成一棵渲染树（包含每个节点的视觉信息）</li><li>生成布局（layout），即将所有渲染树的所有节点进行平面合成</li><li>将布局绘制（paint）在屏幕上</li></ol></blockquote><p>这五步里面，第一步到第三步都非常快，耗时的是第四步和第五步。</p><p>\"生成布局\"（flow）和\"绘制\"（paint）这两步，合称为\"渲染\"（render）。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091502.png\" alt=\"\"></p><h2>二、重排和重绘</h2><p>网页生成的时候，至少会渲染一次。用户访问的过程中，还会不断重新渲染。</p><p>以下三种情况，会导致网页重新渲染。</p><blockquote><ul><li>修改DOM</li><li>修改样式表</li><li>用户事件（比如鼠标悬停、页面滚动、输入框键入文字、改变窗口大小等等）</li></ul></blockquote><p>重新渲染，就需要重新生成布局和重新绘制。前者叫做\"重排\"（reflow），后者叫做\"重绘\"（repaint）。</p><p>需要注意的是，\"重绘\"不一定需要\"重排\"，比如改变某个网页元素的颜色，就只会触发\"重绘\"，不会触发\"重排\"，因为布局没有改变。但是，\"重排\"必然导致\"重绘\"，比如改变一个网页元素的位置，就会同时触发\"重排\"和\"重绘\"，因为布局改变了。</p><h2>三、对于性能的影响</h2><p>重排和重绘会不断触发，这是不可避免的。但是，它们非常耗费资源，是导致网页性能低下的根本原因。</p><p>提高网页性能，就是要降低\"重排\"和\"重绘\"的频率和成本，尽量少触发重新渲染。</p><p>前面提到，DOM变动和样式变动，都会触发重新渲染。但是，浏览器已经很智能了，会尽量把所有的变动集中在一起，排成一个队列，然后一次性执行，尽量避免多次重新渲染。</p><blockquote><p><br></p><pre><code>div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>color <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'blue'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\ndiv<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>marginTop <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'30px'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面代码中，div元素有两个样式变动，但是浏览器只会触发一次重排和重绘。</p><p>如果写得不好，就会触发两次重排和重绘。</p><blockquote><p><br></p><pre><code class=\"lang-js\">div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>color <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'blue'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> margin <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">parseInt<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>marginTop<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\ndiv<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>marginTop <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>margin <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'px'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面代码对div元素设置背景色以后，第二行要求浏览器给出该元素的位置，所以浏览器不得不立即重排。</p><p>一般来说，样式的写操作之后，如果有下面这些属性的读操作，都会引发浏览器立即重新渲染。</p><blockquote><ul><li>offsetTop/offsetLeft/offsetWidth/offsetHeight</li><li>scrollTop/scrollLeft/scrollWidth/scrollHeight</li><li>clientTop/clientLeft/clientWidth/clientHeight</li><li>getComputedStyle()</li></ul></blockquote><p>所以，从性能角度考虑，尽量不要把读操作和写操作，放在一个语句里面。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token comment\" spellcheck=\"true\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: slategray;\">\n// bad\n</span>div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>offsetLeft <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\ndiv<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>top <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>offsetTop <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token comment\" spellcheck=\"true\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: slategray;\">\n// good\n</span><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>offsetLeft<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> top  <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>offsetTop<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\ndiv<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\ndiv<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>top <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> top <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>一般的规则是：</p><blockquote><ul><li>样式表越简单，重排和重绘就越快。</li><li>重排和重绘的DOM元素层级越高，成本就越高。</li><li>table元素的重排和重绘成本，要高于div元素</li></ul></blockquote><h2>四、提高性能的九个技巧</h2><p>有一些技巧，可以降低浏览器重新渲染的频率和成本。</p><p>第一条是上一节说到的，DOM 的多个读操作（或多个写操作），应该放在一起。不要两个读操作之间，加入一个写操作。</p><p>第二条，如果某个样式是通过重排得到的，那么最好缓存结果。避免下一次用到的时候，浏览器又要重排。</p><p>第三条，不要一条条地改变样式，而要通过改变class，或者csstext属性，一次性地改变样式。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token comment\" spellcheck=\"true\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: slategray;\">\n// bad\n</span><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> top <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">10</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\nel<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\nel<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>top  <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> top  <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token comment\" spellcheck=\"true\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: slategray;\">\n// good \n</span>el<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>className <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span><span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\" theclassname\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token comment\" spellcheck=\"true\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: slategray;\">\n// good\n</span>el<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>cssText <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span><span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"; left: \"</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> left <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px; top: \"</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> top <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"px;\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>第四条，尽量使用离线DOM，而不是真实的网面DOM，来改变元素样式。比如，操作Document Fragment对象，完成后再把这个对象加入DOM。再比如，使用 cloneNode() 方法，在克隆的节点上进行操作，然后再用克隆的节点替换原始节点。</p><p>第五条，先将元素设为<code>display: none</code>（需要1次重排和重绘），然后对这个节点进行100次操作，最后再恢复显示（需要1次重排和重绘）。这样一来，你就用两次重新渲染，取代了可能高达100次的重新渲染。</p><p>第六条，position属性为<code>absolute</code>或<code>fixed</code>的元素，重排的开销会比较小，因为不用考虑它对其他元素的影响。</p><p>第七条，只在必要的时候，才将元素的display属性为可见，因为不可见的元素不影响重排和重绘。另外，<code>visibility : hidden</code>的元素只对重绘有影响，不影响重排。</p><p>第八条，使用虚拟DOM的脚本库，比如React等。</p><p>第九条，使用 window.requestAnimationFrame()、window.requestIdleCallback() 这两个方法调节重新渲染（详见后文）。</p><h2>五、刷新率</h2><p>很多时候，密集的重新渲染是无法避免的，比如scroll事件的回调函数和网页动画。</p><p>网页动画的每一帧（frame）都是一次重新渲染。每秒低于24帧的动画，人眼就能感受到停顿。一般的网页动画，需要达到每秒30帧到60帧的频率，才能比较流畅。如果能达到每秒70帧甚至80帧，就会极其流畅。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091509.jpg\" alt=\"\"></p><p>大多数显示器的刷新频率是60Hz，为了与系统一致，以及节省电力，浏览器会自动按照这个频率，刷新动画（如果可以做到的话）。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091510.jpg\" alt=\"\"></p><p>所以，如果网页动画能够做到每秒60帧，就会跟显示器同步刷新，达到最佳的视觉效果。这意味着，一秒之内进行60次重新渲染，每次重新渲染的时间不能超过16.66毫秒。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091511.png\" alt=\"\"></p><p>一秒之间能够完成多少次重新渲染，这个指标就被称为\"刷新率\"，英文为FPS（frame per second）。60次重新渲染，就是60FPS。</p><p>如果想达到60帧的刷新率，就意味着JavaScript线程每个任务的耗时，必须少于16毫秒。一个解决办法是使用Web Worker，主线程只用于UI渲染，然后跟UI渲染不相干的任务，都放在Worker线程。</p><h2>六、开发者工具的Timeline面板</h2><p>Chrome浏览器开发者工具的Timeline面板，是查看\"刷新率\"的最佳工具。这一节介绍如何使用这个工具。</p><p>首先，按下 F12 打开\"开发者工具\"，切换到Timeline面板。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091512.png\" alt=\"\"></p><p>左上角有一个灰色的圆点，这是录制按钮，按下它会变成红色。然后，在网页上进行一些操作，再按一次按钮完成录制。</p><p>Timeline面板提供两种查看方式：横条的是\"事件模式\"（Event Mode），显示重新渲染的各种事件所耗费的时间；竖条的是\"帧模式\"（Frame Mode），显示每一帧的时间耗费在哪里。</p><p>先看\"事件模式\"，你可以从中判断，性能问题发生在哪个环节，是JavaScript的执行，还是渲染？</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091514.png\" alt=\"\"></p><p>不同的颜色表示不同的事件。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091503.png\" alt=\"\"></p><blockquote><ul><li>蓝色：网络通信和HTML解析</li><li>黄色：JavaScript执行</li><li>紫色：样式计算和布局，即重排</li><li>绿色：重绘</li></ul></blockquote><p>哪种色块比较多，就说明性能耗费在那里。色块越长，问题越大。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091515.png\" alt=\"\"></p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091516.png\" alt=\"\"></p><p>帧模式（Frames mode）用来查看单个帧的耗时情况。每帧的色柱高度越低越好，表示耗时少。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091505.png\" alt=\"\"></p><p>你可以看到，帧模式有两条水平的参考线。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091517.png\" alt=\"\"></p><p>下面的一条是60FPS，低于这条线，可以达到每秒60帧；上面的一条是30FPS，低于这条线，可以达到每秒30次渲染。如果色柱都超过30FPS，这个网页就有性能问题了。</p><p>此外，还可以查看某个区间的耗时情况。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091518.png\" alt=\"\"></p><p>或者点击每一帧，查看该帧的时间构成。</p><p><img src=\"http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091519.png\" alt=\"\"></p><h2>七、window.requestAnimationFrame()</h2><p>有一些JavaScript方法可以调节重新渲染，大幅提高网页性能。</p><p>其中最重要的，就是 window.requestAnimationFrame() 方法。它可以将某些代码放到下一次重新渲染时执行。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span> <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">doubleHeight<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>element<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n  <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> currentHeight <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> element<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>clientHeight<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  element<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>height <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>currentHeight <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">*</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">2</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'px'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span>\nelements<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">forEach<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>doubleHeight<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面的代码使用循环操作，将每个元素的高度都增加一倍。可是，每次循环都是，读操作后面跟着一个写操作。这会在短时间内触发大量的重新渲染，显然对于网页性能很不利。</p><p>我们可以使用<code>window.requestAnimationFrame()</code>，让读操作和写操作分离，把所有的写操作放到下一次重新渲染。</p><blockquote><p><br></p><pre><code><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span> <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">doubleHeight<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>element<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n  <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> currentHeight <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> element<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>clientHeight<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  window<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestAnimationFrame<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n    element<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>height <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>currentHeight <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">*</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">2</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'px'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span>\nelements<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">forEach<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>doubleHeight<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>页面滚动事件（scroll）的监听函数，就很适合用 window.requestAnimationFrame() ，推迟到下一次重新渲染。</p><blockquote><p><br></p><pre><code>$<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>window<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">on<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'scroll'</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">,</span> <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n   window<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestAnimationFrame<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>scrollHandler<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>当然，最适用的场合还是网页动画。下面是一个旋转动画的例子，元素每一帧旋转1度。</p><blockquote><p><br></p><pre><code><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> rAF <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> window<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>requestAnimationFrame<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n\n<span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">var</span> degrees <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">0</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span> <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">update<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n  div<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>style<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>transform <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"rotate(\"</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> degrees <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">\"deg)\"</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  console<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">log<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token string\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(102, 153, 0);\">'updated to degrees '</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> degrees<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  degrees <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">=</span> degrees <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">+</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">1</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">rAF<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>update<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span>\n<span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">rAF<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>update<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><h2><br></h2><h2><br></h2><h2>八、window.requestIdleCallback()</h2><p>还有一个函数<a href=\"https://w3c.github.io/requestidlecallback/\" target=\"_blank\">window.requestIdleCallback()</a>，也可以用来调节重新渲染。</p><p>它指定只有当一帧的末尾有空闲时间，才会执行回调函数。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestIdleCallback<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>fn<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面代码中，只有当前帧的运行时间小于16.66ms时，函数fn才会执行。否则，就推迟到下一帧，如果下一帧也没有空闲时间，就推迟到下下一帧，以此类推。</p><p>它还可以接受第二个参数，表示指定的毫秒数。如果在指定 的这段时间之内，每一帧都没有空闲时间，那么函数fn将会强制执行。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestIdleCallback<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>fn<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">,</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">5000</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面的代码表示，函数fn最迟会在5000毫秒之后执行。</p><p>函数 fn 可以接受一个 deadline 对象作为参数。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestIdleCallback<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span> <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">someHeavyComputation<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>deadline<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n  <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">while</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>deadline<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">timeRemaining<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">&gt;</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">0</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n    <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">doWorkIfNeeded<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span>\n\n  <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">if</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>thereIsMoreWorkToDo<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n    <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestIdleCallback<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>someHeavyComputation<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n  <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span>\n<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面代码中，回调函数 someHeavyComputation 的参数是一个 deadline 对象。</p><p>deadline对象有一个方法和一个属性：timeRemaining() 和 didTimeout。</p><p><br></p><p>（1）timeRemaining() 方法</p><p>timeRemaining() 方法返回当前帧还剩余的毫秒。这个方法只能读，不能写，而且会动态更新。因此可以不断检查这个属性，如果还有剩余时间的话，就不断执行某些任务。一旦这个属性等于0，就把任务分配到下一轮<code>requestIdleCallback</code>。</p><p>前面的示例代码之中，只要当前帧还有空闲时间，就不断调用doWorkIfNeeded方法。一旦没有空闲时间，但是任务还没有全执行，就分配到下一轮<code>requestIdleCallback</code>。</p><p><br></p><p>（2）didTimeout属性</p><p>deadline对象的&nbsp;<code>didTimeout</code>&nbsp;属性会返回一个布尔值，表示指定的时间是否过期。这意味着，如果回调函数由于指定时间过期而触发，那么你会得到两个结果。</p><blockquote><ul><li>timeRemaining方法返回0</li><li>didTimeout 属性等于 true</li></ul></blockquote><p>因此，如果回调函数执行了，无非是两种原因：当前帧有空闲时间，或者指定时间到了。</p><blockquote><p><br></p><pre><code class=\"lang-js\"><span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">function</span> myNonEssentialWork <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>deadline<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">{</span>\n  <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">while</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>deadline<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span><span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">timeRemaining<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">&gt;</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">0</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">||</span> deadline<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>didTimeout<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span> <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">&amp;&amp;</span> tasks<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>length <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">&gt;</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">0</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span>\n    <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">doWorkIfNeeded<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n\n  <span class=\"token keyword\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(0, 119, 170);\">if</span> <span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span>tasks<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">.</span>length <span class=\"token operator\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(166, 127, 89); background: rgba(255, 255, 255, 0.498039);\">&gt;</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">0</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span>\n    <span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestIdleCallback<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>myNonEssentialWork<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">}</span>\n\n<span class=\"token function\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(17, 17, 17);\">requestIdleCallback<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">(</span></span>myNonEssentialWork<span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">,</span> <span class=\"token number\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 0, 85);\">5000</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">)</span><span class=\"token punctuation\" style=\"margin: 0px; padding: 0px; list-style-type: none; border: none; color: rgb(153, 153, 153);\">;</span>\n</code></pre><p><br></p></blockquote><p>上面代码确保了，doWorkIfNeeded 函数一定会在将来某个比较空闲的时间（或者在指定时间过期后）得到反复执行。</p><p>requestIdleCallback 是一个很新的函数，刚刚引入标准，目前只有Chrome支持，不过其他浏览器可以用<a href=\"https://gist.github.com/paullewis/55efe5d6f05434a96c36\" target=\"_blank\">垫片库</a>。</p><h2><br></h2><h2><br></h2><h2>九、参考链接</h2><ul><li>Domenico De Felice,&nbsp;<a href=\"http://domenicodefelice.blogspot.sg/2015/08/how-browsers-work.html\" target=\"_blank\">How browsers work</a></li><li>Stoyan Stefanov,&nbsp;<a href=\"http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/\" target=\"_blank\">Rendering: repaint, reflow/relayout, restyle</a></li><li>Addy Osmani,&nbsp;<a href=\"http://addyosmani.com/blog/performance-optimisation-with-timeline-profiles/\" target=\"_blank\">Improving Web App Performance With the Chrome DevTools Timeline and Profiles</a></li><li>Tom Wiltzius,&nbsp;<a href=\"http://www.html5rocks.com/en/tutorials/speed/rendering/\" target=\"_blank\">Jank Busting for Better Rendering Performance</a></li><li>Paul Lewis,&nbsp;<a href=\"https://developers.google.com/web/updates/2015/08/27/using-requestidlecallback?hl=en\" target=\"_blank\">Using requestIdleCallback</a></li></ul><p>（完）</p>","excerpt":"转自：http://www.ruanyifeng.com/blog/2015/09/web-page-performance-in-depth.html作者： 阮一峰 你遇到过性能很差的网页吗？这种网页响应非常缓慢，占用大量的CPU和内存，浏览起来常常有卡顿，页面的动画效果也不流畅。你会有什么反应？我猜想，大多数用户会关闭这个页面，改为访问其他网站。作为一个开发者，肯定不愿意看到这种情况，那么怎样才能提高性能呢？本文将详细介绍性能问题的出现原因，以及解决方法。一、网页生成的过程要理解网页性能为什么不好，就要了解网页是怎么生成的。网页的生成过程，大致可以分","img":["http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091508.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091501.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091502.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091509.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091510.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091511.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091512.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091514.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091503.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091515.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091516.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091505.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091517.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091518.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091519.png"],"title":"网页性能管理详解","author":"阮一峰 ","type":"tech","en_gallery":false,"enable":true,"tag":["前端","Web"],"thumb":["http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091508.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091501.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091502.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091509.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091510.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091511.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091512.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091514.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091503.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091515.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091516.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091505.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091517.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091518.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091519.png"],"mid":["http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091508.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091501.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091502.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091509.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091510.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091511.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091512.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091514.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091503.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091515.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091516.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091505.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091517.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091518.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091519.png"],"raw":["http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091508.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091501.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091502.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091509.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091510.jpg","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091511.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091512.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091514.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091503.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091515.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091516.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091505.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091517.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091518.png","http://www.ruanyifeng.com/blogimg/asset/2015/bg2015091519.png"],"createdAt":"2015-12-05T05:08:25.460Z","updatedAt":"2015-12-05T05:11:48.574Z","pv_count":1902,"article_id":"56627149dbde3d97180380d3","id":"56627149dbde3d97180380d3"}]}