(.|\n)*<\/div>/g, function (match) {
83 | nestMarkdowns.push(match);
84 | return '${nestMarkdown}';
85 | });
86 |
87 | source = source.replace(/^\n+/, '');
88 | var uselessSpaceCount = source.match(/^\s*/)[0].length;
89 | source = source.replace(new RegExp('^ {' + uselessSpaceCount + '}', 'gm'), '');
90 | return '
'
91 | + marked(source, {renderer: renderer})
92 | .replace(/\${nestMarkdown}/g, function () {
93 | return nestMarkdowns.shift();
94 | })
95 | + '
';
96 | });
97 | ```
98 |
99 | 刷一下页面,再看,符合预期,完全正常!
100 |
--------------------------------------------------------------------------------
/source/_posts/使用marked解析markdown.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 使用 marked 解析 markdown
3 | date: 2016-05-20T13:49:00.000Z
4 | tags:
5 | - markdown
6 | - ETPL
7 | ---
8 |
9 | [marked](https://github.com/chjj/marked) 是一个解析 markdown 的 JavaScript 库,可以运行在 Node 环境或者浏览器环境。
10 |
11 | 最简单直接的一种使用方式:
12 |
13 | ```javascript
14 | var marked = require('marked');
15 | console.log(marked('I am using __markdown__.'));
16 | // Outputs:
I am using markdown.
17 | ```
18 |
19 |
20 |
21 | marked 库主要提供了一个 marked 函数,该函数声明为:
22 |
23 | ```
24 | type OptionsType = {
25 | highlight: (function(code: string, lang: string, callback: function(err: Error, code: string)))=,
26 | renderer: marked.Renderer=,
27 | gfm: boolean=,
28 | tables: boolean=,
29 | breaks: boolean=,
30 | pedantic: boolean=,
31 | sanitize: boolean=,
32 | smartLists: boolean=
33 | };
34 | marked(markdownString: string, options: OptionsType=, callback: Function=): string;
35 | ```
36 |
37 | 其中,marked 可以通过 renderer 配置提供了自定义解析途径。
38 |
39 | renderer 配置对应的是一个 marked.Renderer 类,此类主要包含了如下的钩子方法:
40 |
41 | - code(string code, string language)
42 | - blockquote(string quote)
43 | - html(string html)
44 | - heading(string text, number level)
45 | - hr()
46 | - list(string body, boolean ordered)
47 | - listitem(string text)
48 | - paragraph(string text)
49 | - table(string header, string body)
50 | - tablerow(string content)
51 | - tablecell(string content, object flags)
52 | - strong(string text)
53 | - em(string text)
54 | - codespan(string code)
55 | - br()
56 | - del(string text)
57 | - link(string href, string title, string text)
58 | - image(string href, string title, string text)
59 |
60 | 所有的这些方法,都可以在 renderer 实例上面覆盖掉。marked 在解析到 markdown 标记的时候,都会去调用相应的钩子方法,而钩子方法的返回结果,就会是该标记最终的解析结果。这样一来,就生成了自定义的解析结果。
61 |
62 | marked 还有一个重要的配置:highlight,可以对代码块进行解析,配合相应的 css ,达到语法高亮效果。
63 |
64 | 以上就是 marked 最基本最核心的用法了。
65 |
66 | 其实本文的重点是记录在使用过程中遇到的一些坑,下面进入重点。
67 |
68 | # markdown 缩进问题
69 |
70 | 在 markdown 的语法中,标题下面(换行之后)标记是不能缩进的,而列表项下面的标记是可以缩进的。
71 |
72 | 现在前端开发,经常会使用一些模板引擎,比如 [ETPL](https://github.com/ecomfe/etpl) ,这些模板,一般都会提供过滤器的功能。以 ETPL 为例,可以在 js 代码中这样添加一个过滤器:
73 |
74 | ```javascript
75 | var etpl = require('etpl');
76 | var marked = require('marked');
77 | etpl.addFilter('markdown', function (source, useExtra) {
78 | return marked(source);
79 | });
80 | ```
81 |
82 | 此时在对应的模板中,就可以使用该过滤器了:
83 |
84 | ```html
85 |
86 |
87 | ### 标题
88 |
89 | 内容
90 |
91 |
92 | ```
93 |
94 | 此时,解析出来的样子会让人瞠目结舌:过滤器里面的 markdown 标记根本不会被解析掉,整个 markdown 标记块会被当成代码块。
95 |
96 | 为什么会这样呢?
97 |
98 | 如果打印一下 markdown 过滤器处理函数中的 source 参数:
99 |
100 | ```javascript
101 | var etpl = require('etpl');
102 | var marked = require('marked');
103 | etpl.addFilter('markdown', function (source, useExtra) {
104 | console.log(source);
105 | return marked(source);
106 | });
107 | ```
108 |
109 | 可以发现,打印出来的内容会是这个样子:
110 |
111 | ```
112 | "
113 | ### 标题
114 |
115 | 内容
116 | "
117 | ```
118 |
119 | 第一行没啥内容,第二行并没有顶行,而是有缩进的,然后最后一行没实际内容,只有一个缩进。
120 |
121 | 这明显跟 markdown 语法有冲突,必须要进行如下处理:
122 |
123 | - 1、第一行和最后一行没啥实际内容,可以去掉;
124 | - 2、检测第一行前面的缩进空格数(这里假定缩进用的是空格),记录下来,假设为 `n` ;
125 | - 3、将每一行前面的 `n` 个空格去掉。
126 |
127 | 具体的代码实现如下:
128 |
129 | ```javascript
130 | var etpl = require('etpl');
131 | var marked = require('marked');
132 | etpl.addFilter('markdown', function (source, useExtra) {
133 | source = source.replace(/(^\n+|\n+$)/g, '');
134 | var uselessSpaceCount = source.match(/^\s*/)[0].length;
135 | source = source.replace(new RegExp('^ {' + uselessSpaceCount + '}', 'gm'), '');
136 | return marked(source);
137 | });
138 | ```
139 |
140 | # HTML 标签
141 |
142 | 有的时候,可能想给 markdown 标记的某一块加上背景色,比如:
143 |
144 | ```html
145 |
146 |
147 | ### 标题
148 |
149 | 内容
150 |
151 |
152 | ```
153 |
154 | 这样写又会崩溃了, div 内部的 markdown 标记并不会被解析!
155 |
156 | 解决方法就是把 div 放过滤器外边吧:
157 |
158 | ```html
159 |
160 |
161 | ### 标题
162 |
163 | 内容
164 |
165 |
166 | ```
167 |
--------------------------------------------------------------------------------
/source/_posts/如何展示表单控件.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 如何展示表单控件
3 | date: 2016-12-15 22:34
4 | tags:
5 | - CSS
6 | ---
7 |
8 | 在 Web 开发中,经常需要展示左右结构的表单。如下所示:
9 |
10 | 
11 |
12 | 面对这张图,最先想到的实现方式就是借助浮动:
13 |
14 | {% iframe ../demos/2016-12-15/form1.html 100% 250 %}
15 |
16 | 基本的结构就这样,看起来挺好的。
17 |
18 | 但是有一个忧伤的地方,左侧`form-key`部分的宽度太烦人,不同的表单`form-key`部分存在宽度差异,很难统一。如果把`form-key`部分统一设置成一个比较大的值,那么在`form-key`比较短的表单里面会非常难看。这样一来,只能选择不同的表单设置不同的`form-key`的宽度值,很烦人。
19 |
20 | **如何让左侧的宽度自适应呢?**
21 |
22 | 从一位前端牛人学习到如下利用`table`布局的写法:
23 |
24 | {% iframe ../demos/2016-12-15/form2.html 100% 250 %}
25 |
26 | 此处`form-operations`部分有点小问题,`form-operations`是一个`table-row`,所以直接子元素应该是`table-cell`,改一改就好了。
27 |
28 | 同时也因为这个手误,发现在 IE9 中,鼠标 hover 到`table-row`上面去之后,会触发下面第一个`button`的 hover 效果。
29 |
--------------------------------------------------------------------------------
/source/_posts/实现第一个 vscode 扩展.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 实现第一个 vscode 扩展
3 | date: 2016-01-10 18:20
4 | tags:
5 | - vscode
6 | ---
7 |
8 |
9 | > 提前声明:
10 | > 此处使用的 vscode 版本是0.10.6
11 |
12 | vscode 是微软最近弄出来的代码编辑器,基于 Electron ,对于前端程序员来说,颇亲切。
13 |
14 | 个人觉得,到目前这个版本为止, vscode 还不是很成熟,总体体验上离 sublime 还有一定差距。
15 |
16 |
17 | 但是我个人很看重 vscode 的这些点:
18 |
19 | * 1、虽然使用 Electron ,但是代码各方面处理还是挺快的,特别是打开比较大的 js 文件,基本不会挂掉,性能堪比 sublime ;
20 | * 2、里面全是 js 系列的东西(虽然加了一层 ts ),对于前端来说,很是亲切,如果成熟到一定程度的话,将会有大把的前端程序员参与插件的开发。相比于 sublime 使用 python , vscode 真是太爽了,深度定制的时候少了语言的门槛。
21 |
22 | 目前个人感觉的小缺点有:
23 |
24 | * 1、无法代码折叠;
25 | * 2、扩展 API 还不完善,有些比较酷的功能依据现有 API 还无法实现。
26 |
27 | 废话不对说,走一个插件先。
28 |
29 | ### 插件功能
30 |
31 | 对 JavaScript 代码进行检查,基于的检查规则是 `fecs` 。
32 |
33 | ### 安装必要的东西
34 |
35 | > npm install -g yo generator-code
36 |
37 | ### 生成扩展项目
38 |
39 | 执行下面的代码:
40 |
41 | > yo code
42 |
43 | 然后会出现这样的选择界面:
44 |
45 | 
46 |
47 | 选择:
48 |
49 | > New Extension (JavaScript)
50 |
51 | 这样就会生成使用 JavaScript 进行插件开发的项目结构。
52 |
53 | 后续还会设置扩展的名字(此处设为 test )、扩展的唯一标识、扩展的描述、扩展的发布者名字、是否初始化为 Git 仓库。根据提示做相应设置就好了。设置完之后就会自动运行 `npm install` ,安装好 vscode 模块。
54 |
55 | 一切结束之后,你会发现在当前目录下生成了一个叫 `test` 的目录,进入这个目录,下面就有了一堆文件。
56 |
57 | ### 修改 package.json 文件
58 |
59 | 更改 `activationEvents` 配置项,设为:
60 |
61 | ```js
62 | [
63 | "onLanguage:javascript"
64 | ]
65 | ```
66 |
67 | 意思就是在打开 JavaScript 文件的时候会激活这个扩展。
68 |
69 | 删掉 `contributes` 配置项,此处用不上这个配置。
70 |
71 | ### 修改 extension.js 文件
72 |
73 | 这个文件是 package.json 里面 `main` 配置指向的文件,扩展激活的时候会调用这个文件提供的 activate 方法。
74 |
75 | 对于该扩展,其执行流程为:
76 |
77 | * 1、在用户打开 js 文件的时候激活扩展,注册好文件保存的回调方法;
78 | * 2、在用户保存文件的时候,执行 fecs 检查;
79 | * 3、将第二步中检查出的错误和警告等信息显示到编辑器中。
80 |
81 | #### 开发过程
82 |
83 | 在开发扩展的时候,要使用到 `vscode` 和 `fecs` 两个模块:
84 |
85 | ```js
86 | var vscode = require('vscode');
87 | var fecs = require('fecs');
88 | ```
89 |
90 | 然后注册文件保存的回调函数:
91 |
92 | ```js
93 | var disposable = vscode.workspace.onDidSaveTextDocument(function (event) {
94 | // do something while saving
95 | });
96 | context.subscriptions.push(diagnosticCollection);
97 | ```
98 |
99 | > **注意:**
100 | > 此处 `onDidSaveTextDocument` 返回了一个 disposable 对象,这个对象有一个 `dispose` 方法,在扩展销毁的时候,会调用这个方法。因此,这个对象要事先放到 `context.subscriptions` ,`context` 是 `activate` 方法调用的时候传入的上下文对象。
101 |
102 | 在这个回调函数里面就可以执行 fecs 检查了:
103 |
104 | ```js
105 | fecs.check(
106 | {
107 | type: 'js',
108 | name: 'FECS JS',
109 | _: [event.uri.path],
110 | stream: false
111 | },
112 | function (hasNoError, errors) {
113 | // the result of check
114 | }
115 | );
116 | ```
117 |
118 | `hasNoError` 和 `errors` 表明了检查结果。此处可以忽略 `hasNoError` ,直接将 errors 转换成 vscode 能够展示的错误。
119 |
120 | vscode 提供了 `DiagnosticCollection` ,用于向界面上展示错误信息。那么如何操作呢?
121 |
122 | 首先要拿到一个 `DiagnosticCollection` 对象:
123 |
124 | ```js
125 | var diagnosticCollection = vscode.languages.createDiagnosticCollection('fecs');
126 | ```
127 |
128 | 然后往这个对象里面塞错误信息:
129 |
130 | ```js
131 | diagnosticCollection.set(someErrorObject);
132 | ```
133 |
134 | #### 整合所有代码之后的样子
135 |
136 | 整个 `extension.js` 的代码整合起来如下:
137 |
138 | ```js
139 | var path = require('path');
140 | var vscode = require('vscode');
141 | var fecs = require('fecs');
142 |
143 | fecs.leadName = 'fecs';
144 |
145 | exports.activate = function activate(context) {
146 | var diagnosticCollection = vscode.languages.createDiagnosticCollection('fecs');
147 | context.subscriptions.push(diagnosticCollection);
148 |
149 | vscode.workspace.onDidSaveTextDocument(function (event) {
150 | diagnosticCollection.clear();
151 | fecs.check(
152 | {
153 | type: 'js',
154 | name: 'FECS JS',
155 | _: [event.uri.path],
156 | stream: false
157 | },
158 | function (hasNoError, errors) {
159 | diagnosticCollection.set(convertErrors(errors));
160 | }
161 | );
162 | });
163 | };
164 |
165 | function convertErrors(fecsErrors) {
166 | return fecsErrors.map(function (error) {
167 | return [
168 | vscode.Uri.file(error.path),
169 | error.errors.map(function (fileError) {
170 | // fecs的行号和列号与vscode有差异。。。。
171 | var line = fileError.line - 1;
172 | var column = fileError.column - 1;
173 |
174 | return new vscode.Diagnostic(
175 | new vscode.Range(line, column, line, column + 1),
176 | `[FECS]: ${fileError.message} (${fileError.rule})`,
177 | {
178 | 1: vscode.DiagnosticSeverity.Warning,
179 | 2: vscode.DiagnosticSeverity.Error
180 | }[fileError.severity]
181 | );
182 | })
183 | ];
184 | });
185 | }
186 | ```
187 |
188 | > **注:** [fecs 是什么?](http://fecs.baidu.com/)
189 |
--------------------------------------------------------------------------------
/source/_posts/当心,babel 处理 Symbol 的麻烦.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 当心,babel 处理 Symbol 的麻烦
3 | date: 2016-12-28 22:29
4 | tags:
5 | - JavaScript
6 | - babel
7 | ---
8 |
9 | 在使用 babel 转换 ES next 代码的时候,并不会将 Symbol 直接转换成 ES5 中对应的内容,需要引入额外的 polyfill 才能正常工作。
10 |
11 |
12 | 有的团队为了避免引入这个额外的 polyfill ,会选择不使用 Symbol ,包括通过 babel 生成 Symbol 的特性(比如 `for of` 等)。
13 |
14 | 这时候就会有个比较隐蔽的地方需要注意,就是尽量不要让 babel 生成这样的代码:
15 |
16 | ```js
17 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
18 | ```
19 |
20 | 这个里面包含了一个 `Symbol` ,为了让 `Symbol` 不至于报错,又要想办法在全局先声明一下 `Symbol` 变量,比较丑陋。
21 |
22 | 目前在实践中,发现这样的 ES next 代码会生成上述代码:
23 |
24 | ```js
25 | function fn1() {
26 | if (1) {
27 | let a = 1;
28 | filter(function fn() {
29 | console.log(a);
30 | });
31 | return;
32 | }
33 | }
34 | ```
35 |
36 | 生成的代码为:
37 |
38 | ```js
39 | "use strict";
40 |
41 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
42 |
43 | function fn1() {
44 | if (1) {
45 | var _ret = function () {
46 | var a = 1;
47 | filter(function fn() {
48 | console.log(a);
49 | });
50 | return {
51 | v: void 0
52 | };
53 | }();
54 |
55 | if ((typeof _ret === "undefined" ? "undefined" : _typeof(_ret)) === "object") return _ret.v;
56 | }
57 | }
58 | ```
59 |
60 | 这段代码有什么特征呢?就是在 `if` 块中定义了函数,函数中访问了 `if` 块中的“块级变量”,并且 `if` 块使用了 `return` 语句。
61 |
62 | 可以看出,babel 为了保证 `if` 块内变量的作用域,会套一个匿名函数,同时由于 `if` 块中存在 `return` 返回,所以就用 `_ret` 来接收匿名函数的返回值。然后后面为啥会生成那串长长的对 `_ret` 的类型判断代码,目前还不太清楚,可能要结合 babel 的内部处理逻辑去看了,单从生成的代码看,这个完全是多余的。
63 |
64 | 推而广之, `for` 块等局部非函数作用域都会有类似的问题。
65 |
66 | 实际上,从代码编写规范角度来看,是不应该在这种局部作用域块里面定义函数的。函数应该是一段通用的代码,不应该缩在那一小块里面。
67 |
--------------------------------------------------------------------------------
/source/_posts/爬虫与编码.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 爬虫与编码
3 | date: 2016-01-09 13:23
4 | ---
5 |
6 | 作为一名 web 开发人员,时不时爬爬别人家的网站还是很有趣的。
7 |
8 |
9 | 其实,爬一个网站的数据也是爬取者和被爬取者的一种攻防较量:一般情况下,被爬取者总是会想方设法地阻止爬取者爬取自家网站数据。
10 |
11 | 于是,一些网站就会采取一些措施来阻止非正常访问:
12 |
13 | * 某某关键接口只能每分钟调用若干次;
14 | * 某某 IP 访问网站太频繁,直接拒绝掉该 IP 发过来的请求。
15 |
16 | 当然,这些措施都只是治标不治本,不能从根本上杜绝自己网站数据被爬。
17 |
18 | 从爬取者的角度来看,要突破层层限制,拿到目标网站的数据,还是要做一些事情的:
19 |
20 | * 如果要爬取的目标网页需要登录才能访问到,那么可以采用 phantomjs 来简化掉 session 的处理;
21 | * 在爬取的过程中,如果发现服务器从某个时刻开始一直拒绝掉自己的请求,那么就要怀疑自己的 IP 是否被屏蔽掉了,或者某个接口是否访问太频繁了;
22 | * 对于有 IP 限制策略的网站,尽量模拟正常用户访问,频率不要太快,最好做多个节点来爬取。
23 |
24 | **等等,有点偏题了!下面进入正轨:**
25 |
26 | 在初次写爬虫代码的时候,很容易遇到解析出来的数据是乱码的问题:
27 |
28 | 
29 |
30 | 面对这些乱码,如何解决呢?
31 |
32 | ### 注意 HTTP 响应的头部
33 |
34 | 留意一下 HTTP 响应的头部是否有用 gzip 压缩过:
35 |
36 | ```
37 | Content-Encoding:gzip
38 | ```
39 |
40 | 如果有这种字眼,那么响应正文部分就是使用 gzip 压缩过的,在拿到这种压缩过的数据之后,要先解压。
41 |
42 | Node.js 中,提供了 zlib 模块,用于处理 gzip 相关的操作。对于解压 gzip ,可以这样做:
43 |
44 | ```js
45 | // `res` 是响应对象,http.IncommingMessage 类型的
46 |
47 | var buffers = [];// 暂存 gzip 解压过后的 buffer
48 | var size = 0;// 记录整个响应体解压后的数据大小
49 | var gunzipStream = zlib.createGunzip();
50 | res.pipe(gunzipStream);
51 | gunzipStream.on('data', function (buffer) {
52 | buffers.push(buffer);
53 | size += buffer.length;
54 | });
55 | gunzipStream.on('error', function (error) {
56 | // 发生了错误,处理下吧!
57 | });
58 | gunzipStream.on('end', function () {
59 | var unzipedBuffer = Buffer.concat(buffers, size); // unzipedBuffer 就是解压过后的数据
60 | });
61 | ```
62 |
63 | ### 注意文本编码
64 |
65 | 拿着最终 gzip 解压出来的数据,开心的去进行后续处理,结果继续乱码,为什么会这样?
66 |
67 | Node.js 里面默认字符串是 `utf-8` 编码的,如果 gzip 解压出来的数据不是 `utf-8` 编码的话,那么把这堆 buffer 数据转换成字符串的时候就可能产生乱码。 到目前为止,Node.js 内置支持的解码方式很有限,只能依靠一些第三方模块进行某些文本解码。
68 |
69 | 怎么办呢?
70 |
71 | 留意一下响应头当中的 `Content-Type` 部分,如果 charset 是非 `utf-8` 的话,那就要考虑继续对数据进行解码了。
72 |
73 | 对于中文网站,可能会使用 `GBK` 或者 `GB2312` 进行编码,对于此种场景,需要用到第三方的解码工具,此处选用了 `iconv-lite` 。解码过程如下:
74 |
75 | ```js
76 | var finallyResponseText = require('iconv-lite').decode(unzipedBuffer, 'gbk');
77 | ```
78 |
79 | 这样,就拿到了最终想要的文本数据。
80 |
--------------------------------------------------------------------------------
/source/_posts/百度 EFE 前端框架学习笔记(ef).md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 百度(EFE)前端框架学习笔记(ef)
3 | date: 2015-06-01
4 | tags:
5 | - JavaScript
6 | ---
7 |
8 | 官方 EF 学习资料:[ActionPanel](https://github.com/ecomfe/ef/blob/master/doc/ActionPanel.md)、[UIModel](https://github.com/ecomfe/ef/blob/master/doc/UIModel.md)、[UIView](https://github.com/ecomfe/ef/blob/master/doc/UIView.md)。
9 |
10 |
11 | ### UIView.js
12 |
13 | 与 ESUI 结合的 `View` 基类。该类有一个主入口方法 enterDocument(),该函数在容器渲染完毕后触发,用于控制元素可见性及绑定事件等 DOM 操作。
14 |
15 | 是 ESUI 中 View 类的子类。
16 |
17 | 该类对应的实例上会有一个视图上下文对象( view.viewContext ),此上下文对象会传递给每个子控件,也就是说每个子控件都会有一个 viewContext 属性。此上下文对象的详细信息参看[百度 EFE 前端框架学习笔记(esui)](https://github.com/yibuyisheng/blogs/issues/4)的 `ViewContext.js` 部分。
18 |
19 | enterDocument() 方法会调用 ESUI 的 main.init() 方法,初始化当前 UIView 实例所管辖的 container 部分,生成各种各样的控件等等。
20 |
21 | 此类生成的实例上有一个很重要的事件属性 uiView.uiEvents,该属性有2种方式:
22 |
23 | * 以 `id:eventName` 为键,以处理函数为值,比如 `{'someId:click': function() {/* do something */}}`。
24 | * 以 `id` 为键,值为一个对象,对象中以 `eventName` 为键,处理函数为值,比如 `{someId: {eventName: function() {/* do something */}}}`。
25 |
26 | 在此处声明的事件,运行时的 `this` 对象均是 `View` 实例,而非控件的实例。同时,在运行期,`UIView` 会克隆该属性,将其中所有的处理函数都进行一次 `bind`,将 `this` 指向自身,因此运行时的 `uiEvents` 与类声明时的不会相同。
27 |
28 | 此类上的 bindEvents() 方法就会根据 uiEvents 指定的事件配置来给子控件绑定事件。
29 |
30 | ### UIModel.js
31 |
32 | 处理 ESUI 场景的 `Model` 实现。 UIModel 继承自 er 的 Model。
33 |
34 | UIModel 添加了 formatter 属性,用于对日期进行格式化。同时增加了一些操作数据的方法:set() 、 fill() 、 getPart()。
35 |
36 | ### ActionPanel.js
37 |
38 | 用于加载子Action的面板控件。继承自 esui 的 Panel 类,不过没有 setContent() 方法。
39 |
40 | ### 小技巧
41 |
42 | ```js
43 | function getControl(node) {
44 | var controls = require('er/controller').currentAction.view.viewContext.getControls();
45 | for (var k in controls) {
46 | var control = controls[k];
47 | if (control.main === node) {
48 | return control;
49 | }
50 | }
51 | }
52 | ```
53 |
54 | 该函数可以根据节点找到这个节点对应的控件对象,对debug有一定帮助。
55 |
--------------------------------------------------------------------------------
/source/_posts/记一次坑爹的对接经历.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 记一次坑爹的对接经历
3 | date: 2015-05-07
4 | tags:
5 | - HTTP
6 | ---
7 |
8 | 事情是这样的:
9 |
10 | 后端提供了一个数据接口 `/account/my/address/` 。咱是有追求的程序员,自然接口要采用 RESTful 的思想,于是服务器端非成功的处理,都会返回 http code 非200的状态码,坑由此而生。
11 |
12 |
13 | 在前端请求这个地方,由于做的是移动端应用,果断采用了手写 xhr 请求,大致接口请求代码如下:
14 |
15 | ```js
16 | function encodeParams(params) {
17 | var paramsStr = [];
18 | for (var k in params) {
19 | paramsStr.push(k + '=' + params[k]);
20 | }
21 | return paramsStr.join('&');
22 | }
23 |
24 | function post(url, params) {
25 | return new Promise(function(resolve, reject) {
26 | var xhr = new XMLHttpRequest();
27 | xhr.open('POST', url);
28 | xhr.onload = function() { resolve(xhr.response); };
29 | xhr.onerror = function() { reject(xhr.response); };
30 | xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
31 | xhr.send(encodeParams(params));
32 | });
33 | }
34 |
35 | post('/account/my/address/', {/*参数*/})
36 | .then(function(response) {
37 | // some code
38 | });
39 | ```
40 |
41 |
42 | 代码写好,拿到 chrome 中一测,出现一个似乎像是请求没发出去的错误:
43 |
44 | 
45 |
46 | 对于当时不知道 chrome://net-internals/ 这个强大工具的我来说,这种错误简直就是一个莫名其妙的东西,很难搞。
47 |
48 | 于是仔细看一眼 request header ,发现没有 `Content-Length` !这是怎么回事?为什么浏览器没计算出来 `Content-Length` ?很不可思议!
49 |
50 | 于是,尝试改变一下请求 body 的编码方式,将上述 post 函数改成这样:
51 |
52 | ```js
53 | function createFormData(params) {
54 | var fd = new FormData();
55 | for (var k in params) {
56 | fd.append(k, params[k]);
57 | }
58 | return fd;
59 | }
60 |
61 | function post(url, params) {
62 | return new Promise(function(resolve, reject) {
63 | var xhr = new XMLHttpRequest();
64 | xhr.open('POST', url);
65 | xhr.onload = function() { resolve(xhr.response); };
66 | xhr.onerror = function() { reject(xhr.response); };
67 | xhr.setRequestHeader('Content-Type', 'multipart/form-data');
68 | xhr.send(createFormData(params));
69 | });
70 | }
71 | ```
72 |
73 | 再测,出现这样的错:
74 |
75 | 
76 |
77 | 仍然没有 `Content-Length` ,错误依旧,简直令人发指!
78 |
79 | 于是重新审视当前的开发模式,整个结构是这样的:我在本地开发前端静态部分,需要数据的时候通过 xhr 请求到后端去请求,为了避免我本地开发的时候还要启动一个后端服务器程序,于是让后端的同学将后端代码部署在一个公网的服务器上,这样我就可以通过代理或者 CORS 的方式来请求相应的接口了。
80 |
81 | 所以此时此刻,有点怀疑是不是这种模式引发的问题,但是再一想,其它很多获取数据提交数据都是这种模式啊,为啥就正常呢!所以这种怀疑被打消。
82 |
83 | chrome 的开发者工具提供的信息太有限,实在想不出来是什么问题,于是到 QQ 群求助网友,其中一位网页给出了这个: chrome://net-internals/ ,抱着试一试的心态,打开,观察,哇咔咔,好牛逼,请求的各个过程尽收眼底!其中我找到了我的 POST 请求:
84 |
85 | 
86 |
87 | 嗯,看来请求还是被正常发送出去了的。再往下看,发现了这个:
88 |
89 | 
90 |
91 | `ERR_UNEXPECTED_PROXY_AUTH` 映入眼帘,代理需要认证?啥玩意儿?然后再看到一个 `Server: nginx/1.4.6 (Ubuntu)` ,仔细想想,为毛 nginx 会说代理认证错误!抓狂,去找后端人员,后端人员果断说不可能是 nginx 有问题!
92 |
93 | 于是,再次崩溃, google 吧!于是尝试各种关键字搜索: `ERR_UNEXPECTED_PROXY_AUTH` 、 `net_error = -323` ...
94 |
95 | 搜索的时候,出现了一条关于 http code 407 的记录,点进去一看,惊呆了, 407 的含义如下:
96 |
97 | > Proxy Authentication Required
98 |
99 | 需要代理授权!再看看上面的那张图,后端返回的 http code 果然是407,于是找到后端人员,问他可能会返回407吗?答案是 yes !(我“怒发冲冠”,于是后端同学,卒)
100 |
101 | #### 总结
102 |
103 | 这次问题解决总结下来有这么几个点,以后要注意:
104 |
105 | * 1、在 RESTful 开发中,一定要对状态码足够敏感;
106 | * 2、好好使用 chrome://net-internals/ ,确实挺强大;
107 | * 3、chrome 出现上述类似错误的时候(407、请求未成功发送出去等等),很可能不显示完整的请求头,不显示响应信息(因为按照语义,此时根本无响应信息可显示)。
108 |
--------------------------------------------------------------------------------
/source/demos/-webkit-border-image.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: false
3 | ---
4 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/source/demos/2016-12-15/form1.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: false
3 | ---
4 |
32 |
33 |
60 |
--------------------------------------------------------------------------------
/source/demos/2016-12-15/form2.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: false
3 | ---
4 |
30 |
31 |
58 |
--------------------------------------------------------------------------------
/source/demos/border-image.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: false
3 | ---
4 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/source/demos/border-radius.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: false
3 | ---
4 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/source/demos/css background.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: false
3 | ---
4 |
33 |
34 |
59 |
60 |
--------------------------------------------------------------------------------
/source/demos/css skew.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: false
3 | ---
4 |
51 |
52 |
53 |
skewX(45deg)
54 |
55 |
56 |
skewY(45deg)
57 |
58 |
59 |
--------------------------------------------------------------------------------
/source/demos/envelope.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: false
3 | ---
4 |
19 |
the envelope border
20 |
--------------------------------------------------------------------------------
/source/demos/half ellipse.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: false
3 | ---
4 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/source/demos/marching ants borders.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: false
3 | ---
4 |
21 |
--------------------------------------------------------------------------------
/source/demos/transform-origin.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: false
3 | ---
4 |
5 |
28 |
29 |
34 |
35 |
58 |
59 |
--------------------------------------------------------------------------------
/source/demos/transform-style.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: false
3 | ---
4 |
41 |
42 |
50 |
51 |
87 |
88 |
--------------------------------------------------------------------------------
/source/demos/空心字1.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: false
3 | ---
4 |
25 |
空心字
--------------------------------------------------------------------------------
/source/demos/空心字2.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: false
3 | ---
4 |
24 |
BARCITO
--------------------------------------------------------------------------------
/source/images/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/source/images/1.jpg
--------------------------------------------------------------------------------
/source/images/10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/source/images/10.jpg
--------------------------------------------------------------------------------
/source/images/11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/source/images/11.jpg
--------------------------------------------------------------------------------
/source/images/12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/source/images/12.png
--------------------------------------------------------------------------------
/source/images/13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/source/images/13.png
--------------------------------------------------------------------------------
/source/images/14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/source/images/14.png
--------------------------------------------------------------------------------
/source/images/15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/source/images/15.png
--------------------------------------------------------------------------------
/source/images/16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/source/images/16.png
--------------------------------------------------------------------------------
/source/images/17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/source/images/17.png
--------------------------------------------------------------------------------
/source/images/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/source/images/2.jpg
--------------------------------------------------------------------------------
/source/images/2016-12-15/form.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/source/images/2016-12-15/form.png
--------------------------------------------------------------------------------
/source/images/2016-12-26/directory.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/source/images/2016-12-26/directory.png
--------------------------------------------------------------------------------
/source/images/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/source/images/3.jpg
--------------------------------------------------------------------------------
/source/images/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/source/images/4.jpg
--------------------------------------------------------------------------------
/source/images/5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/source/images/5.jpg
--------------------------------------------------------------------------------
/source/images/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/source/images/6.png
--------------------------------------------------------------------------------
/source/images/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/source/images/7.png
--------------------------------------------------------------------------------
/source/images/8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/source/images/8.jpg
--------------------------------------------------------------------------------
/source/images/9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/source/images/9.jpg
--------------------------------------------------------------------------------
/themes/indigo/README.md:
--------------------------------------------------------------------------------
1 | hexo-theme-material-indigo
2 | ================
3 |
4 | Material Design 风格的Hexo主题,基于 Hexo 3.0+ 制作。预览 [我的博客](http://www.imys.net/)
5 |
6 | ## 特色
7 |
8 | 1. 仅支持 IE10+ 等现代浏览器。
9 | 2. 去 jQuery,更轻。相信现代浏览器的原生兼容性。
10 | 3. 去 fancybox。没了 jQuery, 这个自然也失效了。
11 | 4. 使用 Less 作为 css 预处理器,需要安装 `hexo-renderer-less`。
12 | 5. 添加了英文字体支持 Roboto。
13 | 6. 添加了一些波纹效果。By [Waves](https://github.com/fians/Waves)
14 | 7. 分享直接使用了 JiaThis API 接口,免去了一次加载请求。
15 | 8. 基于静态数据的站内搜索,无第三方侵入。
16 |
17 | ## 使用
18 |
19 | [Document](https://github.com/yscoder/hexo-theme-indigo/wiki)
20 |
21 |
22 | ## 截图
23 |
24 | ### PC
25 |
26 | 
27 |
28 | ### Pad
29 |
30 | 
31 |
32 | ### Phone
33 |
34 | 
35 | 
36 |
37 |
--------------------------------------------------------------------------------
/themes/indigo/_config.yml:
--------------------------------------------------------------------------------
1 | # 添加新菜单项遵循以下规则
2 | # menu:
3 | # link: fontawesome图标,省略前缀,本主题前缀为 icon-,必须
4 | # text: About 菜单显示的文字,如果省略即默认与图标一致,首字母会转大写
5 | # url: /about 链接,绝对或相对路径,必须。
6 | # target: _blank 是否跳出,省略则在当前页面打开
7 | menu:
8 | home:
9 | text: 主页
10 | url: /
11 | archives:
12 | text: 归档
13 | url: /archives
14 | github:
15 | text: GitHub
16 | url: https://github.com/yibuyisheng
17 | target: _blank
18 | link:
19 | text: 知乎
20 | url: https://www.zhihu.com/people/yibuyisheng
21 | target: _blank
22 | weibo:
23 | text: 微博
24 | url: http://weibo.com/2674779523
25 | target: _blank
26 |
27 | rss: /atom.xml
28 |
29 | #你的头像url
30 | avatar: https://avatars3.githubusercontent.com/u/2581682?v=3&s=460
31 |
32 | # email
33 | email: yibuyisheng@163.com
34 |
35 | # Content
36 | tags:
37 | title: 标签
38 |
39 | excerpt_link: more
40 | mathjax: false
41 | archive_yearly: true
42 |
43 | #是否开启分享
44 | share: false
45 |
46 | #是否开启搜索
47 | search: false
48 |
49 | #是否大屏幕下文章页隐藏导航
50 | hideMenu: true
51 |
52 | #是否开启toc
53 | #toc: false
54 | toc:
55 | list_number: false # 是否显示数字排序
56 |
57 | #站长统计,如要开启,输入CNZZ站点id,如 cnzz: 1255152447
58 | cnzz: false
59 |
60 | # Miscellaneous
61 | google_analytics: ''
62 | favicon: /favicon.ico
63 |
64 | # less
65 | less:
66 | paths:
67 | - source/css/style.less
68 |
69 | #是否开启多说评论,填写你在多说申请的项目名称 duoshuo: duoshuo-key
70 | #若使用disqus,请在博客config文件中填写disqus_shortname,并关闭多说评论
71 | duoshuo: yibuyishengblogs
72 |
--------------------------------------------------------------------------------
/themes/indigo/layout/_partial/after-footer.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | <% if(theme.share){ %>
4 |
12 | <%- partial('post/share', {className: 'global-share'}) %>
13 | <% } %>
14 |
--------------------------------------------------------------------------------
/themes/indigo/layout/_partial/archive-post.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%- partial('post/title') %>
6 |
7 |
8 |
14 |
15 |
--------------------------------------------------------------------------------
/themes/indigo/layout/_partial/archive.ejs:
--------------------------------------------------------------------------------
1 | <% if (pagination == 2){ %>
2 |
3 | <% page.posts.each(function(post){ %>
4 | - <%- partial('article', {post: post, index: true}) %>
5 | <% }) %>
6 |
7 | <% if (page.total > 1){ %>
8 |
16 | <% } %>
17 | <% } else { %>
18 | <% var last; %>
19 | <% page.posts.each(function(post, i){ %>
20 | <% var year = post.date.year(); %>
21 | <% if (last != year){ %>
22 | <% if (last != null){ %>
23 |
24 | <% } %>
25 | <% last = year; %>
26 |
5 | <% if(index) { %>
6 | <%- partial('post/title') %>
7 |
8 |
<%- partial('post/tag') %>
9 | <%- partial('post/date', {date_format: config.date_format}) %>
10 |
11 |
12 | <% if (post.excerpt){ %>
13 | <%- post.excerpt %>
14 | <% } else { %>
15 | <%- post.content %>
16 | <% } %>
17 |
18 |
21 | <% } else { %>
22 |
23 |
<%- partial('post/tag') %>
24 |
25 |
26 |
27 |
44 |
45 |
46 |
47 |
48 | <%- post.content %>
49 |
50 |
51 | <%- partial('post/comment') %>
52 |
53 |
54 |
55 |
56 |
57 | <% } %>
58 |
59 |
60 |
61 | <% } %>
62 |
--------------------------------------------------------------------------------
/themes/indigo/layout/_partial/cnzz.ejs:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/themes/indigo/layout/_partial/footer.ejs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yibuyisheng/blogs/b83390ebe3d52a57d17ae917452b6b319ab64fae/themes/indigo/layout/_partial/footer.ejs
--------------------------------------------------------------------------------
/themes/indigo/layout/_partial/google-analytics.ejs:
--------------------------------------------------------------------------------
1 | <% if (theme.google_analytics){ %>
2 |
3 |
13 |
14 | <% } %>
15 |
--------------------------------------------------------------------------------
/themes/indigo/layout/_partial/head.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
3 | <%- list_categories(post.categories, {
4 | show_count: false,
5 | class: 'article-category',
6 | style: 'none',
7 | separator: ''
8 | }) %>
9 |
10 | <% } %>
11 |
--------------------------------------------------------------------------------
/themes/indigo/layout/_partial/post/comment.ejs:
--------------------------------------------------------------------------------
1 | <% if (!index && theme.duoshuo && post.comments){ %>
2 | <%- partial('duoshuo', {
3 | key: post.slug,
4 | title: post.title,
5 | url: url
6 | }) %>
7 | <% } %>
8 |
9 | <% if (!index && post.comments && config.disqus_shortname){ %>
10 |
25 | <% } %>
26 |
--------------------------------------------------------------------------------
/themes/indigo/layout/_partial/post/date.ejs:
--------------------------------------------------------------------------------
1 |