<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.7.3">Jekyll</generator><link href="https://andrewuetyang.github.io/myGitBlog/feed.xml" rel="self" type="application/atom+xml" /><link href="https://andrewuetyang.github.io/myGitBlog/" rel="alternate" type="text/html" /><updated>2018-06-06T22:43:58+08:00</updated><id>https://andrewuetyang.github.io/myGitBlog/</id><title type="html">知晓</title><subtitle>写博客，是学习的一种方式，通过写作，回顾知识，提炼精华，理清思绪。所以，我的博客跟随者这样的精神，诞生了。
</subtitle><author><name>杨峰</name><uri></uri></author><entry><title type="html">git代码托管服务之码云其实也不错</title><link href="https://andrewuetyang.github.io/myGitBlog/front-end/gitee/" rel="alternate" type="text/html" title="git代码托管服务之码云其实也不错" /><published>2018-05-06T15:32:00+08:00</published><updated>2018-05-06T15:32:00+08:00</updated><id>https://andrewuetyang.github.io/myGitBlog/front-end/gitee</id><content type="html" xml:base="https://andrewuetyang.github.io/myGitBlog/front-end/gitee/">&lt;h2 id=&quot;被我忽视的代码托管gitee码云&quot;&gt;被我忽视的代码托管gitee码云&lt;/h2&gt;

&lt;p&gt;其实在2015年码云这个词出来的时候，就大概知道它是干嘛的，但是，也许是高度跟马云爸爸重名的原因吧，很是避讳，而且当时github作为业界的标杆，无论是成熟度还是知名度都不是后来者码云能比的，所以也就没有去使用这个产品。为什么现在开始要使用了呢？原因如下：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;网速&lt;/li&gt;
  &lt;li&gt;网速&lt;/li&gt;
  &lt;li&gt;网速&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;总要的事情说三遍。。。其实还有其他原因，是因为码云的功能也对标github了，提供的定制服务也想当健全了，虽然对我来说我还没用上（笑），但是有一个很重要的东西，不能没有。之前一直忽视码云，感觉身边人用的也少，一不小心错过了它发展的新闻，竟然最近才得知，码云其实也支持pages功能，虽然人家在2016年就开始提供这个服务了。（笑哭）&lt;/p&gt;

&lt;h2 id=&quot;不想放弃github也想托管码云怎么办&quot;&gt;不想放弃github也想托管码云，怎么办&lt;/h2&gt;

&lt;p&gt;码云是后来者，所以提供了一个可以导入项目的功能，这个可以直接将github上的代码同步到码云上来，很方便。然后就是在本地开发，想要同步两个仓库的问题。以前，我们没有这个问题，我们直接是一个远程origin，这一套玩儿法我们已经很熟悉了，那再来一个仓库，要怎么同时同步呢？答案对于超级熟悉git的人来说应该很容易，但是很多人是只是熟悉普通的git命令, 大家通常是去百度或者google，其实我也是（笑），嘿嘿。百度之后，就知道，一个本地git项目其实是很容易可以添加两个甚至多个远程仓库的，命令为&lt;code class=&quot;highlighter-rouge&quot;&gt;git remote add [name_your_remote_channel] master&lt;/code&gt;。&lt;/p&gt;

&lt;h2 id=&quot;说说码云的pages功能&quot;&gt;说说码云的pages功能&lt;/h2&gt;

&lt;p&gt;码云的pages功能相比于github的pages功能，对于我们国内来说有，那速度就爽翻了，个人展示类项目和博客，打开速度从此告别2G时代，很爽。&lt;/p&gt;</content><author><name>杨峰</name></author><category term="front-end" /><summary type="html">被我忽视的代码托管gitee码云</summary></entry><entry><title type="html">对PWA(Progressive Web Application)的认识</title><link href="https://andrewuetyang.github.io/myGitBlog/front-end/pwa/" rel="alternate" type="text/html" title="对PWA(Progressive Web Application)的认识" /><published>2018-01-29T10:32:00+08:00</published><updated>2018-01-29T10:32:00+08:00</updated><id>https://andrewuetyang.github.io/myGitBlog/front-end/pwa</id><content type="html" xml:base="https://andrewuetyang.github.io/myGitBlog/front-end/pwa/">&lt;h2 id=&quot;前言&quot;&gt;前言&lt;/h2&gt;
&lt;p&gt;时间大概是在2016年，google推出了PWA技术，旨在提升web app的用户体验, 总体来说，这个技术将会对web应用的普及及市场占有率推向新的高潮，它的意义是非凡的，可以说是下一代的web应用模型。下面简要罗列一下我对web app的劣势和优势的认识，来一窥PWA技术是如何弥补web app的不足的。&lt;/p&gt;

&lt;h2 id=&quot;web-app的优势&quot;&gt;web app的优势&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;轻量，不用下载&lt;/li&gt;
  &lt;li&gt;开发成本低&lt;/li&gt;
  &lt;li&gt;跨平台能力强&lt;/li&gt;
  &lt;li&gt;用户获取成本低&lt;/li&gt;
  &lt;li&gt;迭代快
…&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;web-app的劣势&quot;&gt;web app的劣势&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;体验较native app弱（离线体验，动效，消息推送等）&lt;/li&gt;
  &lt;li&gt;无一级入口（native级别的入口）
…&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;google的pwa技术&quot;&gt;google的PWA技术&lt;/h2&gt;
&lt;p&gt;针对web应用比较大的两个劣势，google推出了自己的解决方案——PWA技术。PWA技术主要分两个方面，分别针对以上分析的web app的劣势。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;用service-worker技术来弥补离线体验和消息推送方面的劣势&lt;/li&gt;
  &lt;li&gt;用manifest.json的实现，使得web app可以添加到系统桌面并以native app一样有全局窗口，而不是打开浏览器的体验&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;最后&quot;&gt;最后&lt;/h2&gt;
&lt;p&gt;这里对于PWA应用的实现，我就不做介绍了，因为官网文档实在是太细致了，跟着官网的教程，你绝对能实现一个PWA应用，并对其有一定的认识，比各种百度google要强很多（亲身体验…）。&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://codelabs.developers.google.com/codelabs/your-first-pwapp/#0&quot;&gt;google PWA 教程&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://andrewuet.gitbooks.io/pwa-tutorial-translate2chinese/content/&quot;&gt;我翻译的google PWA教程&lt;/a&gt;&lt;/p&gt;</content><author><name>杨峰</name></author><category term="front-end" /><summary type="html">前言 时间大概是在2016年，google推出了PWA技术，旨在提升web app的用户体验, 总体来说，这个技术将会对web应用的普及及市场占有率推向新的高潮，它的意义是非凡的，可以说是下一代的web应用模型。下面简要罗列一下我对web app的劣势和优势的认识，来一窥PWA技术是如何弥补web app的不足的。</summary></entry><entry><title type="html">使用nodeJS来做一个cli工具</title><link href="https://andrewuetyang.github.io/myGitBlog/os/node-cli/" rel="alternate" type="text/html" title="使用nodeJS来做一个cli工具" /><published>2018-01-11T09:42:00+08:00</published><updated>2018-01-11T09:42:00+08:00</updated><id>https://andrewuetyang.github.io/myGitBlog/os/node-cli</id><content type="html" xml:base="https://andrewuetyang.github.io/myGitBlog/os/node-cli/">&lt;h2 id=&quot;前言&quot;&gt;前言&lt;/h2&gt;

&lt;p&gt;nodeJS是javascript的一个运行环境，是基于chrome v8引擎的封装，由于其具备的一些优点，使得它极大延伸了javascript的用武之地，本篇文章就是探索实现一个基于nodeJS环境的cli工具。&lt;/p&gt;

&lt;h2 id=&quot;准备工作&quot;&gt;准备工作&lt;/h2&gt;

&lt;p&gt;安装nodeJS（此处省略100字…）&lt;/p&gt;

&lt;h2 id=&quot;撸代码&quot;&gt;撸代码&lt;/h2&gt;

&lt;p&gt;代码没啥好说的，你想实现怎样的一个cli工具，你就使用nodeJS相应的api去封装，去实现功能，唯一额外需要注意以下跟代码不太相关的东西：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;由于是使用node作为运行环境，因此命令行工具执行文件头部需要指明环境，一般为：&lt;code class=&quot;highlighter-rouge&quot;&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/usr/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;node&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;cli工具需要全局使用或者供他人使用，你需要按照npm包的编写规则来组织代码结构，包的规则最基本的是，你需要有一个package.json的文件，及一个bin目录，package.json对bin目录需要进行描述，其描述的键值对中，键会在发布后作为cli命令的关键字，值即为cli命令指向运行的js脚本。具体示例如下：&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
&quot;bin&quot;: {
  &quot;cli-command-name&quot;: &quot;bin/index.js&quot;
}
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;编写过程需要注意，如果需要给不同操作系统用，需要注意windows与unix的会有差别。一般来说unix系统上编写的cli命令可在windows上运行，而在windows上编写的cli命令工具，在unix系统上会报错&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;cli命令最好不要与npm包中其他已发布的包重名，可以先去npm官网去搜下&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;编写命令行cli工具可以借助一个第三方库commander.js&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;在发布前，可以先使用&lt;code class=&quot;highlighter-rouge&quot;&gt;npm link&lt;/code&gt;将包内容发布到本机全局部署，然后就可以在本机上使用该cli命令&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;发布后给人使用的系统中，请务必保证有nodeJS环境，否则无法生效&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;发布&quot;&gt;发布&lt;/h2&gt;

&lt;p&gt;首先，你需要一个npm账号；然后就是简单的一些操作命令，如&lt;code class=&quot;highlighter-rouge&quot;&gt;npm login&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;npm publish&lt;/code&gt;。此时发布的代码只是在npm托管的，如果你想把代码开源托管在github上，你需要自己上传到github上，同时你可能注意到，其他很多npm包都有链接跳转到github的开源代码处，如果你熟悉package.json文件的配置和npm官网的显示规则，就会知道，你需要再package.json中加入一段如下代码：&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;repository&quot;: {
  &quot;type&quot;: &quot;git&quot;,
  &quot;url&quot;: &quot;git+https://github.com/Andrewuetyang/rname-cli.git&quot; // git + 后面是你的npm包在github上的托管位置
},
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;另外发布过程中，可能会遇到发布不成功报403，这极有可能是因为npm注册是淘宝镜像，需要切换回原地址。&lt;/p&gt;

&lt;h2 id=&quot;最后&quot;&gt;最后&lt;/h2&gt;

&lt;p&gt;嘿嘿，自己在学习这个后，我的第一个cli工具是写了一个可以批量重命名文件名的工具，由于这种工具已经很多了，所以关键字被占用了，只能取了一个rname-cli这样的命令名字，吨吨吨…自己写的cli符合自己的使用习惯，是的，虽然有很多这种rename工具，但是不喜欢他们的规则，自己写的用的很爽。&lt;/p&gt;</content><author><name>杨峰</name></author><category term="os" /><summary type="html">前言</summary></entry><entry><title type="html">webpack2及以上的tree-shaking功能探索</title><link href="https://andrewuetyang.github.io/myGitBlog/front-end/webpack-tree-shaking/" rel="alternate" type="text/html" title="webpack2及以上的tree-shaking功能探索" /><published>2018-01-05T21:00:00+08:00</published><updated>2018-01-05T21:00:00+08:00</updated><id>https://andrewuetyang.github.io/myGitBlog/front-end/webpack-tree-shaking</id><content type="html" xml:base="https://andrewuetyang.github.io/myGitBlog/front-end/webpack-tree-shaking/">&lt;h2 id=&quot;从很容易就会思考的一个问题开始&quot;&gt;从很容易就会思考的一个问题开始&lt;/h2&gt;

&lt;p&gt;以下代码是es6语法关于模块导入的，当我们使用webpack打包的时候，很自然会想到这个打包过程是将整个模块打包进来还是我要用的即引入的部分打包进来呢？&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;import { a } from './module'

a()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;在webpack1的时候，这个打包过程是将整个模块打包进来，不管你这个文件使用了模块多少的代码。显然，这是不合理的，理想情况，我们更愿意见到使用的部分打包进来，其余部分最好给我们清理掉，打包一堆没用的东西进来，占用了bundle的体积。据说最开始，rollup.js(前端打包工具，跟webpack是同类型产品)，实现了这个功能，并起了一个非常形象的名词，叫tree-shaking。webpack2开始，也加入了这个功能。&lt;/p&gt;

&lt;h2 id=&quot;那么webpack的tree-shaking要如何开启呢&quot;&gt;那么webpack的tree-shaking要如何开启呢？&lt;/h2&gt;

&lt;p&gt;其实很简单，需要有几个前提条件：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;webpack2.0及以上&lt;/li&gt;
  &lt;li&gt;使用了es6的模块语法导出导入&lt;/li&gt;
  &lt;li&gt;使用了uglifyJS压等压缩工具压缩代码&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;发现的问题&quot;&gt;发现的问题&lt;/h2&gt;

&lt;p&gt;以上是网上说的比较多的，但是本人在使用过程中发现，还需要注意一个细节，那就是在配置babelrc（指所有配置babel的配置，其他可配置babel的地方如webpack配置babel-loader的options，还有package.json）时虽然可以归并到第一个前提条件，但是容易被忽略。&lt;/p&gt;

&lt;p&gt;这个细节就是，配置presets时，一定要将modules设置为false，这个如果没设置，就没卵用，作者亲身体会。现在看看，这个设置理所当然，因为即使你使用了es6的语法来处理模块，在没设置这个参数时，默认是true，也就是默认将es6等的语法转换成common.js。&lt;/p&gt;

&lt;p&gt;下面用实验代码来证实一下吧。（本次使用webpack3）&lt;/p&gt;

&lt;h2 id=&quot;没有配置modules为false即modules默认值为true&quot;&gt;没有配置modules为false即modules默认值为true&lt;/h2&gt;

&lt;p&gt;index.js文件代码&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;import { a } from './module'

a()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;module.js文件代码&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;export function a() {
  console.log('a');
}

export function b() {
  console.log('b');
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;webpack.config.js文件代码&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;const path = require('path')
const webpack = require('webpack')

module.exports = {
  entry: path.resolve(__dirname, 'index'),
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].bundle.js'
  },
  module: {
    rules: [{
      test: /\.js$/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['env']
        }
      }
    }]
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin()
  ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;打包得到的文件index.bundle.js代码，注意，此时打包的文件里面是可以查到有关b函数的定义的，并没有shaking掉。&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;!function(n){function e(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return n[o].call(r.exports,r,r.exports,e),r.l=!0,r.exports}var t={};e.m=n,e.c=t,e.i=function(n){return n},e.d=function(n,t,o){e.o(n,t)||Object.defineProperty(n,t,{configurable:!1,enumerable:!0,get:o})},e.n=function(n){var t=n&amp;amp;&amp;amp;n.__esModule?function(){return n.default}:function(){return n};return e.d(t,&quot;a&quot;,t),t},e.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},e.p=&quot;&quot;,e(e.s=1)}([function(n,e,t){&quot;use strict&quot;;function o(){console.log(&quot;a&quot;)}function r(){console.log(&quot;b&quot;)}Object.defineProperty(e,&quot;__esModule&quot;,{value:!0}),e.a=o,e.b=r},function(n,e,t){&quot;use strict&quot;;(0,t(0).a)()}]);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;配置modules为false&quot;&gt;配置modules为false&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;对webpack.config.js的配置更改部分&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;options: {
  presets: [
    ['env', {modules: false}]
  ]
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;打包结果—无b函数定义&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;!function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var n={};t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&amp;amp;&amp;amp;e.__esModule?function(){return e.default}:function(){return e};return t.d(n,&quot;a&quot;,n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p=&quot;&quot;,t(t.s=1)}([function(e,t,n){&quot;use strict&quot;;function r(){console.log(&quot;a&quot;)}t.a=r},function(e,t,n){&quot;use strict&quot;;Object.defineProperty(t,&quot;__esModule&quot;,{value:!0});var r=n(0);n.i(r.a)()}]);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;完！&lt;/p&gt;</content><author><name>杨峰</name></author><category term="front-end" /><summary type="html">从很容易就会思考的一个问题开始</summary></entry><entry><title type="html">当前阶段对函数式编程的认识感受</title><link href="https://andrewuetyang.github.io/myGitBlog/coding/functional-programming/" rel="alternate" type="text/html" title="当前阶段对函数式编程的认识感受" /><published>2017-12-14T22:00:00+08:00</published><updated>2017-12-14T22:00:00+08:00</updated><id>https://andrewuetyang.github.io/myGitBlog/coding/functional-programming</id><content type="html" xml:base="https://andrewuetyang.github.io/myGitBlog/coding/functional-programming/">&lt;p&gt;废话不多说，直接进入今天的话题，函数式编程。这个名字很高大上，最近几年在编程届也是炙手可热，大家都很推崇。那么问题来了，函数式编程是什么，究竟要解决什么问题，它又有着什么样的思想，是否有缺点呢。&lt;/p&gt;

&lt;h2 id=&quot;什么是函数式编程&quot;&gt;什么是函数式编程？&lt;/h2&gt;

&lt;p&gt;网上一搜，有很多解释：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;函数式编程是种编程方式，它将电脑运算视为函数的计算。函数编程语言最重要的基础是λ演算（lambda calculus），而且λ演算的函数可以接受函数当作输入（参数）和输出（返回值）。和指令式编程相比，函数式编程强调函数的计算比指令的执行重要。和过程化编程相比，函数式编程里函数的计算可随时调用。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;与面向对象编程（Object-oriented programming）和过程式编程（Procedural programming）并列的编程范式。最主要的特征是，函数是第一等公民。最主要的特征是，函数是第一等公民。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;还有非常通俗的认识：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;函数式编程与命令式编程最大的不同其实在于：函数式编程关心数据的映射，命令式编程关心解决问题的步骤，这里的映射就是数学上「函数」的概念——一种东西和另一种东西之间的对应关系。这也是为什么「函数式编程」叫做「函数」式编程。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;嗯，很好，我若有所思的样子。。。额。。。&lt;/p&gt;

&lt;h2 id=&quot;函数式编程的特征&quot;&gt;函数式编程的特征&lt;/h2&gt;

&lt;p&gt;综合所看的一些资料，主要说到关于运算的合成和柯里化。合成即是说一个值需要经过多个函数演变成另一个值，就可以把这些中间步骤的函数合并成一个函数。函数柯里化，形式上来说就是把一个多个参数的函数，转变成一些了单参数的函数。&lt;/p&gt;

&lt;h2 id=&quot;函数式编程想要解决的问题&quot;&gt;函数式编程想要解决的问题&lt;/h2&gt;

&lt;p&gt;综合之前看过的一些资料和自己的一些理解，这个范式其实是想更语义化的用函数而不是指令将计算过程表达出来，这样表现出来的就是一种数据的映射，让人理解起来非常一目了然。这样，计算过程不再杂乱，而是由具体的函数单元，执行一个个具体的计算过程，而不是将一堆计算过程放在一起，代码的阅读和维护性方面会更好。这样演变，如果可能的话（作为一个菜鸡，不确定这个结论，吨吨吨），也许写业务代码就可以利用这些函数库还有更高级的函数库，像人类语言那样的描述，让代码工作起来，岂不快哉。当然，现阶段很难达到。而且个人认为可能永远行不通。因为我算了一笔账（可能不正确，但是whatever），计算过程被函数封装，以最基本的单元，那光是语义化的计算单元封装出来的，应该是一个很大的数字，然后基于这些函数单元合成出来的函数，我了个去，不可想象。&lt;/p&gt;

&lt;p&gt;虽然如此，但我也是矛盾的，诚惶诚恐的。毕竟语言就是这么发展的，从机器二进制码，到晦涩难懂的汇编，再到c这种中级语言，最后到现在大多数程序员在使用的高级语言，让编程变得更加容易。这些都是逐渐变得语义化，借助编译器将计算过程breakdown到底层。还是很期待那一天，使用人类自然语言，控制各种计算过程，人类的能力将无可限量。&lt;/p&gt;</content><author><name>杨峰</name></author><category term="coding" /><summary type="html">废话不多说，直接进入今天的话题，函数式编程。这个名字很高大上，最近几年在编程届也是炙手可热，大家都很推崇。那么问题来了，函数式编程是什么，究竟要解决什么问题，它又有着什么样的思想，是否有缺点呢。</summary></entry><entry><title type="html">Vue SSR学习小结</title><link href="https://andrewuetyang.github.io/myGitBlog/front-end/vue-ssr/" rel="alternate" type="text/html" title="Vue SSR学习小结" /><published>2017-11-26T11:08:00+08:00</published><updated>2017-11-26T11:08:00+08:00</updated><id>https://andrewuetyang.github.io/myGitBlog/front-end/vue-ssr</id><content type="html" xml:base="https://andrewuetyang.github.io/myGitBlog/front-end/vue-ssr/">&lt;h2 id=&quot;前言&quot;&gt;前言&lt;/h2&gt;

&lt;p&gt;ssr即服务器端渲染，是一个有利于SEO，及首屏加载等优势的一种view层的处理。ssr简单来说就是在保持前后端分离的开发模式下，在前后端中间加一个node中间层，在node中间层对页面数据进行组装，即node层去请求后端数据，然后在html模板进行填充，完了之后就返回给客户端。缺点也有，可以参考&lt;a href=&quot;https://ssr.vuejs.org/zh/&quot;&gt;官方文档&lt;/a&gt;。选取时，最好综合考虑。&lt;/p&gt;

&lt;h2 id=&quot;为什么会出现这种技术&quot;&gt;为什么会出现这种技术？&lt;/h2&gt;

&lt;p&gt;当前SPA应用是彻底的将内容变成服务器端的一种服务，后端对于前端来说，就是提供动态数据的服务人员。SPA技术将内容和模板的结合放在浏览器端，内容是通过ajax异步获取的。这样的话，根据搜索引擎原理，必然导致SEO很烂。同时，如果客户端网络环境差，也会延长内容到达时间。SSR就是来解决这个问题的。这项技术已经经过充分实践了，最典型的例子就是手机淘宝app，据淘宝内部团队人员透露，目前手机淘宝app里绝大部分的页面都是SSR技术，即他们口中所说的，在服务器端和客户端之间加一个node中间层来渲染页面，手机淘宝的体验，相信绝大多数中国人都是有体验的，非常完美。&lt;/p&gt;

&lt;h2 id=&quot;核心思想&quot;&gt;核心思想&lt;/h2&gt;

&lt;p&gt;在node层进行内容数据预取，然后在html模板中进行填充，返回客户端进行展示。&lt;/p&gt;

&lt;h2 id=&quot;vue-spa应用的ssr构建&quot;&gt;vue SPA应用的SSR构建&lt;/h2&gt;

&lt;p&gt;将spa应用处理为ssr的模式，还是有很大的复杂性的。当然，社区繁荣一片的现在，你可以使用开源的NUXT.js，来做ssr处理。要想自己有更多的项目结构控制权的话，就需要知道这些东西是怎么根据构建工具串起来的了。在我经过了几天学习官方文档之后，我试着总结一下这个串接过程。在讲述串接过程前，先需要知道vue作者的ssr构建的设计。&lt;/p&gt;

&lt;p&gt;首先顶层上，有1个工具叫vue-server-renderer。这个模块负责支持整个构建过程必要环节的处理。这个工具下，提供了一些模块和api。在一个基本的构建过程中需要用到的有：&lt;/p&gt;

&lt;p&gt;api: createBundleRenderer // 创建renderer，renderer的作用是将vue实例渲染成html&lt;/p&gt;

&lt;p&gt;模块：client-plugin和server-plugin // webpack插件，分别处理客户端打包和服务器端打包&lt;/p&gt;

&lt;p&gt;为了将相同的应用程序提供给客户端，我们使用webpack来打包构建。ssr同样也需要打包构建。因此作者的基本思路就是，对服务器端渲染打包成一个bundle，对客户端程序打包成一个bundle。在客户端发起请求的时候，返回服务器对应的渲染页面和客户端bundle，由于服务器端渲染页面已经留下了静态标记，客户端bundle会识别这个标记，并以混合模式挂载（具体怎么实现的需要去阅读源码）。&lt;/p&gt;

&lt;h2 id=&quot;最后输出应用程序&quot;&gt;最后输出应用程序&lt;/h2&gt;

&lt;p&gt;有了构建工具构建出来的工件，可以进一步输出程序。基本思路是借助createBundleRenderer根据打包好的bundle创建一个renderer，然后在node服务器的帮助下，根据请求路径来确定一个context上下文对象，renderer再依据这个context，返回必要的静态资源给客户端用于展示。&lt;/p&gt;</content><author><name>杨峰</name></author><category term="front-end" /><summary type="html">前言</summary></entry><entry><title type="html">webpack学习再回顾</title><link href="https://andrewuetyang.github.io/myGitBlog/front-end/webpack/" rel="alternate" type="text/html" title="webpack学习再回顾" /><published>2017-10-15T13:47:00+08:00</published><updated>2017-10-15T13:47:00+08:00</updated><id>https://andrewuetyang.github.io/myGitBlog/front-end/webpack</id><content type="html" xml:base="https://andrewuetyang.github.io/myGitBlog/front-end/webpack/">&lt;p&gt;在我的心中，webpack是一个变革者，他提供了前端一个全新的开发模式，并将这一职业推向一个新的高点。&lt;/p&gt;

&lt;h2 id=&quot;追溯webpack的起源&quot;&gt;追溯webpack的起源&lt;/h2&gt;

&lt;p&gt;这些年互联网发展迅速，越来越多的网站以及web应用的需求不断增加，一个井喷的web程序井喷的时代，为数不多的程序猿们，如何应对呢？自然，得提高效率嘛，于是大家就想办法提高效率，怎么提高呢？啦啦啦，此处省略一千字，答案是web设计师行业开始变更为前端工程师，前后端概念出现，简单的说，前端负责人机交互、内容的良好呈现、把需要的信息提交给后端，而后端即服务器端，负责处理服务器问题、与前端交互、以及数据的处理并与数据库交互。这样初步解决了团队效率问题。日复一日，程序越来越复杂，前端的代码量开始增多，代码维护性出现了性功能问题，哈哈。于是渐渐的，为了解决前端开发工程化复杂的问题，使其代码更加结构化、维护性更好，出现了grunt、gulp、webpack等工具。&lt;/p&gt;

&lt;h2 id=&quot;webpack概念&quot;&gt;webpack概念&lt;/h2&gt;

&lt;p&gt;webpack 是一个现代 JavaScript 应用程序的模块打包器(module bundler)。当 webpack 处理应用程序时，它会递归地构建一个依赖关系图(dependency graph)，其中包含应用程序需要的每个模块，然后将所有这些模块打包成少量的 bundle - 通常只有一个，由浏览器加载。&lt;/p&gt;

&lt;p&gt;它是高度可配置的，但是，在开始前你需要先理解四个核心概念：入口(entry)、输出(output)、loader、插件(plugins)。不详细解释，如有需要，见其官网。&lt;/p&gt;

&lt;h2 id=&quot;webpack能力大致描述&quot;&gt;webpack能力大致描述&lt;/h2&gt;

&lt;p&gt;我们都知道，前端从大致的方向上看，主要关注点在四个方面，一个是html模板，一个是css样式，一个是javaScript负责的行为逻辑，最后是其他资源，如图片。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;js需要模块打包，好的，简单的说，webpack内部使用了browserify来处理commonJS和es6的模块的依赖关系来完成打包。你写的jsx语法、es6语法等，浏览器不支持不兼容怎么办？没关系，提前准备了babel的编译器,实现优雅编译。js想要丑化压缩下，没问题，咱有插件系统。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;对于css文件，由于webpack本身只理解javaScript，css文件如何打包呢？简单的说，借助loader来实现，css-loader和style-loader就是很好的任务完成者。css-loader出色的完成了css模块化的问题，style-loader出色的完成了在html中对模块化的css插入问题。你写了less，好的，聪明的开发者搞了个less-loader，负责less的编译问题。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;图片想要处理下，base64能做得到吗？没问题，咱有url-loader。资源想要集中化一下，没事咱有file-loader。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;感受webpack的架构&quot;&gt;感受webpack的架构&lt;/h2&gt;

&lt;p&gt;nodeJS诞生后，各种前端自动化工具成为了可能。webpack出色的架构，很好的解决了自动化过程中需要处理的问题。在我看来，webpack将资源处理或者说应用程序源代码处理，看做一个文件流，甚至可以形象的比喻为一根有很多处理工厂的管道，从这头到那头的过程，自动识别要处理的资源，进行预先设定的加工处理，然后输出。加工厂可以自定义无限扩展，主要分成两类，一类是loader，一类是plugins。loader主要是做文件转换工作的。而plugins是用来做loader不能做的事儿的，因为loader局限在了文件转换，而在打包的生命周期需要执行的任务，它无法完成，插件就是来做这个工作的，比如打包完成需要对js进行执行uglify，这个时候就需要插件来完成这个任务。&lt;/p&gt;

&lt;p&gt;废话说完了，嘻嘻。&lt;/p&gt;</content><author><name>杨峰</name></author><category term="front-end" /><summary type="html">在我的心中，webpack是一个变革者，他提供了前端一个全新的开发模式，并将这一职业推向一个新的高点。</summary></entry><entry><title type="html">纯前端canvas俄罗斯方块小游戏实现</title><link href="https://andrewuetyang.github.io/myGitBlog/front-end/tetris/" rel="alternate" type="text/html" title="纯前端canvas俄罗斯方块小游戏实现" /><published>2017-10-10T19:11:00+08:00</published><updated>2017-10-10T19:11:00+08:00</updated><id>https://andrewuetyang.github.io/myGitBlog/front-end/tetris</id><content type="html" xml:base="https://andrewuetyang.github.io/myGitBlog/front-end/tetris/">&lt;p&gt;小时候打的第一款游戏，说起来大概就是俄罗斯方块了，这种游戏老少咸宜，设计的非常巧妙，不高冷，不装逼，之前查询过这个游戏的过往，发现那些年火爆经典的游戏中，俄罗斯方块的火爆经典程度简直超乎我的想象。其实仔细想下，其实我们的确可以自己来实现一个类似的游戏。于是乎，经过多天的构思和参考别人写过的demo，我也自己实现了一遍，下面我就来谈谈自己的俄罗斯方块。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://wx4.sinaimg.cn/mw690/a72c2deegy1fkdirgqzagj20we0rkacu.jpg&quot; alt=&quot;我的俄罗斯方块&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;功能点罗列&quot;&gt;功能点罗列&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;地图数据结构&lt;/li&gt;
  &lt;li&gt;方块数据结构&lt;/li&gt;
  &lt;li&gt;地图生成&lt;/li&gt;
  &lt;li&gt;地图绘制&lt;/li&gt;
  &lt;li&gt;地图更新&lt;/li&gt;
  &lt;li&gt;方块创建&lt;/li&gt;
  &lt;li&gt;方块擦除&lt;/li&gt;
  &lt;li&gt;方块下落&lt;/li&gt;
  &lt;li&gt;方块的方向键操作&lt;/li&gt;
  &lt;li&gt;方块变形&lt;/li&gt;
  &lt;li&gt;方块满行消除&lt;/li&gt;
  &lt;li&gt;方块触底检测&lt;/li&gt;
  &lt;li&gt;方块左右碰撞检测&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;当然还有canvas元素的处理，这里就不说了。&lt;/p&gt;

&lt;h2 id=&quot;地图数据结构&quot;&gt;地图数据结构&lt;/h2&gt;

&lt;p&gt;使用0， 1这样的数字来代表有无方块，地图上无方块时，就都是0. 示例如下：&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;方块数据结构&quot;&gt;方块数据结构&lt;/h2&gt;

&lt;p&gt;跟地图类似，使用0，1来代表形状，总结归纳出方块的几种情况：&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[
    [1, 1, 1, 1]], // 一字形
    [[1, 1], [1, 1]], // 田字形
    [[1, 1, 0], [0, 1, 1]], // z字形
    [[0, 1, 1], [1, 1, 0]], // 反z字形
    [[1, 0, 0], [1, 1, 1]], // L字形
    [[0, 0, 1], [1, 1, 1]], // 反L字形
    [[0, 1, 0], [1, 1, 1]] // T字形
]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;地图生成&quot;&gt;地图生成&lt;/h2&gt;

&lt;p&gt;我们将地图控制的变量明确出来，这样就可通过设置控制地图的生成。 这些变量是，多少行，多少列，一个格子多大，格子间距多大，方块生成初始化时离x轴起点的位置，方块下落速度， 加速下落速度等。&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var tetrisGame = new Tetris({
    row: 12,
    col: 12,
    grid: 30,
    margin: 10,
    offsetX: 4,
    interval: 400,
    fasterInterval: 100
})
tetrisGame.start()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;地图绘制&quot;&gt;地图绘制&lt;/h2&gt;

&lt;p&gt;根据地图的数据，借助canvas提供的api（就两个api就可以搞定，分别是fillStyle和fillRect），给不同的数据点绘制不同的颜色。&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// 地图绘制
render: function () {
    var map = this.map
    var mRowLen = map.length
    var mColLen = map[0].length
    var margin
    var grid = this.etting.grid
    margin = this.setting.margin
    for (var i = 0; i &amp;lt; mRowLen; i++) {
        for (var j = 0; j &amp;lt; mColLen; j++) {
            if (!map[i][j]) {
                this.ctx.fillStyle = 'grey'
            } else if (map[i][j] === 1) {
                this.ctx.fillStyle = 'orange'
            }
            this.ctx.fillRect(j * (grid + margin), i * (grid + margin), grid, grid)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;地图更新&quot;&gt;地图更新&lt;/h2&gt;

&lt;p&gt;方块的移动需要地图做更新操作，方块就是地图中的一部分，它的移动其实就是每个格子状态根据一定的算法来改变，达到动画的效果的。因此地图或者说游戏的更新，就是根据方块当前的位置和方块本身的数据结构来更新的。&lt;/p&gt;

&lt;h2 id=&quot;方块创建&quot;&gt;方块创建&lt;/h2&gt;

&lt;p&gt;方块的生成是随机的，利用js的随机数以及预定义好的方块数据结构，很容易做到。然后根据我们预设的方块的初始化的位置，就可以在地图中生成。&lt;/p&gt;

&lt;h2 id=&quot;方块擦除&quot;&gt;方块擦除&lt;/h2&gt;

&lt;p&gt;方块是随着时间运动的，直到触底。因此在运动的时候，我们根据时间的特性，下一个状态的方块来临之前，我们将上一个状态的方块清掉，这里注意的是，只清除那些格子有形的部分，否则会出现当与其他已定方块耦合时，将已定方块的某些部分也清除了。&lt;/p&gt;

&lt;h2 id=&quot;方块下落&quot;&gt;方块下落&lt;/h2&gt;

&lt;p&gt;方块下落使用定时器来处理，每一个时间点，做一次清除然后增加方块y轴的值，然后再更新地图。同时在下落的时候，需要判断是否落地。&lt;/p&gt;

&lt;h2 id=&quot;方块的方向键操作&quot;&gt;方块的方向键操作&lt;/h2&gt;

&lt;p&gt;根据keydown事件和keyCode的值，我们给不同的方向键提供不同的处理方法。向上时，我们做方块变形，向下时，我们加速下落，左右键做左右移动操作。&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// 方块移动及变形操作
enableKeyControl: function () {
    var _this = this
    document.onkeydown = function (e) {
        switch (e.keyCode) {
            case 37: // 向左
                if (!_this.borderTest(_this.curBlock, -1)) {
                    _this.clearBlock()
                    _this.x--
                    _this.updateMap()
                }
                break
            case 39: // 向右
                if (!_this.borderTest(_this.curBlock, 1)) {
                    _this.clearBlock()
                    _this.x++
                    _this.updateMap()
                }
                break
            case 38: // 向上即变形
                _this.clearBlock()
                _this.transform()
                _this.updateMap()
                break
            case 40: // 向下即加速
                if (!_this.onkeydownFlag) {
                    _this.onkeydownFlag = true
                    clearInterval(_this.timer)
                    _this.fall(_this.setting.fasterInterval)
                }
                break
        }
    }
    document.onkeyup = function (e) {
        if (e.keyCode === 40) {
            _this.onkeydownFlag = false
            clearInterval(_this.timer)
            _this.fall(_this.setting.interval)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;方块变形&quot;&gt;方块变形&lt;/h2&gt;

&lt;p&gt;方块变形就是方块的旋转，我们通常喜欢顺时针来旋转，比较舒服，当然你喜欢逆时针，也可以做的。我是用的顺时针。所以根据旋转的规律，就可以根据旋转前方块的数据结构得出旋转后的数据结构。这里也需要注意一点，是否可以旋转，需要判断，因为有时候一旋转出了边界，一旋转和底部实体融合了，等等。判断的方法是，方块的数据暂时不变更，我们将旋转后的数据，去做测试，判断是否触底或超出边界，即去做方块触底检测和左右方向碰撞检测，如果没有碰撞，就更新方块的数据，如果有，就不允许更新方块数据。&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// 方块变形
transform: function () {
    var result = []
    var curBlock = this.curBlock
    var blockRowLen = curBlock.length
    var blockColLen = curBlock[0].length
    for (var i = 0; i &amp;lt; blockColLen; i++) {
        result.push([])
        for (var j = 0; j &amp;lt; blockRowLen; j++) {
            result[i][blockRowLen - j - 1] = curBlock[j][i]
        }
    }
    if (
        !this.groundTest(result) &amp;amp;&amp;amp;
        !this.borderTest(result, -1, true) &amp;amp;&amp;amp;
        !this.borderTest(result, 1, true)
    ) this.curBlock = result
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;方块满行消除&quot;&gt;方块满行消除&lt;/h2&gt;

&lt;p&gt;满行的条件触发是以方块落地开始的，所以落地判断成功，就应该需要去判断是否满行，然后做相应的处理。满行的判断，是通过遍历整个地图，看是否有那么些行的格子里都填满了，如果是就需要消除，消除就是在地图的数据结构中，干掉这一样，当然，这个时候的同时，我们可以在地图的最前面行unshift一个充满空格子的空行。&lt;/p&gt;

&lt;h2 id=&quot;方块触底检测&quot;&gt;方块触底检测&lt;/h2&gt;

&lt;p&gt;触底分为两种情况，第一种，是最底部，这个很好判断。第二种，是与其他已经落下的方块之间的判断，看是否还需要往下走。第二种判断方法是，先判断方块的最底部那一行，如果有实体的地方对应的正下方的地图的格子也是实体，那么就不应该再下落，也就是说触底了，如果没有，就去对底部没有实体的那些列去做while循环，向上找到方块的实体格子，这个是总能找到的，因为方块的设计缘故，找到后，就也做类似的判断，看这个方块处的格子对应的正下方地图的格子是否是实体，进而判断是否触底。&lt;/p&gt;

&lt;h2 id=&quot;方块左右碰撞检测&quot;&gt;方块左右碰撞检测&lt;/h2&gt;

&lt;p&gt;左右碰撞也分为两种，一种是边界，一种是与其他方块。这里碰撞后，下落还是继续的，不是停止。这个地方的判断，归根结底，其实和下落时与其他方块的判断很类似，只是判断的时候换了一个方向而已。&lt;/p&gt;

&lt;p&gt;啦啦啦，终于写完啦。这个简易的俄罗斯方块的代码我上传到了github，看源码请参考&lt;a href=&quot;https://github.com/Andrewuetyang/tetris&quot;&gt;https://github.com/Andrewuetyang/tetris&lt;/a&gt;。&lt;/p&gt;</content><author><name>杨峰</name></author><category term="front-end" /><summary type="html">小时候打的第一款游戏，说起来大概就是俄罗斯方块了，这种游戏老少咸宜，设计的非常巧妙，不高冷，不装逼，之前查询过这个游戏的过往，发现那些年火爆经典的游戏中，俄罗斯方块的火爆经典程度简直超乎我的想象。其实仔细想下，其实我们的确可以自己来实现一个类似的游戏。于是乎，经过多天的构思和参考别人写过的demo，我也自己实现了一遍，下面我就来谈谈自己的俄罗斯方块。</summary></entry><entry><title type="html">websocket通信的实现</title><link href="https://andrewuetyang.github.io/myGitBlog/back-end/node-websocket/" rel="alternate" type="text/html" title="websocket通信的实现" /><published>2017-10-09T22:01:00+08:00</published><updated>2017-10-09T22:01:00+08:00</updated><id>https://andrewuetyang.github.io/myGitBlog/back-end/node-websocket</id><content type="html" xml:base="https://andrewuetyang.github.io/myGitBlog/back-end/node-websocket/">&lt;h2 id=&quot;什么是websocket用处是什么&quot;&gt;什么是websocket？用处是什么？&lt;/h2&gt;

&lt;p&gt;WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。通俗的说，就是基于TCP的HTTP协议只能客户端发起请求，服务器来应答，是单向的，而现在这个协议，使得服务器变得更加灵活更加聪明不那么高冷了而也有主动的一面了，同时减少了很多客户端资源的浪费。&lt;/p&gt;

&lt;p&gt;搬个场景来说明它的好处（http协议下的ajax轮询场景）：&lt;/p&gt;

&lt;p&gt;客户端：啦啦啦，有没有新信息(Request)&lt;/p&gt;

&lt;p&gt;服务端：没有（Response）&lt;/p&gt;

&lt;p&gt;客户端：啦啦啦，有没有新信息(Request)&lt;/p&gt;

&lt;p&gt;服务端：没有。。（Response）&lt;/p&gt;

&lt;p&gt;客户端：啦啦啦，有没有新信息(Request)&lt;/p&gt;

&lt;p&gt;服务端：你好烦啊，没有啊。。（Response）&lt;/p&gt;

&lt;p&gt;客户端：啦啦啦，有没有新消息（Request）&lt;/p&gt;

&lt;p&gt;服务端：好啦好啦，有啦给你。（Response）&lt;/p&gt;

&lt;p&gt;客户端：啦啦啦，有没有新消息（Request）&lt;/p&gt;

&lt;p&gt;服务端：。。。。。没。。。。没。。。没有（Response） —- loop&lt;/p&gt;

&lt;p&gt;为了解决这种问题，于是出现了websocket技术。就说这么多，如果想了解更多可以去查找更多的资料，接下来我们就来实现一个这样的通信。&lt;/p&gt;

&lt;h2 id=&quot;基于node的websocket通信的实现&quot;&gt;基于node的websocket通信的实现&lt;/h2&gt;

&lt;p&gt;nodeJS的socket.io模块可以很简单的让你将websocket通信玩起来。还是直接上代码吧，以下是一个非常简单的聊天室用户登录栗子，大家可以实时看到哪些人上机了。&lt;/p&gt;

&lt;p&gt;下面是服务器端代码：&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;// 引入必要的模块
var http = require('http')
var express = require('express')
var sio = require('socket.io')
var fs = require('fs')

var app = express()
var server = http.createServer(app)

app.get('/', function (req, res) {
    res.sendFile(__dirname + '/index.html')
})

server.listen(3000)

// socket.io监听服务器得到一个io对象，可对websocket做处理
var io = sio.listen(server)

var names = []

// 监听连接事件，连接成功可获得一个socket对象，可对websocket通信进行处理
io.on('connection', function (socket) {
    socket.emit('login', names)
    socket.on('login', function (data) {
        names.push(data)
        io.sockets.emit('login', names)
    })
})

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;nodeJS提供的socket.io可以监听创建的服务器获得一个websocket服务器，此服务器可监听客户端发起的websocket连接，一旦连接事件触发，就能通过回调函数获取到一个socket对象，该对象对应一个客户端连接，多个客户端连接会在内存里生成多个，它可on监听事件和emit发送事件，达到数据通信的目的。io下面有一个sockets对象，它是一个集合，代表内存中存在的所有socket对象，这个对象就可以轻松的达到群发消息的目的了。上面例子中，就可以给所有连接成功的客户端派发login事件。&lt;/p&gt;

&lt;p&gt;下面是客户端代码：&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;lang=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;charset=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;UTF-8&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;viewport&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;width=device-width, initial-scale=1.0&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;http-equiv=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;X-UA-Compatible&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;ie=edge&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Document&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/socket.io/socket.io.js&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;ul&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;li&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;ol&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;nl&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;label&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;for=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;userName&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;用户名：&lt;span class=&quot;nt&quot;&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;input&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;userName&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;userName&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;button&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;button&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;登录&lt;span class=&quot;nt&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;ul&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;content&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;userNameInput&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'userName'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'button'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'content'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;items&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;

        &lt;span class=&quot;nx&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'click'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'login'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;userNameInput&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'login'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;items&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;已登录&amp;lt;/li&amp;gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerHTML&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;客户端的处理需要引入socket.io.js文件，这个无需在本地存在，只要服务器端使用了nodeJS的socket.io模块，就可以通过script标签获取到。如果正确的获取到了socket.io.js这个文件，那么其将生成一个io全局对象，这个对象就可以发起websocket连接请求，连接成功就能获取到一个socket对象，同样可对on监听事件和emit派发事件来和服务器端进行数据通信。前后端的书写都很一致，是不是很爽。&lt;/p&gt;

&lt;p&gt;当然这只是一个简单的例子，socket.io提供的api还有很多需要学习的，如果有兴趣，就可以深入下去。官方的api文档还是很全的，可以查阅一下&lt;a href=&quot;http://nodejs.cn/api/&quot;&gt;http://nodejs.cn/api/(中文文档)&lt;/a&gt;。同时写得很不错的《Node.js权威指南》也是很值得一看的。&lt;/p&gt;</content><author><name>杨峰</name></author><category term="back-end" /><summary type="html">什么是websocket？用处是什么？</summary></entry><entry><title type="html">使用jekyll玩儿博客的心路历程</title><link href="https://andrewuetyang.github.io/myGitBlog/ghpages/gh-pages/" rel="alternate" type="text/html" title="使用jekyll玩儿博客的心路历程" /><published>2017-08-31T20:01:00+08:00</published><updated>2017-08-31T20:01:00+08:00</updated><id>https://andrewuetyang.github.io/myGitBlog/ghpages/gh-pages</id><content type="html" xml:base="https://andrewuetyang.github.io/myGitBlog/ghpages/gh-pages/">&lt;h2 id=&quot;jekyll入门&quot;&gt;jekyll入门&lt;/h2&gt;
&lt;p&gt;还记得，以前读书最讨厌的就是语文的作文，由于阅读量跟阅读方向问题，对文学的不感兴趣等原因，导致好多时候，写作文都需要编故事，哪怕是举名人的例子，有时候都可以编一下，可别提多痛苦了，此处，请允许我做一个悲伤的表情…Anyway, 现在我倒是有一点冲动，想要通过写作，来反馈自己的学习，所以就开始了。刚开始，这个博客是用最基本的方式搭建起来的，跟着&lt;a href=&quot;http://www.ruanyifeng.com/home.html&quot;&gt;阮一峰&lt;/a&gt;的博客&lt;a href=&quot;http://www.ruanyifeng.com/blog/2012/08/blogging_with_jekyll.html&quot;&gt;《搭建一个免费的，无限流量的Blog—-github Pages和Jekyll入门》&lt;/a&gt;一步一步撘起来的。搭建起来后，觉得这种方式来建静态站点还是不错的，于是去认真看了一遍&lt;a href=&quot;http://jekyllrb.com/&quot;&gt;jekyll&lt;/a&gt;的官方文档。初次玩的，的确需要好好看看。&lt;/p&gt;

&lt;h2 id=&quot;jekyll主题&quot;&gt;jekyll主题&lt;/h2&gt;
&lt;p&gt;看了官方文档，对&lt;code class=&quot;highlighter-rouge&quot;&gt;jekyll&lt;/code&gt;的理解有所升级，于是想装修一下站点，毕竟跟着阮老师搭建的站点，太素。但是自己写css比较麻烦，知道网上有很多现成的主题可用，于是，我决定抄捷径。去找主题，&lt;code class=&quot;highlighter-rouge&quot;&gt;Github Pages&lt;/code&gt;官方只支持十几种主题，涵盖了基本需求，加上自己写一些样式，其实的确可以满足需求。但是，都不太符合我的要求，虽然可以在这些主题的基础上加样式，我还是想更直接一点的，开箱即用，这样才符合专注于写作上，而不是样式上或其他交互逻辑等不相干的事上。&lt;/p&gt;

&lt;p&gt;给jekyll项目添加主题有两种方法：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;gem安装 &lt;code class=&quot;highlighter-rouge&quot;&gt;gem-based theme&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;在项目中添加theme中才存在的文件，将&lt;code class=&quot;highlighter-rouge&quot;&gt;gem-based theme&lt;/code&gt;转化为&lt;code class=&quot;highlighter-rouge&quot;&gt;regular theme&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;说明下，&lt;code class=&quot;highlighter-rouge&quot;&gt;gh-pages&lt;/code&gt;只支持官方提供的十几种主题，所以用其他的jekyll主题，需要使用&lt;code class=&quot;highlighter-rouge&quot;&gt;regular theme&lt;/code&gt;模式，也就是第二种方法。&lt;/p&gt;

&lt;h2 id=&quot;结语&quot;&gt;结语&lt;/h2&gt;
&lt;p&gt;由于对jekyll的运行机理吃的还不是很透，想要自己玩出点花样就有点痛苦。特别是你想对你的站点做出点不一样的表现形式的时候。如果后面还有兴趣的话，我会对jekyll的运行机理吃个透，不过现在目前没有这个想法，因为已经可以专注于写作了，样式方面基本符合简洁明了，也有一定的特色的要求。&lt;/p&gt;</content><author><name>杨峰</name></author><category term="ghpages" /><summary type="html">jekyll入门 还记得，以前读书最讨厌的就是语文的作文，由于阅读量跟阅读方向问题，对文学的不感兴趣等原因，导致好多时候，写作文都需要编故事，哪怕是举名人的例子，有时候都可以编一下，可别提多痛苦了，此处，请允许我做一个悲伤的表情…Anyway, 现在我倒是有一点冲动，想要通过写作，来反馈自己的学习，所以就开始了。刚开始，这个博客是用最基本的方式搭建起来的，跟着阮一峰的博客《搭建一个免费的，无限流量的Blog—-github Pages和Jekyll入门》一步一步撘起来的。搭建起来后，觉得这种方式来建静态站点还是不错的，于是去认真看了一遍jekyll的官方文档。初次玩的，的确需要好好看看。</summary></entry></feed>