-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
508 lines (297 loc) · 347 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>brucewar</title>
<link href="/atom.xml" rel="self"/>
<link href="http://brucewar.cn/"/>
<updated>2020-05-19T14:25:28.870Z</updated>
<id>http://brucewar.cn/</id>
<author>
<name>brucewar</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>使用requestAnimationFrame实现通知栏滚动</title>
<link href="http://brucewar.cn/2020/05/19/%E4%BD%BF%E7%94%A8requestAnimationFrame%E5%AE%9E%E7%8E%B0%E9%80%9A%E7%9F%A5%E6%A0%8F%E6%BB%9A%E5%8A%A8/"/>
<id>http://brucewar.cn/2020/05/19/使用requestAnimationFrame实现通知栏滚动/</id>
<published>2020-05-19T14:21:33.000Z</published>
<updated>2020-05-19T14:25:28.870Z</updated>
<content type="html"><![CDATA[<h1 id="requestAnimationFrame是什么"><a href="#requestAnimationFrame是什么" class="headerlink" title="requestAnimationFrame是什么"></a>requestAnimationFrame是什么</h1><p><code>window.requestAnimationFrame()</code> 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。如果想让浏览器在下一次重绘前继续更新下一帧动画,需要在回调函数中再次调用<code>window.requestAnimationFrame()</code>。</p><p>回调函数执行次数通常是每秒<strong>60</strong>次,但在大多数遵循W3C建议的浏览器中,回调函数执行次数通常与浏览器屏幕刷新次数相匹配。为了提高性能和电池寿命,因此在大多数浏览器里,当<code>requestAnimationFrame()</code> 运行在后台标签页或者隐藏的<code><iframe></code> 里时,<code>requestAnimationFrame()</code> 会被暂停调用以提升性能和电池寿命。</p><p>回调函数执行时,会被传入一个时间戳参数,表示当前执行回调函数的时刻。</p><h2 id="如何使用"><a href="#如何使用" class="headerlink" title="如何使用"></a>如何使用</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">let</span> frameId = <span class="built_in">window</span>.requestAnimationFrame(callback)</div><div class="line"></div><div class="line"><span class="comment">// 停止动画</span></div><div class="line"><span class="built_in">window</span>.cancelAnimationFrame()</div></pre></td></tr></table></figure><h2 id="优缺点"><a href="#优缺点" class="headerlink" title="优缺点"></a>优缺点</h2><p>和<code>setTimeout(callback, 16)</code>类似,但又不同,<code>requestAnimationFrame</code>是通过浏览器刷新频率决定执行的最佳时机,动画不会出现卡顿现象。</p><ul><li>优点<ul><li>动画保持60fps(每帧16ms),浏览器内部决定渲染的最佳时机</li><li>API简洁标准,维护成本低</li></ul></li><li>缺点<ul><li>动画的开始/取消需要开发者自己控制</li><li>浏览器标签未激活时,一切都不会执行</li><li>老版本浏览器不支持IE9</li><li>Node.js不支持,无法用在服务器的文件系统事件</li></ul></li></ul><h1 id="实现滚动通知栏"><a href="#实现滚动通知栏" class="headerlink" title="实现滚动通知栏"></a>实现滚动通知栏</h1><p>以下基于React实现了一个文字可滚动的通知栏:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> React, { Component } <span class="keyword">from</span> <span class="string">'react'</span></div><div class="line"></div><div class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="class"><span class="keyword">class</span> <span class="title">NoticeBar</span> <span class="keyword">extends</span> <span class="title">Component</span> </span>{</div><div class="line">  <span class="keyword">constructor</span> (props) {</div><div class="line">    <span class="keyword">super</span>(props)</div><div class="line">    <span class="keyword">this</span>.state = {</div><div class="line">      <span class="attr">closed</span>: <span class="literal">false</span></div><div class="line">    }</div><div class="line">    <span class="keyword">this</span>.marquee = <span class="literal">null</span></div><div class="line">    <span class="keyword">this</span>.aFrameId = <span class="literal">null</span></div><div class="line">  }</div><div class="line">  componentDidMount () {</div><div class="line">    <span class="keyword">if</span> (<span class="built_in">window</span>.requestAnimationFrame && <span class="keyword">this</span>.props.marqueeText) {</div><div class="line">      <span class="keyword">let</span> scrollWidth = <span class="keyword">this</span>.marquee.parentElement.offsetWidth</div><div class="line">      <span class="keyword">let</span> textWidth = <span class="keyword">this</span>.marquee.offsetWidth</div><div class="line">      <span class="keyword">let</span> right = <span class="number">0</span></div><div class="line">      <span class="keyword">let</span> marquee = <span class="function"><span class="params">()</span> =></span> {</div><div class="line">        right++</div><div class="line">        <span class="keyword">if</span> (right >= textWidth - scrollWidth + <span class="number">30</span>) {</div><div class="line">          right = <span class="number">0</span></div><div class="line">        }</div><div class="line">        <span class="keyword">this</span>.marquee.style.right = right + <span class="string">'px'</span></div><div class="line">        <span class="keyword">this</span>.aFrameId = <span class="built_in">window</span>.requestAnimationFrame(marquee)</div><div class="line">      }</div><div class="line">      <span class="keyword">if</span>(textWidth > scrollWidth) <span class="keyword">this</span>.aFrameId = <span class="built_in">window</span>.requestAnimationFrame(marquee)</div><div class="line">    }</div><div class="line"> }</div><div class="line">  componentWillUnmount () {</div><div class="line"> <span class="comment">// 为了提高性能,组件卸载前,记得停止动画</span></div><div class="line">    <span class="built_in">window</span>.cancelAnimationFrame(<span class="keyword">this</span>.aFrameId)</div><div class="line">    <span class="keyword">this</span>.aFrameId = <span class="literal">null</span></div><div class="line">  }</div><div class="line">  onClose = <span class="function"><span class="params">()</span> =></span> {</div><div class="line">    <span class="keyword">if</span> (<span class="keyword">this</span>.aFrameId) {</div><div class="line">      <span class="built_in">window</span>.cancelAnimationFrame(<span class="keyword">this</span>.aFrameId)</div><div class="line">      <span class="keyword">this</span>.aFrameId = <span class="literal">null</span></div><div class="line">    }</div><div class="line">    <span class="keyword">this</span>.setState({ <span class="attr">closed</span>: <span class="literal">true</span> })</div><div class="line">  }</div><div class="line">  render () {</div><div class="line">    <span class="keyword">const</span> { mode, marqueeText, onClick, children } = <span class="keyword">this</span>.props</div><div class="line">    <span class="keyword">const</span> { onClose } = <span class="keyword">this</span></div><div class="line">    <span class="keyword">const</span> { closed } = <span class="keyword">this</span>.state</div><div class="line">    <span class="keyword">if</span> (closed) <span class="keyword">return</span> <span class="literal">null</span></div><div class="line">    <span class="keyword">return</span> (</div><div class="line">      <div className="notice-bar"></div><div class="line">        <div className="notice-bar-icon"/></div><div class="line">        <div className="notice-bar-content"></div><div class="line">          {!!children && children}</div><div class="line">          {</div><div class="line">            !!marqueeText && !children && (</div><div class="line">              <div className="notice-bar-marquee-wrap"></div><div class="line">                <div className="notice-bar-marquee" ref={ele => this.marquee = ele}></div><div class="line">                  {marqueeText}</div><div class="line">                </div></div><div class="line">              </div></div><div class="line">            )</div><div class="line">          }</div><div class="line">        </div></div><div class="line">        {</div><div class="line">          mode === 'link' && (</div><div class="line">            <div className="notice-bar-operation" onClick={onClick}></div><div class="line">              <i className="icon-link"/></div><div class="line">            </div></div><div class="line">          )</div><div class="line">        }</div><div class="line">        {</div><div class="line">          mode === 'closable' && (</div><div class="line">            <div className="notice-bar-operation" onClick={onClose}></div><div class="line">              <i className="icon-close"/></div><div class="line">            </div></div><div class="line">          )</div><div class="line">        }</div><div class="line">      </div></div><div class="line">    )</div><div class="line">  }</div><div class="line">}</div></pre></td></tr></table></figure><figure class="highlight scss"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div></pre></td><td class="code"><pre><div class="line"><span class="selector-class">.notice-bar</span>{</div><div class="line">  <span class="attribute">width</span>: <span class="number">100%</span>;</div><div class="line">  <span class="attribute">height</span>: <span class="number">30px</span>;</div><div class="line">  <span class="attribute">border-radius</span>: <span class="number">6px</span>;</div><div class="line">  <span class="attribute">background</span>: <span class="number">#ffe37e</span>;</div><div class="line">  <span class="attribute">font-size</span>: <span class="number">12px</span>;</div><div class="line">  <span class="attribute">color</span>: <span class="number">#222</span>;</div><div class="line">  <span class="attribute">display</span>: flex;</div><div class="line">  <span class="attribute">align-items</span>: center;</div><div class="line">  <span class="attribute">padding</span>: <span class="number">0</span> <span class="number">0</span> <span class="number">0</span> <span class="number">9px</span>;</div><div class="line">  & > <span class="selector-class">.notice-bar-icon</span>{</div><div class="line">    <span class="attribute">background</span>: url(<span class="string">"../img/notice-bar-icon.png"</span>) center no-repeat;</div><div class="line">    <span class="attribute">background-size</span>: <span class="number">100%</span>;</div><div class="line">    <span class="attribute">width</span>: <span class="number">9px</span>;</div><div class="line">    <span class="attribute">height</span>: <span class="number">9px</span>;</div><div class="line">    <span class="attribute">margin-right</span>: <span class="number">6px</span>;</div><div class="line">    <span class="attribute">flex-shrink</span>: <span class="number">0</span>;</div><div class="line">    <span class="attribute">flex-grow</span>: <span class="number">0</span>;</div><div class="line">  }</div><div class="line">  & > <span class="selector-class">.notice-bar-content</span>{</div><div class="line">    <span class="attribute">margin-right</span>: <span class="number">12px</span>;</div><div class="line">    <span class="attribute">white-space</span>: nowrap;</div><div class="line">    <span class="attribute">overflow</span>: hidden;</div><div class="line">    <span class="attribute">text-overflow</span>: ellipsis;</div><div class="line">    <span class="attribute">flex</span>: <span class="number">1</span>;</div><div class="line">    & <span class="selector-class">.notice-bar-marquee-wrap</span>{</div><div class="line">      <span class="attribute">overflow</span>: hidden;</div><div class="line">      & <span class="selector-class">.notice-bar-marquee</span>{</div><div class="line">        <span class="attribute">white-space</span>: nowrap;</div><div class="line">        <span class="attribute">display</span>: inline-block;</div><div class="line">        <span class="attribute">position</span>: relative;</div><div class="line">      }</div><div class="line">    }</div><div class="line">  }</div><div class="line">  & > <span class="selector-class">.notice-bar-operation</span>{</div><div class="line">    <span class="attribute">height</span>: <span class="number">100%</span>;</div><div class="line">    <span class="attribute">display</span>: flex;</div><div class="line">    & <span class="selector-class">.icon-close</span>{</div><div class="line">      <span class="attribute">background</span>: url(<span class="string">"../img/notice-bar-close.png"</span>) center no-repeat;</div><div class="line">      <span class="attribute">background-size</span>: <span class="number">100%</span>;</div><div class="line">      <span class="attribute">width</span>: <span class="number">12px</span>;</div><div class="line">      <span class="attribute">height</span>: <span class="number">12px</span>;</div><div class="line">      <span class="attribute">display</span>: block;</div><div class="line">      <span class="attribute">align-self</span>: flex-start;</div><div class="line">      <span class="attribute">flex-shrink</span>: <span class="number">0</span>;</div><div class="line">      <span class="attribute">flex-grow</span>: <span class="number">0</span>;</div><div class="line">    }</div><div class="line">    & <span class="selector-class">.icon-link</span>{</div><div class="line">      <span class="attribute">background</span>: url(<span class="string">"../img/notice-bar-link.png"</span>) center no-repeat;</div><div class="line">      <span class="attribute">background-size</span>: <span class="number">100%</span>;</div><div class="line">      <span class="attribute">width</span>: <span class="number">12px</span>;</div><div class="line">      <span class="attribute">height</span>: <span class="number">12px</span>;</div><div class="line">      <span class="attribute">display</span>: block;</div><div class="line">      <span class="attribute">align-self</span>: center;</div><div class="line">      <span class="attribute">flex-shrink</span>: <span class="number">0</span>;</div><div class="line">      <span class="attribute">flex-grow</span>: <span class="number">0</span>;</div><div class="line">      <span class="attribute">margin-right</span>: <span class="number">12px</span>;</div><div class="line">    }</div><div class="line">  }</div><div class="line">}</div></pre></td></tr></table></figure>]]></content>
<summary type="html">
<h1 id="requestAnimationFrame&#x662F;&#x4EC0;&#x4E48;"><a href="#requestAnimationFrame&#x662F;&#x4EC0;&#x4E48;" class="headerlink" title="re
</summary>
<category term="Web前端" scheme="http://brucewar.cn/categories/Web%E5%89%8D%E7%AB%AF/"/>
<category term="React" scheme="http://brucewar.cn/tags/React/"/>
<category term="requestAnimationFrame" scheme="http://brucewar.cn/tags/requestAnimationFrame/"/>
</entry>
<entry>
<title>什么是thunk?</title>
<link href="http://brucewar.cn/2019/05/07/%E4%BB%80%E4%B9%88%E6%98%AFthunk%EF%BC%9F/"/>
<id>http://brucewar.cn/2019/05/07/什么是thunk?/</id>
<published>2019-05-07T06:40:53.000Z</published>
<updated>2020-05-19T14:25:05.379Z</updated>
<content type="html"><![CDATA[<blockquote><p>问:什么是<code>thunk</code>?<br>答:第一次听到这个词是通过<code>redux-thunk</code></p></blockquote><p>言归正传,当第一次听到Redux Thunk时,令人非常困惑。很可能就是因为<code>thunk</code>这个词。所以我们首先要弄清楚这一点。</p><h3 id="thunk"><a href="#thunk" class="headerlink" title="thunk"></a>thunk</h3><p><code>thunk</code>是函数的另一个词,但它不仅仅只是我们所认识的函数。它是另一个函数返回的一个特殊的函数。如下所示:<br></p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">wrapper_function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="comment">// 这就是thunk,因为它把一些任务推迟做</span></div><div class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> <span class="title">thunk</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="built_in">console</span>.log(<span class="string">'do stuff now'</span>);</div><div class="line"> };</div><div class="line">}</div></pre></td></tr></table></figure><p></p><p>你可能已经见过这样的代码,只是你不把它叫做<code>thunk</code>。如果想要执行“do stuff now”部分,你必须调用两次<code>wrapper_function()()</code>。</p><h3 id="redux-thunk"><a href="#redux-thunk" class="headerlink" title="redux-thunk"></a>redux-thunk</h3><p>那么如何应用在Redux。<br>如果熟悉Redux,下面这些概念对你来说应该不陌生:<strong>actions</strong>,<strong>action creators</strong>,<strong>reducers</strong>和<strong>middleware</strong>。如果不熟悉的话,建议先看下<a href="https://redux.js.org/introduction/getting-started" target="_blank" rel="external">Redux基础教程</a>。</p><p>在Redux中,<strong>actions</strong>只是一个普通的JavaScript对象,并且这个对象中包含<code>type</code>属性。除此之外,可以包含任何你想要的——描述要执行的action。<br></p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 1. 普通对象</span></div><div class="line"><span class="comment">// 2. 有type属性</span></div><div class="line"><span class="comment">// 3. 其他任意内容</span></div><div class="line">{</div><div class="line"> <span class="attr">type</span>: <span class="string">'USER_LOGGED_IN'</span>,</div><div class="line"> <span class="attr">username</span>: <span class="string">'dave'</span></div><div class="line">}</div></pre></td></tr></table></figure><p></p><p>因为一直手工编写这些对象很烦人(更别说容易出错),Redux通过“action creators”这个概念解决:<br></p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">userLoggedIn</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">return</span> {</div><div class="line"> <span class="attr">type</span>: <span class="string">'USER_LOGGED_IN'</span>,</div><div class="line"> <span class="attr">username</span>: <span class="string">'dave'</span></div><div class="line"> };</div><div class="line">}</div></pre></td></tr></table></figure><p></p><p>两个完全相同的<strong>action</strong>,只是现在抽象了一层,你需要通过调用<code>userLoggedIn</code>函数创建。如果想在应用的不同位置触发同样的<strong>action</strong>,可以很方便的使用<strong>action creator</strong>。</p><h3 id="烦人的Actions"><a href="#烦人的Actions" class="headerlink" title="烦人的Actions"></a>烦人的Actions</h3><p>Redux所谓的“actions”其实并没做任何事,它们只是普通的对象。如果让他们做点事岂不是更酷?比如说,API调用或者触发别的<strong>actions</strong>?<br>因为<strong>reducers</strong>应该是纯函数,不会改变其作用域范围之外的任何东西,所以我们不能在其内部做API调用或者触发<strong>actions</strong>。<br>如果你希望<strong>action</strong>执行某些操作,则这部分代码存在某个函数。这个函数(<strong>thunk</strong>)就是这一系列操作。<br>如果<strong>action creator</strong>能够返回一个函数(一系列的操作)而不是一个<strong>action</strong>对象岂不是更好,就像下面这样:<br></p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">getUser</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">return</span> axios.get(<span class="string">'/current_user'</span>);</div><div class="line"> };</div><div class="line">}</div></pre></td></tr></table></figure><p></p><p>如果有一种方法可以告诉Redux把函数当作<strong>actions</strong>处理。<br>当然,这正是<strong>redux-thunk</strong>做的:它是一个<strong>middleware</strong>,系统中所有的action都会经过它,如果action是一个函数,就会调用那个函数。<br>上面那一小段代码中遗漏了一些东西,那就是Redux会传递两个参数给thunk函数:</p><ul><li><code>dispatch</code>:可以用来触发新的action</li><li><code>getState</code>:访问当前的state<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">logOutUser</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params">dispatch, getState</span>) </span>{</div><div class="line"> <span class="keyword">return</span> axios.post(<span class="string">'/logout'</span>).then(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="comment">// 假设我们声明了一个叫 userLoggedOut 的 action creator,现在我们触发它</span></div><div class="line"> dispatch(userLoggedOut());</div><div class="line"> });</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure></li></ul><p>依赖当前state,<code>getState</code>函数在决定是否获取数据还是返回缓存数据时非常有用。</p><h3 id="确实非常小的库"><a href="#确实非常小的库" class="headerlink" title="确实非常小的库"></a>确实非常小的库</h3><p><strong>redux-thunk</strong>库的所有代码如下:<br></p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">createThunkMiddleware</span>(<span class="params">extraArgument</span>) </span>{</div><div class="line"> <span class="keyword">return</span> <span class="function">(<span class="params">{ dispatch, getState }</span>) =></span> next => <span class="function"><span class="params">action</span> =></span> {</div><div class="line"> <span class="comment">// 触发每个action这里都会被调用</span></div><div class="line"> <span class="comment">// 如果是函数就调用它</span></div><div class="line"> <span class="keyword">if</span> (<span class="keyword">typeof</span> action === <span class="string">'function'</span>) {</div><div class="line"> <span class="keyword">return</span> action(dispatch, getState, extraArgument);</div><div class="line"> }</div><div class="line"> </div><div class="line"> <span class="comment">// 否则继续按正常处理</span></div><div class="line"> <span class="keyword">return</span> next(action);</div><div class="line"> };</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keyword">const</span> thunk = createThunkMiddleware();</div><div class="line">thunk.withExtraArgument = createThunkMiddleware;</div><div class="line"></div><div class="line"><span class="keyword">export</span> <span class="keyword">default</span> thunk;</div></pre></td></tr></table></figure><p></p><p>如果项目中安装了redux-thunk,并且把它当成中间件,触发的每个action都会进入这部分代码。如果action是函数就调用那个函数(不管函数返回什么),否则将它传递给下一个中间件,最终会交给Redux(<code>netx(action)</code>完成这部分工作)。</p><h3 id="项目中使用redux-thunk"><a href="#项目中使用redux-thunk" class="headerlink" title="项目中使用redux-thunk"></a>项目中使用redux-thunk</h3><p>如果项目中已经安装了Redux,只需两步就可添加redux-thunk。<br>首先,安装包:<br></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">npm install --save redux-thunk</div></pre></td></tr></table></figure><p></p><p>然后在使用redux的代码部分,引入<code>redux-thunk</code>中间件,添加到Redux中。<br></p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 你可以已经引入了createStore,还需要引入applyMiddleware</span></div><div class="line"><span class="keyword">import</span> { createStore, applyMiddleware } <span class="keyword">from</span> <span class="string">'redux'</span>;</div><div class="line"><span class="comment">// 引入`thunk` 中间件</span></div><div class="line"><span class="keyword">import</span> thunk <span class="keyword">from</span> <span class="string">'redux-thunk'</span>;</div><div class="line"><span class="keyword">import</span> rootReducer <span class="keyword">from</span> <span class="string">'./reducers/index'</span>;</div><div class="line"><span class="comment">// 使用applyMiddleware创建thunk中间件</span></div><div class="line"><span class="keyword">const</span> store = createStore(</div><div class="line"> rootReducer,</div><div class="line"> applyMiddleware(thunk)</div><div class="line">);</div></pre></td></tr></table></figure><p></p><p>确保<code>thunk</code>作为<code>applyMiddleware</code>参数调用,否则不起作用。这样你已经完成了所有设置,现在可以dispatch任何函数。</p>]]></content>
<summary type="html">
<blockquote><p>&#x95EE;&#xFF1A;&#x4EC0;&#x4E48;&#x662F;<code>thunk</code>&#xFF1F;<br>&#x7B54;&#xFF1A;&#x7B2C;&#x4E00;&#x6B21;&#x542C;&#x5230
</summary>
<category term="React" scheme="http://brucewar.cn/categories/React/"/>
<category term="React" scheme="http://brucewar.cn/tags/React/"/>
<category term="redux" scheme="http://brucewar.cn/tags/redux/"/>
<category term="redux-thunk" scheme="http://brucewar.cn/tags/redux-thunk/"/>
<category term="thunk" scheme="http://brucewar.cn/tags/thunk/"/>
</entry>
<entry>
<title>2017:清白之年</title>
<link href="http://brucewar.cn/2017/12/30/2017%EF%BC%9A%E6%B8%85%E7%99%BD%E4%B9%8B%E5%B9%B4/"/>
<id>http://brucewar.cn/2017/12/30/2017:清白之年/</id>
<published>2017-12-30T07:51:37.000Z</published>
<updated>2017-12-30T08:03:42.467Z</updated>
<content type="html"><![CDATA[<iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width="330" height="86" src="//music.163.com/outchain/player?type=2&id=487590187&auto=1&height=66"></iframe><p>转眼又到了年终,我原本不想写今年的总结,因为不想让自己内心再经历这一段痛苦的回忆。</p><p>这一年,经历了太多,也失去太多。2016年12月底,我和朋友定好了元旦去黄山看新年日出,突如其来的噩耗,让我不知所措。堂姐告诉我,父亲得了很重的病,当时,我脑子一片空白。后来我打电话问我姐具体的情况,电话中,我没控制住自己的情绪,姐安慰我说,要等明天去县医院的检查结果。那一晚,我一直祈祷事情没那么糟。第二天检查完,姐姐让我定好江苏省肿瘤医院附近的宾馆,我就感觉到父亲的病情很不好。当晚,爸妈、姐姐、二叔一起到了南京,我看到县城医院核磁检查报告:胰腺癌晚期,最严重的癌症,这对于我们全家是一次沉重的打击。1月4号,父亲接受了手术治疗,手术很成功。从那开始,我白天在公司工作,晚上回医院陪护,工作的时候也不在状态,还一直安慰自己,“一切都会好起来”。就在我以为一切真的会好起来的时候,母亲的胃疼的越来越严重,我陪她去鼓楼医院做了胃镜检查,结果很不理想,”怀疑胃Ca”,但还需要等病理报告。提着心过了一周,病理报告确诊,赶紧带着母亲去鼓楼医院找医生。因为医院需要家属签字,所以作为儿子的我,担起照顾母亲的责任,姐姐留下来照顾父亲。1月22号,母亲接受手术治疗,因为正好快要过年,母亲刚做完手术,所以我陪着母亲在鼓楼医院过了一个今生难忘的年。</p><p><img src="/2017/12/30/2017:清白之年/gulou.JPG" alt="鼓楼医院大厅看到的天空"></p><p>父母术后身体渐渐恢复,为了能照顾到他们,劝他们去姐姐家住段时间,他们最终也接受了。从这之后,我白天努力集中精力工作,虽然人偶尔还是会不在状态。每天晚上我都会给他们打一个电话,听到他们的声音,我的心才能平静。鼓楼医院的医生让我联系省肿瘤医院为我妈安排化疗,而我爸的主治医生不建议给我爸化疗,虽然不愿接受这个现实,但真的只能听天由命。每次来南京化疗,我都会早早地站在医院那边的路口等她,每次看到她,我都难掩心中的泪水。看到医院那么多接受化疗的病人,我能体会到那种痛苦,吃不下东西、呕吐,常人也无法忍受。</p><p>四月份开始,父亲渐渐感觉腹部开始疼痛,因为当时手术的时候就已经确定转移了,我知道应该是复发了,我们也安慰他,说是术后炎症,带他去挂了消炎水。然而,疼痛还是会让他吃不下饭,渐渐的,人越来越消瘦,我因为工作,也很少回去看他,他也不让母亲和二叔打电话给我。每次接完家里的电话,我都控制不住自己的情绪,因为我觉得对不起他们,没尽到做儿子的责任,平时对他们的关心太少。</p><p>9月23号晚上父亲离开了我们,我也不能再叫他一声爸爸,但我永远记得父亲走之前交代给我的两件事。树欲静而风不止,子欲养而亲不待。现在回想,失去了才知道痛的滋味,遗憾太多,这些遗憾也会跟着我一辈子,我所能做的,就是好好照顾我的母亲,尽我最大的努力。</p><p>虽然今年经历了太多痛苦,但他们不是我颓的理由。书没读几本,新知识也没学多少,发现自己越来越失去竞争力,也时常自我反省。对我来说,2018年会是一个新的开始,我要以全新的姿态,勤奋工作,坚持学习,努力赚钱,以积极的态度面对生活。</p>]]></content>
<summary type="html">
<iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width="330" height="86" src="//music.163.com/outchain/player?type=2&amp
</summary>
<category term="随笔" scheme="http://brucewar.cn/categories/%E9%9A%8F%E7%AC%94/"/>
<category term="年终总结" scheme="http://brucewar.cn/tags/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/"/>
</entry>
<entry>
<title>flexbox布局的响应式表格</title>
<link href="http://brucewar.cn/2017/07/06/flexbox%E5%B8%83%E5%B1%80%E7%9A%84%E5%93%8D%E5%BA%94%E5%BC%8F%E8%A1%A8%E6%A0%BC/"/>
<id>http://brucewar.cn/2017/07/06/flexbox布局的响应式表格/</id>
<published>2017-07-06T00:57:19.000Z</published>
<updated>2017-07-06T02:40:10.997Z</updated>
<content type="html"><![CDATA[<p>HTML <code>table</code>元素做响应式表格是非常难用的,我们需要大量的样板和嵌套的HTML来解决这样一个简单的问题。我们来探讨一种使用<code>div</code>和<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Using_CSS_flexible_boxes" target="_blank" rel="external">Flexbox</a>的替代方法。这将给我们带来的好处是能够创建在所有尺寸屏幕上都看起来很棒的响应式表格。</p><p>首先,解决方案将使用<a href="http://inlehmansterms.net/2014/08/25/modular-css-with-suitcss/" target="_blank" rel="external">SUIT CSS</a>以模块化方式写入<a href="http://sass-lang.com/" target="_blank" rel="external">Sass</a>。我们将使用一些Sass库帮助我们完成任务。<a href="https://autoprefixer.github.io/" target="_blank" rel="external">autoprefixer</a>用于帮助我们生成必要的Flexbox CSS供应商前缀,以及<a href="http://breakpoint-sass.com/" target="_blank" rel="external">Breakpoint</a>来帮助我们做media query。如果你喜欢用CSS,请随时将生成的CSS从链接复制到<a href="http://sassmeister.com/gist/b38aca96fc6024a28514" target="_blank" rel="external">Sassmeister</a>示例。</p><p>我们需要的是构建<code>Table</code>组件的3个基本类。首先,我们需要<code>Table</code>类,它将使用Flexbox来使所有的子节点(行)按列布局。接下来,我们需要一个<code>Table-row</code>类,它将使用Flexbox来使其所有的子节点(行/列)按行排列,而不需要包装。最后我们需要<code>Table-row-item</code>,它基本上是表格组件的一个单元格。现在,我们需要的是一个<code>Table-header</code>类,我们可以添加到任何行元素,以给它一个标题的样式。根据这些标准,我们可以为我们的组件编写HTML和Sass,如下所示。</p><p><img src="/2017/07/06/flexbox布局的响应式表格/table1.png" alt="列等宽表格"></p><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table"</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row Table-header"</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span>></span>Header1<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span>></span>Header2<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span>></span>Header3<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span>></span>Header4<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row"</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header1"</span>></span>row1 col1<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header2"</span>></span>row1 col2<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header3"</span>></span>row1 col3<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header4"</span>></span>row1 col4<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row"</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header1"</span>></span>row2 col1<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header2"</span>></span>row2 col2<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header3"</span>></span>row2 col3<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header4"</span>></span>row2 col4<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"></<span class="name">div</span>></span></div><div class="line"><span class="tag"></<span class="name">div</span>></span></div></pre></td></tr></table></figure><figure class="highlight scss"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div></pre></td><td class="code"><pre><div class="line">@<span class="keyword">import</span> <span class="string">"breakpoint"</span>;</div><div class="line"></div><div class="line"><span class="selector-class">.Table</span> {</div><div class="line"> <span class="variable">$light-color</span>: <span class="number">#ffffff</span>;</div><div class="line"> <span class="variable">$dark-color</span>: <span class="number">#f2f2f2</span>;</div><div class="line"> <span class="variable">$md</span>: <span class="number">500px</span>;</div><div class="line"></div><div class="line"> <span class="attribute">display</span>: flex;</div><div class="line"> <span class="attribute">flex-flow</span>: column nowrap;</div><div class="line"> <span class="attribute">justify-content</span>: space-between;</div><div class="line"> <span class="attribute">border</span>: <span class="number">1px</span> solid <span class="variable">$dark-color</span>;</div><div class="line"> <span class="attribute">font-size</span>: <span class="number">1rem</span>;</div><div class="line"> <span class="attribute">margin</span>: <span class="number">0.5rem</span>;</div><div class="line"> <span class="attribute">line-height</span>: <span class="number">1.5</span>;</div><div class="line"></div><div class="line"> <span class="comment">// .Table-header</span></div><div class="line"> &-<span class="selector-tag">header</span> {</div><div class="line"> <span class="attribute">display</span>: none;</div><div class="line"> @<span class="keyword">include</span> breakpoint(<span class="variable">$md</span>) {</div><div class="line"> <span class="attribute">font-weight</span>: <span class="number">700</span>;</div><div class="line"> <span class="attribute">background-color</span>: <span class="variable">$dark-color</span>;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="comment">// .Table-row</span></div><div class="line"> &-row {</div><div class="line"> <span class="attribute">width</span>: <span class="number">100%</span>;</div><div class="line"> &:nth-of-type(even) { <span class="attribute">background-color</span>: <span class="variable">$dark-color</span>; }</div><div class="line"> &:nth-of-type(odd) { <span class="attribute">background-color</span>: <span class="variable">$light-color</span>; }</div><div class="line"> @<span class="keyword">include</span> breakpoint(<span class="variable">$md</span>) {</div><div class="line"> <span class="attribute">display</span>: flex;</div><div class="line"> <span class="attribute">flex-flow</span>: row nowrap;</div><div class="line"> &:nth-of-type(even) { <span class="attribute">background-color</span>: <span class="variable">$light-color</span>; }</div><div class="line"> &:nth-of-type(odd) { <span class="attribute">background-color</span>: <span class="variable">$dark-color</span>; }</div><div class="line"> }</div><div class="line"> <span class="comment">// .Table-row-item</span></div><div class="line"> &-item {</div><div class="line"> <span class="attribute">display</span>: flex;</div><div class="line"> <span class="attribute">flex-flow</span>: row nowrap;</div><div class="line"> <span class="attribute">flex-grow</span>: <span class="number">1</span>;</div><div class="line"> <span class="attribute">flex-basis</span>: <span class="number">0</span>;</div><div class="line"> <span class="attribute">padding</span>: <span class="number">0.5em</span>;</div><div class="line"> <span class="attribute">word-break</span>: break-word;</div><div class="line"> &:before {</div><div class="line"> <span class="attribute">content</span>: attr(data-header);</div><div class="line"> <span class="attribute">width</span>: <span class="number">30%</span>;</div><div class="line"> <span class="attribute">font-weight</span>: <span class="number">700</span>;</div><div class="line"> }</div><div class="line"> @<span class="keyword">include</span> breakpoint(<span class="variable">$md</span>) {</div><div class="line"> <span class="attribute">border</span>: <span class="number">1px</span> solid <span class="variable">$light-color</span>;</div><div class="line"> <span class="attribute">padding</span>: <span class="number">0.5em</span>;</div><div class="line"> &:before { <span class="attribute">content</span>: none; }</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure><p><a href="http://sassmeister.com/gist/b38aca96fc6024a28514" target="_blank" rel="external">在Sassmeister尝试这个例子</a></p><p>根据此实现,我们可以轻松创建响应式表格。每行简单地将项目的数量分解成等于列。这使我们能够灵活地创建具有不同列数的表格。然而,同样的好处也有缺点。</p><p>我们的表格组件的问题是每个列的宽度相同。如果我们有的列包含的数据比其他列更宽或更窄会发生什么呢?幸运的是,Flexbox也使得这个很容易实现。我们可以简单地添加一些实用的工具类来设置不同列的Flexbox增长率。</p><p><img src="/2017/07/06/flexbox布局的响应式表格/table2.png" alt="列不等宽表格"></p><figure class="highlight scss"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// generate Flexbox grow-rate utility classes</span></div><div class="line">@<span class="keyword">for</span> <span class="variable">$i</span> from 1 through 10 {</div><div class="line"> <span class="selector-class">.u-Flex-grow</span>#{<span class="variable">$i</span>} {</div><div class="line"> <span class="attribute">flex-grow</span>: i;</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table"</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row Table-header"</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item u-Flex-grow2"</span>></span>Long Header1<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span>></span>Header2<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span>></span>Header3<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span>></span>Header4<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item u-Flex-grow3"</span>></span>Longer Header5<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span>></span>Header6<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span>></span>Header7<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row"</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item u-Flex-grow2"</span> <span class="attr">data-header</span>=<span class="string">"Header1"</span>></span>row1 col1<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header2"</span>></span>row1 col2<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header3"</span>></span>row1 col3<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header4"</span>></span>row1 col4<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item u-Flex-grow3"</span> <span class="attr">data-header</span>=<span class="string">"Header5"</span>></span>row1 col5<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header6"</span>></span>row1 col6<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header7"</span>></span>row1 col7<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row"</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item u-Flex-grow2"</span> <span class="attr">data-header</span>=<span class="string">"Header1"</span>></span>row2 col1<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header2"</span>></span>row2 col2<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header3"</span>></span>row2 col3<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header4"</span>></span>row2 col4<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item u-Flex-grow3"</span> <span class="attr">data-header</span>=<span class="string">"Header5"</span>></span>row2 col5<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header6"</span>></span>row2 col6<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header7"</span>></span>row2 col7<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row"</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item u-Flex-grow2"</span> <span class="attr">data-header</span>=<span class="string">"Header1"</span>></span>row3 col1<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header2"</span>></span>row3 col2<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header3"</span>></span>row3 col3<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header4"</span>></span>row3 col4<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item u-Flex-grow3"</span> <span class="attr">data-header</span>=<span class="string">"Header5"</span>></span>row3 col5<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header6"</span>></span>row3 col6<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"Table-row-item"</span> <span class="attr">data-header</span>=<span class="string">"Header7"</span>></span>row3 col7<span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"></<span class="name">div</span>></span></div><div class="line"><span class="tag"></<span class="name">div</span>></span></div></pre></td></tr></table></figure><p><a href="http://sassmeister.com/gist/de4eab2113204729ea50" target="_blank" rel="external">在Sassmeister尝试这个例子</a></p><blockquote><p>本文翻译自<a href="http://inlehmansterms.net/2014/10/11/responsive-tables-with-flexbox/" target="_blank" rel="external">http://inlehmansterms.net/2014/10/11/responsive-tables-with-flexbox/</a></p></blockquote>]]></content>
<summary type="html">
<p>HTML <code>table</code>&#x5143;&#x7D20;&#x505A;&#x54CD;&#x5E94;&#x5F0F;&#x8868;&#x683C;&#x662F;&#x975E;&#x5E38;&#x96BE;&#x7528;&#x7684;&#
</summary>
<category term="前端开发" scheme="http://brucewar.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
<category term="CSS" scheme="http://brucewar.cn/tags/CSS/"/>
<category term="flex" scheme="http://brucewar.cn/tags/flex/"/>
</entry>
<entry>
<title>理解AngularJS Providers</title>
<link href="http://brucewar.cn/2017/05/27/%E7%90%86%E8%A7%A3AngularJS-Providers/"/>
<id>http://brucewar.cn/2017/05/27/理解AngularJS-Providers/</id>
<published>2017-05-27T06:17:30.000Z</published>
<updated>2017-05-27T10:19:37.083Z</updated>
<content type="html"><![CDATA[<p>AngularJS 1.x提供了如下5个provider方法,使用这些方法能创建可被注入的服务。但是如何使用这些方法,以及这些方法之间有什么区别呢?所以这篇博客重点记录下这些方法的区别,来帮助自己理解它们。</p><ul><li><a href="#value">value</a></li><li><a href="#factory">factory</a></li><li><a href="#service">service</a></li><li><a href="#constant">provider</a></li><li><a href="#constant">constant</a></li></ul><h1 id="value"><a href="#value" class="headerlink" title="value"></a>value</h1><p>这个方法用来定义常量,并且能在运行阶段注入Controller中。比如我们可以创建一个简单的服务叫”clientId”,并提供一个用于身份验证的id。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> myApp = angular.module(<span class="string">'myApp'</span>, []);</div><div class="line">myApp.value(<span class="string">'clientId'</span>, <span class="string">'12345678'</span>);</div><div class="line"></div><div class="line">myApp.controller(<span class="string">'DemoController'</span>, [<span class="string">'clientId'</span>, <span class="function"><span class="keyword">function</span> <span class="title">DemoController</span>(<span class="params">clientId</span>) </span>{</div><div class="line"> <span class="keyword">this</span>.clientId = clientId;</div><div class="line">}]);</div></pre></td></tr></table></figure><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="tag"><<span class="name">html</span> <span class="attr">ng-app</span>=<span class="string">"myApp"</span>></span></div><div class="line"> <span class="tag"><<span class="name">body</span> <span class="attr">ng-controller</span>=<span class="string">"DemoController as demo"</span>></span></div><div class="line"> Client ID: {{demo.clientId}}</div><div class="line"> <span class="tag"></<span class="name">body</span>></span></div><div class="line"><span class="tag"></<span class="name">html</span>></span></div></pre></td></tr></table></figure><p>注:常量值可以为JS的任意基本类型</p><h1 id="factory"><a href="#factory" class="headerlink" title="factory"></a>factory</h1><p><code>value</code>方法非常简单,但缺少创建服务时常常需要的一些重要功能。所以<code>factory</code>方法增加了以下功能:</p><ul><li>使用其他服务的能力</li><li>服务初始化</li><li>延时初始化</li></ul><p><code>factory</code>方法使用0个或多个参数(其他服务)的函数构建新的服务,并且此函数的返回值为工厂方法创建的服务实例。</p><p>注:AngularJS中所有的服务都是单例,注射器injector最多使用这些provider方法一次来创建服务对象,并将它们缓存下来。</p><p>同样的例子,我们通过<code>factory</code>实现一下:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line">myApp.factory(<span class="string">'clientId'</span>, <span class="function"><span class="keyword">function</span> <span class="title">clientIdFactory</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">return</span> <span class="string">'12345678'</span>;</div><div class="line">});</div><div class="line"></div><div class="line"><span class="comment">// 这里只是返回一个字符串,可能用value更好点。如果需要运算,可以这样写</span></div><div class="line">myApp.factory(<span class="string">'apiToken'</span>, [<span class="string">'clientId'</span>, <span class="function"><span class="keyword">function</span> <span class="title">apiTokenFactory</span>(<span class="params">clientId</span>) </span>{</div><div class="line"> <span class="keyword">var</span> encrypt = <span class="function"><span class="keyword">function</span>(<span class="params">data1, data2</span>) </span>{</div><div class="line"> <span class="keyword">return</span> (data1 + <span class="string">':'</span> + data2).toUpperCase();</div><div class="line"> };</div><div class="line"></div><div class="line"> <span class="keyword">var</span> secret = <span class="built_in">window</span>.localStorage.getItem(<span class="string">'myApp.secret'</span>);</div><div class="line"> <span class="keyword">var</span> apiToken = encrpty(clientId, secret);</div><div class="line"></div><div class="line"> <span class="keyword">return</span> apiToken;</div><div class="line">}]);</div></pre></td></tr></table></figure><p><code>factory</code>方法可以创建任何类型的服务,比如JavaScript基本类型,对象字面量,函数或者自定义类型的实例。</p><h1 id="service"><a href="#service" class="headerlink" title="service"></a>service</h1><p>可能我们经常需要使用自定义类型编写面向对象的代码。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">UnicornLauncher</span>(<span class="params">apiToken</span>) </span>{</div><div class="line"> <span class="keyword">this</span>.launchedCount = <span class="number">0</span>;</div><div class="line"> <span class="keyword">this</span>.launch = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">this</span>.lanuchedCount++;</div><div class="line"> };</div><div class="line">}</div><div class="line"></div><div class="line">myApp.factory(<span class="string">'unicornLauncher'</span>, [<span class="string">'apiToken'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">apiToken</span>) </span>{</div><div class="line"> <span class="keyword">return</span> <span class="keyword">new</span> UnicornLauncher(apiToken);</div><div class="line">}]);</div></pre></td></tr></table></figure><p>上面是通过<code>factory</code>实现对象实例化,然而这里需要我们自己初始化实例,所以Angular提供了<code>service</code>这个方法,它接受一个构造函数作为参数。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">myApp.service(<span class="string">'unicornLauncher'</span>, [<span class="string">'apiToken'</span>, UnicornLauncher]);</div></pre></td></tr></table></figure><h1 id="provider"><a href="#provider" class="headerlink" title="provider"></a>provider</h1><p><code>provider</code>是核心方法,其他方法都是在基于它的语法糖。它的作用是在应用启动前提供可配置的API。通常用在一些可重用的服务,并且这些服务在不同的应用程序之间需要不同配置。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line">myApp.provider(<span class="string">'unicornLauncher'</span>, <span class="function"><span class="keyword">function</span> <span class="title">UnicornLauncherProvider</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">var</span> useTinfoilShielding = <span class="literal">false</span>;</div><div class="line"></div><div class="line"> <span class="keyword">this</span>.useTinfoilShielding = <span class="function"><span class="keyword">function</span>(<span class="params">value</span>) </span>{</div><div class="line"> useTinfoilShielding = !!value;</div><div class="line"> };</div><div class="line"></div><div class="line"> <span class="keyword">this</span>.$get = [<span class="string">"apiToken"</span>, <span class="function"><span class="keyword">function</span> <span class="title">unicornLauncherFactory</span>(<span class="params">apiToken</span>) </span>{</div><div class="line"></div><div class="line"> <span class="comment">// let's assume that the UnicornLauncher constructor was also changed to</span></div><div class="line"> <span class="comment">// accept and use the useTinfoilShielding argument</span></div><div class="line"> <span class="keyword">return</span> <span class="keyword">new</span> UnicornLauncher(apiToken, useTinfoilShielding);</div><div class="line"> }];</div><div class="line">});</div><div class="line"></div><div class="line">myApp.config([<span class="string">"unicornLauncherProvider"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">unicornLauncherProvider</span>) </span>{</div><div class="line"> unicornLauncherProvider.useTinfoilShielding(<span class="literal">true</span>);</div><div class="line">}]);</div></pre></td></tr></table></figure><p>在应用启动之前,AngularJS调用<code>config</code>方法对服务完成配置,运行阶段会初始化所有的服务,所以,在配置阶段是访问不到服务,即不可注入。一旦配置阶段结束,就不能与provider交互。</p><h1 id="constant"><a href="#constant" class="headerlink" title="constant"></a>constant</h1><p>由于<code>config</code>函数在没有服务可用的配置阶段运行,所以<code>value</code>方法创建的值或对象也无法访问。所以为了在配置阶段能访问到一些常量,引入了<code>constant</code>函数,用法和<code>value</code>类似。</p><h1 id="特殊用途对象"><a href="#特殊用途对象" class="headerlink" title="特殊用途对象"></a>特殊用途对象</h1><p>由<code>Controller</code>,<code>Directive</code>,<code>Filter</code>,<code>Animation</code>创建的对象,和<code>factory</code>写法类似,在函数中返回对象实例,Controller对象除外。</p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><ul><li>注射器使用这些方法创建两种类型的对象:服务和特殊用途对象</li><li>五种方法定义如何创建对象:value,factory,service,provider,constant</li><li>factory和service是最常用的方法,它们之间唯一的区别是,service对于创建自定义类型的对象更好,而factory方法可用生成JavaScript基本类型和函数</li><li>provider是核心方法,其他所有方法只是其上的语法糖</li><li>provider是最复杂的方法,除非你需要构建可重用的代码块,否则最好别用它</li><li>除Controller之外,所有特殊用途的对象均通过factory方法定义</li></ul>]]></content>
<summary type="html">
<p>AngularJS 1.x&#x63D0;&#x4F9B;&#x4E86;&#x5982;&#x4E0B;5&#x4E2A;provider&#x65B9;&#x6CD5;&#xFF0C;&#x4F7F;&#x7528;&#x8FD9;&#x4E9B;&#x65B9;&#x
</summary>
<category term="前端开发" scheme="http://brucewar.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
<category term="AngularJS" scheme="http://brucewar.cn/tags/AngularJS/"/>
<category term="Provider" scheme="http://brucewar.cn/tags/Provider/"/>
</entry>
<entry>
<title>青岛三日游攻略</title>
<link href="http://brucewar.cn/2017/05/13/%E9%9D%92%E5%B2%9B%E4%B8%89%E6%97%A5%E6%B8%B8%E6%94%BB%E7%95%A5/"/>
<id>http://brucewar.cn/2017/05/13/青岛三日游攻略/</id>
<published>2017-05-13T01:48:21.000Z</published>
<updated>2017-05-14T06:41:13.636Z</updated>
<content type="html"><![CDATA[<h1 id="市南区"><a href="#市南区" class="headerlink" title="市南区"></a>市南区</h1><p>栈桥、海军博物馆、鲁迅公园、小青岛、第一海水浴场、八大关、音乐广场、五四广场、青岛奥林匹克帆船中心</p><h1 id="市北区"><a href="#市北区" class="headerlink" title="市北区"></a>市北区</h1><p>啤酒一条街、青岛啤酒博物馆、天幕城、劈柴院、崂山</p><h1 id="Day1"><a href="#Day1" class="headerlink" title="Day1"></a>Day1</h1><p>如果到酒店还早,就去登州路和或者台东步行街转转</p><h2 id="登州路"><a href="#登州路" class="headerlink" title="登州路"></a>登州路</h2><p>啤酒一条街、青岛啤酒博物馆、天幕城</p><h1 id="Day2"><a href="#Day2" class="headerlink" title="Day2"></a>Day2</h1><h2 id="崂山"><a href="#崂山" class="headerlink" title="崂山"></a>崂山</h2><p>南线:香港东路或东海东路 ——> 沙子口 ——> 登赢 ——> 流清河 ——> 太清宫 ——> 上清景区或巨峰景区(时间允许)</p><p>交通:旅游专线、公交104、113、304</p><p>如果回来比较早,可以去五四广场、奥林匹克帆船中心<br>香港中路:家乐福、佳世客 家乐福对面阳光百货、佳世客后面海信广场,百丽广场</p><h1 id="Day3"><a href="#Day3" class="headerlink" title="Day3"></a>Day3</h1><p>海底世界、八大关、栈桥、中山路、劈柴院</p><p>民俗小吃街,王姐烧烤,高家锅贴,<br>商业街:台东商业区、香港中路、中山路商业区、李村商业区<br>中山路夜景很美<br>中山路(美达尔烧烤)、圣弥额尔教堂</p>]]></content>
<summary type="html">
<h1 id="&#x5E02;&#x5357;&#x533A;"><a href="#&#x5E02;&#x5357;&#x533A;" class="headerlink" title="&#x5E02;&#x5357;&#x533A;"></a>&#x5E02;&#x535
</summary>
<category term="旅行" scheme="http://brucewar.cn/categories/%E6%97%85%E8%A1%8C/"/>
<category term="青岛" scheme="http://brucewar.cn/tags/%E9%9D%92%E5%B2%9B/"/>
<category term="自由行" scheme="http://brucewar.cn/tags/%E8%87%AA%E7%94%B1%E8%A1%8C/"/>
<category term="旅游攻略" scheme="http://brucewar.cn/tags/%E6%97%85%E6%B8%B8%E6%94%BB%E7%95%A5/"/>
</entry>
<entry>
<title>RESTful web API文档生成器</title>
<link href="http://brucewar.cn/2017/05/10/RESTful-web-API%E6%96%87%E6%A1%A3%E7%94%9F%E6%88%90%E5%99%A8/"/>
<id>http://brucewar.cn/2017/05/10/RESTful-web-API文档生成器/</id>
<published>2017-05-10T05:45:49.000Z</published>
<updated>2017-05-10T16:11:48.016Z</updated>
<content type="html"><![CDATA[<blockquote><p>问:开发业务模块代码最重要的是什么?<br>答:API接口文档</p></blockquote><p>如果你是后台开发,是否会有以下困扰:</p><ul><li>开发API接口,还要通过wiki写接口文档,严重影响效率</li><li>接口不是一次就能定下来的,后续可能还要维护,所以还需要去修改文档</li></ul><p>如果你是前端工程师,是否有过下面的困扰:</p><ul><li>返回的数据怎么少字段,后台什么时候改了接口</li></ul><p>我们总是吐槽文档不全,文档写的不好,然而却没有想到开发的同时顺便把文档也写了。这篇博文的重点就是为大家介绍一款生成RESTful web API文档的神器——<a href="http://apidocjs.com" target="_blank" rel="external">apidoc</a>,GitHub 4000多star。这款神器通过源代码中的注释生成最终的文档,所以需要按照规范编写注释。</p><h1 id="安装和使用"><a href="#安装和使用" class="headerlink" title="安装和使用"></a>安装和使用</h1><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>文中的例子全部使用Javadoc-Style编写,也可以在所有支持Javadoc的语言(如C#, Go, Dart, Java, JavaScript, PHP, TypeScript等)中使用。其他语言可以使用它们特定的多行注释。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * This is a comment.</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">npm install apidoc -g</div></pre></td></tr></table></figure><h2 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">apidoc -i myapp/ -o apidoc/ -t mytemplate/</div></pre></td></tr></table></figure><p>使用<code>mytemplate/</code>下的模板文件,为<code>myapp/</code>目录下的所有文件创建api文档,并保存在<code>apidoc/</code>目录下。如果不带任何参数,apiDoc为当前目录以及子目录下的所有<code>.cs</code>, <code>.dart</code>, <code>.erl</code>, <code>.go</code>, <code>.java</code>, <code>.js</code>, <code>.php</code>, <code>.py</code>, <code>.rb</code>, <code>.ts</code>文件创建文档,并保存在<code>./doc/</code>目录。</p><h2 id="命令行参数"><a href="#命令行参数" class="headerlink" title="命令行参数"></a>命令行参数</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="comment"># 查看命令行参数</span></div><div class="line">apidoc -h</div></pre></td></tr></table></figure><p>列出部分重要参数:</p><table><thead><tr><th>参数</th><th>描述</th><th>示例</th></tr></thead><tbody><tr><td>-f, –file-filters</td><td>通过正则过滤出需要解析的文件(可以使用多个-f)。默认为<code>.cs</code>, <code>.dart</code>, <code>.erl</code>, <code>.go</code>, <code>.java</code>, <code>.js</code>, <code>.php</code>, <code>.py</code>, <code>.rb</code>, <code>.ts</code>。</td><td>仅解析.js和.ts文件:<br><code>apidoc -f ".*\\.js$" -f ".*\\.ts$"</code></td></tr><tr><td>-i, –input</td><td>源文件或项目目录</td><td><code>apidoc -i myapp/</code></td></tr><tr><td>-o, –output</td><td>存放生成的文档的目录</td><td><code>apidoc -o apidoc/</code></td></tr><tr><td>-t, –template</td><td>为生成的文档使用模板,也可以创建和使用自己的模板</td><td><code>apidoc -t mytemplate/</code></td></tr></tbody></table><h2 id="Grunt模块"><a href="#Grunt模块" class="headerlink" title="Grunt模块"></a>Grunt模块</h2><p>作者也为大家开发了一款grunt的打包工具<a href="http://github.com/apidoc/grunt-apidoc" target="_blank" rel="external">http://github.com/apidoc/grunt-apidoc</a>。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">npm install grunt-apidoc --save-dev</div></pre></td></tr></table></figure><h2 id="模板"><a href="#模板" class="headerlink" title="模板"></a>模板</h2><p>apiDoc默认模板:使用了<a href="http://handlebarsjs.com/" target="_blank" rel="external">handlebars</a>,<a href="http://twitter.github.io/bootstrap/" target="_blank" rel="external">Bootstrap</a>,<a href="http://requirejs.org/" target="_blank" rel="external">RequireJS</a>和<a href="http://jquery.com/" target="_blank" rel="external">jQuery</a>为输出的<code>api_data.js</code>和<code>api_project.js</code>文件生成html页面。</p><p>apiDoc默认使用一个复杂的模板,支持如下功能:</p><ul><li>版本管理:查看不同版本的API</li><li>比较:查看一个API的两个版本之间的区别</li></ul><p>你也可以使用自己创建的模板,为apiDoc生成的文件<code>api_data.js</code>, <code>api_project.js</code>或者json格式的文件<code>api_data.json</code>, <code>api_project.json</code>。</p><p>模板源代码:<a href="https://github.com/apidoc/apidoc/tree/master/template" target="_blank" rel="external">https://github.com/apidoc/apidoc/tree/master/template</a></p><h2 id="扩展"><a href="#扩展" class="headerlink" title="扩展"></a>扩展</h2><p>apiDoc也可以扩展自己的参数,具体细节请查看<a href="https://github.com/apidoc/apidoc-core" target="_blank" rel="external">apidoc/apidoc-core</a>项目的<code>lib/parsers/</code>, <code>lib/workers/</code>目录。</p><h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h2><p>apiDoc提供了两种配置方式,要么在工程根目录添加<code>apidoc.json</code>文件,要么在<code>package.json</code>中添加<code>apidoc</code>字段。</p><p><code>apidoc.json</code></p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">{</div><div class="line"> <span class="string">"name"</span>: <span class="string">"example"</span>,</div><div class="line"> <span class="string">"version"</span>: <span class="string">"0.1.0"</span>,</div><div class="line"> <span class="string">"description"</span>: <span class="string">"apiDoc basic example"</span>,</div><div class="line"> <span class="string">"title"</span>: <span class="string">"Custom apiDoc browser title"</span>,</div><div class="line"> <span class="string">"url"</span> : <span class="string">"https://api.github.com/v1"</span></div><div class="line">}</div></pre></td></tr></table></figure><p><code>package.json</code></p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line">{</div><div class="line"> <span class="string">"name"</span>: <span class="string">"example"</span>,</div><div class="line"> <span class="string">"version"</span>: <span class="string">"0.1.0"</span>,</div><div class="line"> <span class="string">"description"</span>: <span class="string">"apiDoc basic example"</span>,</div><div class="line"> <span class="string">"apidoc"</span>: {</div><div class="line"> <span class="string">"title"</span>: <span class="string">"Custom apiDoc browser title"</span>,</div><div class="line"> <span class="string">"url"</span> : <span class="string">"https://api.github.com/v1"</span></div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure><p>apidoc.json配置字段</p><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>name</td><td>工程名称。如果<code>apidoc.json</code>中不包含此字段,则由<code>package.json确定</code></td></tr><tr><td>version</td><td>工程版本号。如果<code>apidoc.json</code>中不包含此字段,则由<code>package.json确定</code></td></tr><tr><td>description</td><td>工程描述。如果<code>apidoc.json</code>中不包含此字段,则由<code>package.json确定</code></td></tr><tr><td>title</td><td>文档页面标题</td></tr><tr><td>url</td><td>api前缀,如:<code>https://api/github.com/v1</code></td></tr><tr><td>sampleUrl</td><td>测试api方法的表单请求链接更多细节请查看<a href="#apiSampleRequest"><code>@apiSampleRequest</code></a></td></tr><tr><td>header</td><td></td></tr><tr><td>    title</td><td>被包含的header.md文件的导航文本(查看<a href="#header-footer">Header/Footer</a>)</td></tr><tr><td>    filename</td><td>被包含的header.md文件(必须为markdown文件)的文件名</td></tr><tr><td>footer</td><td></td></tr><tr><td>    title</td><td>被包含的footer.md文件的导航文本</td></tr><tr><td>    filename</td><td>被包含的footer.md文件(必须为markdown文件)的文件名</td></tr><tr><td>order</td><td>输出的api名和api分组名的顺序列表,未定义名称的api自动在后面展示。<br><code>"order": ["Error", "Define", "PostTitleAndError", "PostError"]</code></td></tr></tbody></table><p>apiDoc默认模板特定的配置字段</p><table><thead><tr><th>字段</th><th>类型</th><th>描述</th></tr></thead><tbody><tr><td>template</td><td></td><td></td></tr><tr><td>forceLanguage</td><td>String</td><td>禁用浏览器自动语言检测,并设置一个特定的语言。例如:<code>de</code>, <code>en</code>。<a href="https://github.com/apidoc/apidoc/tree/master/template/locales" target="_blank" rel="external">可选语言</a></td></tr><tr><td>withCompare</td><td>Boolean</td><td>开启与旧版本API比较,默认<code>true</code></td></tr><tr><td>withGenerator</td><td>Boolean</td><td>在页尾输出生成信息,默认<code>true</code></td></tr><tr><td>jQueryAjaxSetup</td><td>Object</td><td>为Ajax请求设置<a href="http://api.jquery.com/jquery.ajaxsetup/" target="_blank" rel="external">默认参数</a></td></tr></tbody></table><h2 id="Header-Footer"><a href="#Header-Footer" class="headerlink" title="Header/Footer"></a>Header/Footer</h2><p>在<code>apidoc.json</code>添加header和footer。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">{</div><div class="line"> <span class="string">"header"</span>: {</div><div class="line"> <span class="string">"title"</span>: <span class="string">"My own header title"</span>,</div><div class="line"> <span class="string">"filename"</span>: <span class="string">"header.md"</span></div><div class="line"> },</div><div class="line"> <span class="string">"footer"</span>: {</div><div class="line"> <span class="string">"title"</span>: <span class="string">"My own footer title"</span>,</div><div class="line"> <span class="string">"filename"</span>: <span class="string">"footer.md"</span></div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure><h1 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h1><h2 id="继承"><a href="#继承" class="headerlink" title="继承"></a>继承</h2><p>你可以将文档中多次使用的部分放到一个定义中。如下:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @apiDefine UserNotFoundError</div><div class="line"> *</div><div class="line"> * @apiError UserNotFound The id of the User was not found.</div><div class="line"> *</div><div class="line"> * @apiErrorExample Error-Response:</div><div class="line"> * HTTP/1.1 404 Not Found</div><div class="line"> * {</div><div class="line"> * "error": "UserNotFound"</div><div class="line"> * }</div><div class="line"> */</div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id Request User information</div><div class="line"> * @apiName GetUser</div><div class="line"> * @apiGroup User</div><div class="line"> *</div><div class="line"> * @apiParam {Number} id Users unique ID.</div><div class="line"> *</div><div class="line"> * @apiSuccess {String} firstname Firstname of the User.</div><div class="line"> * @apiSuccess {String} lastname Lastname of the User.</div><div class="line"> *</div><div class="line"> * @apiSuccessExample Success-Response:</div><div class="line"> * HTTP/1.1 200 OK</div><div class="line"> * {</div><div class="line"> * "firstname": "John",</div><div class="line"> * "lastname": "Doe"</div><div class="line"> * }</div><div class="line"> *</div><div class="line"> * @apiUse UserNotFoundError</div><div class="line"> */</div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {put} /user/ Modify User information</div><div class="line"> * @apiName PutUser</div><div class="line"> * @apiGroup User</div><div class="line"> *</div><div class="line"> * @apiParam {Number} id Users unique ID.</div><div class="line"> * @apiParam {String} [firstname] Firstname of the User.</div><div class="line"> * @apiParam {String} [lastname] Lastname of the User.</div><div class="line"> *</div><div class="line"> * @apiSuccessExample Success-Response:</div><div class="line"> * HTTP/1.1 200 OK</div><div class="line"> *</div><div class="line"> * @apiUse UserNotFoundError</div><div class="line"> */</div></pre></td></tr></table></figure><p><strong>继承只能包含一层</strong>,多层级将会降低行内代码的可读性,增加复杂度。</p><h2 id="版本控制"><a href="#版本控制" class="headerlink" title="版本控制"></a>版本控制</h2><p>保存之前定义的文档块,用于不同版本的接口比较,因此前端开发很容易看到哪些地方有变化。</p><p>在修改接口文档之前,将历史文档块复制到文件<code>_apidoc.js</code>。</p><p>所以在每个文档块设置<a href="#apiVersion"><code>@apiVersion</code></a>非常重要。</p><h1 id="apiDoc参数"><a href="#apiDoc参数" class="headerlink" title="apiDoc参数"></a>apiDoc参数</h1><p>结构体参数<a href="#apiDefine"><code>@apiDefine</code></a>用于将文档块定义为可复用的整体,并且可以包含在api文档块中。</p><p>除了其它定义块,一个定义的块中可以包含所有的参数(如<a href="#apiParam"><code>@apiParam</code></a>)。</p><h2 id="api"><a href="#api" class="headerlink" title="@api"></a>@api</h2><p>必须包含这个标记,否则apiDoc将会忽略文档块。定义块<a href="#apiDefine"><code>@apiDefine</code></a>不需要<code>@api</code>。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">@api {method} path [title]</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>method</td><td>请求方法名:<code>DELETE</code>, <code>GET</code>, <code>POST</code>, <code>PUT</code>, …。更多信息请查看<a href="https://zh.wikipedia.org/wiki/%E8%B6%85%E6%96%87%E6%9C%AC%E4%BC%A0%E8%BE%93%E5%8D%8F%E8%AE%AE#.E8.AF.B7.E6.B1.82.E6.96.B9.E6.B3.95" target="_blank" rel="external">Wikipedia HTTP请求方法</a></td></tr><tr><td>path</td><td>请求路径</td></tr><tr><td>title <code>可选</code></td><td>用于导航的简称</td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="apiDefine"><a href="#apiDefine" class="headerlink" title="@apiDefine"></a>@apiDefine</h2><p>定义一个通用块或者权限块,每个块中只能有一个<code>@apiDefine</code>,使用<a href="#apiUser"><code>@apiUse</code></a>导入通用块。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">@apiDefine name [title]</div><div class="line"> [description]</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>name</td><td>块或值的唯一名称</td></tr><tr><td>title <code>可选</code></td><td>简称,只用在命名函数中,如<a href="#apiPermission"><code>@apiPermission</code></a>和<a href="#apiParam"><code>@apiParam(name)</code></a></td></tr><tr><td>description <code>可选</code></td><td>下一行开始的详细说明,可以多行,仅用在命名函数,如<a href="#apiPermission"><code>@apiPermission</code></a></td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @apiDefine MyError</div><div class="line"> * @apiError UserNotFound The <code>id</code> of the User was not found.</div><div class="line"> */</div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiUse MyError</div><div class="line"> */</div></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @apiDefine admin User access only</div><div class="line"> * This optional description belong to to the group admin.</div><div class="line"> */</div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiPermission admin</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="apiDeprecated"><a href="#apiDeprecated" class="headerlink" title="@apiDeprecated"></a>@apiDeprecated</h2><p>标记废弃的API</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">@apiDeprecated [text]</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>text</td><td>多行文本</td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @apiDeprecated */</div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * @apiDeprecated use now (#Group:Name).</div><div class="line"> *</div><div class="line"> * Example: to set a link to the GetDetails method of your group User</div><div class="line"> * write (#User:GetDetails)</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="apiDescription"><a href="#apiDescription" class="headerlink" title="@apiDescription"></a>@apiDescription</h2><p>API的详细描述</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">@apiDescription text</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>text</td><td>多行描述文本</td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @apiDescription This is the Description.</div><div class="line"> * It is multiline capable.</div><div class="line"> *</div><div class="line"> * Last line of Description.</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="apiError"><a href="#apiError" class="headerlink" title="@apiError"></a>@apiError</h2><p>返回的错误参数</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">@apiError [(group)] [{type}] field [description]</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>(group) <code>可选</code></td><td>所有参数按这个名称分组,如果未设置此字段,默认为<code>Error 4xx</code>,可以使用<a href="#apiDefine"><code>@apiDefine</code></a>设置标题和描述</td></tr><tr><td>{type} <code>可选</code></td><td>返回类型,例如:<code>{Boolean}</code>,<code>{Number}</code>,<code>{String}</code>,<code>{Object}</code>,<code>{String[]}</code>(字符串数组)等</td></tr><tr><td>field</td><td>返回的标识符</td></tr><tr><td>description</td><td>字段描述</td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiError UserNotFound The <code>id</code> of the User was not found.</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="apiErrorExample"><a href="#apiErrorExample" class="headerlink" title="@apiErrorExample"></a>@apiErrorExample</h2><p>返回的错误示例,输出为格式化的代码</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">@apiErrorExample [{type}] [title]</div><div class="line"> example</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>type <code>可选</code></td><td>响应格式</td></tr><tr><td>title <code>可选</code></td><td>示例简称</td></tr><tr><td>example</td><td>详细示例,支持多行文本</td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiErrorExample {json} Error-Response:</div><div class="line"> * HTTP/1.1 404 Not Found</div><div class="line"> * {</div><div class="line"> * "error": "UserNotFound"</div><div class="line"> * }</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="apiExample"><a href="#apiExample" class="headerlink" title="@apiExample"></a>@apiExample</h2><p>API的使用示例,输出为格式化的代码</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">@apiExample [{type}] title</div><div class="line"> example</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>type <code>可选</code></td><td>代码语言</td></tr><tr><td>title</td><td>示例简称</td></tr><tr><td>example</td><td>详细示例,支持多行文本</td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiExample {curl} Example usage:</div><div class="line"> * curl -i http://localhost/user/4711</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="apiGroup"><a href="#apiGroup" class="headerlink" title="@apiGroup"></a>@apiGroup</h2><p>应该一直使用,定义API文档块所属的分组。分组用于生成输出中的主导航,结构定义不需要<code>@apiGroup</code></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">@apiGroup name</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>name</td><td>分组名称,也用作导航名称</td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiGroup User</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="apiHeader"><a href="#apiHeader" class="headerlink" title="@apiHeader"></a>@apiHeader</h2><p>描述传递给API的请求头,类似<a href="#apiParam"><code>@apiParam</code></a>,只不过输出文档在参数之上。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">@apiHeader [(group)] [{type}] [field=defaultValue] [description]</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>(group) <code>可选</code></td><td>所有参数按此名称分组,如果未设置,默认为<code>Parameter</code>,你也可以在<a href="#apiDefine"><code>@apiDefine</code></a>中定义名称和描述</td></tr><tr><td>{type} <code>可选</code></td><td>参数类型,例如:<code>{Boolean}</code>,<code>{Number}</code>,<code>{String}</code>,<code>{Object}</code>,<code>{String[]}</code>(字符串数组)等</td></tr><tr><td>field</td><td>变量名</td></tr><tr><td>[field]</td><td>带括号标识此参数可选</td></tr><tr><td>=defaultValue <code>可选</code></td><td>参数默认值</td></tr><tr><td>描述 <code>可选</code></td><td>字段描述</td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiHeader {String} access-key Users unique access-key.</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="apiHeaderExample"><a href="#apiHeaderExample" class="headerlink" title="@apiHeaderExample"></a>@apiHeaderExample</h2><p>请求头参数示例</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">@apiHeaderExample [{type}] [title]</div><div class="line"> example</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>type <code>可选</code></td><td>请求格式</td></tr><tr><td>title <code>可选</code></td><td>示例简称</td></tr><tr><td>example</td><td>详细示例,支持多行文本</td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiHeaderExample {json} Header-Example:</div><div class="line"> * {</div><div class="line"> * "Accept-Encoding": "Accept-Encoding: gzip, deflate"</div><div class="line"> * }</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="apiIgnore"><a href="#apiIgnore" class="headerlink" title="@apiIgnore"></a>@apiIgnore</h2><p><code>@apiIgnore</code>块不会被解析,如果你在源代码中留下过期或者未完成的api,并且不想将其发布到文档中,这个标识符非常有用。</p><p><strong>将其放在块的顶部</strong></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">@apiIgnore [hint]</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>hint <code>可选</code></td><td>忽略原因的简短信息</td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @apiIgnore Not finished Method</div><div class="line"> * @api {get} /user/:id</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="apiName"><a href="#apiName" class="headerlink" title="@apiName"></a>@apiName</h2><p>应该永远使用,定义API文档块的名称,名称将用于生成输出文档中的子导航。结构定义不需要<code>@apiName</code></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">@apiName name</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>name</td><td>API的唯一名称,可以为不同的<a href="#apiVersion"><code>@apiVersion</code></a>定义相同的名称</td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiName GetUser</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="apiParam"><a href="#apiParam" class="headerlink" title="@apiParam"></a>@apiParam</h2><p>定义传递给API的参数</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">@apiParam [(group)] [{type}] [field=defultValue] [description]</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>(group) <code>可选</code></td><td>所有参数按此名称分组,默认为<code>Parameter</code>,也可以在<a href="#apiDefine"><code>@apiDefine</code></a>中定义名称和描述</td></tr><tr><td>{type} <code>可选</code></td><td>参数类型,例如:<code>{Boolean}</code>,<code>{Number}</code>,<code>{String}</code>,<code>{Object}</code>,<code>{String[]}</code>(字符串数组)等</td></tr><tr><td>{type{size}} <code>可选</code></td><td>变量大小信息<br><code>{string{..5}}</code> 最多5个字符的字符串<br><code>{string{2..5}}</code> 最少2个字符,最多5个字符的字符串<br><code>{Number{100-999}}</code> 介于100和999之间的数字</td></tr><tr><td>{type=allowedValues} <code>可选</code></td><td>变量允许的值<br><code>{string="small"}</code> 只能包含”small”的字符串<br><code>{string="small","huge"}</code> 包含”small”或”huge”的字符串<br><code>{number=1,2,3,99}</code> 允许为1,2,3,99中的一个值<br><code>{string {..5}="small","huge"}</code> 最多5个字符的字符串,并且只能包含”small”和”huge”</td></tr><tr><td>field</td><td>参数名</td></tr><tr><td>[field]</td><td>带括号标识此参数可选</td></tr><tr><td>=defaultValue <code>可选</code></td><td>参数默认值</td></tr><tr><td>description <code>可选</code></td><td>参数描述</td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiParam {Number} id Users unique ID.</div><div class="line"> */</div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {post} /user/</div><div class="line"> * @apiParam {String} [firstname] Optional Firstname of the User.</div><div class="line"> * @apiParam {String} lastname Mandatory Lastname.</div><div class="line"> * @apiParam {String} country="DE" Mandatory with default value "DE".</div><div class="line"> * @apiParam {Number} [age=18] Optional Age with default 18.</div><div class="line"> *</div><div class="line"> * @apiParam (Login) {String} pass Only logged in users can post this.</div><div class="line"> * In generated documentation a separate</div><div class="line"> * "Login" Block will be generated.</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="apiParamExample"><a href="#apiParamExample" class="headerlink" title="@apiParamExample"></a>@apiParamExample</h2><p>请求参数示例</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">@apiParamExample [{type}] [title]</div><div class="line"> example</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>type <code>可选</code></td><td>请求格式</td></tr><tr><td>title <code>可选</code></td><td>示例简称</td></tr><tr><td>example</td><td>详细示例,支持多行文本</td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiParamExample {json} Request-Example:</div><div class="line"> * {</div><div class="line"> * "id": 4711</div><div class="line"> * }</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="apiPermission"><a href="#apiPermission" class="headerlink" title="@apiPermission"></a>@apiPermission</h2><p>权限名称,如果用<a href="#apiDefine"><code>@apiDefine</code></a>定义名称,生成的文档将会包含额外的名称和描述</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">@apiPermission name</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>name</td><td>权限唯一的名称</td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiPermission none</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="apiSampleRequest"><a href="#apiSampleRequest" class="headerlink" title="@apiSampleRequest"></a>@apiSampleRequest</h2><p>此参数配合<code>apidoc.json</code>配置中的<code>sampleUrl</code>参数使用,如果配置了<code>sampleUrl</code>,所有API方法都将有api测试表单,并追加在<a href="#api"><code>@api</code></a>结束位置。如果未配置<code>sampleUrl</code>,仅包含<code>@apiSampleRequest</code>的方法有测试表单。<br>如果在方法块中配置了<code>@apiSampleRequest url</code>,这个url作为请求地址(当它以http开头,会覆盖<code>sampleUrl</code>)<br>如果配置了<code>sampleUrl</code>,并且想在指定方法不包含测试表单,可以在文档块中配置<code>@apiSampleRequest off</code>。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">@apiSampleRequest url</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>url</td><td>测试api服务地址<br><code>@apiSampleRequest http://www.example.com</code><br><code>@apiSampleRequest /my_test_path</code><br><code>@apiSampleRequest off</code></td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// Configuration parameter sampleUrl: "http://api.github.com"</span></div><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> */</div><div class="line"></div><div class="line"><span class="comment">// Configuration parameter sampleUrl: "http://api.github.com"</span></div><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiSampleRequest http://test.github.com/some_path/</div><div class="line"> */</div><div class="line"></div><div class="line"><span class="comment">// Configuration parameter sampleUrl: "http://api.github.com"</span></div><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiSampleRequest /test</div><div class="line"> */</div><div class="line"></div><div class="line"><span class="comment">// Configuration parameter sampleUrl: "http://api.github.com"</span></div><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiSampleRequest off</div><div class="line"> */</div><div class="line"></div><div class="line"><span class="comment">// Configuration parameter sampleUrl is not set</span></div><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiSampleRequest http://api.github.com/some_path/</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="apiSuccess"><a href="#apiSuccess" class="headerlink" title="@apiSuccess"></a>@apiSuccess</h2><p>成功返回的参数</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">@apiSuccess [(group)] [{type}] field [description]</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>(group) <code>可选</code></td><td>所有参数按此名称分组,默认为<code>Success 200</code>,可以在<a href="#apiDefine"><code>@apiDefine</code></a>中定义名称和描述</td></tr><tr><td>{type} <code>可选</code></td><td>返回类型,例如:<code>{Boolean}</code>,<code>{Number}</code>,<code>{String}</code>,<code>{Object}</code>,<code>{String[]}</code>(字符串数组)等</td></tr><tr><td>field</td><td>返回标识字段</td></tr><tr><td>description <code>可选</code></td><td>字段描述</td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiSuccess {String} firstname Firstname of the User.</div><div class="line"> * @apiSuccess {String} lastname Lastname of the User.</div><div class="line"> */</div><div class="line"></div><div class="line"><span class="comment">// 带(group)示例</span></div><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiSuccess (200) {String} firstname Firstname of the User.</div><div class="line"> * @apiSuccess (200) {String} lastname Lastname of the User.</div><div class="line"> */</div><div class="line"></div><div class="line"><span class="comment">// 带对象示例</span></div><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiSuccess {Boolean} active Specify if the account is active.</div><div class="line"> * @apiSuccess {Object} profile User profile information.</div><div class="line"> * @apiSuccess {Number} profile.age Users age.</div><div class="line"> * @apiSuccess {String} profile.image Avatar-Image.</div><div class="line"> */</div><div class="line"></div><div class="line"><span class="comment">// 带数组示例</span></div><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /users</div><div class="line"> * @apiSuccess {Object[]} profiles List of user profiles.</div><div class="line"> * @apiSuccess {Number} profiles.age Users age.</div><div class="line"> * @apiSuccess {String} profiles.image Avatar-Image.</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="apiSuccessExample"><a href="#apiSuccessExample" class="headerlink" title="@apiSuccessExample"></a>@apiSuccessExample</h2><p>成功响应的信息,按格式化代码输出</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">@apiSuccessExample [{type}] [title]</div><div class="line"> example</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>type <code>可选</code></td><td>响应格式</td></tr><tr><td>title <code>可选</code></td><td>示例简称</td></tr><tr><td>example</td><td>详细示例,支持多行文本</td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiSuccessExample {json} Success-Response:</div><div class="line"> * HTTP/1.1 200 OK</div><div class="line"> * {</div><div class="line"> * "firstname": "John",</div><div class="line"> * "lastname": "Doe"</div><div class="line"> * }</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="apiUse"><a href="#apiUse" class="headerlink" title="@apiUse"></a>@apiUse</h2><p>包含一个<a href="#apiDefine"><code>@apiDefine</code></a>定义的块。如果与<a href="#apiVersion"><code>@apiVersion</code></a>一起使用,将包含相同的或最近的一个</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">@apiUse name</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>name</td><td>定义块的名称</td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @apiDefine MySuccess</div><div class="line"> * @apiSuccess {string} firstname The users firstname.</div><div class="line"> * @apiSuccess {number} age The users age.</div><div class="line"> */</div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiUse MySuccess</div><div class="line"> */</div></pre></td></tr></table></figure><h2 id="apiVersion"><a href="#apiVersion" class="headerlink" title="@apiVersion"></a>@apiVersion</h2><p>配置文档块的版本,也可以在<a href="#apiDefine"><code>@apiDefine</code></a>中使用,具有相同组和名称的API,可以在生成的文档中比较不同的版本,因此你或前端开发人员可以回溯自上一个版本以来API中的更改</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">@apiVersion version</div></pre></td></tr></table></figure><table><thead><tr><th>字段</th><th>描述</th></tr></thead><tbody><tr><td>version</td><td>支持简单的版本控制(主版本号.次版本号.补丁号)。更多信息请参考<a href="http://semver.org/" target="_blank" rel="external">http://semver.org/</a></td></tr></tbody></table><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * @api {get} /user/:id</div><div class="line"> * @apiVersion 1.6.2</div><div class="line"> */</div></pre></td></tr></table></figure><p>到此为止,你应该对apidoc熟悉了一大半了吧!其实作为开发者,一定要养成写注释、写文档的习惯,也是程序员进阶的必要条件。</p><blockquote><p>谨以此文鞭策自己。</p></blockquote>]]></content>
<summary type="html">
<blockquote><p>&#x95EE;&#xFF1A;&#x5F00;&#x53D1;&#x4E1A;&#x52A1;&#x6A21;&#x5757;&#x4EE3;&#x7801;&#x6700;&#x91CD;&#x8981;&#x7684;&#x662F;&#x4E
</summary>
<category term="Node.js" scheme="http://brucewar.cn/categories/Node-js/"/>
<category term="apidoc" scheme="http://brucewar.cn/tags/apidoc/"/>
<category term="RESTful API" scheme="http://brucewar.cn/tags/RESTful-API/"/>
<category term="文档" scheme="http://brucewar.cn/tags/%E6%96%87%E6%A1%A3/"/>
</entry>
<entry>
<title>Node.js aes-128-cbc加密和解密</title>
<link href="http://brucewar.cn/2017/05/06/Node-js-aes-128-cbc%E5%8A%A0%E5%AF%86%E5%92%8C%E8%A7%A3%E5%AF%86/"/>
<id>http://brucewar.cn/2017/05/06/Node-js-aes-128-cbc加密和解密/</id>
<published>2017-05-06T03:31:52.000Z</published>
<updated>2017-05-06T03:58:06.787Z</updated>
<content type="html"><![CDATA[<p>Java程序中经常使用的AES加密模式是<strong>AES/CBC/PKCS5Padding</strong>,在Node.js中对应的是<strong>aes-128-cbc</strong>加密算法。</p><p>为此,我们需要引入Node.js的<em>crypto</em>模块,详细说明请查看<a href="https://nodejs.org/dist/latest-v6.x/docs/api/crypto.html" target="_blank" rel="external">官方文档</a>。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div></pre></td><td class="code"><pre><div class="line"><span class="meta">'use strict'</span>;</div><div class="line"><span class="keyword">const</span> crypto = <span class="built_in">require</span>(<span class="string">'crypto'</span>);</div><div class="line"><span class="keyword">const</span> ALG_STRING = <span class="string">'aes-128-cbc'</span>,</div><div class="line"> KEY = <span class="string">'wjl891014#gmail.com'</span>,</div><div class="line"> IV = [ <span class="number">0xcb</span>, <span class="number">0x53</span>, <span class="number">0x03</span>, <span class="number">0x0f</span>, <span class="number">0xe0</span>, <span class="number">0x79</span>, <span class="number">0x9d</span>, <span class="number">0xdc</span>, <span class="number">0x80</span>, <span class="number">0xa9</span>, <span class="number">0x83</span>, <span class="number">0xf1</span>, <span class="number">0x03</span>, <span class="number">0xb6</span>, <span class="number">0x59</span>, <span class="number">0x83</span> ];</div><div class="line"></div><div class="line"><span class="keyword">const</span> md5sum = <span class="function"><span class="params">str</span> =></span> {</div><div class="line"> <span class="keyword">return</span> crypto.createHash(<span class="string">'md5'</span>)</div><div class="line"> .update(str)</div><div class="line"> .digest()</div><div class="line"> .slice(<span class="number">0</span>, <span class="number">16</span>);</div><div class="line">};</div><div class="line"></div><div class="line"><span class="keyword">const</span> encrypt = <span class="function"><span class="params">str</span> =></span> {</div><div class="line"> <span class="keyword">const</span> key = md5sum(KEY);</div><div class="line"> <span class="comment">// key和IV 必须是16位或32位</span></div><div class="line"> <span class="keyword">const</span> cipher = crypto.createCipheriv(ALG_STRING, key, Buffer.from(IV));</div><div class="line"> cipher.setAutoPadding(<span class="literal">true</span>);</div><div class="line"> <span class="keyword">const</span> cipherChunks = [];</div><div class="line"> cipherChunks.push(cipher.update(str, <span class="string">'utf8'</span>, <span class="string">'binary'</span>));</div><div class="line"> cipherChunks.push(cipher.final(<span class="string">'binary'</span>));</div><div class="line"> <span class="keyword">return</span> Buffer.from(cipherChunks.join(<span class="string">''</span>), <span class="string">'binary'</span>).toString(<span class="string">'base64'</span>);</div><div class="line">};</div><div class="line"></div><div class="line"><span class="keyword">const</span> decrypt = <span class="function"><span class="params">str</span> =></span> {</div><div class="line"> <span class="keyword">const</span> key = md5sum(KEY);</div><div class="line"> <span class="keyword">const</span> decipher = crypto.createDecipheriv(ALG_STRING, key, Buffer.from(IV));</div><div class="line"> decipher.setAutoPadding(<span class="literal">true</span>);</div><div class="line"> <span class="keyword">const</span> cipherChunks = [];</div><div class="line"> cipherChunks.push(decipher.update(Buffer.from(str, <span class="string">'base64'</span>).toString(<span class="string">'binary'</span>), <span class="string">'binary'</span>, <span class="string">'utf8'</span>));</div><div class="line"> cipherChunks.push(decipher.final(<span class="string">'utf8'</span>));</div><div class="line"> <span class="keyword">return</span> cipherChunks.join(<span class="string">''</span>);</div><div class="line">};</div><div class="line"></div><div class="line"><span class="keyword">const</span> data = <span class="string">'bd2983b21dd2aeb1e1453ab0273b4dc'</span>;</div><div class="line"><span class="built_in">console</span>.log(<span class="string">`加密前:<span class="subst">${data}</span>`</span>);</div><div class="line"><span class="keyword">const</span> encryptData = encrypt(data);</div><div class="line"><span class="built_in">console</span>.log(<span class="string">`加密后:<span class="subst">${encryptData}</span>`</span>);</div><div class="line"><span class="keyword">const</span> decryptData = decrypt(encryptData);</div><div class="line"><span class="built_in">console</span>.log(<span class="string">`解密后:<span class="subst">${decryptData}</span>`</span>);</div></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>Java&#x7A0B;&#x5E8F;&#x4E2D;&#x7ECF;&#x5E38;&#x4F7F;&#x7528;&#x7684;AES&#x52A0;&#x5BC6;&#x6A21;&#x5F0F;&#x662F;<strong>AES/CBC/PKCS5Paddi
</summary>
<category term="Node.js" scheme="http://brucewar.cn/categories/Node-js/"/>
<category term="AES" scheme="http://brucewar.cn/tags/AES/"/>
<category term="aes-128-cbc" scheme="http://brucewar.cn/tags/aes-128-cbc/"/>
</entry>
<entry>
<title>CentOS ftp服务搭建</title>
<link href="http://brucewar.cn/2017/05/04/CentOS-ftp%E6%9C%8D%E5%8A%A1%E6%90%AD%E5%BB%BA/"/>
<id>http://brucewar.cn/2017/05/04/CentOS-ftp服务搭建/</id>
<published>2017-05-04T03:33:03.000Z</published>
<updated>2017-05-04T03:49:39.295Z</updated>
<content type="html"><![CDATA[<blockquote><p>好记性不如烂笔头</p></blockquote><p>每次想要windows和linux互传文件时,都得去搜索<em>“Linux ftp服务安装配置”</em>,重复的次数太多,还是把它记录下来吧!!!</p><ol><li><p>安装vsftpd ftp</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">yum -y install ftp vsftpd</div></pre></td></tr></table></figure></li><li><p>备份vsftpd原有的配置文件</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="built_in">cd</span> /etc/vsftpd/</div><div class="line">cp vsftpd.conf vsftpd.conf.origin</div></pre></td></tr></table></figure></li><li><p>创建密码明文文件</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">vim /etc/vsftpd/vftpuser.txt</div><div class="line"><span class="comment"># brucewar</span></div><div class="line"><span class="comment"># password</span></div></pre></td></tr></table></figure></li><li><p>根据明文创建密码DB文件</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">db_load -T -t <span class="built_in">hash</span> <span class="_">-f</span> /etc/vsftpd/vftpuser.txt /etc/vsftpd/vftpuser.db</div></pre></td></tr></table></figure></li><li><p>查看密码数据文件</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">file /etc/vsftpd/vftpuser.db</div><div class="line"><span class="comment"># /etc/vsftpd/vftpuser.db: Berkeley DB(Hash,version9,native byte-order)</span></div></pre></td></tr></table></figure></li><li><p>创建vftpd的guest账户</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">useradd <span class="_">-d</span> /ftp/private <span class="_">-s</span> /sbin/nologin vftpuser</div></pre></td></tr></table></figure><p><strong>Note</strong>:这一步可能会创建<em>/ftp/private</em>失败,可以手动创建文件夹,并将它的权限赋予vftpuser</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">mkdir -p /ftp/private</div><div class="line">chown -R vftpuser.vftpuser /ftp</div></pre></td></tr></table></figure></li><li><p>打开<em>/etc/pam.d/vsftpd</em>, 将<code>auth</code>及<code>account</code>的所有配置行都注释掉,添加如下内容:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">auth required pam_userdb.so db=/etc/vsftpd/vftpuser</div><div class="line">account required pam_userdb.so db=/etc/vsftpd/vftpuser</div></pre></td></tr></table></figure></li><li><p>打开<em>/etc/vsftpd/vsftpd.conf</em>,将<code>anonymous_enable=YES</code>改为<code>anonymous_enable=NO</code>,在最下面添加如下内容:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">virtual_use_local_privs=YES</div><div class="line">guest_enable=YES</div><div class="line">guest_username=vftpuser</div><div class="line">chroot_local_user=YES</div><div class="line">allow_writeable_chroot=YES</div></pre></td></tr></table></figure></li><li><p>设置vsftpd开机启动</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">systemctl <span class="built_in">enable</span> vsftpd</div></pre></td></tr></table></figure></li><li><p>重启vsftpd服务</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">systemctl restart vsftpd</div></pre></td></tr></table></figure></li><li><p>配置防火墙和SELinux</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">firewall-cmd --permanent --zone=public --add-service=ftp</div><div class="line">firewall-cmd --reload</div><div class="line"></div><div class="line">getsebool <span class="_">-a</span> | grep ftp</div><div class="line">setsebool -P ftpd_full_access on</div></pre></td></tr></table></figure></li><li><p>查看vsftpd服务状态</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">systemctl status vsftpd</div></pre></td></tr></table></figure></li></ol>]]></content>
<summary type="html">
<blockquote><p>&#x597D;&#x8BB0;&#x6027;&#x4E0D;&#x5982;&#x70C2;&#x7B14;&#x5934;</p></blockquote><p>&#x6BCF;&#x6B21;&#x60F3;&#x8981;windows&#
</summary>
<category term="Linux" scheme="http://brucewar.cn/categories/Linux/"/>
<category term="Linux" scheme="http://brucewar.cn/tags/Linux/"/>
<category term="CentOS" scheme="http://brucewar.cn/tags/CentOS/"/>
<category term="ftp" scheme="http://brucewar.cn/tags/ftp/"/>
</entry>
<entry>
<title>细胞卫士</title>
<link href="http://brucewar.cn/2017/03/30/%E7%BB%86%E8%83%9E%E5%8D%AB%E5%A3%AB/"/>
<id>http://brucewar.cn/2017/03/30/细胞卫士/</id>
<published>2017-03-29T23:50:51.000Z</published>
<updated>2017-03-30T00:17:53.836Z</updated>
<content type="html"><![CDATA[<p>最近身体不舒服,啥事不想做,与血常规检查接触的也多。发现自己把高中学的生物知识都还给老师了。</p><p>所以有必要来普及一下血液中重要的细胞的作用。</p><ul><li><p>白细胞:杀灭细菌和病毒并监控身体的稳定,白细胞又分为下面4项</p><ul><li>中性粒细胞:白细胞中最重要的成分,起吞噬和杀菌作用</li><li>淋巴细胞:专门对付难缠的病毒,病毒感染时,淋巴细胞一般会升高</li><li>嗜碱性粒细胞:机体过敏时,牺牲自己分泌大量的趋化因子,引起过敏反应</li><li>嗜酸性粒细胞:抑制过敏产生的副作用</li></ul></li><li><p>红细胞:运输氧气和营养到全身器官,再把身体内的废物运出去</p><p>血红蛋白是红细胞中的一种蛋白,专门负责运输氧气,血红蛋白降低,意味着贫血。</p></li><li><p>血小板:凝血,止血</p></li></ul><blockquote><p>身体健康是最重要的,请爱惜自己!</p></blockquote>]]></content>
<summary type="html">
<p>&#x6700;&#x8FD1;&#x8EAB;&#x4F53;&#x4E0D;&#x8212;&#x670D;&#xFF0C;&#x5565;&#x4E8B;&#x4E0D;&#x60F3;&#x505A;&#xFF0C;&#x4E0E;&#x8840;&#x5E38;&
</summary>
<category term="生活" scheme="http://brucewar.cn/categories/%E7%94%9F%E6%B4%BB/"/>
<category term="常识" scheme="http://brucewar.cn/tags/%E5%B8%B8%E8%AF%86/"/>
</entry>
<entry>
<title>仿知乎头像上传</title>
<link href="http://brucewar.cn/2017/02/09/%E4%BB%BF%E7%9F%A5%E4%B9%8E%E5%A4%B4%E5%83%8F%E4%B8%8A%E4%BC%A0/"/>
<id>http://brucewar.cn/2017/02/09/仿知乎头像上传/</id>
<published>2017-02-09T09:47:47.000Z</published>
<updated>2017-02-09T10:21:16.014Z</updated>
<content type="html"><![CDATA[<p>啥都不说, 直接先来一张效果图……</p><p><img src="/2017/02/09/仿知乎头像上传/avatar-upload.png" alt="头像上传效果图"></p><p>小伙伴们,别急,咱们先来分析一下主要功能点:</p><ol><li>图片预览</li><li>图片拖拽</li><li>图片缩放</li><li>图片裁剪</li></ol><h3 id="图片预览"><a href="#图片预览" class="headerlink" title="图片预览"></a>图片预览</h3><p>图片预览的功能技术方案是将用户的图片文件转成Base64编码并设置到<code><img></code>标签的<code>src</code>属性,获取图片文件的Base64编码需要通过HTML5的新特性<a href="https://developer.mozilla.org/en-US/docs/Web/API/FileReader" target="_blank" rel="external">FileReader</a>,具体代码如下:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">getImgBase64: <span class="function"><span class="keyword">function</span>(<span class="params">imgFile, cb</span>)</span>{</div><div class="line"> <span class="keyword">if</span>(!<span class="built_in">window</span>.FileReader){</div><div class="line"> alert(<span class="string">'系统暂不支持针对你的浏览器的文件上传功能,建议使用最新版的Chrome!'</span>);</div><div class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</div><div class="line"> }</div><div class="line"> <span class="keyword">var</span> reader = <span class="keyword">new</span> FileReader();</div><div class="line"> reader.onload = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</div><div class="line"> cb && cb(reader.result);</div><div class="line"> };</div><div class="line"> reader.readAsDataURL(imgFile);</div><div class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</div><div class="line">}</div></pre></td></tr></table></figure><h3 id="图片拖拽"><a href="#图片拖拽" class="headerlink" title="图片拖拽"></a>图片拖拽</h3><p>图片拖拽的功能需要借助鼠标事件<code>mousedown, mousemove, mouseup</code>,这里贴出mousemove里的处理:</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div></pre></td><td class="code"><pre><div class="line">$(<span class="built_in">document</span>).on(<span class="string">'mousemove'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">e</span>)</span>{</div><div class="line"> e.preventDefault();</div><div class="line"> <span class="keyword">var</span> $thumb = $(<span class="string">'.slider-thumb'</span>);</div><div class="line"> <span class="keyword">if</span>($thumb.hasClass(<span class="string">'moving'</span>)){</div><div class="line"> <span class="comment">// 调整大小</span></div><div class="line"> <span class="keyword">var</span> left = <span class="built_in">parseFloat</span>($thumb.css(<span class="string">'left'</span>));</div><div class="line"> <span class="keyword">if</span>(self.lastPosition){</div><div class="line"> <span class="keyword">var</span> max = $thumb.siblings(<span class="string">'.line'</span>).width() - $thumb.width();</div><div class="line"> (e.pageX >= self.lastPosition.x)</div><div class="line"> ? (left >= max ? left = max : left += (e.pageX - self.lastPosition.x))</div><div class="line"> : (left <= <span class="number">0</span> ? left = <span class="number">0</span> : left += (e.pageX - self.lastPosition.x));</div><div class="line"> $thumb.css(<span class="string">'left'</span>, left);</div><div class="line"> }</div><div class="line"> self.currentRadio = left / $thumb.siblings(<span class="string">'.line'</span>).width() + <span class="number">1</span>;</div><div class="line"> self.resizeImg(self.currentRadio);</div><div class="line"> }</div><div class="line"> <span class="keyword">var</span> $imgs = $(<span class="string">'#avatarEditorDialog'</span>).find(<span class="string">'img'</span>);</div><div class="line"> <span class="keyword">if</span>($imgs.hasClass(<span class="string">'moving'</span>)){</div><div class="line"> <span class="comment">// 移动图片位置</span></div><div class="line"> <span class="keyword">var</span> left = <span class="built_in">parseFloat</span>($imgs.css(<span class="string">'left'</span>));</div><div class="line"> <span class="keyword">var</span> top = <span class="built_in">parseFloat</span>($imgs.css(<span class="string">'top'</span>));</div><div class="line"> <span class="keyword">var</span> width = <span class="built_in">parseFloat</span>($imgs.css(<span class="string">'width'</span>));</div><div class="line"> <span class="keyword">var</span> height = <span class="built_in">parseFloat</span>($imgs.css(<span class="string">'height'</span>));</div><div class="line"> <span class="keyword">if</span>(self.lastPosition){</div><div class="line"> <span class="keyword">var</span> leftMin = -(width - BASE - <span class="number">30</span>);</div><div class="line"> <span class="keyword">var</span> topMin = -(height - BASE - <span class="number">30</span>);</div><div class="line"> (e.pageX < self.lastPosition.x)</div><div class="line"> ? (left <= leftMin ? left = leftMin : left += (e.pageX - self.lastPosition.x))</div><div class="line"> : (left >= <span class="number">30</span> ? left = <span class="number">30</span> : left += (e.pageX - self.lastPosition.x));</div><div class="line"> (e.pageY < self.lastPosition.y)</div><div class="line"> ? (top <= topMin ? top = topMin : top += (e.pageY - self.lastPosition.y))</div><div class="line"> : (top >= <span class="number">30</span> ? top = <span class="number">30</span> : top += (e.pageY - self.lastPosition.y));</div><div class="line"> $imgs.css({</div><div class="line"> <span class="attr">left</span>: left,</div><div class="line"> <span class="attr">top</span>: top</div><div class="line"> });</div><div class="line"> }</div><div class="line"> }</div><div class="line"> self.lastPosition = {</div><div class="line"> <span class="attr">x</span>: e.pageX,</div><div class="line"> <span class="attr">y</span>: e.pageY</div><div class="line"> };</div><div class="line">});</div></pre></td></tr></table></figure><p>代码中可以看出,图片拖拽也是有边界的,计算最小的<code>left</code>和<code>top</code>值。</p><h3 id="图片缩放"><a href="#图片缩放" class="headerlink" title="图片缩放"></a>图片缩放</h3><p>图片缩放很简单,主要在宽高比固定的条件下,调整图片的宽度和高度。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line">resizeImg: <span class="function"><span class="keyword">function</span>(<span class="params">radio</span>)</span>{</div><div class="line"> <span class="keyword">var</span> $imgs = $(<span class="string">'#avatarEditorDialog'</span>).find(<span class="string">'img'</span>);</div><div class="line"> <span class="keyword">var</span> height = $imgs.height();</div><div class="line"> <span class="keyword">var</span> width = $imgs.width();</div><div class="line"> <span class="keyword">if</span>(height > width){</div><div class="line"> $imgs.css({</div><div class="line"> <span class="attr">width</span>: BASE * radio,</div><div class="line"> <span class="attr">height</span>: (BASE * height / width) * radio,</div><div class="line"> <span class="attr">top</span>: -((BASE * height / width) * radio - <span class="number">310</span>) / <span class="number">2</span>,</div><div class="line"> <span class="attr">left</span>: -(BASE * radio - <span class="number">310</span>) / <span class="number">2</span></div><div class="line"> });</div><div class="line"> }<span class="keyword">else</span>{</div><div class="line"> $imgs.css({</div><div class="line"> <span class="attr">height</span>: BASE * radio,</div><div class="line"> <span class="attr">width</span>: (BASE * width / height) * radio,</div><div class="line"> <span class="attr">top</span>: -(BASE * radio - <span class="number">310</span>) / <span class="number">2</span>,</div><div class="line"> <span class="attr">left</span> : -((BASE * width / height) * radio - <span class="number">310</span>) / <span class="number">2</span></div><div class="line"> });</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure><h3 id="图片裁剪"><a href="#图片裁剪" class="headerlink" title="图片裁剪"></a>图片裁剪</h3><p>这里的裁剪工作是在前端完成的,需要借助Canvas的一些接口。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> canvas = <span class="built_in">document</span>.createElement(<span class="string">'canvas'</span>);</div><div class="line">canvas.id = <span class="string">'avatarCanvas'</span>;</div><div class="line"><span class="keyword">var</span> ctx = canvas.getContext(<span class="string">'2d'</span>);</div><div class="line"><span class="keyword">var</span> $img = $(<span class="string">'.avatar-editor-window-inner img'</span>);</div><div class="line"><span class="keyword">var</span> originalWidth = <span class="built_in">parseFloat</span>($img.attr(<span class="string">'data-original-width'</span>));</div><div class="line"><span class="keyword">var</span> originalHeight = <span class="built_in">parseFloat</span>($img.attr(<span class="string">'data-original-height'</span>));</div><div class="line"><span class="keyword">var</span> nWidth = $img.width();</div><div class="line"><span class="keyword">var</span> nHeight = $img.height();</div><div class="line"><span class="keyword">var</span> x = (<span class="number">30</span> - <span class="built_in">parseFloat</span>($img.css(<span class="string">'left'</span>))) * originalWidth / nWidth;</div><div class="line"><span class="keyword">var</span> y = (<span class="number">30</span> - <span class="built_in">parseFloat</span>($img.css(<span class="string">'top'</span>))) * originalHeight / nHeight;</div><div class="line">canvas.width = BASE * originalWidth / nWidth;</div><div class="line">canvas.style.width = canvas.width;</div><div class="line">canvas.height = BASE * originalHeight / nHeight;</div><div class="line">canvas.style.height = canvas.height;</div><div class="line">ctx.drawImage($img[<span class="number">0</span>], x, y, canvas.width, canvas.height, <span class="number">0</span>, <span class="number">0</span>, canvas.width, canvas.height);</div><div class="line"><span class="keyword">var</span> avatar = canvas.toDataURL($img.attr(<span class="string">'src'</span>).match(<span class="regexp">/data:(.*);base64/</span>)[<span class="number">1</span>] || <span class="string">'image/jpg'</span>);</div></pre></td></tr></table></figure><p><code>drawImage</code>方法的功能是将图片上的某个点作为锚点,绘制指定的宽度和高度到Canvas标签。</p><blockquote><p>完整的demo代码请移步至<a href="https://github.com/brucewar/avatar-upload" target="_blank" rel="external">brucewar/avatar-upload</a></p></blockquote><p>有心的读者可能已经发现,知乎的头像上传功能已经换了一种实现方案。不错,这还是之前的方案,通过上下两张图片实现预览时的边界半透明效果。</p>]]></content>
<summary type="html">
<p>&#x5565;&#x90FD;&#x4E0D;&#x8BF4;&#xFF0C; &#x76F4;&#x63A5;&#x5148;&#x6765;&#x4E00;&#x5F20;&#x6548;&#x679C;&#x56FE;&#x2026;&#x2026;</p><p><
</summary>
<category term="前端开发" scheme="http://brucewar.cn/categories/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/"/>
<category term="JavaScript" scheme="http://brucewar.cn/tags/JavaScript/"/>
<category term="头像上传" scheme="http://brucewar.cn/tags/%E5%A4%B4%E5%83%8F%E4%B8%8A%E4%BC%A0/"/>
</entry>
<entry>
<title> windows下node版本管理:nvm-windows</title>
<link href="http://brucewar.cn/2017/01/13/windows%E4%B8%8Bnode%E7%89%88%E6%9C%AC%E7%AE%A1%E7%90%86-nvm-windows/"/>
<id>http://brucewar.cn/2017/01/13/windows下node版本管理-nvm-windows/</id>
<published>2017-01-13T01:18:18.000Z</published>
<updated>2017-05-06T03:36:19.617Z</updated>
<content type="html"><![CDATA[<p>最近工作上接手了两个项目,可它们依赖的node版本不同,于是想到了之前用的<strong>nvm</strong>(Node Version Manager)。</p><blockquote><p><a href="https://github.com/creationix/nvm" target="_blank" rel="external">https://github.com/creationix/nvm</a></p></blockquote><p>之前安装nvm的方式是通过<code>npm install nvm</code>,而新版本可以通过脚本或者手动安装。目前,nvm没有提供windows的支持,但是在其文档中提到了<strong>nvm-windows</strong>这个工具。</p><blockquote><p><a href="https://github.com/coreybutler/nvm-windows" target="_blank" rel="external">https://github.com/coreybutler/nvm-windows</a></p></blockquote><h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><p>在安装nvm-windows前,需要做以下步骤:</p><ol><li>卸载系统中已有的node.js</li><li>删除node.js安装目录(例如<code>C:\Program Files\nodejs</code>)</li><li>删除npm包的目录(例如<code>C:\Users<user>\AppData\Roaming\npm</code>)</li></ol><p><img src="/2017/01/13/windows下node版本管理-nvm-windows/release.png" alt="打开release页面"></p><p>打开release页面,下载最新版本的安装包。</p><p><img src="/2017/01/13/windows下node版本管理-nvm-windows/install.png" alt="安装"></p><h3 id="更新"><a href="#更新" class="headerlink" title="更新"></a>更新</h3><p>更新也很简单,直接下载最新版的nvm-windows安装即可。它将安全的覆盖文件。</p><h3 id="使用方法"><a href="#使用方法" class="headerlink" title="使用方法"></a>使用方法</h3><ul><li><code>nvm install <version> [arch]</code>:version可以是指定的node.js版本或者<code>latest</code>(最新版),arch可以是<code>32</code>、<code>64</code>或者<code>all</code></li><li><code>nvm list [available]</code>:列出当前已经安装的node.js版本,<code>available</code>参数列出可安装版本</li><li><code>nvm use <version> [arch]</code>:切换node.js版本</li></ul><p>这里就介绍几个常用命令,更多命令请自行看文档。</p>]]></content>
<summary type="html">
<p>&#x6700;&#x8FD1;&#x5DE5;&#x4F5C;&#x4E0A;&#x63A5;&#x624B;&#x4E86;&#x4E24;&#x4E2A;&#x9879;&#x76EE;&#xFF0C;&#x53EF;&#x5B83;&#x4EEC;&#x4F9D;&
</summary>
<category term="Node.js" scheme="http://brucewar.cn/categories/Node-js/"/>
<category term="nvm" scheme="http://brucewar.cn/tags/nvm/"/>
<category term="node.js" scheme="http://brucewar.cn/tags/node-js/"/>
<category term="nvm-windows" scheme="http://brucewar.cn/tags/nvm-windows/"/>
</entry>
<entry>
<title>2016年终总结</title>
<link href="http://brucewar.cn/2016/12/25/2016%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/"/>
<id>http://brucewar.cn/2016/12/25/2016年终总结/</id>
<published>2016-12-24T16:00:00.000Z</published>
<updated>2016-12-25T01:46:19.161Z</updated>
<content type="html"><![CDATA[<iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width="330" height="86" src="//music.163.com/outchain/player?type=2&id=29750099&auto=0&height=66"></iframe><p>又到了一年一度的圣诞节,每当到了这天就意味着这一年就要结束了,也意味着又长了一岁。其实我不是一个特别喜欢写年终总结的人,但对于我来说,2016是“不安分”的一年。当然这里的<em>不安分</em>加了引号,因为我今年经历了挺多事,也成长了很多,我用下面几个词来总结我的2016:</p><ul><li>读书</li><li>运动</li><li>房奴</li><li>跳槽</li><li>恋爱和分手</li><li>Be myself</li></ul><p>2015年末,我还没有买房的打算,在家人的催促下,我开始看了几个楼盘,但是也没有太过认真对待这件事。再后来,我妈和我姐来南京也一起看了几个小区,最终在2016年的第一天定下了房子,也算在南京扎根了!当然,非常感谢我姐的果断,也感谢亲戚的帮助。说实话,就在那天我脑子里转的是,“嗯,有了它就意味着我肩上的责任更大了,我也将迈入<strong>房奴</strong>的生活…”。这些想法让当时的我有点懵,但是人总要成长,总要面对这些问题,而不能总想着逃避。</p><p>还记得二月份,笛风研发部分组,“有幸”(当然这些事大家都心照不宣)加入蕾爷的笛风CRM开发组,负责CRM的前端开发工作,和蕾爷合作的很开心!并且也和几个小伙伴开始了马拉松的准备,大家互相鼓励和监督,一直坚持跑步。自从跑步后,同事说我气色很好(不管是不是真的,内心都是激动的),当然,我自己也会感觉到比以前更自信、更有精神。感谢在笛风认识的这些小伙伴!</p><blockquote><p>圈子决定人生,接近什么样的人,就会走什么样的路,所谓物以类聚,人以群分。牌友只会催你打牌;酒友只会催你干杯;而靠谱的人却会感染你如何 取得进步!</p></blockquote><p>可能上半年太过浮躁,所以今年也没读几本书。当然,什么时候读书都不晚,只怕你缺乏重新开始的勇气。所以,在这里给大家推荐几本不错的书——《解忧杂货店》、《沟通的艺术》、《当我谈跑步时我谈些什么》、《人类简史》。最近刚看完《人类简史》这本书,作者对人类的历史进程有着深刻的个人理解。同时,也让我对历史越来越感兴趣。常言道,读史可以明志。</p><blockquote class="blockquote-center">唯读书和跑步不可辜负。</blockquote><p>日复一日的工作,我这颗浮躁的心终于按捺不住了,于是九月份鼓起很大的勇气提了离职,也是人生中第一份正式工作的结束。当然,非常感谢笛风假期的同事,大家在一起共事很愉快!第二份工作,我挑了一个很有意义的入职日期(10月10号,1010,程序猿都懂),正式开始了我工作生涯新的篇章。不知不觉,入职<a href="http://www.hansight.com" target="_blank" rel="external">HanSight瀚思</a>快三个月了,在这里与新同事工作的非常愉快。虽然每天都得挤地铁,不过,我也能静下心来好好利用这些碎片时间,看看书,思考思考人生(哈哈)。顺便帮公司做个宣传,HanSight南京研发中心招人,有意向的欢迎投简历到我的工作邮箱<strong>[email protected]</strong>。</p><p>在入职新公司的同时,我也开始了人生中第一段感情,10月15日与她正式确认关系,一个月不到又分手。当然,过去的已成过去,你我都要继续往前走,也感谢这段经历带给我的成长。</p><p>不知不觉,夜已深,可能真的只有夜深人静的时候,才能好好整理自己的思绪。新的一年,也为自己定下目标:做自己(Be myself)。继续坚持跑步、坚持读书、坚持早睡早起的习惯、在技术上对自己要求更严格、静下心来深入前端领域(主要是React技术栈)。</p><p>最后,送给自己一句话:但愿我从不缺乏重新开始的勇气。</p>]]></content>
<summary type="html">
<iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width="330" height="86" src="//music.163.com/outchain/player?type=2&amp
</summary>
<category term="随笔" scheme="http://brucewar.cn/categories/%E9%9A%8F%E7%AC%94/"/>
<category term="2016" scheme="http://brucewar.cn/tags/2016/"/>
<category term="年终总结" scheme="http://brucewar.cn/tags/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/"/>
</entry>
<entry>
<title>npm3.0新的依赖解决方案</title>
<link href="http://brucewar.cn/2016/12/20/npm3-0%E6%96%B0%E7%9A%84%E4%BE%9D%E8%B5%96%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/"/>
<id>http://brucewar.cn/2016/12/20/npm3-0新的依赖解决方案/</id>
<published>2016-12-20T15:02:20.000Z</published>
<updated>2017-05-06T03:35:50.303Z</updated>
<content type="html"><![CDATA[<p>最近给我的装备(<em>Thinkpad S3-s431</em>)升了一下级,将原本用来加速缓存的<code>24G</code>固态硬盘换成了<code>128G</code>。所以得重装系统,然后一堆软件也得重装。包括Node.js。</p><p>安装了最新的Node.js(v6.9.2),npm(v3.10.9)。由于<code>node_modules</code>里的文件夹结构太深,无法移动,只能去项目中使用<code>npm install</code>重新安装依赖,然后发现<code>node_modules</code>文件夹结构是这样的:</p><p><img src="/2016/12/20/npm3-0新的依赖解决方案/npmv3.png" alt="npm v3"></p><p>一个模块被分在了不同文件夹下,满足下好奇心,去看了<a href="https://docs.npmjs.com/how-npm-works/npm3#npm-v3-dependency-resolution" target="_blank" rel="external">npm的官方文档</a>。</p><p>果然NPM开发团队还是解决了这个包冗余和包结构太深的问题,下面我们来看看他们是如何做的。</p><p>npm2以一种嵌套的方式安装所有的依赖,而npm3将所有依赖都安装在主目录的<code>node_modules</code>下。如下图所示:</p><p><img src="/2016/12/20/npm3-0新的依赖解决方案/npm3deps2.png" alt="npm2和npm3比较"></p><p>APP依赖模块A,而模块A又依赖模块B,npm2的方案是将模块B安装在模块A的<code>node_modules</code>。npm3将模块A和模块B都安装在APP的<code>node_modules</code>中。假如APP依赖另一个模块C,而模块C又依赖另一个版本的模块B,我们看它们又有哪些区别:</p><p><img src="/2016/12/20/npm3-0新的依赖解决方案/npm3deps4.png" alt="npm2和npm3不同版本模块管理比较"></p><p>npm2中,会在模块A和C的<code>node_modules</code>下安装不同版本的模块B,而npm3先安装模块A的同时,将其依赖的模块B的1.0版本安装在APP模块下,为了防止模块冲突,同npm2的做法类似,将模块C依赖的模块B2.0安装在模块C下。</p><p>通过<code>npm ls</code>命令,我们可以看到模块依赖关系的树形结构图。如果想看项目主目录的依赖,可以使用如下命令:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">npm ls --depth=0</div></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>&#x6700;&#x8FD1;&#x7ED9;&#x6211;&#x7684;&#x88C5;&#x5907;&#xFF08;<em>Thinkpad S3-s431</em>&#xFF09;&#x5347;&#x4E86;&#x4E00;&#x4E0B;&#x7EA7;
</summary>
<category term="Node.js" scheme="http://brucewar.cn/categories/Node-js/"/>
<category term="npm" scheme="http://brucewar.cn/tags/npm/"/>
<category term="v3" scheme="http://brucewar.cn/tags/v3/"/>
</entry>
<entry>
<title>GitBook平台发布教程</title>
<link href="http://brucewar.cn/2016/12/05/GitBook%E5%B9%B3%E5%8F%B0%E5%8F%91%E5%B8%83%E6%95%99%E7%A8%8B/"/>
<id>http://brucewar.cn/2016/12/05/GitBook平台发布教程/</id>
<published>2016-12-05T09:11:25.000Z</published>
<updated>2016-12-06T02:06:40.861Z</updated>
<content type="html"><![CDATA[<p>最近兴趣所致翻译了一本英文的SVG教程,并将其托管在<strong>GitHub</strong>,部署于<strong>GitBook</strong>。为了给大家最直观的效果,献上教程部署地址:<a href="https://svg.brucewar.me" target="_blank" rel="external">https://svg.brucewar.me</a>。这也是我第一次翻译英文文档,也是我第一次使用GitBook部署电子书。教程虽然简单,但基本涉及了SVG的所有知识点。</p><blockquote><p>喂喂喂,跑题了啊!</p></blockquote><p>回到正题,因为部署电子书涉及的工具比较多,不必担心,我将按以下流程来各个击破:</p><ul><li>本地生成电子书</li><li>托管GitHub</li><li>发布到GitBook</li><li>绑定自定义域名</li></ul><h2 id="本地生成电子书"><a href="#本地生成电子书" class="headerlink" title="本地生成电子书"></a>本地生成电子书</h2><p>GitBook官方提供了一个命令行工具(gitbook),可以使用git和markdown制作本地电子书并支持预览等功能。在安装这个命令行工具之前,你需要安装<a href="https://nodejs.org/zh-cn/" target="_blank" rel="external">Node.js</a>,官网已经提供了安装包,这里就不详细说明Node.js的安装方法了。然后便可以通过Node.js提供的包管理工具<code>npm</code>安装gitbook了。</p><h3 id="安装gitbook"><a href="#安装gitbook" class="headerlink" title="安装gitbook"></a>安装gitbook</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">npm install gitbook-cli -g</div></pre></td></tr></table></figure><p>等待片刻,可以使用下面命令确认是否安装成功:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line">gitbook -V</div><div class="line"></div><div class="line"><span class="comment"># result:</span></div><div class="line"><span class="comment"># CLI version: 2.3.0</span></div><div class="line"><span class="comment"># GitBook version: 3.2.2</span></div><div class="line"></div><div class="line"><span class="comment"># 查看gitbook提供的一些命令</span></div><div class="line">gitbook -h</div></pre></td></tr></table></figure><h3 id="初始化电子书"><a href="#初始化电子书" class="headerlink" title="初始化电子书"></a>初始化电子书</h3><p>首先为电子书建一个文件夹,然后通过命令行工具初始化电子书:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">mkdir ebook && <span class="built_in">cd</span> ebook</div><div class="line">gitbook init</div></pre></td></tr></table></figure><p>最终会在文件夹下生成两个文件:<code>README.md</code>和<code>SUMMARY.md</code>。前者主要是关于你的书的介绍,后者包含书的目录,即章节结构,格式如下:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">* [第一章](chapter1.md)</div><div class="line"> * [第一节](chapter1_section1.md)</div><div class="line"> * [第二节](chapter1_section2.md)</div><div class="line">* [第二章](chapter2.md)</div></pre></td></tr></table></figure><p>下面你就可以使用markdown语法编写电子书啦!如果你想预览电子书,可以使用下面命令:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">gitbook serve</div></pre></td></tr></table></figure><p>第一次使用这个命令会有点慢,它会安装gitbook的一些额外工具。等待一会儿,会出现提示(Serving book on <a href="http://localhost:4000" target="_blank" rel="external">http://localhost:4000</a>),打开链接便可预览你创建的电子书啦!运行该命令会在电子书的文件夹下生成一个<code>_book</code>文件夹,里面的内容就是生成的HTML文件。</p><h3 id="高级配置"><a href="#高级配置" class="headerlink" title="高级配置"></a>高级配置</h3><p>gitbook也提供了一些高级配置信息,可以通过在电子书文件夹下添加一个<code>book.json</code>文件为其添加一些高级配置,主要的配置信息如下:</p><ul><li>title:电子书的名称</li><li>author:作者</li><li>description:本书的简单描述</li><li>language:gitbook使用的语言</li><li>links:左侧导航栏添加的链接</li><li>styles:自定义页面样式</li><li>plugins:配置使用的插件</li><li>pluginsConfig:各个插件对应的配置</li><li>gitbook:指定使用gitbook版本</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div></pre></td><td class="code"><pre><div class="line">{</div><div class="line"> <span class="string">"title"</span>: <span class="string">"SVG教程(中文翻译版)"</span>,</div><div class="line"> <span class="string">"author"</span>: <span class="string">"brucewar <[email protected]>"</span>,</div><div class="line"> <span class="string">"description"</span>: <span class="string">"SVG教程中文翻译版,也是本人第一次翻译英文教程。"</span>,</div><div class="line"> <span class="string">"links"</span>: {</div><div class="line"> <span class="string">"sidebar"</span>: {</div><div class="line"> <span class="string">"博客"</span>: <span class="string">"http://brucewar.me"</span>,</div><div class="line"> <span class="string">"打赏"</span>: <span class="string">"http://brucewar.me/donate/"</span>,</div><div class="line"> <span class="string">"View on GitHub"</span>: <span class="string">"https://github.com/brucewar/svg-tutorial"</span></div><div class="line"> }</div><div class="line"> },</div><div class="line"> <span class="string">"plugins"</span>: [</div><div class="line"> <span class="string">"duoshuo"</span>, <span class="comment">// 多说评论</span></div><div class="line"> <span class="string">"github"</span>, <span class="comment">// 展示github图标</span></div><div class="line"> <span class="string">"ga"</span>, <span class="comment">// google analytics</span></div><div class="line"> <span class="string">"ba"</span> <span class="comment">// 百度统计</span></div><div class="line"> ],</div><div class="line"> <span class="string">"pluginsConfig"</span>: {</div><div class="line"> <span class="string">"duoshuo"</span>: {</div><div class="line"> <span class="string">"short_name"</span>: <span class="string">"brucewar"</span>,</div><div class="line"> <span class="string">"theme"</span>: <span class="string">"default"</span></div><div class="line"> },</div><div class="line"> <span class="string">"github"</span>: {</div><div class="line"> <span class="string">"url"</span>: <span class="string">"https://github.com/brucewar"</span></div><div class="line"> },</div><div class="line"> <span class="string">"ga"</span>: {</div><div class="line"> <span class="string">"token"</span>: <span class="string">"UA-87259783-2"</span></div><div class="line"> },</div><div class="line"> <span class="string">"ba"</span>: {</div><div class="line"> <span class="string">"token"</span>: <span class="string">"80f89a3fe34a9f8e22c53f85908e2d6"</span></div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure><p>上面是我使用的一些配置。如果在你的配置中添加了插件,执行<code>gitbook serve</code>前,需要通过以下命令安装这些插件。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">gitbook install</div></pre></td></tr></table></figure><p>gitbook提供了一个插件平台,你可以去搜索你想要的插件,当然,你也可以为其贡献插件。</p><h2 id="托管GitHub"><a href="#托管GitHub" class="headerlink" title="托管GitHub"></a>托管GitHub</h2><p>首先,你需要有一个<a href="https://github.com" target="_blank" rel="external">GitHub</a>账号。然后创建一个公有仓库。然后,回到电子书目录下,使用git工具初始化一个仓库。并将本地仓库和远程GitHub仓库关联。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line">git init</div><div class="line">git remote add origin 你的远程仓库地址(比如https://github.com/brucewar/svg-tutorial)</div><div class="line"></div><div class="line">// 提交电子书</div><div class="line">git add .</div><div class="line">git commit -m <span class="string">"publish"</span></div><div class="line">git push origin master</div></pre></td></tr></table></figure><h2 id="发布到GitBook"><a href="#发布到GitBook" class="headerlink" title="发布到GitBook"></a>发布到GitBook</h2><p>如果没有<a href="https://www.gitbook.com" target="_blank" rel="external">GitBook</a>账号,可以先注册一个。然后在新建一本book。然后需要做的就是将GitBook和GitHub进行关联。</p><p><img src="/2016/12/05/GitBook平台发布教程/gitbook2github.jpg" alt="GitBook关联GitHub步骤"></p><p>但是,这还不够,因为GitBook不知道何时构建你的电子书,所以这里我们就要用到GitHub的<em>webhook</em>功能。通俗点讲,就是在GitHub提交电子书的同时,让GitHub告诉GitBook,有更新了,你重新构建下。具体操作如下:</p><p>关联完GitHub仓库后,会出现如下界面,复制webhook url:</p><p><img src="/2016/12/05/GitBook平台发布教程/webhook_url.jpg" alt="复制Webhook URL"></p><p>打开GitHub仓库的设置页面,添加一个webhook:</p><p><img src="/2016/12/05/GitBook平台发布教程/webhook_add.jpg" alt="在GitHub添加webhook"></p><h2 id="绑定自定义域名"><a href="#绑定自定义域名" class="headerlink" title="绑定自定义域名"></a>绑定自定义域名</h2><p>此时,你可以通过GitBook提供的域名访问你刚才创建的电子书啦!一般域名格式是<a href="http://{author}.gitbooks.io/{book}/content,但是你也可以使用自定义的域名(首先你得买个域名)。" target="_blank" rel="external">http://{author}.gitbooks.io/{book}/content,但是你也可以使用自定义的域名(首先你得买个域名)。</a></p><p><img src="/2016/12/05/GitBook平台发布教程/custom_domain.jpg" alt="绑定域名"></p>]]></content>
<summary type="html">
<p>&#x6700;&#x8FD1;&#x5174;&#x8DA3;&#x6240;&#x81F4;&#x7FFB;&#x8BD1;&#x4E86;&#x4E00;&#x672C;&#x82F1;&#x6587;&#x7684;SVG&#x6559;&#x7A0B;&#xFF0
</summary>
<category term="GitBook" scheme="http://brucewar.cn/categories/GitBook/"/>
<category term="gitbook" scheme="http://brucewar.cn/tags/gitbook/"/>
<category term="电子书" scheme="http://brucewar.cn/tags/%E7%94%B5%E5%AD%90%E4%B9%A6/"/>
<category term="教程" scheme="http://brucewar.cn/tags/%E6%95%99%E7%A8%8B/"/>
</entry>
<entry>
<title>跑步带给了我什么</title>
<link href="http://brucewar.cn/2016/11/29/%E8%B7%91%E6%AD%A5%E5%B8%A6%E7%BB%99%E4%BA%86%E6%88%91%E4%BB%80%E4%B9%88/"/>
<id>http://brucewar.cn/2016/11/29/跑步带给了我什么/</id>
<published>2016-11-29T07:40:11.000Z</published>
<updated>2016-11-29T09:50:16.599Z</updated>
<content type="html"><![CDATA[<p>从年初2月份到现在,我已经坚持跑步大半年了,虽然频率不高(平均一周跑三次,每次5公里),姑且算是坚持下来了。还记得刚开始是因为前同事(<strong>蕾爷</strong>和<strong>阿汤</strong>)的怂恿,让我一起报名参加上海松江的首届半程马拉松比赛,不过因为大家都是第一次跑,所以没敢报半程,最终报的是<code>12km</code>健康跑。也是当时脑子一热,让我将跑步坚持了这么久,并且参加了今年南京的马拉松,不过跑的是5公里。</p><p><img src="http://brucewar.qiniudn.com/642380720289764615.jpg" alt="上海松江半程马拉松"></p><p>题外话:没错,你看到就是蒋劲夫,他也是一个坚持运动的人,最近看的一档节目《真正的男子汉》也对他有所关注。</p><p><img src="http://brucewar.qiniudn.com/sj-marathon2.jpg" alt="松江12km完赛照"></p><p><img src="http://brucewar.qiniudn.com/nj-marathon1.JPG" alt="2016南京马拉松"></p><p>知乎里常常看到一些关于跑步的话题,如<a href="https://www.zhihu.com/question/28656794" target="_blank" rel="external">“坚持跑步到底有什么改变?”</a>。所以我有时也会想问问自己,坚持跑步给我带来了什么改变,也就有了这篇文章。先说说生理上变化吧!我觉得最大的改变就是整个人的精神面貌不一样了,作为程序员的一员,每天坐着的时间比站着的时间多得多,而且整天面对着电脑,一天下来都是油光满面,提不起精神。自从跑步后,周围的同事都说我“容光焕发”。当然,还有一些附带的变化就是肚子上的赘肉也少了(额,还是有点的),睡眠质量提高,也很少生病了。</p><p>但是,这些生理上的变化微乎其微,坚持跑步贵在<strong>坚持</strong>,它真正带给我的是生活和工作上的变化。因为跑步,我认识了许多同样把跑步真正坚持下来的人,有时大家也会约着一起在咕咚APP上画圈。</p><p><img src="http://brucewar.qiniudn.com/xuanwuhu.png" alt="最大的圈-玄武湖"></p><p>跑步也让我的生活更加规律,早睡早起已然成为我的习惯。每当早上赖床时,我会想到,“跑步时也有过真的坚持不下去的时候,我会告诉自己,你还可以再跑1公里”,我还会想到,坚持跑步这么难的习惯,我都坚持下来了,还有什么习惯不能坚持。坚持跑步给我带来了自制力,也给了我认真对待生活的态度。我很享受跑步过程,一步一个脚印,不断给自己设立新的目标。</p><blockquote><p>违背了自己定下的原则,哪怕只有一次,以后就将违背更多的原则。 —— 村上春树 《当我谈跑步时我谈些什么》</p></blockquote><p>此外,跑步也让我变的更自信了。面对工作和生活中遇到的一些问题,我能从容地面对并解决它们。也正是因为跑步,睡眠质量提高了,所以白天工作的精神状态很好,能更专注的工作和学习。</p><p>现在,我又有了两件坚持做的事,我觉得这也是跑步带给我,一是坚持看书,第二件也就是坚持写博客。跑步给我带来的是身体健康的延续,而看书写博客则给我带来的是精神上积累和沉淀。我相信,我会像坚持跑步一样,把这两件事坚持下去,同样也会继续将跑步坚持下去。</p><blockquote><p>一生做好一件事,一天看一个小时书,这就够了。</p></blockquote>]]></content>
<summary type="html">
<p>&#x4ECE;&#x5E74;&#x521D;2&#x6708;&#x4EFD;&#x5230;&#x73B0;&#x5728;&#xFF0C;&#x6211;&#x5DF2;&#x7ECF;&#x575A;&#x6301;&#x8DD1;&#x6B65;&#x5927;
</summary>
<category term="生活" scheme="http://brucewar.cn/categories/%E7%94%9F%E6%B4%BB/"/>
<category term="跑步" scheme="http://brucewar.cn/tags/%E8%B7%91%E6%AD%A5/"/>
<category term="坚持" scheme="http://brucewar.cn/tags/%E5%9D%9A%E6%8C%81/"/>
<category term="生活态度" scheme="http://brucewar.cn/tags/%E7%94%9F%E6%B4%BB%E6%80%81%E5%BA%A6/"/>
</entry>
<entry>
<title>D3.js(Draggable and Scalable Tree)</title>
<link href="http://brucewar.cn/2016/10/27/D3.js-Draggable%20and%20Scalable%20Tree/"/>
<id>http://brucewar.cn/2016/10/27/D3.js-Draggable and Scalable Tree/</id>
<published>2016-10-27T05:32:26.000Z</published>
<updated>2016-10-27T07:20:01.755Z</updated>
<content type="html"><![CDATA[<p>因为最近手上有个小的需求,设计一个可缩放和可拖拽的树形结构,我便去研读了D3官网给的一个树形的例子。</p><h3 id="布局(Layout)"><a href="#布局(Layout)" class="headerlink" title="布局(Layout)"></a>布局(Layout)</h3><p>原本我以为理解了基本的选择器、元素操作、Enter、Exit就能去看实例的代码了,后来发现我错了,所以这里需要理解一下D3中布局(Layout)的概念。布局是D3中一个十分重要的概念,从布局衍生出很多图表。例如:饼状图(pie)、力导向图(force),树状图(tree)等等,基本实现了很多开源的可视化工具提供的图表。但是它又和很多可视化工具(如Echarts)有很大的不同。</p><p>相对于其它工具来说,D3较底层一点,所以初学者可能会觉得有点困难,但是一旦理解了D3布局的思想,使用起来,会比其它工具更加得心应手。首先,我阐释下D3和大部分可视化工具数据到图表的流程:</p><ul><li>大部分可视化工具:数据 => 封装好的绘图函数 => 图表</li><li>D3:数据 => Layout => 绘图所需的数据 => 绘制图形 => 图表</li></ul><p>可以看出,D3需要自己去绘制图形,但是可以通过布局函数获得绘图所需要的数据,坏处是对初学者是一个很大的考验,好处是它能帮助我们制作出更加精密的图形。</p><h3 id="树状图"><a href="#树状图" class="headerlink" title="树状图"></a>树状图</h3><p>回归正题,如何设计一个树形结构,我将从D3官网提供的示例代码分析。</p><p>页面代码如下:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div></pre></td><td class="code"><pre><div class="line"><span class="meta"><!DOCTYPE html></span></div><div class="line"><span class="tag"><<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>></span></div><div class="line"><span class="tag"><<span class="name">head</span>></span></div><div class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"utf-8"</span>></span></div><div class="line"> <span class="tag"><<span class="name">title</span>></span>tree<span class="tag"></<span class="name">title</span>></span></div><div class="line"> <span class="tag"><<span class="name">style</span>></span><span class="css"></span></div><div class="line"> <span class="selector-tag">body</span>{</div><div class="line"> <span class="attribute">margin</span>: <span class="number">0</span>;</div><div class="line"> }</div><div class="line"> <span class="selector-tag">svg</span>{</div><div class="line"> <span class="attribute">background-color</span>: <span class="number">#eee</span>;</div><div class="line"> }</div><div class="line"> <span class="selector-class">.node</span> <span class="selector-tag">circle</span> {</div><div class="line"> <span class="attribute">cursor</span>: pointer;</div><div class="line"> <span class="attribute">fill</span>: <span class="number">#fff</span>;</div><div class="line"> <span class="attribute">stroke</span>: steelblue;</div><div class="line"> <span class="attribute">stroke-width</span>: <span class="number">1.5px</span>;</div><div class="line"> }</div><div class="line"> <span class="selector-class">.node</span> <span class="selector-tag">text</span> {</div><div class="line"> <span class="attribute">font-size</span>: <span class="number">11px</span>;</div><div class="line"> }</div><div class="line"> <span class="selector-tag">path</span><span class="selector-class">.link</span> {</div><div class="line"> <span class="attribute">fill</span>: none;</div><div class="line"> <span class="attribute">stroke</span>: <span class="number">#ccc</span>;</div><div class="line"> <span class="attribute">stroke-width</span>: <span class="number">1.5px</span>;</div><div class="line"> }</div><div class="line"> <span class="selector-tag">g</span><span class="selector-class">.detail</span> <span class="selector-tag">rect</span>{</div><div class="line"> <span class="attribute">fill</span>: <span class="number">#000</span>;</div><div class="line"> <span class="attribute">fill-opacity</span>: .<span class="number">6</span>;</div><div class="line"> <span class="attribute">rx</span>: <span class="number">5</span>;</div><div class="line"> <span class="attribute">ry</span>: <span class="number">5</span>;</div><div class="line"> }</div><div class="line"> <span class="selector-tag">g</span><span class="selector-class">.detail</span> <span class="selector-tag">text</span>{</div><div class="line"> <span class="attribute">fill</span>: <span class="number">#fff</span>;</div><div class="line"> }</div><div class="line"> <span class="tag"></<span class="name">style</span>></span></div><div class="line"><span class="tag"></<span class="name">head</span>></span></div><div class="line"><span class="tag"><<span class="name">body</span>></span></div><div class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">id</span>=<span class="string">"treeContainer"</span>></span><span class="tag"></<span class="name">div</span>></span></div><div class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"./dist/tree.bundle.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></div><div class="line"><span class="tag"></<span class="name">body</span>></span></div><div class="line"><span class="tag"></<span class="name">html</span>></span></div></pre></td></tr></table></figure><p>因为D3示例代码是同步的形式读出整个树形数据结构,我对其进行了改造,模拟异步数据(async_city.json)。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div></pre></td><td class="code"><pre><div class="line">{</div><div class="line"> <span class="string">"root"</span>: {</div><div class="line"> <span class="string">"name"</span>: <span class="string">"中国"</span></div><div class="line"> },</div><div class="line"> <span class="string">"中国"</span>: {</div><div class="line"> <span class="string">"name"</span>: <span class="string">"中国"</span>,</div><div class="line"> <span class="string">"children"</span>: [</div><div class="line"> {<span class="string">"name"</span>: <span class="string">"浙江"</span>},</div><div class="line"> {<span class="string">"name"</span>: <span class="string">"广西"</span>},</div><div class="line"> {<span class="string">"name"</span>: <span class="string">"黑龙江"</span>},</div><div class="line"> {<span class="string">"name"</span>: <span class="string">"新疆"</span>}</div><div class="line"> ]</div><div class="line"> },</div><div class="line"> <span class="string">"浙江"</span>: {</div><div class="line"> <span class="string">"name"</span>: <span class="string">"浙江"</span>,</div><div class="line"> <span class="string">"children"</span>: [</div><div class="line"> {<span class="string">"name"</span>: <span class="string">"杭州"</span>},</div><div class="line"> {<span class="string">"name"</span>: <span class="string">"宁波"</span>},</div><div class="line"> {<span class="string">"name"</span>:<span class="string">"温州"</span> },</div><div class="line"> {<span class="string">"name"</span>:<span class="string">"绍兴"</span> }</div><div class="line"> ]</div><div class="line"> },</div><div class="line"> <span class="string">"广西"</span>: {</div><div class="line"> <span class="string">"name"</span>: <span class="string">"广西"</span>,</div><div class="line"> <span class="string">"children"</span>: [</div><div class="line"> {<span class="string">"name"</span>: <span class="string">"桂林"</span>},</div><div class="line"> {<span class="string">"name"</span>: <span class="string">"南宁"</span>},</div><div class="line"> {<span class="string">"name"</span>: <span class="string">"柳州"</span>},</div><div class="line"> {<span class="string">"name"</span>: <span class="string">"防城港"</span>}</div><div class="line"> ]</div><div class="line"> },</div><div class="line"> <span class="string">"桂林"</span>: {</div><div class="line"> <span class="string">"name"</span>: <span class="string">"桂林"</span>,</div><div class="line"> <span class="string">"children"</span>: [</div><div class="line"> {<span class="string">"name"</span>:<span class="string">"秀峰区"</span>},</div><div class="line"> {<span class="string">"name"</span>:<span class="string">"叠彩区"</span>},</div><div class="line"> {<span class="string">"name"</span>:<span class="string">"象山区"</span>},</div><div class="line"> {<span class="string">"name"</span>:<span class="string">"七星区"</span>}</div><div class="line"> ]</div><div class="line"> },</div><div class="line"> <span class="string">"黑龙江"</span>: {</div><div class="line"> <span class="string">"name"</span>:<span class="string">"黑龙江"</span>,</div><div class="line"> <span class="string">"children"</span>:</div><div class="line"> [</div><div class="line"> {<span class="string">"name"</span>:<span class="string">"哈尔滨"</span>},</div><div class="line"> {<span class="string">"name"</span>:<span class="string">"齐齐哈尔"</span>},</div><div class="line"> {<span class="string">"name"</span>:<span class="string">"牡丹江"</span>},</div><div class="line"> {<span class="string">"name"</span>:<span class="string">"大庆"</span>}</div><div class="line"> ]</div><div class="line"> },</div><div class="line"> <span class="string">"新疆"</span> : {</div><div class="line"> <span class="string">"name"</span>:<span class="string">"新疆"</span> ,</div><div class="line"> <span class="string">"children"</span>:</div><div class="line"> [</div><div class="line"> {<span class="string">"name"</span>:<span class="string">"乌鲁木齐"</span>},</div><div class="line"> {<span class="string">"name"</span>:<span class="string">"克拉玛依"</span>},</div><div class="line"> {<span class="string">"name"</span>:<span class="string">"吐鲁番"</span>},</div><div class="line"> {<span class="string">"name"</span>:<span class="string">"哈密"</span>}</div><div class="line"> ]</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure><h4 id="画布"><a href="#画布" class="headerlink" title="画布"></a>画布</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> margin = {</div><div class="line"> <span class="attr">top</span>: <span class="number">20</span>,</div><div class="line"> <span class="attr">left</span>: <span class="number">50</span>,</div><div class="line"> <span class="attr">right</span>: <span class="number">50</span>,</div><div class="line"> <span class="attr">bottom</span>: <span class="number">20</span></div><div class="line">};</div><div class="line"><span class="keyword">var</span> width = $(<span class="built_in">document</span>).width(),</div><div class="line"> height = $(<span class="built_in">document</span>).height(),</div><div class="line"> i = <span class="number">0</span>,</div><div class="line"> limit = <span class="number">2</span>,</div><div class="line"> root;</div><div class="line"></div><div class="line"> <span class="comment">// draggable and scalable</span></div><div class="line"> <span class="keyword">var</span> zoomListener = d3.behavior.zoom().scaleExtent([<span class="number">0.1</span>, <span class="number">3</span>]).on(<span class="string">'zoom'</span>, zoom);</div><div class="line"> <span class="function"><span class="keyword">function</span> <span class="title">zoom</span>(<span class="params"></span>)</span>{</div><div class="line"> d3.select(<span class="string">'svg'</span>).select(<span class="string">'g'</span>).attr(<span class="string">'transform'</span>, <span class="string">'translate('</span> + d3.event.translate + <span class="string">')scale('</span> + d3.event.scale + <span class="string">')'</span>);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">var</span> svg = d3.select(<span class="string">"#treeContainer"</span>).append(<span class="string">"svg"</span>)</div><div class="line"> .attr(<span class="string">"width"</span>, width - margin.left - margin.right)</div><div class="line"> .attr(<span class="string">"height"</span>, height - margin.top - margin.bottom)</div><div class="line"> .call(zoomListener)</div><div class="line"> .append(<span class="string">"g"</span>)</div><div class="line"> .attr(<span class="string">"transform"</span>, <span class="string">"translate("</span> + margin.left + <span class="string">","</span> + margin.top + <span class="string">")"</span>);</div></pre></td></tr></table></figure><h4 id="获取异步数据"><a href="#获取异步数据" class="headerlink" title="获取异步数据"></a>获取异步数据</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 异步获取数据</span></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">getData</span>(<span class="params">sd, cb</span>)</span>{</div><div class="line"> d3.json(<span class="string">'data/async_city.json'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">err, json</span>)</span>{</div><div class="line"> <span class="comment">// 通过callback返回部分数据</span></div><div class="line"> cb && cb(json[sd.name]);</div><div class="line"> });</div><div class="line">}</div></pre></td></tr></table></figure><h4 id="构造树"><a href="#构造树" class="headerlink" title="构造树"></a>构造树</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 获取树的root</span></div><div class="line">getData({<span class="attr">name</span>: <span class="string">'root'</span>}, <span class="function"><span class="keyword">function</span>(<span class="params">json</span>)</span>{</div><div class="line"> root = json;</div><div class="line"> root.x0 = height / <span class="number">2</span>;</div><div class="line"> root.y0 = width / <span class="number">2</span>;</div><div class="line"></div><div class="line"> <span class="comment">// 初始化树根</span></div><div class="line"> update(root);</div><div class="line">});</div></pre></td></tr></table></figure><p>从上面的代码可以看出构造树的核心代码就是这个update函数,下面以注释的形式深入理解树形的构造。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div><div class="line">111</div><div class="line">112</div><div class="line">113</div><div class="line">114</div><div class="line">115</div><div class="line">116</div><div class="line">117</div><div class="line">118</div><div class="line">119</div><div class="line">120</div><div class="line">121</div><div class="line">122</div><div class="line">123</div><div class="line">124</div><div class="line">125</div><div class="line">126</div><div class="line">127</div><div class="line">128</div><div class="line">129</div><div class="line">130</div><div class="line">131</div><div class="line">132</div><div class="line">133</div><div class="line">134</div><div class="line">135</div><div class="line">136</div><div class="line">137</div><div class="line">138</div><div class="line">139</div><div class="line">140</div><div class="line">141</div><div class="line">142</div><div class="line">143</div><div class="line">144</div><div class="line">145</div><div class="line">146</div><div class="line">147</div><div class="line">148</div><div class="line">149</div><div class="line">150</div><div class="line">151</div><div class="line">152</div><div class="line">153</div><div class="line">154</div><div class="line">155</div><div class="line">156</div><div class="line">157</div><div class="line">158</div><div class="line">159</div><div class="line">160</div><div class="line">161</div><div class="line">162</div><div class="line">163</div><div class="line">164</div><div class="line">165</div><div class="line">166</div><div class="line">167</div><div class="line">168</div><div class="line">169</div><div class="line">170</div><div class="line">171</div><div class="line">172</div><div class="line">173</div><div class="line">174</div><div class="line">175</div><div class="line">176</div><div class="line">177</div><div class="line">178</div><div class="line">179</div><div class="line">180</div><div class="line">181</div><div class="line">182</div><div class="line">183</div><div class="line">184</div><div class="line">185</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 新建一个树的布局</span></div><div class="line"><span class="keyword">var</span> tree = d3.layout.tree()</div><div class="line"> .size([height - margin.top - margin.bottom, width - margin.left - margin.right]);</div><div class="line"></div><div class="line"><span class="comment">// 因为默认的树布局是自上而下的,这里构建一个自左向右的树,故需要一个转换x和y坐标的函数</span></div><div class="line"><span class="keyword">var</span> diagonal = d3.svg.diagonal()</div><div class="line"> .projection(<span class="function"><span class="keyword">function</span>(<span class="params">d</span>) </span>{ <span class="keyword">return</span> [d.y, d.x]; });</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">update</span>(<span class="params">source</span>) </span>{</div><div class="line"> <span class="keyword">var</span> duration = d3.event && d3.event.altKey ? <span class="number">5000</span> : <span class="number">500</span>;</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"> * 这里实际上是通过tree的nodes函数获得树形结构的每个节点的数据,包括位置信息和深度</div><div class="line"> * 返回的数据结构如下:</div><div class="line"> * [{depth: 0, name: "中国", children: [], x: 380, y: 0}]</div><div class="line"> */</div><div class="line"> <span class="keyword">var</span> nodes = tree.nodes(root).reverse();</div><div class="line"></div><div class="line"> <span class="comment">// 为了让当前节点居中,故更具当前节点的depth来计算各节点的y坐标(即横向位置)</span></div><div class="line"> <span class="keyword">var</span> srcDepth = source.depth;</div><div class="line"> nodes.forEach(<span class="function"><span class="keyword">function</span>(<span class="params">d</span>)</span>{</div><div class="line"> d.y = height / <span class="number">2</span> + <span class="number">180</span> * (d.depth - srcDepth);</div><div class="line"> });</div><div class="line"></div><div class="line"> <span class="comment">// Update the nodes…</span></div><div class="line"> <span class="keyword">var</span> node = svg.selectAll(<span class="string">"g.node"</span>)</div><div class="line"> .data(nodes, <span class="function"><span class="keyword">function</span>(<span class="params">d</span>) </span>{ <span class="keyword">return</span> d.id || (d.id = ++i); });</div><div class="line"></div><div class="line"> <span class="comment">// Enter any new nodes at the parent's previous position.</span></div><div class="line"> <span class="keyword">var</span> nodeEnter = node.enter().append(<span class="string">"g"</span>)</div><div class="line"> .attr(<span class="string">"class"</span>, <span class="string">"node"</span>)</div><div class="line"> .attr(<span class="string">"transform"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">d</span>) </span>{ <span class="keyword">return</span> <span class="string">"translate("</span> + source.y0 + <span class="string">","</span> + source.x0 + <span class="string">")"</span>; })</div><div class="line"> .on(<span class="string">"click"</span>, click)</div><div class="line"> .on(<span class="string">'mouseover'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">d</span>)</span>{</div><div class="line"> <span class="keyword">if</span>(d.name == <span class="string">'more'</span>) <span class="keyword">return</span>;</div><div class="line"> <span class="comment">// 鼠标hover某个节点时,显示一个详细信息的弹层</span></div><div class="line"> <span class="keyword">var</span> detail = d3.select(<span class="keyword">this</span>).append(<span class="string">'g'</span>)</div><div class="line"> .attr(<span class="string">'class'</span>, <span class="string">'detail'</span>)</div><div class="line"> .attr(<span class="string">'dx'</span>, d3.event.x)</div><div class="line"> .attr(<span class="string">'dy'</span>, d3.event.y + <span class="number">10</span>);</div><div class="line"> detail.append(<span class="string">'rect'</span>)</div><div class="line"> .attr(<span class="string">'width'</span>, <span class="number">100</span>)</div><div class="line"> .attr(<span class="string">'height'</span>, <span class="number">100</span>);</div><div class="line"> detail.append(<span class="string">'text'</span>)</div><div class="line"> .attr(<span class="string">'dx'</span>, <span class="string">'.35em'</span>)</div><div class="line"> .attr(<span class="string">'dy'</span>, <span class="string">'2em'</span>)</div><div class="line"> .attr(<span class="string">'text-anchor'</span>, <span class="string">'start'</span>)</div><div class="line"> .text(<span class="function"><span class="keyword">function</span>(<span class="params">d</span>)</span>{</div><div class="line"> <span class="keyword">return</span> <span class="string">'name: '</span> + d.name;</div><div class="line"> });</div><div class="line"> })</div><div class="line"> .on(<span class="string">'mousemove'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">d</span>)</span>{</div><div class="line"> <span class="keyword">var</span> detail = d3.select(<span class="keyword">this</span>).select(<span class="string">'.detail'</span>);</div><div class="line"> detail.attr(<span class="string">'x'</span>, d3.event.x)</div><div class="line"> .attr(<span class="string">'y'</span>, d3.event.y);</div><div class="line"> })</div><div class="line"> .on(<span class="string">'mouseout'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">d</span>)</span>{</div><div class="line"> <span class="keyword">if</span>(d.name == <span class="string">'more'</span>) <span class="keyword">return</span>;</div><div class="line"> d3.select(<span class="keyword">this</span>).select(<span class="string">'.detail'</span>).remove();</div><div class="line"> });</div><div class="line"></div><div class="line"> nodeEnter.append(<span class="string">"circle"</span>)</div><div class="line"> .attr(<span class="string">"r"</span>, <span class="number">1e-6</span>)</div><div class="line"> .style(<span class="string">"fill"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">d</span>)</span>{ <span class="keyword">return</span> !d.isExpand ? <span class="string">"lightsteelblue"</span> : <span class="string">"#fff"</span>; });</div><div class="line"></div><div class="line"> nodeEnter.append(<span class="string">"text"</span>)</div><div class="line"> .attr(<span class="string">"x"</span>, <span class="number">-10</span>)</div><div class="line"> .attr(<span class="string">"dy"</span>, <span class="string">".35em"</span>)</div><div class="line"> .attr(<span class="string">"text-anchor"</span>, <span class="string">"end"</span>)</div><div class="line"> .text(<span class="function"><span class="keyword">function</span>(<span class="params">d</span>) </span>{ <span class="keyword">return</span> d.name; })</div><div class="line"> .style(<span class="string">"fill-opacity"</span>, <span class="number">1e-6</span>);</div><div class="line"></div><div class="line"></div><div class="line"> <span class="comment">// Transition nodes to their new position.</span></div><div class="line"> <span class="keyword">var</span> nodeUpdate = node.transition()</div><div class="line"> .duration(duration)</div><div class="line"> .attr(<span class="string">"transform"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">d</span>) </span>{ <span class="keyword">return</span> <span class="string">"translate("</span> + d.y + <span class="string">","</span> + d.x + <span class="string">")"</span>; });</div><div class="line"></div><div class="line"> nodeUpdate.select(<span class="string">"circle"</span>)</div><div class="line"> .attr(<span class="string">"r"</span>, <span class="number">10</span>)</div><div class="line"> .style(<span class="string">"fill"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">d</span>)</span>{ <span class="keyword">return</span> !d.isExpand ? <span class="string">"lightsteelblue"</span> : <span class="string">"#fff"</span>; });</div><div class="line"></div><div class="line"> nodeUpdate.select(<span class="string">"text"</span>)</div><div class="line"> .style(<span class="string">"fill-opacity"</span>, <span class="number">1</span>);</div><div class="line"></div><div class="line"> <span class="comment">// Transition exiting nodes to the parent's new position.</span></div><div class="line"> <span class="keyword">var</span> nodeExit = node.exit().transition()</div><div class="line"> .duration(duration)</div><div class="line"> .attr(<span class="string">"transform"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">d</span>) </span>{</div><div class="line"> <span class="keyword">if</span>(d.name == <span class="string">'more'</span>) <span class="keyword">this</span>.remove();</div><div class="line"> <span class="keyword">return</span> <span class="string">"translate("</span> + source.y + <span class="string">","</span> + source.x + <span class="string">")"</span>;</div><div class="line"> })</div><div class="line"> .remove();</div><div class="line"></div><div class="line"> nodeExit.select(<span class="string">"circle"</span>)</div><div class="line"> .attr(<span class="string">"r"</span>, <span class="number">1e-6</span>);</div><div class="line"></div><div class="line"> nodeExit.select(<span class="string">"text"</span>)</div><div class="line"> .style(<span class="string">"fill-opacity"</span>, <span class="number">1e-6</span>);</div><div class="line"></div><div class="line"> <span class="comment">/** Update the links...</span></div><div class="line"> * tree.links方法获取连线节点之间的映射,返回的数据结构如下:</div><div class="line"> * [{source: {}, target: {}}]</div><div class="line"> */</div><div class="line"> <span class="keyword">var</span> link = svg.selectAll(<span class="string">"path.link"</span>)</div><div class="line"> .data(tree.links(nodes), <span class="function"><span class="keyword">function</span>(<span class="params">d</span>) </span>{ <span class="keyword">return</span> d.target.id; });</div><div class="line"></div><div class="line"> <span class="comment">// Enter any new links at the parent's previous position.</span></div><div class="line"> link.enter().insert(<span class="string">"path"</span>, <span class="string">"g"</span>)</div><div class="line"> .attr(<span class="string">"class"</span>, <span class="string">"link"</span>)</div><div class="line"> .attr(<span class="string">"d"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">d</span>) </span>{</div><div class="line"> <span class="keyword">var</span> o = {<span class="attr">x</span>: source.x0, <span class="attr">y</span>: source.y0};</div><div class="line"> <span class="keyword">return</span> diagonal({<span class="attr">source</span>: o, <span class="attr">target</span>: o});</div><div class="line"> })</div><div class="line"> .transition()</div><div class="line"> .duration(duration)</div><div class="line"> .attr(<span class="string">"d"</span>, diagonal);</div><div class="line"></div><div class="line"> <span class="comment">// Transition links to their new position.</span></div><div class="line"> link.transition()</div><div class="line"> .duration(duration)</div><div class="line"> .attr(<span class="string">"d"</span>, diagonal);</div><div class="line"></div><div class="line"> <span class="comment">// Transition exiting nodes to the parent's new position.</span></div><div class="line"> link.exit().transition()</div><div class="line"> .duration(duration)</div><div class="line"> .attr(<span class="string">"d"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">d</span>) </span>{</div><div class="line"> <span class="keyword">if</span>(d.target.name == <span class="string">'more'</span>) <span class="keyword">this</span>.remove();</div><div class="line"> <span class="keyword">var</span> o = {<span class="attr">x</span>: source.x, <span class="attr">y</span>: source.y};</div><div class="line"> <span class="keyword">return</span> diagonal({<span class="attr">source</span>: o, <span class="attr">target</span>: o});</div><div class="line"> })</div><div class="line"> .remove();</div><div class="line"></div><div class="line"> <span class="comment">// Stash the old positions for transition.</span></div><div class="line"> <span class="comment">// 记录当前节点所在的位置,为node update提供位移动画</span></div><div class="line"> nodes.forEach(<span class="function"><span class="keyword">function</span>(<span class="params">d</span>) </span>{</div><div class="line"> d.x0 = d.x;</div><div class="line"> d.y0 = d.y;</div><div class="line"> });</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">collapse</span>(<span class="params">d</span>)</span>{</div><div class="line"> <span class="keyword">delete</span> d._children;</div><div class="line"> <span class="keyword">delete</span> d.isExpand;</div><div class="line"> <span class="keyword">delete</span> d.children;</div><div class="line">}</div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">expand</span>(<span class="params">d</span>)</span>{</div><div class="line"> getData({<span class="attr">name</span>: d.name}, <span class="function"><span class="keyword">function</span>(<span class="params">json</span>)</span>{</div><div class="line"> <span class="keyword">if</span>(json && json.children){</div><div class="line"> <span class="comment">// 获取到此节点有子节点</span></div><div class="line"> d._children = json.children;</div><div class="line"> d.children = d._children.slice(<span class="number">0</span>, limit);</div><div class="line"> <span class="keyword">if</span>(d._children.length > d.children.length){</div><div class="line"> d.children.push({<span class="string">'name'</span>: <span class="string">'more'</span>});</div><div class="line"> }</div><div class="line"> }</div><div class="line"> d.isExpand = <span class="literal">true</span>;</div><div class="line"> update(d);</div><div class="line"> });</div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">// 异步获取数据</span></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">getData</span>(<span class="params">sd, cb</span>)</span>{</div><div class="line"> d3.json(<span class="string">'data/async_city.json'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">err, json</span>)</span>{</div><div class="line"> cb && cb(json[sd.name]);</div><div class="line"> });</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">click</span>(<span class="params">d</span>)</span>{</div><div class="line"> <span class="keyword">if</span>(d.name == <span class="string">'more'</span>){</div><div class="line"> <span class="comment">// 点击更多</span></div><div class="line"> d.parent.children = d.parent._children.slice(<span class="number">0</span>, (d.parent.children.length - <span class="number">1</span>) + limit);</div><div class="line"> <span class="keyword">if</span>(d.parent._children.length > d.parent.children.length){</div><div class="line"> d.parent.children.push({<span class="string">'name'</span>: <span class="string">'more'</span>});</div><div class="line"> }</div><div class="line"> update(d.parent);</div><div class="line"> }<span class="keyword">else</span> <span class="keyword">if</span>(d.isExpand && d.children){</div><div class="line"> <span class="comment">// 点击展开的节点</span></div><div class="line"> collapse(d);</div><div class="line"> update(d);</div><div class="line"> }<span class="keyword">else</span>{</div><div class="line"> <span class="comment">// 点击未展开的点</span></div><div class="line"> expand(d);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure><blockquote><p>可以从<a href="https://github.com/brucewar/practice-in-D3" target="_blank" rel="external">https://github.com/brucewar/practice-in-D3</a>获取示例代码</p></blockquote>]]></content>
<summary type="html">
<p>&#x56E0;&#x4E3A;&#x6700;&#x8FD1;&#x624B;&#x4E0A;&#x6709;&#x4E2A;&#x5C0F;&#x7684;&#x9700;&#x6C42;&#xFF0C;&#x8BBE;&#x8BA1;&#x4E00;&#x4E2A;&
</summary>
<category term="D3.js" scheme="http://brucewar.cn/categories/D3-js/"/>
<category term="D3" scheme="http://brucewar.cn/tags/D3/"/>
<category term="树状图" scheme="http://brucewar.cn/tags/%E6%A0%91%E7%8A%B6%E5%9B%BE/"/>
</entry>
<entry>
<title>D3.js(完整的柱状图)</title>
<link href="http://brucewar.cn/2016/10/25/D3.js-%E5%AE%8C%E6%95%B4%E7%9A%84%E6%9F%B1%E7%8A%B6%E5%9B%BE/"/>
<id>http://brucewar.cn/2016/10/25/D3.js-完整的柱状图/</id>
<published>2016-10-25T02:59:26.000Z</published>
<updated>2016-10-27T06:18:29.403Z</updated>
<content type="html"><![CDATA[<p>首先,我们先看一下最终的柱状图效果展示。如下图所示,一个完整的柱状图需要包含三个部分:矩形、文字、坐标轴。</p><p><img src="http://brucewar.qiniudn.com/chart.png" alt="柱状图"></p><h3 id="添加SVG画布"><a href="#添加SVG画布" class="headerlink" title="添加SVG画布"></a>添加SVG画布</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 画布大小</span></div><div class="line"><span class="keyword">var</span> width = <span class="number">400</span>,</div><div class="line">height = <span class="number">400</span>;</div><div class="line"></div><div class="line"><span class="comment">// 画布四个方向上的留白</span></div><div class="line"><span class="keyword">var</span> margin = {</div><div class="line"> <span class="attr">top</span>: <span class="number">20</span>,</div><div class="line"> <span class="attr">right</span>: <span class="number">30</span>,</div><div class="line"> <span class="attr">bottom</span>: <span class="number">20</span>,</div><div class="line"> <span class="attr">left</span>: <span class="number">30</span></div><div class="line">};</div><div class="line"></div><div class="line"><span class="keyword">var</span> chart = d3.select(<span class="string">'.chart'</span>)</div><div class="line">.attr(<span class="string">'width'</span>, width)</div><div class="line">.attr(<span class="string">'height'</span>, height)</div><div class="line">.append(<span class="string">'g'</span>);</div></pre></td></tr></table></figure><h3 id="定义比例尺"><a href="#定义比例尺" class="headerlink" title="定义比例尺"></a>定义比例尺</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// define x,y point rule</span></div><div class="line"><span class="keyword">var</span> x = d3.scale.ordinal()</div><div class="line">.rangeRoundBands([<span class="number">0</span>, width - margin.left - margin.right]);</div><div class="line"><span class="keyword">var</span> y = d3.scale.linear()</div><div class="line">.range([height - margin.top - margin.bottom, <span class="number">0</span>]);</div></pre></td></tr></table></figure><h3 id="添加矩形及文字"><a href="#添加矩形及文字" class="headerlink" title="添加矩形及文字"></a>添加矩形及文字</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 矩形之间的空白</span></div><div class="line"><span class="keyword">var</span> barPadding = <span class="number">4</span>;</div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line">* 这里用到了d3异步读取数据的接口csv</div><div class="line">* chart.csv的文件内容如下:</div><div class="line">* name,value</div><div class="line">* Locke,4</div><div class="line">* Reyes,8</div><div class="line">* Ford,15</div><div class="line">* Jarrah,16</div><div class="line">* Shephard,23</div><div class="line">* Kwon,42</div><div class="line">*/</div><div class="line">d3.csv(<span class="string">'data/chart.csv'</span>, type, <span class="function"><span class="keyword">function</span>(<span class="params">err, data</span>)</span>{</div><div class="line"> x.domain(data.map(<span class="function"><span class="keyword">function</span>(<span class="params">d</span>)</span>{ <span class="keyword">return</span> d.name; }));</div><div class="line"> y.domain([<span class="number">0</span>, d3.max(data, <span class="function"><span class="keyword">function</span>(<span class="params">d</span>)</span>{</div><div class="line"> <span class="keyword">return</span> d.value;</div><div class="line"> })]);</div><div class="line"></div><div class="line"> <span class="comment">// append rect</span></div><div class="line"> chart.selectAll(<span class="string">'.bar'</span>)</div><div class="line"> .data(data)</div><div class="line"> .enter().append(<span class="string">'rect'</span>)</div><div class="line"> .attr(<span class="string">'class'</span>, <span class="string">'bar'</span>)</div><div class="line"> .attr(<span class="string">'transform'</span>, <span class="string">'translate('</span> + margin.left + <span class="string">','</span> + margin.top + <span class="string">')'</span>)</div><div class="line"> .attr(<span class="string">'x'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">d</span>)</span>{ <span class="keyword">return</span> x(d.name) + barPadding / <span class="number">2</span>; })</div><div class="line"> .attr(<span class="string">'y'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">d</span>)</span>{ <span class="keyword">return</span> y(d.value); })</div><div class="line"> .attr(<span class="string">'height'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">d</span>)</span>{ <span class="keyword">return</span> height - margin.top - margin.bottom - y(d.value); })</div><div class="line"> .attr(<span class="string">'width'</span>, x.rangeBand() - barPadding);</div><div class="line"></div><div class="line"> <span class="comment">// append text</span></div><div class="line"> chart.selectAll(<span class="string">'.text'</span>)</div><div class="line"> .data(data)</div><div class="line"> .enter()</div><div class="line"> .append(<span class="string">'text'</span>)</div><div class="line"> .attr(<span class="string">'class'</span>, <span class="string">'text'</span>)</div><div class="line"> .attr(<span class="string">'transform'</span>, <span class="string">'translate('</span> + margin.left + <span class="string">','</span> + margin.top + <span class="string">')'</span>)</div><div class="line"> .attr(<span class="string">'x'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">d</span>)</span>{</div><div class="line"> <span class="keyword">return</span> x(d.name) + barPadding / <span class="number">2</span>;</div><div class="line"> }).attr(<span class="string">'y'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">d</span>)</span>{</div><div class="line"> <span class="keyword">return</span> y(d.value);</div><div class="line"> }).attr(<span class="string">'dx'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</div><div class="line"> <span class="keyword">return</span> (x.rangeBand() - barPadding) / <span class="number">2</span>;</div><div class="line"> }).attr(<span class="string">'dy'</span>, <span class="number">20</span>)</div><div class="line"> .text(<span class="function"><span class="keyword">function</span>(<span class="params">d</span>)</span>{</div><div class="line"> <span class="keyword">return</span> d.value;</div><div class="line"> });</div><div class="line">});</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">type</span>(<span class="params">d</span>)</span>{</div><div class="line"> d.value = +d.value;</div><div class="line"> <span class="keyword">return</span> d;</div><div class="line">}</div></pre></td></tr></table></figure><h3 id="定义并添加坐标轴"><a href="#定义并添加坐标轴" class="headerlink" title="定义并添加坐标轴"></a>定义并添加坐标轴</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// define axis</span></div><div class="line"><span class="keyword">var</span> xAxis = d3.svg.axis()</div><div class="line">.scale(x)</div><div class="line">.orient(<span class="string">'bottom'</span>);</div><div class="line"><span class="keyword">var</span> yAxis = d3.svg.axis()</div><div class="line">.scale(y)</div><div class="line">.orient(<span class="string">'left'</span>)</div><div class="line">.ticks(<span class="number">10</span>); <span class="comment">//显示的刻度值个数</span></div><div class="line"></div><div class="line"><span class="comment">// append x axis</span></div><div class="line">chart.append(<span class="string">'g'</span>)</div><div class="line">.attr(<span class="string">'class'</span>, <span class="string">'x axis'</span>)</div><div class="line">.attr(<span class="string">'transform'</span>, <span class="string">'translate('</span> + margin.left + <span class="string">', '</span> + (height - margin.bottom) + <span class="string">')'</span>)</div><div class="line">.call(xAxis);</div><div class="line"></div><div class="line"><span class="comment">// append y axis</span></div><div class="line">chart.append(<span class="string">'g'</span>)</div><div class="line">.attr(<span class="string">'class'</span>, <span class="string">'y axis'</span>)</div><div class="line">.attr(<span class="string">'transform'</span>, <span class="string">'translate('</span> + margin.left + <span class="string">','</span> + margin.top + <span class="string">')'</span>)</div><div class="line">.call(yAxis)</div><div class="line">.append(<span class="string">'text'</span>)</div><div class="line">.attr(<span class="string">'transform'</span>, <span class="string">'rotate(-90)'</span>)</div><div class="line">.attr(<span class="string">'y'</span>, <span class="number">6</span>)</div><div class="line">.attr(<span class="string">'dy'</span>, <span class="string">'.71em'</span>)</div><div class="line">.style(<span class="string">'text-anchor'</span>, <span class="string">'end'</span>)</div><div class="line">.text(<span class="string">'value'</span>);</div></pre></td></tr></table></figure><blockquote><p>可以从<a href="https://github.com/brucewar/practice-in-D3" target="_blank" rel="external">https://github.com/brucewar/practice-in-D3</a>获取示例代码</p></blockquote>]]></content>
<summary type="html">
<p>&#x9996;&#x5148;&#xFF0C;&#x6211;&#x4EEC;&#x5148;&#x770B;&#x4E00;&#x4E0B;&#x6700;&#x7EC8;&#x7684;&#x67F1;&#x72B6;&#x56FE;&#x6548;&#x679C;&
</summary>
<category term="D3.js" scheme="http://brucewar.cn/categories/D3-js/"/>
<category term="D3" scheme="http://brucewar.cn/tags/D3/"/>
<category term="柱状图" scheme="http://brucewar.cn/tags/%E6%9F%B1%E7%8A%B6%E5%9B%BE/"/>
</entry>
<entry>
<title>D3.js(入门篇)</title>
<link href="http://brucewar.cn/2016/10/24/D3.js-%E5%85%A5%E9%97%A8%E7%AF%87/"/>
<id>http://brucewar.cn/2016/10/24/D3.js-入门篇/</id>
<published>2016-10-24T08:26:58.000Z</published>
<updated>2016-10-25T03:00:41.326Z</updated>
<content type="html"><![CDATA[<h4 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h4><p>D3.js(后面简称D3,官方首页<a href="https://d3js.org/" target="_blank" rel="external">https://d3js.org/</a>)是基于JavaScript开发的一套用于数据可视化工具,项目开源在GitHub,项目排名靠前。它提供了很多API,如DOM(<code>Document Object Model</code>)的一些操作,绘制图形等。截止本文发表时间,D3已更新到v4,v4在v3的基础上,有了很大的改变(因为v3只支持通过svg和dom构图,所以v4在v3的基础上增加了对Canvas的支持以及API的修改),本文使用的版本为v3的API。</p><h4 id="Hello-World"><a href="#Hello-World" class="headerlink" title="Hello World"></a>Hello World</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="meta"><!DOCTYPE html></span></div><div class="line"><span class="tag"><<span class="name">html</span>></span></div><div class="line"> <span class="tag"><<span class="name">head</span>></span></div><div class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"utf-8"</span>></span></div><div class="line"> <span class="tag"><<span class="name">title</span>></span>D3.js Hello World<span class="tag"></<span class="name">title</span>></span></div><div class="line"> <span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://d3js.org/d3.v3.min.js"</span>></span><span class="undefined"></span><span class="tag"></<span class="name">script</span>></span></div><div class="line"> <span class="tag"></<span class="name">head</span>></span></div><div class="line"> <span class="tag"><<span class="name">body</span>></span></div><div class="line"> <span class="tag"><<span class="name">p</span>></span>first text<span class="tag"></<span class="name">p</span>></span></div><div class="line"> <span class="tag"><<span class="name">p</span>></span>second text<span class="tag"></<span class="name">p</span>></span></div><div class="line"> <span class="tag"><<span class="name">p</span>></span>third text<span class="tag"></<span class="name">p</span>></span></div><div class="line"> <span class="tag"><<span class="name">script</span>></span><span class="undefined"></span></div><div class="line"> var p = d3.select('body').selectAll('p')</div><div class="line"> .attr('color', 'red')</div><div class="line"> .attr('font-size', '72px')</div><div class="line"> .text('brucewar');</div><div class="line"> <span class="tag"></<span class="name">script</span>></span></div><div class="line"> <span class="tag"></<span class="name">body</span>></span></div><div class="line"><span class="tag"></<span class="name">html</span>></span></div></pre></td></tr></table></figure><p>上面代码展示了基本的DOM操作,有过jQuery开发经历的人会发现其语法和jQuery很相似,主要是以下两点:</p><ul><li>支持元素选择器</li><li>链式语法结构</li></ul><h5 id="插入元素"><a href="#插入元素" class="headerlink" title="插入元素"></a>插入元素</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 末尾插入p元素</span></div><div class="line">d3.select(<span class="string">'body'</span>).append(<span class="string">'p'</span>).text(<span class="string">'append new prograph'</span>);</div><div class="line"><span class="comment">// 在第一个p元素之前插入p</span></div><div class="line">d3.select(<span class="string">'p'</span>).insert(<span class="string">'p'</span>).text(<span class="string">'insert new prograph'</span>);</div></pre></td></tr></table></figure><h5 id="删除元素"><a href="#删除元素" class="headerlink" title="删除元素"></a>删除元素</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">d3.select(<span class="string">'p'</span>).remove();</div></pre></td></tr></table></figure><h4 id="数据绑定"><a href="#数据绑定" class="headerlink" title="数据绑定"></a>数据绑定</h4><p>在D3中,选择器通常和数据绑定一起使用,这里的<strong>数据绑定</strong>的意思是将DOM元素与数据进行绑定,当需要依靠数据操作元素会非常方便。<br></p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> arr = [<span class="string">'a'</span>, <span class="string">'b'</span>, <span class="string">'c'</span>];</div><div class="line">p.data(arr).text(<span class="function"><span class="keyword">function</span>(<span class="params">d, i</span>)</span>{</div><div class="line"> <span class="comment">// d: 数据 i: 元素索引</span></div><div class="line"> <span class="keyword">return</span> d;</div><div class="line">});</div></pre></td></tr></table></figure><p></p><h4 id="绘制简单的横向柱状图"><a href="#绘制简单的横向柱状图" class="headerlink" title="绘制简单的横向柱状图"></a>绘制简单的横向柱状图</h4><ol><li><p>添加svg画布</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> width = <span class="number">300</span>;</div><div class="line"><span class="keyword">var</span> height = <span class="number">300</span>;</div><div class="line"></div><div class="line"><span class="keyword">var</span> svg = d3.select(<span class="string">'body'</span>)</div><div class="line">.append(<span class="string">'svg'</span>)</div><div class="line">.attr(<span class="string">'width'</span>. width)</div><div class="line">.attr(<span class="string">'height'</span>, height);</div></pre></td></tr></table></figure></li><li><p>绘制矩形</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> data = [<span class="number">250</span>, <span class="number">210</span>, <span class="number">170</span>, <span class="number">130</span>, <span class="number">90</span>]; <span class="comment">// 表示矩形的宽度</span></div><div class="line"><span class="keyword">var</span> rectHeight = <span class="number">25</span>;</div><div class="line"></div><div class="line">svg.selectAll(<span class="string">'rect'</span>)</div><div class="line">.data(data)</div><div class="line">.enter() <span class="comment">// 当元素个数不足数据个数时,自动补全</span></div><div class="line">.append(<span class="string">'rect'</span>)</div><div class="line">.attr(<span class="string">'x'</span>, <span class="number">20</span>)</div><div class="line">.attr(<span class="string">'y'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">d, i</span>)</span>{</div><div class="line"> <span class="keyword">return</span> i * rectHeight;</div><div class="line">})</div><div class="line">.attr(<span class="string">'width'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">d</span>)</span>{</div><div class="line"> <span class="keyword">return</span> d;</div><div class="line">})</div><div class="line">.attr(<span class="string">'height'</span>, rectHeight - <span class="number">2</span>)</div><div class="line">.attr(<span class="string">'fill'</span>, <span class="string">'steelblue'</span>);</div></pre></td></tr></table></figure><p>从上面的代码可以看出当<code>data</code>中的数据大于画布的宽度时,绘制的矩形会超出画布,所以需要引入<em>比例尺</em>(Scale)的概念。比例尺的概念类似数学中的一元二次函数,有x和y两个未知数,当x的值确定时,y的值也就确定了,x范围被称为定义域,y的范围为值域,对应于D3比例尺中的domain和range。D3为我们提供了很多比例尺,这里主要讲这里柱状图所要使用的线性比例尺。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> min = d3.min(data);</div><div class="line"><span class="keyword">var</span> max = d3.max(data);</div><div class="line"></div><div class="line"><span class="keyword">var</span> linear = d3.scale.linear()</div><div class="line">.domain([min, max])</div><div class="line">.range([<span class="number">0</span>, <span class="number">300</span>]);</div></pre></td></tr></table></figure></li><li><p>绘制坐标轴</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//数据</span></div><div class="line"><span class="keyword">var</span> dataset = [ <span class="number">2.5</span> , <span class="number">2.1</span> , <span class="number">1.7</span> , <span class="number">1.3</span> , <span class="number">0.9</span> ];</div><div class="line"><span class="comment">//定义比例尺</span></div><div class="line"><span class="keyword">var</span> linear = d3.scale.linear()</div><div class="line"> .domain([<span class="number">0</span>, d3.max(dataset)])</div><div class="line"> .range([<span class="number">0</span>, <span class="number">250</span>]);</div><div class="line"></div><div class="line"><span class="keyword">var</span> axisX = d3.svg.axis()</div><div class="line"> .scale(linear) <span class="comment">//指定比例尺</span></div><div class="line"> .orient(<span class="string">"bottom"</span>) <span class="comment">//指定刻度的方向</span></div><div class="line"> .ticks(<span class="number">7</span>); <span class="comment">//指定刻度的数量</span></div></pre></td></tr></table></figure><p>定义了坐标轴之后,只要在svg中添加一个分组元素,再将坐标轴的其他元素添加到分组即可。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">svg.append(<span class="string">'g'</span>)</div><div class="line">.attr(<span class="string">'class'</span>, <span class="string">'axis'</span>)</div><div class="line">.attr(<span class="string">'transform'</span>, <span class="string">'translate(20, 130)'</span>)</div><div class="line">.call(axisX);</div></pre></td></tr></table></figure><figure class="highlight css"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/** 修改坐标轴样式 */</span></div><div class="line"><span class="selector-class">.axis</span> <span class="selector-tag">path</span>,</div><div class="line"><span class="selector-class">.axis</span> <span class="selector-tag">line</span>{</div><div class="line"> <span class="attribute">fill</span>: none;</div><div class="line"> <span class="attribute">stroke</span>: black;</div><div class="line"> <span class="attribute">shape-rendering</span>: crispEdges;</div><div class="line">}</div><div class="line"><span class="selector-class">.axis</span> <span class="selector-tag">text</span>{</div><div class="line"> <span class="attribute">font-family</span>: sans-serif;</div><div class="line"> <span class="attribute">font-size</span>: <span class="number">11px</span>;</div><div class="line">}</div></pre></td></tr></table></figure></li></ol>]]></content>
<summary type="html">
<h4 id="&#x7B80;&#x4ECB;"><a href="#&#x7B80;&#x4ECB;" class="headerlink" title="&#x7B80;&#x4ECB;"></a>&#x7B80;&#x4ECB;</h4><p>D3.js&#xFF08;&
</summary>
<category term="D3.js" scheme="http://brucewar.cn/categories/D3-js/"/>
<category term="D3" scheme="http://brucewar.cn/tags/D3/"/>
<category term="JavaScript" scheme="http://brucewar.cn/tags/JavaScript/"/>
</entry>
<entry>
<title>答利器上的六个问题</title>
<link href="http://brucewar.cn/2016/09/29/%E7%AD%94%E5%88%A9%E5%99%A8%E4%B8%8A%E7%9A%84%E5%85%AD%E4%B8%AA%E9%97%AE%E9%A2%98/"/>
<id>http://brucewar.cn/2016/09/29/答利器上的六个问题/</id>
<published>2016-09-29T08:18:27.000Z</published>
<updated>2016-11-29T07:41:31.087Z</updated>
<content type="html"><![CDATA[<p><img src="http://7pumxs.com1.z0.glb.clouddn.com/IMG_1186.JPG" alt="brucewar"></p><h3 id="介绍一下你自己和所做的工作"><a href="#介绍一下你自己和所做的工作" class="headerlink" title="介绍一下你自己和所做的工作"></a>介绍一下你自己和所做的工作</h3><p>我叫王金龙,是一名初级(按照工作年限来说的话)Web前端开发,但是以开发经历来说,我至少应该算一名合格的前端攻城狮。目前在途牛旅游网工作(已经寻找到新的追求)。读书的时候,接触的东西比较少,心里所想唯有学习,所以也就没培养任何一样兴趣,偶尔会和同学一起踢踢球;工作的时候,才逐渐培养了一些兴趣爱好,如跳舞、唱歌等,跳舞是今年才培养起来的一个兴趣,但是因为工作的关系,基本没什么时间练舞,所以跳的非常非常一般。15年研究生毕业后,工作也有一年半了,而且公司是业务驱动开发,所以代码也写了不少,可是自身能力的提升却没看出来。</p><h3 id="你都在使用哪些硬件"><a href="#你都在使用哪些硬件" class="headerlink" title="你都在使用哪些硬件"></a>你都在使用哪些硬件</h3><p><img src="http://7pumxs.com1.z0.glb.clouddn.com/keycool.jpg" alt="keycool红轴"></p><p>这款机械键盘是工作没多久之后买的。话说,当时看到同组的一位老程序员(简称斌哥,后来他们组从我们部门分出去啦)用的机械键盘,黑色键帽配上彩虹键帽,觉得很好看,所以一时冲动想买一把机械键盘。</p><blockquote><p>做什么事都要过一下脑子</p></blockquote><p>上面这句话,印象很深刻,因为我对机械键盘的知识一片空白,所以必须通过各方面的了解,首先从百度百科词条<a href="http://baike.baidu.com/link?url=sKWDdw44eHxUdTb40AbNYLSzOgKJx7xB-FN4uucHCr_FvNreuWYWlgjwDCULDpM4hje9YDkS_8jZwazXiRJl3O-nJ1AaP_pZDoFOw_X4uBOVoSoHaFHOI5pV2SWOq7hn" target="_blank" rel="external">机械键盘</a>学习了基本的知识,然后去问答网站(知乎)关注了话题<em>机械键盘</em>,发现此话题下,有很多问题是“程序员男朋友生日,想送机械键盘,有推荐的吗?”。额!!!被各种虐,心想为啥没有妹子送我。不过,还是有很多人推荐了不错的机械键盘。个人感觉很喜欢<strong>Filco圣手二代</strong>,但是迫于经济能力有限,最终还是买了一把国产的红轴,用起来真的很舒服(PS:好多同事试玩后都觉得不错)。</p><p><img src="http://7pumxs.com1.z0.glb.clouddn.com/akg.jpg" alt="AKG K450"></p><blockquote><p>舞蹈配上音乐之后,才有了灵魂</p></blockquote><p>如果一个舞者在没有背景乐的环境下舞动自己的身体,非专业观者可能会觉得看不懂,专业的人也只能从专业技巧上加以评价。有了音乐后,舞者会随着音乐的轻重缓急表达自己的情绪,这才有了舞魂。<br>程序员写代码时的手指就如同这舞者,在键盘这个舞台上表演,配合音乐的节奏,程序便有了它的灵魂(PS:我写程序时听的歌单<a href="http://music.163.com/#/m/playlist?id=159311553&userid=85782250" target="_blank" rel="external">dance</a>)。AKG的这个经典款的耳机是<strong>昊哥</strong>推荐的,性价比非常高(非广告)。</p><p><img src="http://7pumxs.com1.z0.glb.clouddn.com/samsung.jpg" alt="三星S24D360HL"></p><p>显示器没什么可以说的,做为Web前端开发,两个显示器是必备的,一个放IDE,一个放浏览器,对于开发效率有非常大的提升。</p><h3 id="软件呢"><a href="#软件呢" class="headerlink" title="软件呢"></a>软件呢</h3><p>作为Linux的拥护者,必须向大家推荐Vim编辑器,我觉得它能让你脱离不必要的鼠标操作,大大提高工作效率,很惭愧,Vim新手阶段,用的不是很熟,只了解一些简单的编辑命令。顺带安利一款Chrome插件<a href="https://chrome.google.com/webstore/detail/vimium/dbepggeogbaibhgnhhndojpepiihcmeb" target="_blank" rel="external">Vimium</a>(用Vim命令操作浏览器环境)。</p><h3 id="你最理想的工作环境是什么"><a href="#你最理想的工作环境是什么" class="headerlink" title="你最理想的工作环境是什么"></a>你最理想的工作环境是什么</h3><p>大桌子(圆弧型),两台显示器,一台笔记本,网络一定要好(自带翻墙,Youtube 1080P不卡顿),绿植围绕,周围坐着谦虚耐心的牛人,大家一起干着一件有意义(改变世界,哈哈,这个太大)的事。</p><h3 id="你平时获得工作灵感的方式有哪些"><a href="#你平时获得工作灵感的方式有哪些" class="headerlink" title="你平时获得工作灵感的方式有哪些"></a>你平时获得工作灵感的方式有哪些</h3><p>逛各种网站,知乎,简书等;玩各种流行的APP,微信,Instagram等,任何一个好的产品,自有它的独特的一面,我觉得作为前端开发,也需要有一些设计的想法,我开发过的项目中都曾借鉴过这些应用。</p><h3 id="推荐一件生活中的利器给大家"><a href="#推荐一件生活中的利器给大家" class="headerlink" title="推荐一件生活中的利器给大家"></a>推荐一件生活中的利器给大家</h3><p>VPN,强烈推荐我用的这款,但是这里不方便贴链接,有需要的私信我。</p>]]></content>
<summary type="html">
<p><img src="http://7pumxs.com1.z0.glb.clouddn.com/IMG_1186.JPG" alt="brucewar"></p><h3 id="&#x4ECB;&#x7ECD;&#x4E00;&#x4E0B;&#x4F60;&#x81EA;
</summary>
<category term="随笔" scheme="http://brucewar.cn/categories/%E9%9A%8F%E7%AC%94/"/>
<category term="利器" scheme="http://brucewar.cn/tags/%E5%88%A9%E5%99%A8/"/>
</entry>
</feed>