-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathatom.xml
More file actions
492 lines (290 loc) · 212 KB
/
atom.xml
File metadata and controls
492 lines (290 loc) · 212 KB
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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>gbb</title>
<link href="/atom.xml" rel="self"/>
<link href="http://yoursite.com/"/>
<updated>2021-03-19T08:15:40.951Z</updated>
<id>http://yoursite.com/</id>
<author>
<name>gbb</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>EGG 安全问题</title>
<link href="http://yoursite.com/passages/20201018EGG%E5%AE%89%E5%85%A8%E9%97%AE%E9%A2%98/"/>
<id>http://yoursite.com/passages/20201018EGG安全问题/</id>
<published>2020-10-18T04:00:00.000Z</published>
<updated>2021-03-19T08:15:40.951Z</updated>
<content type="html"><![CDATA[<p><code>EGG</code> 安全问题配置</p><span id="more"></span><h2 id="Egg-https-配置"><a href="#Egg-https-配置" class="headerlink" title="Egg https 配置"></a>Egg https 配置</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">config.<span class="property">cluster</span> = {</span><br><span class="line"> <span class="attr">listen</span>: {</span><br><span class="line"> <span class="attr">path</span>: <span class="string">""</span>,</span><br><span class="line"> <span class="attr">port</span>: <span class="number">443</span></span><br><span class="line"> },</span><br><span class="line"> <span class="attr">https</span>: {</span><br><span class="line"> <span class="attr">key</span>: key,</span><br><span class="line"> <span class="attr">cert</span>: cert,</span><br><span class="line"> <span class="attr">ciphers</span>: <span class="string">'ECDHE-RSA-AES128-GCM-SHA256'</span> <span class="comment">//此参数并不支持,需要修改源码lib包</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><code>node-modules/egg-cluster/lib/app_worker.js</code></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (httpsOptions.<span class="property">ciphers</span>) {</span><br><span class="line"> httpsOptions.<span class="property">ciphers</span> = httpsOptions.<span class="property">ciphers</span>;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="Egg-安全配置"><a href="#Egg-安全配置" class="headerlink" title="Egg 安全配置"></a>Egg 安全配置</h2><p><code>node-modules/egg-cluster/lib/app_worker.js</code></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// SSL/TLS存在重协商漏洞</span></span><br><span class="line"><span class="keyword">var</span> tls = <span class="built_in">require</span>(<span class="string">'tls'</span>);</span><br><span class="line"></span><br><span class="line">tls.<span class="property">CLIENT_RENEG_LIMIT</span> = <span class="number">0</span>;</span><br><span class="line">tls.<span class="property">CLIENT_RENEG_WINDOW</span> = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// HTTPS慢速拒绝服务漏洞</span></span><br><span class="line">server.<span class="property">headersTimeout</span> = <span class="number">9</span> * <span class="number">1000</span>;</span><br><span class="line">server.<span class="property">maxHeadersCount</span> = <span class="number">2000</span>;</span><br></pre></td></tr></table></figure><p><code>静态资源添加响应头</code></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// app/route.js</span></span><br><span class="line"><span class="keyword">const</span> initStatic = app.<span class="property">config</span>.<span class="property">coreMiddleware</span>.<span class="title function_">indexOf</span>(<span class="string">'static'</span>);</span><br><span class="line"><span class="keyword">const</span> uedStatic = app.<span class="property">middleware</span>.<span class="title function_">uedStatic</span>();</span><br><span class="line">app.<span class="property">middleware</span>.<span class="title function_">splice</span>(initStatic, <span class="number">0</span>, uedStatic);</span><br><span class="line"></span><br><span class="line"><span class="comment">// middleware/ued_static.js</span></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = <span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">uedStatic</span>(<span class="params">ctx, next</span>) {</span><br><span class="line"> <span class="keyword">if</span> (ctx.<span class="property">request</span>.<span class="property">url</span>.<span class="title function_">indexOf</span>(<span class="string">"/js/"</span>) || ctx.<span class="property">request</span>.<span class="property">url</span>.<span class="title function_">indexOf</span>(<span class="string">"/css/"</span> || ctx.<span class="property">request</span>.<span class="property">url</span>.<span class="title function_">indexOf</span>(<span class="string">"/img/"</span>))) {</span><br><span class="line"> ctx.<span class="property">response</span>.<span class="title function_">set</span>({</span><br><span class="line"> <span class="string">"响应头key"</span>: <span class="string">"响应头Value"</span></span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">await</span> <span class="title function_">next</span>();</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://github.com/eggjs/egg/issues/3523">EGG router static 捕获</a></li></ul>]]></content>
<summary type="html">
<p><code>EGG</code> 安全问题配置</p>
</summary>
<category term="EGG" scheme="http://yoursite.com/categories/EGG/"/>
<category term="EGG" scheme="http://yoursite.com/tags/EGG/"/>
<category term="HTTPS" scheme="http://yoursite.com/tags/HTTPS/"/>
<category term="安全问题" scheme="http://yoursite.com/tags/%E5%AE%89%E5%85%A8%E9%97%AE%E9%A2%98/"/>
</entry>
<entry>
<title>HTTPS 证书管理</title>
<link href="http://yoursite.com/passages/20200823%E8%AF%81%E4%B9%A6%E7%AE%A1%E7%90%86/"/>
<id>http://yoursite.com/passages/20200823证书管理/</id>
<published>2020-08-23T04:00:00.000Z</published>
<updated>2021-03-17T08:32:45.755Z</updated>
<content type="html"><![CDATA[<p><code>HTTPS</code> 证书管理,自签名证书的生成,证书信息的获取,证书的上传验证,删除等</p><span id="more"></span><h2 id="自签名证书生成"><a href="#自签名证书生成" class="headerlink" title="自签名证书生成"></a>自签名证书生成</h2><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout self.key -out self.crt -subj /CN=*.abc.com</span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用sha256算法</span></span><br><span class="line">-sha256</span><br><span class="line"><span class="comment"># 默认情况下,openssl req自动创建私钥时都要求加密并提示输入加密密码,指定该选项后则禁止对私钥文件加密</span></span><br><span class="line">-nodes</span><br><span class="line"><span class="comment"># 证书有效期365天</span></span><br><span class="line">-days 365</span><br><span class="line"><span class="comment"># 2048位密钥</span></span><br><span class="line">rsa:2048</span><br><span class="line"><span class="comment"># :密钥文件,自己命名</span></span><br><span class="line">self.key</span><br><span class="line"><span class="comment"># iphone、mac等使用的证书文件</span></span><br><span class="line">self.crt</span><br><span class="line"><span class="comment"># 使用abc.com域名的通配方式作为使用者</span></span><br><span class="line">-subj /CN=*.abc.com</span><br><span class="line"></span><br><span class="line"><span class="comment"># 生成windows使用的证书文件pfx, 执行后,会提示输入证书密码</span></span><br><span class="line">openssl pkcs12 -<span class="built_in">export</span> -out self.pfx -inkey self.key -<span class="keyword">in</span> self.crt</span><br></pre></td></tr></table></figure><h2 id="证书信息的获取"><a href="#证书信息的获取" class="headerlink" title="证书信息的获取"></a>证书信息的获取</h2><p>注意:本例初始化的证书存储位置与上传证书位置不一致,上传的证书只保留最新的一份。<br>每次服务启动时读取上传路径的,没有,则读取使用初始化的。<br>获取证书信息同理。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> fs = <span class="built_in">require</span>(<span class="string">'fs'</span>);</span><br><span class="line"><span class="keyword">const</span> childProcess = <span class="built_in">require</span>(<span class="string">'child_process'</span>);</span><br><span class="line"><span class="keyword">const</span> path = <span class="built_in">require</span>(<span class="string">'path'</span>);</span><br><span class="line"><span class="keyword">const</span> uploadDir = <span class="string">"上传路径"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> pem;</span><br><span class="line"><span class="keyword">if</span> (fs.<span class="title function_">existsSync</span>(path.<span class="title function_">join</span>(uploadDir, <span class="string">'cert.pem'</span>))) {</span><br><span class="line"> pem = path.<span class="title function_">join</span>(uploadDir, <span class="string">'cert.pem'</span>);</span><br><span class="line">} <span class="keyword">else</span> {</span><br><span class="line"> pem = <span class="string">'cert.pem'</span>; <span class="comment">//初始</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> cmdStr = <span class="string">`openssl x509 -in <span class="subst">${pem}</span> -noout -serial &&</span></span><br><span class="line"><span class="string"> opensll x509 -in <span class="subst">${pem}</span> -noout -subject && </span></span><br><span class="line"><span class="string"> opensll x509 -in <span class="subst">${pem}</span> -noout -issuer &&</span></span><br><span class="line"><span class="string"> opensll x509 -in <span class="subst">${pem}</span> -noout -startdate &&</span></span><br><span class="line"><span class="string"> opensll x509 -in <span class="subst">${pem}</span> -noout -enddate`</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">let</span> stdoutArray = childProcess.<span class="title function_">execSync</span>(cmdStr).<span class="title function_">toString</span>().<span class="title function_">split</span>(<span class="string">'\n'</span>);</span><br><span class="line"> <span class="keyword">let</span> data = {</span><br><span class="line"> <span class="attr">serial</span>: stdoutArray[<span class="number">0</span>].<span class="title function_">replace</span>(<span class="string">'serial='</span>, <span class="string">""</span>), <span class="comment">//序列号</span></span><br><span class="line"> <span class="attr">subject</span>: stdoutArray[<span class="number">1</span>].<span class="title function_">replace</span>(<span class="string">'subject='</span>, <span class="string">""</span>), <span class="comment">//颁发给</span></span><br><span class="line"> <span class="attr">issuer</span>: stdoutArray[<span class="number">2</span>].<span class="title function_">replace</span>(<span class="string">'issuer='</span>, <span class="string">""</span>), <span class="comment">//颁发者</span></span><br><span class="line"> <span class="attr">notBefore</span>: stdoutArray[<span class="number">3</span>].<span class="title function_">replace</span>(<span class="string">'notBefore='</span>, <span class="string">""</span>), <span class="comment">//开始时间</span></span><br><span class="line"> <span class="attr">notAfter</span>: stdoutArray[<span class="number">4</span>].<span class="title function_">replace</span>(<span class="string">'notAfter='</span>, <span class="string">""</span>), <span class="comment">//失效时间</span></span><br><span class="line"> }</span><br><span class="line">} <span class="keyword">catch</span>(err) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(err);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="证书的验证及上传存储"><a href="#证书的验证及上传存储" class="headerlink" title="证书的验证及上传存储"></a>证书的验证及上传存储</h2><p>本例前端使用表单提交,后端 Nodejs 接收。</p><p>前端使用 <code>Element UI</code> 的文件上传组件, 后端利用 eggjs 的 <code>egg-multipart</code> 插件,需要先配置扩展,支持对应格式 <code>pfx</code></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="title function_">upload</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">const</span> uploadDir = <span class="string">"上传路径"</span></span><br><span class="line"> <span class="keyword">const</span> stream = <span class="keyword">await</span> ctx.<span class="title function_">getFileStream</span>();</span><br><span class="line"> <span class="keyword">if</span> (!fs.<span class="title function_">existsSync</span>(uploadDir)) {</span><br><span class="line"> fs.<span class="title function_">mkdirSync</span>(uploadDir)</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">const</span> target = path.<span class="title function_">join</span>(uploadDir, <span class="string">"temp.pfx"</span>);</span><br><span class="line"> <span class="keyword">const</span> writeStream = fs.<span class="title function_">createWriteStream</span>(target);</span><br><span class="line"> stream.<span class="title function_">pipe</span>(writeStream);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> password = stream.<span class="property">fields</span>.<span class="property">password</span>; <span class="comment">//form 参数 by `stream.fields`</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> pfx = path.<span class="title function_">join</span>(uploadDir, <span class="string">'temp.pfx'</span>);</span><br><span class="line"> <span class="keyword">let</span> pem = path.<span class="title function_">join</span>(uploadDir, <span class="string">'temp.pem'</span>);</span><br><span class="line"> <span class="keyword">let</span> key = path.<span class="title function_">join</span>(uploadDir, <span class="string">'temp-key.pem'</span>);</span><br><span class="line"> <span class="keyword">let</span> cert = path.<span class="title function_">join</span>(uploadDir, <span class="string">'temp-cert.pem'</span>);</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// pfx && password 解析出 pem</span></span><br><span class="line"> <span class="comment">// 验证-可能存在 verify 验证证书报错</span></span><br><span class="line"> <span class="comment">// 转为 key && cert</span></span><br><span class="line"> <span class="keyword">let</span> cmdStr = <span class="string">`openssl pkcs12 -in <span class="subst">${pfx}</span> -nodes -out <span class="subst">${pem}</span> -password pass:<span class="subst">${password}</span> &&</span></span><br><span class="line"><span class="string"> openssl verify <span class="subst">${pem}</span> && </span></span><br><span class="line"><span class="string"> openssl rsa -in <span class="subst">${pem}</span> -out <span class="subst">${key}</span> &&</span></span><br><span class="line"><span class="string"> openssl x509 -in <span class="subst">${pem}</span> -out <span class="subst">${cert}</span>`</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> execPromise = <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =></span> {</span><br><span class="line"> childProcess.<span class="title function_">exec</span>(cmdStr, <span class="keyword">function</span>(<span class="params">error, stdout, stderr</span>) {</span><br><span class="line"> <span class="keyword">if</span> (error) {</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">resolve</span>({</span><br><span class="line"> <span class="attr">code</span>: <span class="number">1</span>,</span><br><span class="line"> <span class="attr">msg</span>: <span class="string">"Wrong certificate or password"</span></span><br><span class="line"> })</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">if</span> (stdout.<span class="title function_">indexof</span>(<span class="string">'certificate has expired'</span>) > -<span class="number">1</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">resolve</span>({</span><br><span class="line"> <span class="attr">code</span>: <span class="number">2</span>,</span><br><span class="line"> <span class="attr">data</span>: <span class="string">"expired"</span>,</span><br><span class="line"> <span class="attr">msg</span>: stdout</span><br><span class="line"> })</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">resolve</span>({</span><br><span class="line"> <span class="attr">code</span>: <span class="number">0</span>,</span><br><span class="line"> <span class="attr">msg</span>: stdout</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> })</span><br><span class="line"> <span class="keyword">let</span> data = <span class="keyword">await</span> execPromise;</span><br><span class="line"> ctx.<span class="property">body</span> = data;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="证书上传后重启服务"><a href="#证书上传后重启服务" class="headerlink" title="证书上传后重启服务"></a>证书上传后重启服务</h2><p>证书上传后,将原来上传证书删除,然后新上传的重命名,保证服务重启后读取的证书为刚刚上传的。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="title function_">restart</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="comment">// 之前上传的先删除,然后把刚上传的重命名</span></span><br><span class="line"> <span class="keyword">let</span> key = path.<span class="title function_">join</span>(uploadDir, <span class="string">'key.pem'</span>);</span><br><span class="line"> <span class="keyword">let</span> cert = path.<span class="title function_">join</span>(uploadDir, <span class="string">'cert.pem'</span>);</span><br><span class="line"> <span class="keyword">if</span> (fs.<span class="title function_">existsSync</span>(key)) {</span><br><span class="line"> fs.<span class="title function_">unlinkSync</span>(key);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (fs.<span class="title function_">existsSync</span>(cert)) {</span><br><span class="line"> fs.<span class="title function_">unlinkSync</span>(cert);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// 上步生成的</span></span><br><span class="line"> <span class="keyword">let</span> tempKey = path.<span class="title function_">join</span>(uploadDir, <span class="string">'temp-key.pem'</span>);</span><br><span class="line"> <span class="keyword">let</span> tempCert = path.<span class="title function_">join</span>(uploadDir, <span class="string">'temp-cert.pem'</span>);</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> fs.<span class="title function_">renameSync</span>(tempKey, key),</span><br><span class="line"> fs.<span class="title function_">renameSync</span>(tempCert, cert);</span><br><span class="line"> } <span class="keyword">catch</span> (e) {</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> cmdStr = <span class="string">`restart node`</span> <span class="comment">//重启服务命令</span></span><br><span class="line"> childProcess.<span class="title function_">exec</span>(<span class="params">cmdStr, <span class="keyword">function</span>(error, stdout, stderr)</span>) {</span><br><span class="line"> <span class="keyword">if</span>(error) {</span><br><span class="line"> ctx.<span class="property">logger</span>.<span class="title function_">error</span>(error)</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 服务重启,无法回调,直接返回</span></span><br><span class="line"> ctx.<span class="property">body</span> = {</span><br><span class="line"> <span class="attr">code</span>: <span class="number">0</span>,</span><br><span class="line"> <span class="attr">msg</span>: <span class="string">""</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="证书文件的删除"><a href="#证书文件的删除" class="headerlink" title="证书文件的删除"></a>证书文件的删除</h2><p>用于上传后提示过期,选择不应用。或者上传后直接取消应用的场景</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="title function_">delete</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">let</span> pfx = path.<span class="title function_">join</span>(uploadDir, <span class="string">'temp.pfx'</span>); </span><br><span class="line"> <span class="keyword">let</span> pem = path.<span class="title function_">join</span>(uploadDir, <span class="string">'temp.pem'</span>); </span><br><span class="line"> <span class="keyword">let</span> key = path.<span class="title function_">join</span>(uploadDir, <span class="string">'temp-key.pem'</span>); </span><br><span class="line"> <span class="keyword">let</span> cert = path.<span class="title function_">join</span>(uploadDir, <span class="string">'temp-cert.pem'</span>); </span><br><span class="line"> <span class="keyword">if</span> (fs.<span class="title function_">existsSync</span>(pfx)) {</span><br><span class="line"> fs.<span class="title function_">unlinkSync</span>(pfx);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (fs.<span class="title function_">existsSync</span>(pem)) {</span><br><span class="line"> fs.<span class="title function_">unlinkSync</span>(pem);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (fs.<span class="title function_">existsSync</span>(key)) {</span><br><span class="line"> fs.<span class="title function_">unlinkSync</span>(key);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (fs.<span class="title function_">existsSync</span>(cert)) {</span><br><span class="line"> fs.<span class="title function_">unlinkSync</span>(cert);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ctx.<span class="property">body</span> = {</span><br><span class="line"> <span class="attr">code</span>: <span class="number">0</span>,</span><br><span class="line"> <span class="attr">msg</span>: <span class="string">""</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="Egg-https-配置"><a href="#Egg-https-配置" class="headerlink" title="Egg https 配置"></a>Egg https 配置</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">config.<span class="property">cluster</span> = {</span><br><span class="line"> <span class="attr">listen</span>: {</span><br><span class="line"> <span class="attr">path</span>: <span class="string">""</span>,</span><br><span class="line"> <span class="attr">port</span>: <span class="number">443</span></span><br><span class="line"> },</span><br><span class="line"> <span class="attr">https</span>: {</span><br><span class="line"> <span class="attr">key</span>: key,</span><br><span class="line"> <span class="attr">cert</span>: cert,</span><br><span class="line"> <span class="attr">ciphers</span>: <span class="string">'ECDHE-RSA-AES128-GCM-SHA256'</span> <span class="comment">//此参数并不支持,需要修改源码lib包</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><code>node-modules/egg-cluster/lib/app_worker.js</code></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (httpsOptions.<span class="property">ciphers</span>) {</span><br><span class="line"> httpsOptions.<span class="property">ciphers</span> = httpsOptions.<span class="property">ciphers</span>;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://www.openssl.org/">OpenSSL 官网</a></li><li><a href="http://nodejs.cn/api/https.html">Nodejs HTTPS</a></li><li><a href="http://nodejs.cn/api/tls.html">Nodejs TLS</a></li><li><a href="http://nodejs.cn/api/child_process.html">Nodejs child_process</a></li><li><a href="http://nodejs.cn/api/fs.html">Nodejs fs</a></li><li><a href="https://blog.csdn.net/wuwo333/article/details/53020403">OpenSSL 生成自签名证书</a></li><li><a href="https://www.cnblogs.com/shenlinken/p/9968274.html">OpenSSL 查看证书细节</a></li><li><a href="https://www.cnblogs.com/aixiaoxiaoyu/p/8650180.html">OpenSSL 命令目录</a></li><li><a href="https://blog.csdn.net/as3luyuan123/article/details/16872101">OpenSSL verify</a></li><li><a href="https://blog.csdn.net/u010358168/article/details/83508851">OpenSSL 证书格式转换</a></li><li><a href="https://wiki.jikexueyuan.com/project/nodejs/tls.html">TLS/SSL</a></li><li><a href="https://www.ctolib.com/docs-nodejs-learn-c-a18q1iu5.html#tls_class_tls_tlssocket">TLS/SSL</a></li></ul>]]></content>
<summary type="html">
<p><code>HTTPS</code> 证书管理,自签名证书的生成,证书信息的获取,证书的上传验证,删除等</p>
</summary>
<category term="工程部署" scheme="http://yoursite.com/categories/%E5%B7%A5%E7%A8%8B%E9%83%A8%E7%BD%B2/"/>
<category term="证书管理" scheme="http://yoursite.com/tags/%E8%AF%81%E4%B9%A6%E7%AE%A1%E7%90%86/"/>
<category term="HTTPS" scheme="http://yoursite.com/tags/HTTPS/"/>
</entry>
<entry>
<title>JavaScript 屏幕可视元素</title>
<link href="http://yoursite.com/passages/20200814%E5%B1%8F%E5%B9%95%E5%8F%AF%E8%A7%86%E5%85%83%E7%B4%A0/"/>
<id>http://yoursite.com/passages/20200814屏幕可视元素/</id>
<published>2020-08-15T04:00:00.000Z</published>
<updated>2020-08-14T08:00:46.017Z</updated>
<content type="html"><![CDATA[<p><code>JavaScript</code> 屏幕可视</p><span id="more"></span><h2 id="需求描述"><a href="#需求描述" class="headerlink" title="需求描述"></a>需求描述</h2><p>日常开发中, 遇到元素特别多的页面, 例如全是图表的页面,如果图表过多,造成页面卡顿。<br>若<code>只显示在屏幕可视范围内的图</code>,范围外的<code>销毁</code>,可大大提高页面性能。</p><h2 id="具体实现"><a href="#具体实现" class="headerlink" title="具体实现"></a>具体实现</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">isOnScreen</span>(<span class="params">element</span>) {</span><br><span class="line"> <span class="keyword">let</span> on_screen_height = <span class="number">20</span>; <span class="comment">// 偏移量</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> rect = element.<span class="title function_">getBoundingClientRect</span>();</span><br><span class="line"> <span class="keyword">let</span> windowHeight = <span class="variable language_">window</span>.<span class="property">innerHeight</span> || <span class="variable language_">document</span>.<span class="property">documentElement</span>.<span class="property">clientHeight</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> elementHeight = element.<span class="property">offsetHeight</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> onScreenHeight = on_screen_height > elementHeight ?</span><br><span class="line"> elementHeight : on_screen_height;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 元素在屏幕上方, 如果元素不是从屏幕最上侧开始的,需要减去对应值(rect.top 不是 0)</span></span><br><span class="line"> <span class="keyword">let</span> elementBottomToWindowTop = rect.<span class="property">top</span> + elementHeight;</span><br><span class="line"> <span class="keyword">let</span> bottomBoundingOnScreen = elementBottomToWindowTop >= onScreenHeight;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 元素在屏幕下方</span></span><br><span class="line"> <span class="keyword">let</span> elementTopToWindowBottom = windowHeight - (rect.<span class="property">bottom</span> - elementHeight);</span><br><span class="line"> <span class="keyword">let</span> topBoundingOnScreen = elementTopToWindowBottom >= onScreenHeight;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> bottomBoundingOnScreen && topBoundingOnScreen;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">let</span> i=<span class="number">0</span>; i<=<span class="number">6</span>; i++) {</span><br><span class="line"> <span class="keyword">let</span> element = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(i);</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">isOnScreen</span>(element))</span><br><span class="line"> <span class="keyword">if</span> (<span class="title function_">isOnScreen</span>(element)) {</span><br><span class="line"> <span class="keyword">if</span> () { <span class="comment">//没数据</span></span><br><span class="line"> <span class="comment">// 获取对应数据</span></span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// 销毁</span></span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">ul</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span> <span class="attr">id</span>=<span class="string">"0"</span>></span><span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span> <span class="attr">id</span>=<span class="string">"1"</span>></span><span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span> <span class="attr">id</span>=<span class="string">"2"</span>></span><span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span> <span class="attr">id</span>=<span class="string">"3"</span>></span><span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span> <span class="attr">id</span>=<span class="string">"4"</span>></span><span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span> <span class="attr">id</span>=<span class="string">"5"</span>></span><span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">li</span> <span class="attr">id</span>=<span class="string">"6"</span>></span><span class="tag"></<span class="name">li</span>></span></span><br><span class="line"> ...</span><br><span class="line"><span class="tag"></<span class="name">ul</span>></span></span><br></pre></td></tr></table></figure><h2 id="滚动结束事件"><a href="#滚动结束事件" class="headerlink" title="滚动结束事件"></a>滚动结束事件</h2><p>由于原生 JavaScript 没有对应滑动结束事件,需要采取定时模拟</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> element = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'id'</span>);</span><br><span class="line"></span><br><span class="line">element.<span class="property">onscroll</span> = <span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">if</span> (<span class="variable language_">window</span>.<span class="property">scrollTimer</span>) {</span><br><span class="line"> <span class="built_in">clearTimeout</span>(<span class="variable language_">window</span>.<span class="property">scrollTimer</span>) <span class="comment">// 普通写法</span></span><br><span class="line"> <span class="comment">// vue写法,由于vue对setTimeout修改,则需要id,否则无法清除</span></span><br><span class="line"> <span class="built_in">clearTimeout</span>(<span class="variable language_">window</span>.<span class="property">scrollTimer</span>.<span class="property">_id</span>)</span><br><span class="line"> }</span><br><span class="line"> <span class="variable language_">window</span>.<span class="property">scrollTimer</span> = <span class="built_in">setTimeout</span>(callback, <span class="number">300</span>)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">callback</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="comment">// 执行滑动结束后内容</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 平滑过渡</span></span><br><span class="line">element.<span class="title function_">scrollTo</span>({</span><br><span class="line"> <span class="attr">left</span>: <span class="number">0</span>,</span><br><span class="line"> <span class="attr">top</span>: num,</span><br><span class="line"> <span class="attr">behavior</span>: <span class="string">'smooth'</span></span><br><span class="line">})</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p><code>JavaScript</code> 屏幕可视</p>
</summary>
<category term="JavaScript" scheme="http://yoursite.com/categories/JavaScript/"/>
<category term="屏幕可视" scheme="http://yoursite.com/tags/%E5%B1%8F%E5%B9%95%E5%8F%AF%E8%A7%86/"/>
</entry>
<entry>
<title>JavaScript 原型与原型链</title>
<link href="http://yoursite.com/passages/20200807%E5%8E%9F%E5%9E%8B%E4%B8%8E%E5%8E%9F%E5%9E%8B%E9%93%BE/"/>
<id>http://yoursite.com/passages/20200807原型与原型链/</id>
<published>2020-08-08T04:00:00.000Z</published>
<updated>2020-08-07T10:08:25.184Z</updated>
<content type="html"><![CDATA[<p><code>JavaScript</code> 原型与原型链</p><span id="more"></span><h2 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h2><blockquote><p>每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。那么,假如我们让原型对象等于另一个类型的实例,结果会怎么样呢?显然,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实例与原型的链条。这就是所谓原型链的基本概念</p></blockquote><ul><li>构造函数 <code>Person</code></li><li>原型对象 <code>Person.prototype</code></li><li>原型对象都包含一个指向构造函数的指针 <code>constructor</code></li><li>实例都包含一个指向原型对象的内部指针 <code>person --- __proto__ > Person.prototype</code></li><li>结果:<code>Person.prototype</code> === <code>obejct</code> ?<br> => 由上推出条件一:<code>Person.prototype.__proto__ == obejct.__proto__</code> ,条件二:<code>object.__proto__ == Object.prototype</code></li><li>从而推出 <code>Person.prototype.__proto__ === Object.prototype</code></li></ul><p>每一个对象都有 <code>__proto__</code> 属性, 指向对应的构造函数的 <code>prototype</code> 属性.</p><p><code>class</code> 为构造函数的语法糖, 数据类型是函数,类本身就指向构造函数。</p><p><img src="/images/post/原型链.png" alt=""></p><p>图中由相互关联的原型 <code>(__proto__)</code> 组成的链状结构就是原型链,也就是由 <code>__proto__</code> 连接的这条线.</p><h2 id="类的实例对象"><a href="#类的实例对象" class="headerlink" title="类的实例对象"></a>类的实例对象</h2><p>类的所有实例共享一个原型对象.</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Point</span> {</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> p1 = <span class="keyword">new</span> <span class="title class_">Point</span>();</span><br><span class="line"><span class="keyword">let</span> p2 = <span class="keyword">new</span> <span class="title class_">Point</span>();</span><br><span class="line"></span><br><span class="line">p1.<span class="property">__proto__</span> === p2.<span class="property">__proto__</span> <span class="comment">// true</span></span><br><span class="line">p1.<span class="property">__proto__</span> === p2.<span class="property">__proto__</span> == <span class="title class_">Point</span>.<span class="property"><span class="keyword">prototype</span></span> <span class="comment">//true</span></span><br><span class="line"><span class="title class_">Point</span>.<span class="property">__proto__</span> === <span class="title class_">Function</span>.<span class="property"><span class="keyword">prototype</span></span> <span class="comment">// true</span></span><br></pre></td></tr></table></figure><p><code>p1 p2</code> 都为 Point 的实例,它们的原型 <code>(p1.__proto__, p2.__proto__)</code> 都等于 <code>Point.prototype</code>.</p><p>可以通过实例的 <code>__proto__</code> 给类添加方法,且所有共享.</p><h2 id="类的继承"><a href="#类的继承" class="headerlink" title="类的继承"></a>类的继承</h2><p><code>class</code> 为构造函数的语法糖. 同时有 <code>prototype</code> 和 <code>__proto__</code> 属性. 则存在两条继承链.</p><ul><li>子类的 <code>__proto__</code> 属性表示构造函数的继承,总是指向父类.</li><li>子类 <code>prototype</code> 属性的 <code>__proto__</code> 属性表示方法的继承,总是指向父类的 <code>prototype</code> 属性</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Animal</span> {</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Dog</span> <span class="keyword">extends</span> <span class="title class_ inherited__">Animal</span> {</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="title class_">Dog</span>.<span class="property">__proto__</span> === <span class="title class_">Animal</span> <span class="comment">// true</span></span><br><span class="line"><span class="title class_">Dog</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">__proto__</span> === <span class="title class_">Animal</span>.<span class="property"><span class="keyword">prototype</span></span> <span class="comment">// true</span></span><br></pre></td></tr></table></figure><ul><li>作为对象,子类(Dog)的 <code>__proto__</code> 属性是父类(Animal)</li><li>作为构造函数,子类(Dog)的 <code>prototype</code> 属性的 <code>__proto__</code> 属性是父类的 <code>prototype</code> 属性</li></ul><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://www.cnblogs.com/loveyaxin/p/11151586.html">javascript——原型与原型链</a></li><li><a href="https://www.cnblogs.com/weiyalin/p/9417361.html">JavaScript 原型链学习(四)原型链的基本概念、原型链实现继承</a></li></ul>]]></content>
<summary type="html">
<p><code>JavaScript</code> 原型与原型链</p>
</summary>
<category term="JavaScript" scheme="http://yoursite.com/categories/JavaScript/"/>
<category term="原型与原型链" scheme="http://yoursite.com/tags/%E5%8E%9F%E5%9E%8B%E4%B8%8E%E5%8E%9F%E5%9E%8B%E9%93%BE/"/>
</entry>
<entry>
<title>EGG 日志梳理</title>
<link href="http://yoursite.com/passages/20200510EGG%E6%97%A5%E5%BF%97/"/>
<id>http://yoursite.com/passages/20200510EGG日志/</id>
<published>2020-05-10T04:00:00.000Z</published>
<updated>2021-03-18T03:10:43.932Z</updated>
<content type="html"><![CDATA[<p><code>EGG</code> 日志梳理</p><span id="more"></span><h2 id="EGG-启动"><a href="#EGG-启动" class="headerlink" title="EGG 启动"></a>EGG 启动</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 本地</span></span><br><span class="line">npm run dev</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 生产环境</span></span><br><span class="line">npm run stop</span><br><span class="line">npm run start (--daemon <span class="comment">//后台启动)</span></span><br></pre></td></tr></table></figure><h2 id="EGG-生产环境日志"><a href="#EGG-生产环境日志" class="headerlink" title="EGG 生产环境日志"></a>EGG 生产环境日志</h2><h3 id="启动日志"><a href="#启动日志" class="headerlink" title="启动日志"></a>启动日志</h3><p>默认在 <code>${appInfo.root}/logs/</code></p><p><code>master-stderr.log</code><br><code>master-stdout.log</code></p><p>如果修改路径在 <code>package.json</code> 加参数</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">--stdout=<span class="regexp">/opt/</span>node/logs/master-stdout.<span class="property">log</span></span><br><span class="line">--stderr=<span class="regexp">/opt/</span>node/logs/master-stderr.<span class="property">log</span></span><br></pre></td></tr></table></figure><h3 id="定时任务日志"><a href="#定时任务日志" class="headerlink" title="定时任务日志"></a>定时任务日志</h3><p>默认在 <code>${appInfo.root}/logs/${appInfo.name}</code></p><p><code>egg-schedule.log</code></p><p>如果修改路径在 <code>config.prod.js</code></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">config.<span class="property">logger</span> = {</span><br><span class="line"> <span class="attr">dir</span>: path.<span class="title function_">join</span>(<span class="string">'/opt/node/logs/'</span>, appInfo.<span class="property">name</span>)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="业务日志"><a href="#业务日志" class="headerlink" title="业务日志"></a>业务日志</h3><p>默认在 <code>${appInfo.root}/logs/${appInfo.name}</code></p><p><code>common-error.log</code><br><code>egg-agent.log</code><br><code>egg-web.log</code><br><code>${appInfo.name}-web.log</code></p><p>如果修改路径在 <code>config.prod.js</code></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">config.<span class="property">logger</span> = {</span><br><span class="line"> <span class="attr">dir</span>: path.<span class="title function_">join</span>(<span class="string">'/opt/node/logs/'</span>, appInfo.<span class="property">name</span>)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="访问日志"><a href="#访问日志" class="headerlink" title="访问日志"></a>访问日志</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//方式一-router.js</span></span><br><span class="line"><span class="keyword">const</span> requestRecord = app.<span class="property">middleware</span>.<span class="title function_">requestRecord</span>();</span><br><span class="line">router.<span class="title function_">all</span>(<span class="string">`<span class="subst">${ROOT_URL}</span>*`</span>, requestRecord);</span><br><span class="line"><span class="comment">//方式二-config.js</span></span><br><span class="line">config.<span class="property">middleware</span> = [<span class="string">'requestRecord'</span>];</span><br></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// app/middleware/request_record.js</span></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = <span class="function">(<span class="params">options, app</span>) =></span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">requestRecord</span>(<span class="params">ctx, next</span>) {</span><br><span class="line"> ctx.<span class="property">logger</span>.<span class="title function_">info</span>(<span class="string">"httpVersion: %i referer: %j user-agent:"</span>, ctx.<span class="property">req</span>.<span class="property">httpVersion</span>, ctx.<span class="property">req</span>.<span class="property">headers</span>.<span class="property">referer</span>, ctx.<span class="property">req</span>.<span class="property">headers</span>[<span class="string">'user-agent'</span>]);</span><br><span class="line"> <span class="keyword">await</span> <span class="title function_">next</span>()</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="EGG-生产环境日志策略路径说明"><a href="#EGG-生产环境日志策略路径说明" class="headerlink" title="EGG 生产环境日志策略路径说明"></a>EGG 生产环境日志策略路径说明</h2><h3 id="分片策略"><a href="#分片策略" class="headerlink" title="分片策略"></a>分片策略</h3><ul><li>按天分割,且默认保存一个月(31天)</li></ul><h3 id="启动日志路径"><a href="#启动日志路径" class="headerlink" title="启动日志路径"></a>启动日志路径</h3><ul><li>/opt/node/logs/master-stdout.log</li><li>/opt/node/logs/master-stderr.log</li></ul><h3 id="定时任务日志路径"><a href="#定时任务日志路径" class="headerlink" title="定时任务日志路径"></a>定时任务日志路径</h3><ul><li>/opt/node/logs/server-egg/egg-schedule.log</li></ul><h3 id="业务日志路径"><a href="#业务日志路径" class="headerlink" title="业务日志路径"></a>业务日志路径</h3><ul><li>错误日志(errorLogger): /opt/node/logs/server-egg/common-error.log</li><li>应用相关日志,访问日志(appLogger): /opt/node/logs/server-egg/server-egg-web.log</li><li>框架内核、插件日志(coreLogger): /opt/node/logs/server-egg/egg-web.log</li><li>agent进程日志(agentLogger): /opt/node/logs/server-egg/egg-agent.log</li></ul><h3 id="注意"><a href="#注意" class="headerlink" title="注意"></a>注意</h3><ul><li>默认错误日志都会转到错误日志。</li></ul>]]></content>
<summary type="html">
<p><code>EGG</code> 日志梳理</p>
</summary>
<category term="EGG" scheme="http://yoursite.com/categories/EGG/"/>
<category term="EGG" scheme="http://yoursite.com/tags/EGG/"/>
<category term="日志" scheme="http://yoursite.com/tags/%E6%97%A5%E5%BF%97/"/>
</entry>
<entry>
<title>从零搭建 Spring boot 工程</title>
<link href="http://yoursite.com/passages/20190902%E4%BB%8E0%E6%90%AD%E5%BB%BAspringboot%E5%B7%A5%E7%A8%8B/"/>
<id>http://yoursite.com/passages/20190902从0搭建springboot工程/</id>
<published>2019-09-02T07:00:00.000Z</published>
<updated>2021-03-18T01:49:42.799Z</updated>
<content type="html"><![CDATA[<p>从零搭建 Spring boot 工程, 小白搭建后端工程记录。</p><span id="more"></span><h2 id="环境配置"><a href="#环境配置" class="headerlink" title="环境配置"></a>环境配置</h2><h3 id="JDK-安装配置"><a href="#JDK-安装配置" class="headerlink" title="JDK 安装配置"></a>JDK 安装配置</h3><ol><li>首先下载 <a href="https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html">jdk 1.8</a>,官网下载可能需要注册登录。</li><li>环境变量的配置,安装时按照默认路径安装完之后,环境变量自动配置完成。</li><li>启动控制台,<code>java -version</code> 看到版本说明安装成功。</li></ol><h3 id="maven-安装配置"><a href="#maven-安装配置" class="headerlink" title="maven 安装配置"></a>maven 安装配置</h3><ol><li>下载 <a href="https://maven.apache.org/download.cgi">maven</a>, <code>zip</code> 格式即可, 解压。</li><li>环境变量配置, 新建环境变量 变量名:<code>MAVEN_HOME</code>, 变量值:<code>E:\maven\apache-maven-3.6.1</code>.</li><li>修改 <code>PATH</code> 增加 <code>Maven</code> 路径。 <code>%MAVEN_HOME%\bin</code>.</li><li><code>mvn -v</code> 验证, 安装成功。</li><li>镜像库的更换与否,可以替换为阿里镜像库,或许会更快。</li></ol><p>若需要更换镜像库,修改 <code>settings.xml</code>即可,以下为阿里maven库配置。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">mirror</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">id</span>></span>alimaven<span class="tag"></<span class="name">id</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">name</span>></span>aliyun maven<span class="tag"></<span class="name">name</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">url</span>></span>http://maven.aliyun.com/nexus/content/groups/public/<span class="tag"></<span class="name">url</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">mirrorOf</span>></span>central<span class="tag"></<span class="name">mirrorOf</span>></span></span><br><span class="line"><span class="tag"></<span class="name">mirror</span>></span></span><br></pre></td></tr></table></figure><h3 id="IntelliJ-IDEA-下载安装"><a href="#IntelliJ-IDEA-下载安装" class="headerlink" title="IntelliJ IDEA 下载安装"></a>IntelliJ IDEA 下载安装</h3><ol><li>下载安装 <a href="https://www.jetbrains.com/idea/download/#section=windows">IntelliJ IDEA</a></li><li>专业版的需要激活,试用30天.</li><li>按照提示直接安装即可.</li></ol><h2 id="新建工程"><a href="#新建工程" class="headerlink" title="新建工程"></a>新建工程</h2><h3 id="工程初始化"><a href="#工程初始化" class="headerlink" title="工程初始化"></a>工程初始化</h3><ol><li><code>New Project</code> -> <code>Spring Initializr</code> -> <code>Next</code>.</li><li><code>Group</code> 及 <code>artifact</code> 按照自己需要修改,对应 <code>package</code> 变化,-> <code>Next</code></li><li>选择 <code>Web</code> -> <code>Spring Web starter</code> -> <code>Next</code>.</li><li>选择 路径及文件夹,确定即可,等待工程初始化完成.</li><li>初始化下载依赖过程比较慢,提到上步 <code>Maven</code> 配置,可以改成阿里的。</li></ol><h3 id="工程配置"><a href="#工程配置" class="headerlink" title="工程配置"></a>工程配置</h3><ol><li><code>pom</code> 文件学习</li></ol><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">parent</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="comment"><!-- 这个依赖包含了应用运行需要的所有信息,它包含了Spring Boot应用所必须的类似于Spring FrameWork(spring-core)</span></span><br><span class="line"><span class="comment"> Spring Test(spring-test)等基础依赖的依赖描述。你只需要使用这个parent pom就能完成所有的依赖描述添加工作--></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-parent<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">version</span>></span>2.1.7.RELEASE<span class="tag"></<span class="name">version</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">relativePath</span>/></span> <span class="comment"><!-- lookup parent from repository --></span></span><br><span class="line"><span class="tag"></<span class="name">parent</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="comment"><!-- 添加这个依赖之后就可以创建一个web应用程序。starter poms部分可以引入所有需要在实际项目中使用的依赖。</span></span><br><span class="line"><span class="comment"> spring-boot-starter-web依赖包含所有的spring-core, spring-web, spring-webmvc,嵌入的Tomcat server和其他web应用相关的库。 --></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-starter-web<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure><ol start="2"><li>工程运行</li></ol><p>点击 <code>运行图标</code> 或者进入 项目根目录 <code>mvn spring-boot:run</code></p><ul><li>点击运行图标,启动正常。</li><li>项目个目录执行命令,可能会报 <code>No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?</code>, 环境问题.</li></ul><p>如果遇到上述,查看设置,file->settings->build->maven 配置是否正确,及参考以下方式解决。</p><ul><li><a href="https://blog.csdn.net/javajxz008/article/details/82791138">No compiler is provided in this environment</a></li></ul><ol start="3"><li>热加载</li></ol><p>新增如下依赖,热部署,但是设置完并未生效,修改ide配置, 验证成功.</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">dependency</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">groupId</span>></span>org.springframework.boot<span class="tag"></<span class="name">groupId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">artifactId</span>></span>spring-boot-devtools<span class="tag"></<span class="name">artifactId</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">optional</span>></span>true<span class="tag"></<span class="name">optional</span>></span> <span class="comment"><!-- 这个需要为 true 热部署才有效 --></span></span><br><span class="line"><span class="tag"></<span class="name">dependency</span>></span></span><br></pre></td></tr></table></figure><ul><li><a href="https://blog.csdn.net/qq_34491508/article/details/83830075">Spring-boot-devTools无效解决办法,idea中devtools不起作用</a></li></ul><h2 id="运行"><a href="#运行" class="headerlink" title="运行"></a>运行</h2><p>运行正常,后续开发.</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://www.cnblogs.com/tufujie/p/8950169.html">IDEA创建Spring Boot项目</a></li><li><a href="http://www.imooc.com/article/74491">使用IDEA创建spring boot项目与项目解析</a></li></ul>]]></content>
<summary type="html">
<p>从零搭建 Spring boot 工程, 小白搭建后端工程记录。</p>
</summary>
<category term="Spring" scheme="http://yoursite.com/categories/Spring/"/>
<category term="Spring" scheme="http://yoursite.com/tags/Spring/"/>
<category term="工程搭建" scheme="http://yoursite.com/tags/%E5%B7%A5%E7%A8%8B%E6%90%AD%E5%BB%BA/"/>
</entry>
<entry>
<title>Spring 相关常识</title>
<link href="http://yoursite.com/passages/20190826Spring%E5%B8%B8%E8%AF%86/"/>
<id>http://yoursite.com/passages/20190826Spring常识/</id>
<published>2019-08-26T10:00:00.000Z</published>
<updated>2021-03-18T01:49:38.955Z</updated>
<content type="html"><![CDATA[<p>关于 spring 的一些常识</p><span id="more"></span><h2 id="spring"><a href="#spring" class="headerlink" title="spring"></a>spring</h2><p><code>Spring</code> 是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架。</p><h2 id="spring-mvc"><a href="#spring-mvc" class="headerlink" title="spring mvc"></a>spring mvc</h2><p><code>springMvc</code> 是 spring 基础之上的一个 MVC 框架, Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块.<br>主要处理 web 开发的路径映射和视图渲染,属于 spring 框架中 WEB 层开发的一部分.</p><h2 id="ssm"><a href="#ssm" class="headerlink" title="ssm"></a>ssm</h2><p><code>SSM(Spring + SpringMVC + MyBatis)</code> 框架集由 Spring、MyBatis 两个开源框架整合而成(SpringMVC是Spring中的部分内容).</p><h2 id="spring-boot"><a href="#spring-boot" class="headerlink" title="spring boot"></a>spring boot</h2><p><code>Spring Boot</code> 就是一些库的集合, 默认优于配置,简化了插件配置流程,不需要配置xml. 不仅继承了 Spring 框架原有的优秀特性,而且还通过简化配置来进一步简化了 Spring 应用的整个搭建和开发过程。另外 SpringBoot 通过集成大量的框架使得依赖包的版本冲突,以及引用的不稳定性等问题得到了很好的解决</p><h2 id="spring-cloud"><a href="#spring-cloud" class="headerlink" title="spring cloud"></a>spring cloud</h2><p><code>Spring Cloud</code> 是一系列框架的有序集合, 利用 Spring Boot 的开发便利性巧妙地简化了分布式系统基础设施的开发. <code>Spring Cloud</code> 关注于全局的微服务整合和管理,将多个 Spring Boot单体微服务进行整合以及管理, SpringCloud 依赖于 SpringBoot 开发,而 SpringBoot 可以独立开发;</p>]]></content>
<summary type="html">
<p>关于 spring 的一些常识</p>
</summary>
<category term="Spring" scheme="http://yoursite.com/categories/Spring/"/>
<category term="Spring" scheme="http://yoursite.com/tags/Spring/"/>
</entry>
<entry>
<title>JavaScript 实现版权信息固定在页面底部</title>
<link href="http://yoursite.com/passages/20190710%E7%89%88%E6%9D%83%E5%9B%BA%E5%AE%9A%E5%BA%95%E9%83%A8/"/>
<id>http://yoursite.com/passages/20190710版权固定底部/</id>
<published>2019-07-10T04:00:00.000Z</published>
<updated>2020-02-06T07:49:20.399Z</updated>
<content type="html"><![CDATA[<p>日常工作中,关于版权的布局,要一直在页面底部,需要处理屏幕高度和网页真实高度的关系。</p><span id="more"></span><h2 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h2><ol><li>若采用 <code>fixed</code> 定位,则可以保持版权一直在底部。(适用于屏幕高度 > 网页真实高度)</li><li>采用正常文档流,版权出现在网页底部。(适用于屏幕高度 < 网页真实高度)。否则会漂上去。</li></ol><h2 id="CSS-定位"><a href="#CSS-定位" class="headerlink" title="CSS 定位"></a>CSS 定位</h2><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.layout-copy2</span> {</span><br><span class="line"> <span class="attribute">position</span>: fixed;</span><br><span class="line"> <span class="attribute">bottom</span>: <span class="number">30px</span>;</span><br><span class="line"> <span class="attribute">left</span>: <span class="number">50%</span>;</span><br><span class="line"> <span class="attribute">transform</span>: <span class="built_in">translateX</span>(-<span class="number">50%</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="JavaScript-处理兼容"><a href="#JavaScript-处理兼容" class="headerlink" title="JavaScript 处理兼容"></a>JavaScript 处理兼容</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">copyrightAuto</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">let</span> winHeight = <span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">clientHeight</span>; <span class="comment">//窗口高度</span></span><br><span class="line"> <span class="keyword">let</span> bodyHeight = <span class="variable language_">document</span>.<span class="title function_">getElementsByTagName</span>(<span class="string">'body'</span>)[<span class="number">0</span>].<span class="property">clientHeight</span> <span class="comment">//网页高度</span></span><br><span class="line"> <span class="keyword">if</span> (winHeight > bodyHeight) { <span class="comment">//窗口 > 网页</span></span><br><span class="line"> <span class="variable language_">document</span>.<span class="title function_">getElementsByClassName</span>(<span class="string">'layout-copy'</span>)[<span class="number">0</span>].<span class="property">classList</span>.<span class="title function_">add</span>(<span class="string">'layout-copy2'</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="variable language_">document</span>.<span class="title function_">getElementsByClassName</span>(<span class="string">'layout-copy'</span>)[<span class="number">0</span>].<span class="property">classList</span>.<span class="title function_">remove</span>(<span class="string">'layout-copy2'</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="调用"><a href="#调用" class="headerlink" title="调用"></a>调用</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">copyrightAuto</span>();</span><br><span class="line"><span class="variable language_">window</span>.<span class="property">onresize</span> = <span class="keyword">function</span>(<span class="params"></span>) { <span class="comment">//监控窗口变化</span></span><br><span class="line"> <span class="title function_">copyrightAuto</span>();</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>日常工作中,关于版权的布局,要一直在页面底部,需要处理屏幕高度和网页真实高度的关系。</p>
</summary>
<category term="JavaScript" scheme="http://yoursite.com/categories/JavaScript/"/>
<category term="版权固定" scheme="http://yoursite.com/tags/%E7%89%88%E6%9D%83%E5%9B%BA%E5%AE%9A/"/>
</entry>
<entry>
<title>CSS Grid 布局</title>
<link href="http://yoursite.com/passages/20190608Grid%E5%B8%83%E5%B1%80/"/>
<id>http://yoursite.com/passages/20190608Grid布局/</id>
<published>2019-06-08T10:00:00.000Z</published>
<updated>2020-02-06T07:49:20.397Z</updated>
<content type="html"><![CDATA[<p>CSS <code>网格布局(Grid)</code> 布局,学习练习。</p><span id="more"></span><h2 id="关于-Grid"><a href="#关于-Grid" class="headerlink" title="关于 Grid"></a>关于 Grid</h2><p><code>CSS Grid</code> 布局是 CSS 中最强大的布局系统。与 flexbox 的一维布局系统不同,<code>CSS Grid</code> 布局是一个 <code>二维布局系统</code>,也就意味着它可以同时处理列和行。通过将 CSS 规则应用于 父元素 (成为 <code>Grid Container 网格容器</code>)和其子元素(成为 <code>Grid Items 网格项</code>),你就可以轻松使用 <code>Grid(网格)</code> 布局。</p><p><em>Grid</em> 布局 比 <em>Flex</em> 布局, 从一维到二维。</p><h2 id="相关术语"><a href="#相关术语" class="headerlink" title="相关术语"></a>相关术语</h2><ol><li><code>网格容器(Grid Container)</code>: 应用 <code>display: grid</code> 的元素.</li><li><code>网格项(Grid Item)</code>: 网格容器(Grid Container)的子元素(直接子元素).</li><li><code>网格线(Grid Line)</code>: 构成网格结构的分界线。它们既可以是垂直的(“列网格线(column grid lines)”),也可以是水平的(“行网格线(row grid lines)”),并位于行或列的任一侧。</li><li><code>网格轨道(Grid Track)</code>: 两条<code>相邻网格线</code>之间的空间。你可以把它们想象成网格的列或行。</li><li><code>网格单元格(Grid Cell)</code>: 两个相邻的行和两个相邻的列网格线之间的空间.</li><li><code>网格区域(Grid Area)</code>: 4条网格线包围的总空间。一个网格区域(Grid Area)可以由任意数量的网格单元格(Grid Cell) 组成。</li></ol><h2 id="主要属性"><a href="#主要属性" class="headerlink" title="主要属性"></a>主要属性</h2><p>Grid 布局的属性分成两类。一类定义在容器上面,称为 <code>容器属性</code>;另一类定义在项目上面,称为 <code>项目属性</code>。</p><h3 id="容器属性"><a href="#容器属性" class="headerlink" title="容器属性"></a>容器属性</h3><h4 id="display-属性"><a href="#display-属性" class="headerlink" title="display 属性"></a>display 属性</h4><ul><li><code>display: grid</code> 指定一个容器采用块级网格布局。</li><li><code>display: inline-grid</code> 指定一个容器采用内联网格布局。</li></ul><h4 id="grid-template-columns-grid-template-rows-属性"><a href="#grid-template-columns-grid-template-rows-属性" class="headerlink" title="grid-template-columns,grid-template-rows 属性"></a>grid-template-columns,grid-template-rows 属性</h4><ul><li><code>grid-template-columns</code>: 属性定义每一列的列宽</li><li><code>grid-template-rows</code>: 属性定义每一行的行高</li></ul><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*定义了两行三列的网格,行高为200px 100px, 列宽都为100px*/</span></span><br><span class="line"></span><br><span class="line"><span class="selector-class">.container</span> {</span><br><span class="line"> <span class="attribute">display</span>: grid;</span><br><span class="line"> <span class="attribute">grid-template-columns</span>: <span class="number">100px</span> <span class="number">100px</span> <span class="number">100px</span>;</span><br><span class="line"> <span class="attribute">grid-template-rows</span>: <span class="number">200px</span> <span class="number">100px</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 除了长度值,也可以使用百分比,或者等份网格容器中可用空间(使用 fr 单位)*/</span></span><br><span class="line"><span class="selector-class">.container</span> {</span><br><span class="line"> <span class="attribute">grid-template-columns</span>: <span class="number">40px</span> <span class="number">50px</span> auto <span class="number">50px</span> <span class="number">40px</span>;</span><br><span class="line"> <span class="attribute">grid-template-rows</span>: <span class="number">25%</span> <span class="number">100px</span> auto;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>如果定义了多个值,可以采用 <code>repeat()</code> 函数</p><p>repeat()接受两个参数,第一个参数是重复的次数,第二个参数是所要重复的值。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">grid-template-rows</span>: <span class="built_in">repeat</span>(<span class="number">3</span>, <span class="number">33.33%</span>);</span><br><span class="line"><span class="attribute">grid-template-columns</span>: <span class="built_in">repeat</span>(<span class="number">2</span>, <span class="number">100px</span> <span class="number">20px</span> <span class="number">80px</span>);</span><br></pre></td></tr></table></figure><p><code>auto-fill</code> 关键字, 单元格的大小是固定的,但是容器的大小不确定, 可以用 auto-fill 关键字表示自动填充。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.container</span> {</span><br><span class="line"> <span class="attribute">display</span>: grid;</span><br><span class="line"> <span class="attribute">grid-template-columns</span>: <span class="built_in">repeat</span>(auto-fill, <span class="number">100px</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><code>fr</code>(fraction 的缩写,意为”片段”) 关键字,等分网格容器剩余可用空间来设置 网格轨道(Grid Track) 的大小。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.container</span> {</span><br><span class="line"> <span class="attribute">grid-template-columns</span>: <span class="number">1</span>fr <span class="number">50px</span> <span class="number">1</span>fr <span class="number">1</span>fr;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><code>minmax()</code> 关键字, 产生一个长度范围,表示长度就在这个范围之中。它接受两个参数,分别为最小值和最大值。</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*minmax(100px, 1fr)表示列宽不小于100px,不大于1fr*/</span></span><br><span class="line"><span class="attribute">grid-template-columns</span>: <span class="number">1</span>fr <span class="number">1</span>fr <span class="built_in">minmax</span>(<span class="number">100px</span>, <span class="number">1</span>fr);</span><br></pre></td></tr></table></figure><h4 id="grid-template-areas-属性"><a href="#grid-template-areas-属性" class="headerlink" title="grid-template-areas 属性"></a>grid-template-areas 属性</h4><p>网格布局允许指定”区域”(area),一个区域由单个或多个单元格组成。grid-template-areas属性用于定义区域。常用布局示例.</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"container"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"item-a"</span>></span><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"item-b"</span>></span><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"item-c"</span>></span><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span> <span class="attr">class</span>=<span class="string">"item-d"</span>></span><span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.item-a</span> {</span><br><span class="line"> <span class="attribute">grid-area</span>: header;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.item-b</span> {</span><br><span class="line"> <span class="attribute">grid-area</span>: main;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.item-c</span> {</span><br><span class="line"> <span class="attribute">grid-area</span>: sidebar;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.item-d</span> {</span><br><span class="line"> <span class="attribute">grid-area</span>: footer;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.container</span> {</span><br><span class="line"> <span class="attribute">display</span>: grid;</span><br><span class="line"> <span class="attribute">grid-template-columns</span>: <span class="number">100px</span> <span class="number">100px</span> <span class="number">100px</span> <span class="number">100px</span>;</span><br><span class="line"> <span class="attribute">grid-template-rows</span>: <span class="number">100px</span> <span class="number">100px</span> <span class="number">100px</span>;</span><br><span class="line"> <span class="attribute">grid-template-areas</span>: <span class="string">"header header header header"</span></span><br><span class="line"> <span class="string">"main main . sidebar"</span></span><br><span class="line"> <span class="string">"footer footer footer footer"</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="grid-row-gap-grid-column-gap-grid-gap-属性"><a href="#grid-row-gap-grid-column-gap-grid-gap-属性" class="headerlink" title="grid-row-gap,grid-column-gap,grid-gap 属性"></a>grid-row-gap,grid-column-gap,grid-gap 属性</h4><ul><li><code>grid-row-gap</code> 属性设置行与行的间隔(行间距)</li><li><code>grid-column-gap</code> 属性设置列与列的间隔(列间距)</li><li><code>grid-gap</code> 属性是 grid-column-gap 和 grid-row-gap的合并简写形式。如果grid-gap省略了第二个值,浏览器认为第二个值等于第一个值。</li></ul><p>上述属性将可以删除 <code>grid-</code> 前缀</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.container</span> {</span><br><span class="line"> <span class="attribute">grid-row</span>-<span class="attribute">gap</span>: <span class="number">20px</span>;</span><br><span class="line"> <span class="attribute">grid-column</span>-<span class="attribute">gap</span>: <span class="number">20px</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/*简写*/</span></span><br><span class="line"><span class="selector-class">.container</span> {</span><br><span class="line"> <span class="attribute">grid-gap</span>: <span class="number">20px</span> <span class="number">20px</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="justify-items-align-items-place-items-属性"><a href="#justify-items-align-items-place-items-属性" class="headerlink" title="justify-items,align-items,place-items 属性"></a>justify-items,align-items,place-items 属性</h4><ul><li><code>justify-items</code> 属性设置 <code>单元格内容</code> 的水平位置(左中右)</li><li><code>align-items</code> 属性设置 <code>单元格内容</code> 的垂直位置(上中下)</li><li><code>place-items</code> 属性是 align-items 属性和 justify-items 属性的合并简写形式。</li></ul><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.container</span> {</span><br><span class="line"> justify-items: start | end | center | stretch;</span><br><span class="line"> <span class="attribute">align-items</span>: start | end | center | stretch;</span><br><span class="line">}</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">* start:对齐单元格的起始边缘。</span></span><br><span class="line"><span class="comment">* end:对齐单元格的结束边缘。</span></span><br><span class="line"><span class="comment">* center:单元格内部居中。</span></span><br><span class="line"><span class="comment">* stretch:拉伸,占满单元格的整个宽度(默认值)。</span></span><br><span class="line"><span class="comment">*/</span></span><br></pre></td></tr></table></figure><h4 id="justify-content-align-content-place-content-属性"><a href="#justify-content-align-content-place-content-属性" class="headerlink" title="justify-content,align-content,place-content 属性"></a>justify-content,align-content,place-content 属性</h4><ul><li><code>justify-content</code> 属性是整个 <code>内容区域</code> 在容器里面的水平位置(左中右)</li><li><code>align-content</code> 属性是整个 <code>内容区域</code> 的垂直位置(上中下)</li><li><code>place-content</code> 属性是align-content属性和justify-content属性的合并简写形式。</li></ul><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.container</span> {</span><br><span class="line"> <span class="attribute">justify-content</span>: start | end | center | stretch | space-around | space-between | space-evenly;</span><br><span class="line"> <span class="attribute">align-content</span>: start | end | center | stretch | space-around | space-between | space-evenly; </span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="grid-auto-columns-grid-auto-rows-属性"><a href="#grid-auto-columns-grid-auto-rows-属性" class="headerlink" title="grid-auto-columns,grid-auto-rows 属性"></a>grid-auto-columns,grid-auto-rows 属性</h4><p><code>grid-auto-columns</code> 属性和 <code>grid-auto-rows</code> 属性用来设置,浏览器自动创建的多余网格的列宽和行高.</p><h4 id="grid-auto-flow-属性"><a href="#grid-auto-flow-属性" class="headerlink" title="grid-auto-flow 属性"></a>grid-auto-flow 属性</h4><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">grid-auto-flow</span>: row; <span class="comment">/*先行后列*/</span></span><br><span class="line"><span class="attribute">grid-auto-flow</span>: column; <span class="comment">/*先列后行*/</span></span><br><span class="line"></span><br><span class="line"><span class="attribute">grid-auto-flow</span>: row dense; <span class="comment">/*先行后列,并且尽可能紧密填满,尽量不出现空格。*/</span></span><br><span class="line"><span class="attribute">grid-auto-flow</span>: column dense; <span class="comment">/*先列后行,并且尽可能紧密填满,尽量不出现空格。*/</span></span><br></pre></td></tr></table></figure><h3 id="项目属性"><a href="#项目属性" class="headerlink" title="项目属性"></a>项目属性</h3><h4 id="grid-column-start-grid-column-end-grid-row-start-grid-row-end-属性"><a href="#grid-column-start-grid-column-end-grid-row-start-grid-row-end-属性" class="headerlink" title="grid-column-start,grid-column-end,grid-row-start,grid-row-end 属性"></a>grid-column-start,grid-column-end,grid-row-start,grid-row-end 属性</h4><p>锁定项目位置</p><ul><li><code>grid-column-start</code> 属性:左边框所在的垂直网格线</li><li><code>grid-column-end</code> 属性:右边框所在的垂直网格线</li><li><code>grid-row-start</code> 属性:上边框所在的水平网格线</li><li><code>grid-row-end</code> 属性:下边框所在的水平网格线</li></ul><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.item-1</span> {</span><br><span class="line"> <span class="attribute">grid-column-start</span>: <span class="number">1</span>;</span><br><span class="line"> <span class="attribute">grid-column-end</span>: <span class="number">3</span>;</span><br><span class="line"> <span class="attribute">grid-row-start</span>: <span class="number">2</span>;</span><br><span class="line"> <span class="attribute">grid-row-end</span>: <span class="number">4</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">这四个属性的值还可以使用span关键字,表示"跨越",即左右边框(上下边框)之间跨越多少个网格。</span></span><br><span class="line"><span class="comment">1号项目的左边框距离右边框跨越2个网格。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="selector-class">.item-1</span> {</span><br><span class="line"> <span class="attribute">grid-column-start</span>: span <span class="number">2</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="grid-column-grid-row-grid-area-属性"><a href="#grid-column-grid-row-grid-area-属性" class="headerlink" title="grid-column,grid-row,grid-area 属性"></a>grid-column,grid-row,grid-area 属性</h4><ul><li><code>grid-column</code> 属性是 grid-column-start 和 grid-column-end 的合并简写形式</li><li><code>grid-row</code> 属性是 grid-row-start 属性和 grid-row-end 的合并简写形式。</li><li><code>grid-area</code> 属性指定项目放在哪一个区域, 还可用作 grid-row-start、grid-column-start、grid-row-end、grid-column-end 的合并简写形式,直接指定项目的位置。</li></ul><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*用 / 分开 */</span></span><br><span class="line"><span class="selector-class">.item</span> {</span><br><span class="line"> <span class="attribute">grid-column</span>: <span class="number">1</span> / <span class="number">3</span>;</span><br><span class="line"> <span class="attribute">grid-row</span>: / ;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.item</span> {</span><br><span class="line"> <span class="attribute">grid-area</span>: <row-start> / <column-start> / <row-end> / <column-end>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="justify-self-align-self-place-self-属性"><a href="#justify-self-align-self-place-self-属性" class="headerlink" title="justify-self,align-self,place-self 属性"></a>justify-self,align-self,place-self 属性</h4><ul><li><code>justify-self</code> 属性设置 <code>单元格内容</code> 的水平位置(左中右),跟 justify-items 属性的用法完全一致,但只作用于单个项目。</li><li><code>align-self</code> 属性设置 <code>单元格内容</code> 的垂直位置(上中下),跟 align-items 属性的用法完全一致,也是只作用于单个项目。</li><li><code>place-self</code> 属性是 align-self 属性和 justify-self 属性的合并简写形式。</li></ul><h2 id="CSS3-兼容各种浏览器的前缀"><a href="#CSS3-兼容各种浏览器的前缀" class="headerlink" title="CSS3 兼容各种浏览器的前缀"></a>CSS3 兼容各种浏览器的前缀</h2><ol><li><code>-webkit-</code> <strong>chrome、safari</strong></li><li><code>-moz-</code> <strong>firefox</strong></li><li><code>-ms-</code> <strong>IE</strong></li><li><code>-o-</code> <strong>opera</strong></li></ol><h2 id="相关参考"><a href="#相关参考" class="headerlink" title="相关参考"></a>相关参考</h2><ul><li><a href="http://www.ruanyifeng.com/blog/2019/03/grid-layout-tutorial.html">阮一峰-CSS Grid 网格布局教程</a></li><li><a href="https://www.html.cn/archives/8510">CSS Grid 布局完全指南</a></li></ul>]]></content>
<summary type="html">
<p>CSS <code>网格布局(Grid)</code> 布局,学习练习。</p>
</summary>
<category term="CSS" scheme="http://yoursite.com/categories/CSS/"/>
<category term="Grid" scheme="http://yoursite.com/tags/Grid/"/>
</entry>
<entry>
<title>Axios 发送 post 请求下载文件 blob 流</title>
<link href="http://yoursite.com/passages/20190606axios%E6%96%87%E4%BB%B6%E4%B8%8B%E8%BD%BD/"/>
<id>http://yoursite.com/passages/20190606axios文件下载/</id>
<published>2019-06-06T10:00:00.000Z</published>
<updated>2022-04-29T06:13:32.167Z</updated>
<content type="html"><![CDATA[<p>关于下载文件,有时候会分步骤进行。第一步发送 <code>post</code> 请求传递参数,服务端接受请求,查询到对应的 <code>文件id</code>。第二步发送 <code>get</code> 请求,服务端根据传递的文件标识返回文件地址,客户端从而实现下载。</p><p>此文介绍的是利用 <code>Axios</code> 发送 <code>post</code> 请求实现文件下载。服务端返回的为 <code>blob</code> 流的形式。</p><span id="more"></span><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//fileDownload.js</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> axios <span class="keyword">from</span> <span class="string">'axios'</span>;</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 发送post请求下载文件,返回的为 blob 流</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> {<span class="type">*</span>} url 接口地址</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> {<span class="type">*</span>} data 参数</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> {<span class="type">*</span>} fileName 文件名</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">fileDownload</span>(<span class="params">url, data, fileName</span>) {</span><br><span class="line"> axios.<span class="property">defaults</span>.<span class="property">headers</span>.<span class="property">post</span>[<span class="string">'Content-Type'</span>] = <span class="string">'application/json'</span>;</span><br><span class="line"> <span class="keyword">await</span> <span class="title function_">axios</span>({</span><br><span class="line"> <span class="attr">method</span>: <span class="string">'post'</span>,</span><br><span class="line"> <span class="attr">url</span>: url,</span><br><span class="line"> <span class="attr">data</span>: <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(data),</span><br><span class="line"> <span class="attr">responseType</span>: <span class="string">'blob'</span></span><br><span class="line"> }).<span class="title function_">then</span>(<span class="function">(<span class="params">res</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> content = res.<span class="property">data</span>;</span><br><span class="line"> <span class="keyword">const</span> contentType = res.<span class="property">headers</span>[<span class="string">'content-type'</span>] || <span class="string">"application/octet-stream"</span>; <span class="comment">// 处理浏览器兼容</span></span><br><span class="line"> <span class="keyword">const</span> blob = <span class="keyword">new</span> <span class="title class_">Blob</span>([content], {<span class="attr">type</span>: contentType});</span><br><span class="line"> <span class="keyword">if</span> (<span class="string">'download'</span> <span class="keyword">in</span> <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">'a'</span>)) { <span class="comment">//非ie</span></span><br><span class="line"> <span class="keyword">const</span> fileLink = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">'a'</span>);</span><br><span class="line"> fileLink.<span class="property">download</span> = fileName;</span><br><span class="line"> fileLink.<span class="property">style</span>.<span class="property">display</span> = <span class="string">'none'</span>;</span><br><span class="line"> fileLink.<span class="property">href</span> = <span class="variable constant_">URL</span>.<span class="title function_">createObjectURL</span>(blob);</span><br><span class="line"> <span class="variable language_">document</span>.<span class="property">body</span>.<span class="title function_">appendChild</span>(fileLink);</span><br><span class="line"> fileLink.<span class="title function_">click</span>();</span><br><span class="line"> <span class="variable constant_">URL</span>.<span class="title function_">revokeObjectURL</span>(fileLink.<span class="property">href</span>); <span class="comment">// 释放URL 对象</span></span><br><span class="line"> <span class="variable language_">document</span>.<span class="property">body</span>.<span class="title function_">removeChild</span>(fileLink);</span><br><span class="line"> } <span class="keyword">else</span> { <span class="comment">//ie10+</span></span><br><span class="line"> navigator.<span class="title function_">msSaveBlob</span>(blob, fileName);</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//具体使用</span></span><br><span class="line"><span class="keyword">import</span> fileDownload <span class="keyword">from</span> <span class="string">'fileDownload'</span>;</span><br><span class="line"><span class="title function_">fileDownload</span>(<span class="string">"url"</span>, <span class="string">"data"</span>, <span class="string">"fileName"</span>).<span class="title function_">then</span>( <span class="function">() =></span> {</span><br><span class="line"> <span class="comment">//可以处理回调,例如下载状态</span></span><br><span class="line">})</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 返回pdf 流并预览</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">pdfPreview</span>(<span class="params">method, url, data, fileName</span>) {</span><br><span class="line"> <span class="keyword">let</span> open;</span><br><span class="line"> <span class="keyword">if</span> (<span class="string">'download'</span> <span class="keyword">in</span> <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">'a'</span>)) {</span><br><span class="line"> open = <span class="variable language_">window</span>.<span class="title function_">open</span>(); <span class="comment">//防止拦截</span></span><br><span class="line"> }</span><br><span class="line"> axios.<span class="property">defaults</span>.<span class="property">headers</span>.<span class="property">post</span>[<span class="string">'Content-Type'</span>] = <span class="string">'application/json'</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">await</span> <span class="title function_">axios</span>({</span><br><span class="line"> <span class="attr">method</span>: method,</span><br><span class="line"> <span class="attr">url</span>: url,</span><br><span class="line"> <span class="attr">data</span>: <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(data),</span><br><span class="line"> <span class="attr">responseType</span>: <span class="string">'blob'</span></span><br><span class="line"> }).<span class="title function_">then</span>(<span class="function">(<span class="params">res</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> content = res.<span class="property">data</span>;</span><br><span class="line"> <span class="keyword">const</span> contentType = res.<span class="property">headers</span>[<span class="string">'content-type'</span>] || <span class="string">"application/pdf"</span>; <span class="comment">// 处理浏览器兼容</span></span><br><span class="line"> <span class="keyword">const</span> blob = <span class="keyword">new</span> <span class="title class_">Blob</span>([content], {<span class="attr">type</span>: contentType});</span><br><span class="line"> <span class="keyword">if</span> (<span class="string">'download'</span> <span class="keyword">in</span> <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">'a'</span>)) { <span class="comment">//非ie -ie不支持预览</span></span><br><span class="line"> <span class="keyword">const</span> href = <span class="variable constant_">URL</span>.<span class="title function_">createObjectURL</span>(blob);</span><br><span class="line"> open.<span class="property">location</span> = href;</span><br><span class="line"> } <span class="keyword">else</span> { <span class="comment">//ie10+</span></span><br><span class="line"> navigator.<span class="title function_">msSaveBlob</span>(blob, fileName);</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> } <span class="keyword">catch</span>(err) {</span><br><span class="line"> } </span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>关于下载文件,有时候会分步骤进行。第一步发送 <code>post</code> 请求传递参数,服务端接受请求,查询到对应的 <code>文件id</code>。第二步发送 <code>get</code> 请求,服务端根据传递的文件标识返回文件地址,客户端从而实现下载。</p>
<p>此文介绍的是利用 <code>Axios</code> 发送 <code>post</code> 请求实现文件下载。服务端返回的为 <code>blob</code> 流的形式。</p>
</summary>
<category term="请求" scheme="http://yoursite.com/categories/%E8%AF%B7%E6%B1%82/"/>
<category term="axios" scheme="http://yoursite.com/tags/axios/"/>
<category term="文件下载" scheme="http://yoursite.com/tags/%E6%96%87%E4%BB%B6%E4%B8%8B%E8%BD%BD/"/>
</entry>
<entry>
<title>CSS 实现元素居于页面中间</title>
<link href="http://yoursite.com/passages/20190529%E5%85%83%E7%B4%A0%E5%B1%85%E4%BA%8E%E9%A1%B5%E9%9D%A2%E6%AD%A3%E4%B8%AD/"/>
<id>http://yoursite.com/passages/20190529元素居于页面正中/</id>
<published>2019-05-29T04:00:00.000Z</published>
<updated>2020-02-06T07:49:20.393Z</updated>
<content type="html"><![CDATA[<p>关于 CSS 实现元素居于页面中间,方法汇总记录。</p><span id="more"></span><h2 id="方式一-Flex布局"><a href="#方式一-Flex布局" class="headerlink" title="方式一 Flex布局"></a>方式一 Flex布局</h2><p>此种方式无需定义 <code>元素宽高</code>。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span>></span>居中div<span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br></pre></td></tr></table></figure><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">html</span>, <span class="selector-tag">body</span> {</span><br><span class="line"> <span class="attribute">margin</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">padding</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">height</span>: <span class="number">100%</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="selector-tag">body</span> { </span><br><span class="line"> <span class="attribute">display</span>: flex;</span><br><span class="line"> <span class="attribute">justify-content</span>: center;</span><br><span class="line"> <span class="attribute">align-items</span>: center;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="selector-tag">div</span> {</span><br><span class="line"> <span class="attribute">border</span>: <span class="number">1px</span> solid <span class="number">#dddddd</span>;</span><br><span class="line"> <span class="attribute">padding</span>: <span class="number">100px</span>;</span><br><span class="line"> <span class="attribute">background-color</span>:green;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="方式二-定位-未知宽高"><a href="#方式二-定位-未知宽高" class="headerlink" title="方式二 定位-未知宽高"></a>方式二 定位-未知宽高</h2><p>此种方式无需定义 <code>元素宽高</code>。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span>></span>居中div<span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br></pre></td></tr></table></figure><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">html</span>, <span class="selector-tag">body</span> {</span><br><span class="line"> <span class="attribute">margin</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">padding</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">height</span>: <span class="number">100%</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-tag">body</span> { </span><br><span class="line"> <span class="attribute">position</span>: relative;</span><br><span class="line">}</span><br><span class="line"><span class="selector-tag">div</span> {</span><br><span class="line"> <span class="attribute">position</span>: absolute;</span><br><span class="line"> <span class="attribute">left</span>: <span class="number">50%</span>;</span><br><span class="line"> <span class="attribute">top</span>: <span class="number">50%</span>;</span><br><span class="line"> <span class="attribute">transform</span>: <span class="built_in">translate</span>(-<span class="number">50%</span>, -<span class="number">50%</span>); <span class="comment">/*元素向上向左移动元素高宽的50%,使元素中心在正中*/</span></span><br><span class="line"> <span class="attribute">border</span>: <span class="number">1px</span> solid <span class="number">#dddddd</span>;</span><br><span class="line"> <span class="attribute">padding</span>: <span class="number">100px</span>;</span><br><span class="line"> <span class="attribute">background-color</span>:green;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="方式三-定位-已知宽高"><a href="#方式三-定位-已知宽高" class="headerlink" title="方式三 定位-已知宽高"></a>方式三 定位-已知宽高</h2><p>此种方式需要定义 <code>元素宽高</code>。思路同上,设置 <code>margin-top: -height/2</code>, <code>margin-left: -width/2</code>.</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span>></span>居中div<span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br></pre></td></tr></table></figure><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">html</span>, <span class="selector-tag">body</span> {</span><br><span class="line"> <span class="attribute">margin</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">padding</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">height</span>: <span class="number">100%</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-tag">body</span> { </span><br><span class="line"> <span class="attribute">position</span>: relative;</span><br><span class="line">}</span><br><span class="line"><span class="selector-tag">div</span> {</span><br><span class="line"> <span class="attribute">position</span>: absolute;</span><br><span class="line"> <span class="attribute">left</span>: <span class="number">50%</span>;</span><br><span class="line"> <span class="attribute">top</span>: <span class="number">50%</span>;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">80px</span>;</span><br><span class="line"> <span class="attribute">margin-left</span>: -<span class="number">40px</span>;</span><br><span class="line"> <span class="attribute">text-align</span>: center;</span><br><span class="line"> <span class="attribute">height</span>: <span class="number">80px</span>;</span><br><span class="line"> <span class="attribute">margin-top</span>: -<span class="number">40px</span>;</span><br><span class="line"> <span class="attribute">line-height</span>: <span class="number">80px</span>;</span><br><span class="line"> <span class="attribute">border</span>: <span class="number">1px</span> solid <span class="number">#dddddd</span>;</span><br><span class="line"> <span class="attribute">background-color</span>:green;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="方式四-换一种定位"><a href="#方式四-换一种定位" class="headerlink" title="方式四 换一种定位"></a>方式四 换一种定位</h2><p>与方式 2, 3 一样,只是换一种定位方式 <code>fixed</code>。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span>></span>居中div<span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br></pre></td></tr></table></figure><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">html</span>, <span class="selector-tag">body</span> {</span><br><span class="line"> <span class="attribute">margin</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">padding</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">height</span>: <span class="number">100%</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-tag">div</span> {</span><br><span class="line"> <span class="attribute">position</span>: fixed;</span><br><span class="line"> <span class="attribute">left</span>: <span class="number">50%</span>;</span><br><span class="line"> <span class="attribute">top</span>: <span class="number">50%</span>;</span><br><span class="line"> <span class="attribute">transform</span>: <span class="built_in">translate</span>(-<span class="number">50%</span>, -<span class="number">50%</span>);</span><br><span class="line"> <span class="attribute">padding</span>: <span class="number">100px</span>;</span><br><span class="line"> <span class="attribute">border</span>: <span class="number">1px</span> solid <span class="number">#dddddd</span>;</span><br><span class="line"> <span class="attribute">background-color</span>:green;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="方式五-利用-margin"><a href="#方式五-利用-margin" class="headerlink" title="方式五 利用 margin"></a>方式五 利用 margin</h2><p>此种方式需要定义 <code>元素宽高</code>. <code>absolute</code> 定位上下左右为0, 设置 <code>margin:auto</code>.</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">div</span>></span>居中div<span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br></pre></td></tr></table></figure><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">* {</span><br><span class="line"> <span class="attribute">margin</span>: <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="selector-tag">div</span> {</span><br><span class="line"> <span class="attribute">position</span>: absolute;</span><br><span class="line"> <span class="attribute">left</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">right</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">top</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">bottom</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">margin</span>: auto;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">200px</span>;</span><br><span class="line"> <span class="attribute">height</span>: <span class="number">200px</span>;</span><br><span class="line"> <span class="attribute">background-color</span>: green;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
<p>关于 CSS 实现元素居于页面中间,方法汇总记录。</p>
</summary>
<category term="CSS" scheme="http://yoursite.com/categories/CSS/"/>
<category term="元素居中" scheme="http://yoursite.com/tags/%E5%85%83%E7%B4%A0%E5%B1%85%E4%B8%AD/"/>
</entry>
<entry>
<title>WebSocket</title>
<link href="http://yoursite.com/passages/websocket/"/>
<id>http://yoursite.com/passages/websocket/</id>
<published>2019-05-08T04:00:00.000Z</published>
<updated>2021-03-18T09:01:42.782Z</updated>
<content type="html"><![CDATA[<p>对 <code>WebSocket</code> 一种网络通信协议 的初步学习,记录。</p><span id="more"></span><h2 id="关于-WebSocket"><a href="#关于-WebSocket" class="headerlink" title="关于 WebSocket"></a>关于 WebSocket</h2><h3 id="WebSocket-与-Http-?"><a href="#WebSocket-与-Http-?" class="headerlink" title="WebSocket 与 Http ?"></a>WebSocket 与 Http ?</h3><ul><li><code>HTTP</code> 协议有一个缺陷:通信只能由客户端发起, 做不到服务器主动向客户端推送信息。</li></ul><blockquote><p><code>单向请求</code>: 注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。只能使用 <code>轮询</code>, 每隔一段时候,就发出一个询问,了解服务器有没有新的信息。轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)</p></blockquote><ul><li><code>WebSocket</code> 协议: 服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的 <code>双向平等</code> 对话,属于服务器推送技术的一种.</li></ul><h2 id="socket-io-示例-Demo"><a href="#socket-io-示例-Demo" class="headerlink" title="socket.io 示例 Demo"></a><code>socket.io</code> 示例 Demo</h2><ol><li>服务端代码 <code>socket.js</code>, <code>node socket.js</code></li></ol><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> http = <span class="built_in">require</span>(<span class="string">'http'</span>);</span><br><span class="line"><span class="keyword">var</span> fs = <span class="built_in">require</span>(<span class="string">'fs'</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//创建服务器,返回 index.html</span></span><br><span class="line"><span class="keyword">var</span> app = http.<span class="title function_">createServer</span>(<span class="function">(<span class="params">req, res</span>) =></span> {</span><br><span class="line"> fs.<span class="title function_">readFile</span>(<span class="string">'index.html'</span>, <span class="function">(<span class="params">err, data</span>)=></span> {</span><br><span class="line"> <span class="comment">//指定res head 及 data</span></span><br><span class="line"> res.<span class="title function_">writeHead</span>(<span class="number">200</span>, { <span class="string">'Content-Type'</span>: <span class="string">'text/html;charset=utf-8'</span> });</span><br><span class="line"> res.<span class="title function_">end</span>(data);</span><br><span class="line"> })</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line"><span class="comment">//创建连接</span></span><br><span class="line"><span class="keyword">var</span> io = <span class="built_in">require</span>(<span class="string">'socket.io'</span>)(app);</span><br><span class="line">io.<span class="title function_">on</span>(<span class="string">'connection'</span>, <span class="function"><span class="params">client</span> =></span> {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"连接建立"</span>)</span><br><span class="line"> <span class="comment">//服务器端通过 emit 广播,通过 on 接收广播</span></span><br><span class="line"> client.<span class="title function_">on</span>(<span class="string">'add'</span>, <span class="function"><span class="params">data</span> =></span> { </span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(data);</span><br><span class="line"> io.<span class="title function_">emit</span>(<span class="string">'to-client'</span>, <span class="string">'我是服务器的数据'</span> + data.<span class="property">client</span>)</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">app.<span class="title function_">listen</span>(<span class="number">3000</span>);</span><br></pre></td></tr></table></figure><ol start="2"><li>客户端 <code>index.html</code></li></ol><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta"><!DOCTYPE <span class="keyword">html</span>></span></span><br><span class="line"><span class="tag"><<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>></span></span><br><span class="line"><span class="tag"><<span class="name">head</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">name</span>=<span class="string">"viewport"</span> <span class="attr">content</span>=<span class="string">"width=device-width, initial-scale=1.0"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">"X-UA-Compatible"</span> <span class="attr">content</span>=<span class="string">"ie=edge"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">title</span>></span>聊天室1<span class="tag"></<span class="name">title</span>></span></span><br><span class="line"><span class="tag"></<span class="name">head</span>></span></span><br><span class="line"><span class="tag"><<span class="name">body</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">button</span> <span class="attr">id</span>=<span class="string">"button"</span>></span>给服务发送数据<span class="tag"></<span class="name">button</span>></span></span><br><span class="line"><span class="tag"></<span class="name">body</span>></span></span><br><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"http://localhost:3000/socket.io/socket.io.js"</span>></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="tag"><<span class="name">script</span>></span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript"> <span class="keyword">var</span> socket = <span class="title function_">io</span>(<span class="string">'http://localhost:3000'</span>);</span></span><br><span class="line"><span class="language-javascript"> <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">'button'</span>).<span class="property">onclick</span> = <span class="keyword">function</span>(<span class="params"></span>) {</span></span><br><span class="line"><span class="language-javascript"> socket.<span class="title function_">emit</span>(<span class="string">'add'</span>, {</span></span><br><span class="line"><span class="language-javascript"> <span class="string">'client'</span>: <span class="string">'我是客户端的数据'</span></span></span><br><span class="line"><span class="language-javascript"> })</span></span><br><span class="line"><span class="language-javascript"> }</span></span><br><span class="line"><span class="language-javascript"> <span class="comment">//监听服务端的广播</span></span></span><br><span class="line"><span class="language-javascript"> socket.<span class="title function_">on</span>(<span class="string">'to-client'</span>, <span class="keyword">function</span>(<span class="params">data</span>){</span></span><br><span class="line"><span class="language-javascript"> <span class="variable language_">console</span>.<span class="title function_">log</span>(data);</span></span><br><span class="line"><span class="language-javascript"> })</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag"></<span class="name">script</span>></span> </span><br><span class="line"><span class="tag"></<span class="name">html</span>></span></span><br></pre></td></tr></table></figure><h2 id="相关资料"><a href="#相关资料" class="headerlink" title="相关资料"></a>相关资料</h2><ul><li><a href="http://www.ruanyifeng.com/blog/2017/05/websocket.html">WebSocket 教程-阮一峰</a></li><li><a href="https://www.w3cschool.cn/socket/socket-1olq2egc.html">socket.io教程-w3c</a></li><li><a href="https://www.jianshu.com/p/9d8b2e42328c">Vue中使用Websocket</a></li></ul>]]></content>
<summary type="html">
<p>对 <code>WebSocket</code> 一种网络通信协议 的初步学习,记录。</p>
</summary>
<category term="请求" scheme="http://yoursite.com/categories/%E8%AF%B7%E6%B1%82/"/>
<category term="WebSocket" scheme="http://yoursite.com/tags/WebSocket/"/>
</entry>
<entry>
<title>vue-cli + nodejs + mongodb 基础</title>
<link href="http://yoursite.com/passages/vuecli+nodejs+mongodb/"/>
<id>http://yoursite.com/passages/vuecli+nodejs+mongodb/</id>
<published>2019-04-12T04:00:00.000Z</published>
<updated>2021-03-18T01:46:52.376Z</updated>
<content type="html"><![CDATA[<p>使用 <code>vue-cli</code> 搭建工程,配合 <code>nodejs + mongodb</code> 作为后端服务, 基本流程记录。</p><span id="more"></span><h2 id="环境准备"><a href="#环境准备" class="headerlink" title="环境准备"></a>环境准备</h2><ul><li>vue</li><li>nodejs</li><li>mongodb</li></ul><ol><li><p>下载安装 <code>mongodb</code> <a href="https://www.mongodb.com/download-center/community">mongodb下载</a><br>根据系统选择下载即可,下载 <code>.msi</code> 文件,按照提示安装即可,可以点击 <code>Custom(自定义)</code> 修改安装目录等。注: 安装过层中由于没有去掉 <code>install mongoDB compass</code> 的勾选,则会很慢,因为在下载安装这个 <code>GUI</code>.</p><p>启动:<code>cd E:\mongodb\bin></code>, 输入 <code>mongo.exe</code>,发现启动失败,输入 <code>mongod.exe</code>, 发现报错原因是缺少对应文件目录。原因是 <code>MongoDB 将数据目录存储在 db 目录下。但是这个数据目录不会主动创建,我们在安装完成后需要创建它。请注意,数据目录应该放在根目录下((如: C:\ 或者 D:\ 等 )。</code>。 这里则创建 <code>E:\data\db</code> 目录。</p><p>后续:命令行 <code>cd E:\mongodb\bin></code>, 输入 <code>mongod.exe</code>, 即发现启动正常,此时使用 <code>MongoDB Compass Community————GUI</code>, 可以正常连接。</p></li><li><p>集成 mongodb, <code>npm install mongoose --save</code>, 连接示例如下:</p> <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//配置mongoose</span></span><br><span class="line"><span class="keyword">var</span> mongoose = <span class="built_in">require</span>(<span class="string">"mongoose"</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">connectMongoose</span>(<span class="params">dbName</span>) {</span><br><span class="line"></span><br><span class="line"> <span class="comment">//连接数据库,createConnection支持多个数据库的连接</span></span><br><span class="line"> <span class="keyword">var</span> db = mongoose.<span class="title function_">createConnection</span>(<span class="string">'mongodb://localhost:27017/'</span> + dbName);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// connect 只能连接一个数据库,这里需要连接多个,不合适。</span></span><br><span class="line"> <span class="comment">// mongoose.connect("mongodb://localhost:27017/" + dbName);</span></span><br><span class="line"> <span class="comment">// const db = mongoose.connection;</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">//如果连接失败会执行error回调</span></span><br><span class="line"> db.<span class="title function_">once</span>(<span class="string">"error"</span>, <span class="keyword">function</span> (<span class="params">error</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"数据库 "</span> + dbName + <span class="string">" 连接失败:"</span> + error);</span><br><span class="line"> });</span><br><span class="line"> <span class="comment">//如果连接成功会执行open回调</span></span><br><span class="line"> db.<span class="title function_">once</span>(<span class="string">"open"</span>, <span class="keyword">function</span> (<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"数据库 "</span> + dbName + <span class="string">" 连接成功"</span>);</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="comment">//return mongoose;</span></span><br><span class="line"> <span class="keyword">return</span> db;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure></li><li><p>集成 nodejs (express), <code>npm install express --save</code>, 示例如下:</p> <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> express = <span class="built_in">require</span>(<span class="string">'express'</span>);</span><br><span class="line"><span class="keyword">var</span> path = <span class="built_in">require</span>(<span class="string">'path'</span>);</span><br><span class="line"><span class="keyword">var</span> bodyParser = <span class="built_in">require</span>(<span class="string">'body-parser'</span>); <span class="comment">//req.body本来为undefined, 引入此 body-parsing middleware</span></span><br><span class="line"><span class="keyword">var</span> cookieParser = <span class="built_in">require</span>(<span class="string">'cookie-parser'</span>); <span class="comment">//cookie格式化</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> app = <span class="title function_">express</span>();</span><br><span class="line">app.<span class="title function_">use</span>(bodyParser.<span class="title function_">json</span>()); <span class="comment">//for parsing application/json</span></span><br><span class="line">app.<span class="title function_">use</span>(bodyParser.<span class="title function_">urlencoded</span>({ <span class="attr">extended</span>: <span class="literal">true</span> })); <span class="comment">// for parsing application/x-www-form-urlencoded</span></span><br><span class="line">app.<span class="title function_">use</span>(<span class="title function_">cookieParser</span>());</span><br><span class="line"></span><br><span class="line"><span class="comment">//设置静态资源目录</span></span><br><span class="line">app.<span class="title function_">use</span>(express.<span class="title function_">static</span>(path.<span class="title function_">join</span>(__dirname, <span class="string">'../dist'</span>)));</span><br><span class="line"></span><br><span class="line"><span class="comment">//所有访问,都指定返回 index.html</span></span><br><span class="line">app.<span class="title function_">get</span>(<span class="string">'/*'</span>, <span class="keyword">function</span> (<span class="params">req, res</span>) {</span><br><span class="line"> res.<span class="title function_">sendFile</span>(path.<span class="title function_">join</span>(__dirname, <span class="string">'../dist'</span>, <span class="string">'index.html'</span>));</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="comment">//设置服务器</span></span><br><span class="line"><span class="keyword">var</span> server = app.<span class="title function_">listen</span>(<span class="number">3000</span>, <span class="keyword">function</span> (<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">var</span> host = server.<span class="title function_">address</span>().<span class="property">address</span>;</span><br><span class="line"> <span class="keyword">var</span> port = server.<span class="title function_">address</span>().<span class="property">port</span>;</span><br><span class="line"> <span class="comment">// eslint-disable-next-line no-console</span></span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">'server listening at http://%s:%s'</span>, host, port);</span><br><span class="line">});</span><br></pre></td></tr></table></figure></li></ol><h2 id="后续使用"><a href="#后续使用" class="headerlink" title="后续使用"></a>后续使用</h2><ol><li><p>首先为 <code>node</code> 服务收到请求,通过不同路由(也可以说是接口),连接不同的数据库,进行增删改查等等操作。</p> <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//node服务对应文件中添加路由</span></span><br><span class="line">app.<span class="title function_">use</span>(<span class="string">'/api/login'</span>, <span class="built_in">require</span>(<span class="string">'./routes/login'</span>));</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//路由文件,后端具体路由(接口)请求数据库,调用不同的方法</span></span><br><span class="line"><span class="keyword">var</span> express = <span class="built_in">require</span>(<span class="string">'express'</span>);</span><br><span class="line"><span class="keyword">var</span> router = express.<span class="title class_">Router</span>();</span><br><span class="line"><span class="keyword">var</span> admin = <span class="built_in">require</span>(<span class="string">'../mongodb/schemas/admin'</span>)</span><br><span class="line"></span><br><span class="line">router.<span class="title function_">post</span>(<span class="string">'/'</span>, <span class="keyword">function</span>(<span class="params">req, res, next</span>) {</span><br><span class="line"> admin.<span class="title function_">selectAdmin</span>(req.<span class="property">body</span>, <span class="keyword">function</span>(<span class="params">docs</span>) {</span><br><span class="line"> res.<span class="title function_">send</span>(docs);</span><br><span class="line"> })</span><br><span class="line">});</span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = router;</span><br><span class="line"></span><br><span class="line"><span class="comment">//具体对应数据库的操作,dao层</span></span><br><span class="line"><span class="keyword">var</span> connectMongoose = <span class="built_in">require</span>(<span class="string">"../mongoose"</span>).<span class="property">connectMongoose</span></span><br><span class="line"><span class="comment">//var mongoose = connectMongoose("admin");</span></span><br><span class="line"><span class="comment">//createConnection 创建的不能直接操作 schema, 仍需引入mongoose</span></span><br><span class="line"><span class="keyword">var</span> mongoose = <span class="built_in">require</span>(<span class="string">"mongoose"</span>);</span><br><span class="line"><span class="keyword">var</span> db = <span class="title function_">connectMongoose</span>(<span class="string">"admin"</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//定义一个 schema,描述此集合里有哪些字段,字段是什么类型</span></span><br><span class="line"><span class="comment">//只有schema中有的属性才能被保存到数据库中</span></span><br><span class="line"><span class="keyword">var</span> adminSchema = <span class="keyword">new</span> mongoose.<span class="title class_">Schema</span>({</span><br><span class="line"> account : { <span class="attr">type</span>: <span class="title class_">String</span> },</span><br><span class="line"> password : { <span class="attr">type</span>: <span class="title class_">String</span> },</span><br><span class="line"> time : { <span class="attr">type</span>: <span class="title class_">Date</span>, <span class="attr">default</span>: <span class="title class_">Date</span>.<span class="property">now</span> },</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> adminModel = db.<span class="title function_">model</span>(<span class="string">"person"</span>, adminSchema);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">selectAdmin</span>(<span class="params">data, callback</span>) {</span><br><span class="line"> adminModel.<span class="title function_">find</span>({</span><br><span class="line"> <span class="string">'account'</span>: {<span class="string">"$gte"</span>: data.<span class="property">account</span>, <span class="string">"$lte"</span>: data.<span class="property">account</span>},</span><br><span class="line"> <span class="string">'password'</span>: {<span class="string">"$gte"</span>: data.<span class="property">password</span>, <span class="string">"$lte"</span>: data.<span class="property">password</span>}</span><br><span class="line"> },</span><br><span class="line"> {<span class="attr">account</span>: <span class="number">1</span>, <span class="attr">password</span>: <span class="number">1</span>},</span><br><span class="line"> <span class="keyword">function</span>(<span class="params">err,docs</span>) {</span><br><span class="line"> <span class="title function_">callback</span>(docs);</span><br><span class="line"> })</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = {</span><br><span class="line"> <span class="string">"selectAdmin"</span> : selectAdmin</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>上述 <code>node->mongodb</code> 已走通, 下述从 <code>vue->node</code> 的流程。</p> <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//vue.config.js , 需要配置代理到node</span></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = {</span><br><span class="line"> <span class="attr">devServer</span>: {</span><br><span class="line"> <span class="attr">proxy</span>: {</span><br><span class="line"> <span class="string">"^/api"</span>: {</span><br><span class="line"> <span class="attr">target</span>: <span class="string">"http://localhost:3000"</span>,</span><br><span class="line"> <span class="attr">ws</span>: <span class="literal">true</span>,</span><br><span class="line"> <span class="attr">changeOrigin</span>: <span class="literal">true</span></span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//vue 文件</span></span><br><span class="line"><span class="keyword">import</span> {login} <span class="keyword">from</span> <span class="string">'@/request/api'</span>;</span><br><span class="line"><span class="keyword">async</span> <span class="title function_">login</span>(<span class="params">data</span>) {</span><br><span class="line"> <span class="keyword">let</span> res = <span class="keyword">await</span> <span class="title function_">login</span>(data);</span><br><span class="line">}</span><br><span class="line"><span class="variable language_">this</span>.<span class="title function_">login</span>(data);</span><br><span class="line"></span><br><span class="line"><span class="comment">//api.js</span></span><br><span class="line"><span class="keyword">import</span> {post} <span class="keyword">from</span> <span class="string">'./request'</span>;</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">login</span>(<span class="params">data</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">post</span>(<span class="string">'/api/login'</span>, data);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//request.js</span></span><br><span class="line"><span class="comment">//此处不做粘贴,是对 `axios` 的一个封装</span></span><br></pre></td></tr></table></figure></li><li><p>至此,<code>vue</code> 通过 <code>axios</code> 发送请求,然后被代理到 <code>node</code> 服务,通过 <code>express</code> 的 路由转发,去请求数据库做一些列操作,完成。</p></li></ol><h2 id="上述代码见项目"><a href="#上述代码见项目" class="headerlink" title="上述代码见项目"></a>上述代码见项目</h2><p><a href="https://github.com/zzugbb/vue/tree/master/my-manage-system">my-manage-system</a></p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://my.oschina.net/AndyShang/blog/865875">在vue-cli中引入mongodb数据库</a></li><li><a href="https://www.cnblogs.com/web-fengmin/p/6435681.html">mongoDB与mongoose</a></li><li><a href="https://blog.csdn.net/younglao/article/details/76443726">mongoose中connect()、createConnection()和connection的区别和作用</a></li><li><a href="https://mongoosejs.com/docs/api.html#mongoose_Mongoose">mongoose 官方 api</a></li></ul>]]></content>
<summary type="html">
<p>使用 <code>vue-cli</code> 搭建工程,配合 <code>nodejs + mongodb</code> 作为后端服务, 基本流程记录。</p>
</summary>
<category term="Vue" scheme="http://yoursite.com/categories/Vue/"/>
<category term="vue-cli" scheme="http://yoursite.com/tags/vue-cli/"/>
<category term="nodejs" scheme="http://yoursite.com/tags/nodejs/"/>
<category term="mongodb" scheme="http://yoursite.com/tags/mongodb/"/>
</entry>
<entry>
<title>个人手记(一)</title>
<link href="http://yoursite.com/passages/20190327%E4%B8%AA%E4%BA%BA%E6%89%8B%E8%AE%B0/"/>
<id>http://yoursite.com/passages/20190327个人手记/</id>
<published>2019-03-27T12:15:00.000Z</published>
<updated>2020-02-06T07:49:20.391Z</updated>
<content type="html"><![CDATA[<p>2019.3.27 随手记 <i class="fa fa-empire" aria-hidden="true"></i></p><span id="more"></span><h2 id="个人经历"><a href="#个人经历" class="headerlink" title="个人经历"></a>个人经历</h2><p>新的环境需要努力,加油!,不知所云~~~ <i class="fa fa-gratipay" aria-hidden="true"></i></p>]]></content>
<summary type="html">
<p>2019.3.27 随手记 <i class="fa fa-empire" aria-hidden="true"></i></p>
</summary>
<category term="手记" scheme="http://yoursite.com/categories/%E6%89%8B%E8%AE%B0/"/>
<category term="个人手记" scheme="http://yoursite.com/tags/%E4%B8%AA%E4%BA%BA%E6%89%8B%E8%AE%B0/"/>
</entry>
<entry>
<title>面试常见问题(二)</title>
<link href="http://yoursite.com/passages/%E9%9D%A2%E8%AF%95%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98%EF%BC%88%E4%BA%8C%EF%BC%89/"/>
<id>http://yoursite.com/passages/面试常见问题(二)/</id>
<published>2019-03-04T07:30:00.000Z</published>
<updated>2021-03-18T01:25:53.037Z</updated>
<content type="html"><![CDATA[<p>前端面试的常见问题记录, ajax, http && https, 响应式布局, cookie/session 等。</p><span id="more"></span><h2 id="AJAX"><a href="#AJAX" class="headerlink" title="AJAX"></a>AJAX</h2><h3 id="什么是-AJAX-?"><a href="#什么是-AJAX-?" class="headerlink" title="什么是 AJAX ?"></a>什么是 AJAX ?</h3><blockquote><p><code>AJAX</code> 全称为 <code>Asynchronous JavaScript and XML</code>(异步JavaScript和XML),是一种创建交互式网页应用的网页开发技术。</p></blockquote><ul><li>AJAX 不是新的编程语言,而是一种使用现有标准的新方法。</li><li>AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。</li><li>AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。</li></ul><h3 id="AJAX-的优点"><a href="#AJAX-的优点" class="headerlink" title="AJAX 的优点"></a>AJAX 的优点</h3><ol><li><code>无刷新更新数据</code>, 不刷新整个页面的前提下与服务器通信维护数据, 减少用户等待时间, 更好的用户体验。</li><li><code>异步与服务器通信</code>, 不需要打断用户的操作,具有更加迅速的响应能力</li><li><code>前端和后端负载平衡</code>, 最大程度的减少冗余请求和响应对服务器造成的负担,提升站点性能。</li><li><code>基于标准被广泛支持</code>。</li><li><code>界面与应用分离</code>, 有利于分工合作、减少非技术人员对页面的修改造成的WEB应用程序错误、提高效率、也更加适用于现在的发布系统。</li></ol><h3 id="AJAX-的缺点"><a href="#AJAX-的缺点" class="headerlink" title="AJAX 的缺点"></a>AJAX 的缺点</h3><ol><li><code>back和History,对浏览器机制的破坏</code>。</li><li><code>安全问题</code>, 跨站点脚步攻击、SQL注入攻击</li><li><code>对搜索引擎支持较弱</code></li><li><code>违背URL和资源定位的初衷</code></li><li>等…</li></ol><h2 id="Http-amp-amp-Https"><a href="#Http-amp-amp-Https" class="headerlink" title="Http && Https"></a>Http && Https</h2><h3 id="什么是-Http-Https-?"><a href="#什么是-Http-Https-?" class="headerlink" title="什么是 Http , Https ?"></a>什么是 Http , Https ?</h3><blockquote><p>HTTP(HyperText Transfer Protocol:超文本传输协议)是一种用于分布式、协作式和超媒体信息系统的应用层协议。 简单来说就是一种发布和接收 HTML 页面的方法,被用于在 Web 浏览器和网站服务器之间传递信息。</p></blockquote><blockquote><p>HTTPS(Hypertext Transfer Protocol Secure:超文本传输安全协议)是一种透过计算机网络进行安全通信的传输协议。HTTPS 经由 HTTP 进行通信,但利用 SSL/TLS 来加密数据包。HTTPS 开发的主要目的,是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。</p></blockquote><h3 id="Http-Https-区别?"><a href="#Http-Https-区别?" class="headerlink" title="Http , Https 区别?"></a>Http , Https 区别?</h3><ul><li>HTTP 明文传输,数据都是未加密的,安全性较差,HTTPS(SSL+HTTP) 数据传输过程是加密的,安全性较好。</li><li>使用 HTTPS 协议需要到 CA(Certificate Authority,数字证书认证机构) 申请证书,一般免费证书较少,因而需要一定费用。证书颁发机构如:Symantec、Comodo、GoDaddy 和 GlobalSign 等。</li><li>HTTP 页面响应速度比 HTTPS 快,主要是因为 HTTP 使用 TCP 三次握手建立连接,客户端和服务器需要交换 3 个包,而 HTTPS除了 TCP 的三个包,还要加上 ssl 握手需要的 9 个包,所以一共是 12 个包。</li><li>http 和 https 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。</li><li>HTTPS 其实就是建构在 SSL/TLS 之上的 HTTP 协议,所以,HTTPS 比 HTTP 要更耗费服务器资源。</li></ul><h2 id="cookie-session"><a href="#cookie-session" class="headerlink" title="cookie, session"></a>cookie, session</h2><p><code>cookie</code> 机制采用的是在 <code>客户端保持状态</code> 的方案,而 <code>session</code> 机制采用的是在 <code>服务器端保持状态</code> 的方案。</p><blockquote><p>Cookie 是一些数据, 存储于你电脑上的文本文件中, 当 web 服务器向浏览器发送 web 页面时,在连接关闭后,服务端不会记录用户的信息。</p></blockquote><p>Cookie 的作用就是用于解决 “如何记录客户端的用户信息”:</p><ul><li>当用户访问 web 页面时,他的名字可以记录在 cookie 中。</li><li>在用户下一次访问该页面时,可以在 cookie 中读取用户访问记录。</li></ul><blockquote><p>Session 是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上, 这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。</p></blockquote><h2 id="响应式布局"><a href="#响应式布局" class="headerlink" title="响应式布局"></a>响应式布局</h2><blockquote><p><code>响应式布局</code> 意在实现不同屏幕分辨率的终端上浏览网页的不同展示方式。通过响应式设计能使网站在手机和平板电脑上有更好的浏览阅读体验。</p></blockquote><blockquote><p><code>RWD-响应式网站设计</code> (简称RWD)是一种新的网站设计模式,以此构建的网站可自动适应不同的访问设备(从桌面电脑、平板电脑到智能手机),方便用户阅读和导航浏览,减少用户的放大/缩小/滑动操作,从而提供完整而友好的用户体验。</p></blockquote><h3 id="RWD-关键"><a href="#RWD-关键" class="headerlink" title="RWD 关键"></a>RWD 关键</h3><ol><li><code>media query</code>, 基于 RWD 设计的网站利用CSS3 media query规则来自动适应不同访问设备的屏幕尺寸和显示要求.</li><li><code>流动网格</code>, 采用页面元素大小的相对单位(百分比或EM),而非传统设计使用的绝对单位(像素或点数),以确定页面各组成元素的大小.</li><li><code>灵活缩放的图片</code>, 不至于在小屏幕的移动设备上超出显示区域.</li></ol><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://www.cnblogs.com/yelp/p/3725664.html">AJAX工作原理及其优缺点</a></li><li><a href="http://www.runoob.com/w3cnote/http-vs-https.html">HTTP 与 HTTPS 的区别</a></li><li><a href="https://www.jianshu.com/p/6baa79ab9393">响应式网页设计</a></li></ul>]]></content>
<summary type="html">
<p>前端面试的常见问题记录, ajax, http &amp;&amp; https, 响应式布局, cookie/session 等。</p>
</summary>
<category term="面试" scheme="http://yoursite.com/categories/%E9%9D%A2%E8%AF%95/"/>
<category term="HTTPS" scheme="http://yoursite.com/tags/HTTPS/"/>
<category term="AJAX" scheme="http://yoursite.com/tags/AJAX/"/>
<category term="cookie/session" scheme="http://yoursite.com/tags/cookie-session/"/>
<category term="响应式布局" scheme="http://yoursite.com/tags/%E5%93%8D%E5%BA%94%E5%BC%8F%E5%B8%83%E5%B1%80/"/>
</entry>
<entry>
<title>Mocha-单元测试</title>
<link href="http://yoursite.com/passages/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95-Mocha/"/>
<id>http://yoursite.com/passages/单元测试-Mocha/</id>
<published>2019-02-28T02:00:00.000Z</published>
<updated>2020-02-06T07:49:20.480Z</updated>
<content type="html"><![CDATA[<p>前端开发过程中,测试有着非常重要的角色, 分为 <code>单元测试</code>, <code>功能测试</code>, 等等,本文主要记录对 <code>单元测试框架-Mocha</code> 的学习。</p><span id="more"></span><h2 id="关于-Mocha"><a href="#关于-Mocha" class="headerlink" title="关于 Mocha"></a>关于 Mocha</h2><blockquote><p><code>Mocha</code> 是 <code>JavaScript</code> 的一种单元测试框架,既可以在 <code>浏览器</code> 环境下运行,也可以在 <code>Node.js</code> 环境下运行。使用 <code>Mocha</code> ,我们就只需要专注于编写单元测试本身,然后,让 <code>Mocha</code> 去自动运行所有的测试,并给出测试结果。</p></blockquote><p>Mocha 的特点:</p><ul><li>既可以测试简单的JavaScript函数,又可以测试异步代码,因为异步是JavaScript的特性之一;</li><li>可以自动运行所有测试,也可以只运行特定的测试;</li><li>可以支持before、after、beforeEach和afterEach来编写初始化代码。</li></ul><h2 id="Mocha-的使用"><a href="#Mocha-的使用" class="headerlink" title="Mocha 的使用"></a>Mocha 的使用</h2><h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 全局安装</span></span><br><span class="line">npm install mocha -g</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装 mocha</span></span><br><span class="line">npm install --save-dev mocha</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装chai-断言 也可选择其它</span></span><br><span class="line">npm install --save-dev chai</span><br></pre></td></tr></table></figure><h3 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h3><p><code>add.js</code></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">add</span>(<span class="params">x, y</span>) {</span><br><span class="line"> <span class="keyword">return</span> x + y;</span><br><span class="line">}</span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = add;</span><br></pre></td></tr></table></figure><p>测试脚本 <code>add.test.js</code></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> add = <span class="built_in">require</span>(<span class="string">'./add.js'</span>);</span><br><span class="line"><span class="keyword">var</span> expect = <span class="built_in">require</span>(<span class="string">'chai'</span>).<span class="property">expect</span>;</span><br><span class="line"></span><br><span class="line"><span class="title function_">describe</span>(<span class="string">'加法函数的测试'</span>, <span class="keyword">function</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="title function_">it</span>(<span class="string">'1 加 1 应该等于 2'</span>, <span class="keyword">function</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="title function_">expect</span>(<span class="title function_">add</span>(<span class="number">1</span>, <span class="number">1</span>)).<span class="property">to</span>.<span class="property">be</span>.<span class="title function_">equal</span>(<span class="number">2</span>);</span><br><span class="line"> });</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p>测试脚本与所要测试的源码脚本同名,但是后缀名为 <code>.test.js</code>(表示测试).</p><p>测试脚本里面应该包括一个或多个 <code>describe</code> 块,每个 <code>describe</code> 块应该包括一个或多个 <code>it</code> 块。</p><p><code>describe</code> 块称为”测试套件”(test suite),表示一组相关的测试。它是一个函数,第一个参数是测试套件的名称(”加法函数的测试”),第二个参数是一个实际执行的函数。</p><p><code>it</code> 块称为”测试用例”(test case),表示一个单独的测试,是测试的最小单位。它也是一个函数,第一个参数是测试用例的名称(”1 加 1 应该等于 2”),第二个参数是一个实际执行的函数。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//断言</span></span><br><span class="line"><span class="title function_">expect</span>(<span class="title function_">add</span>(<span class="number">1</span>, <span class="number">1</span>)).<span class="property">to</span>.<span class="property">be</span>.<span class="title function_">equal</span>(<span class="number">2</span>)</span><br></pre></td></tr></table></figure><p>所谓”断言”,就是判断源码的实际执行结果与预期结果是否一致,如果不一致就抛出一个错误。上面这句断言的意思是,调用add(1, 1),结果应该等于2。</p><p>所有的测试用例( <code>it</code> 块)都应该含有一句或多句的断言。它是编写测试用例的关键。断言功能由断言库来实现,Mocha本身不带断言库,所以必须先引入断言库。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> expect = <span class="built_in">require</span>(<span class="string">'chai'</span>).<span class="property">expect</span>;</span><br></pre></td></tr></table></figure><p>断言库有很多种,Mocha并不限制使用哪一种。上面代码引入的断言库是 <code>chai</code>,并且指定使用它的 <code>expect</code> 断言风格.</p><h3 id="使用命令"><a href="#使用命令" class="headerlink" title="使用命令"></a>使用命令</h3><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">"scripts"</span><span class="punctuation">:</span> <span class="punctuation">{</span></span><br><span class="line"> <span class="attr">"test"</span><span class="punctuation">:</span> <span class="string">"mocha"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"test-all"</span> <span class="punctuation">:</span> <span class="string">"mocha --recursive"</span><span class="punctuation">,</span></span><br><span class="line"> <span class="attr">"test-js"</span><span class="punctuation">:</span> <span class="string">"mocha *.test.js"</span></span><br><span class="line"><span class="punctuation">}</span><span class="punctuation">,</span></span><br></pre></td></tr></table></figure><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">npm <span class="built_in">test</span> <span class="comment"># Mocha 默认运行 test 子目录里面的测试脚本, test目录的子目录里面的测试脚本不会运行</span></span><br><span class="line">npm run test-all <span class="comment"># Mocha 默认运行 test 子目录里面的测试脚本, test下所有,包含子目录</span></span><br><span class="line">npm run test-js <span class="comment"># Mocha 运行所有根目录下 以 .test.js 的测试脚本</span></span><br></pre></td></tr></table></figure><h3 id="关于异步"><a href="#关于异步" class="headerlink" title="关于异步"></a>关于异步</h3><p><code>Mocha</code> 默认每个测试用例最多执行 <code>2000</code> 毫秒.</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 改变默认的超时设置</span></span><br><span class="line">mocha -t 5000 timeout.test.js</span><br></pre></td></tr></table></figure><p><code>Mocha</code> 内置对 <code>Promise</code> 的支持,允许直接返回 <code>Promise</code>,等到它的状态改变,再执行断言,而不用显式调用 <code>done</code> 方法。</p><h3 id="测试用例的钩子"><a href="#测试用例的钩子" class="headerlink" title="测试用例的钩子"></a>测试用例的钩子</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">describe</span>(<span class="string">'hooks'</span>, <span class="keyword">function</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="title function_">before</span>(<span class="keyword">function</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="comment">// 在本区块的所有测试用例之前执行</span></span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="title function_">after</span>(<span class="keyword">function</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="comment">// 在本区块的所有测试用例之后执行</span></span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="title function_">beforeEach</span>(<span class="keyword">function</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="comment">// 在本区块的每个测试用例之前执行</span></span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="title function_">afterEach</span>(<span class="keyword">function</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="comment">// 在本区块的每个测试用例之后执行</span></span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="comment">// test cases</span></span><br><span class="line">});</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="测试用例管理"><a href="#测试用例管理" class="headerlink" title="测试用例管理"></a>测试用例管理</h3><p>大型项目有很多测试用例, 有时,我们希望只运行其中的几个,这时可以用 <code>only</code> 方法。<code>describe</code> 块和 <code>it</code> 块都允许调用 <code>only</code> 方法,表示只运行某个测试套件或测试用例。</p><p>此外,还有 <code>skip</code> 方法,表示跳过指定的测试套件或测试用例。</p><h2 id="断言"><a href="#断言" class="headerlink" title="断言"></a>断言</h2><blockquote><p>所谓”断言”,就是判断源码的实际执行结果与预期结果是否一致.</p></blockquote><p>所有的测试用例(it块)都应该含有一句或多句的断言, 它是编写测试用例的关键。断言功能由断言库来实现,Mocha本身不带断言库,所以必须先引入断言库。</p><p>断言库有很多种,Mocha并不限制使用哪一种。上面代码引入的断言库是 <code>chai</code>,并且指定使用它的 <code>expect</code> 断言风格。</p><p>基本上,<code>expect</code> 断言的写法都是一样的。头部是 <code>expect</code> 方法,尾部是 断言方法,比如 <code>equal、a/an、ok、match</code> 等。两者之间使用 <code>to</code> 或<code>to.be</code> 连接。</p><h2 id="具体demo"><a href="#具体demo" class="headerlink" title="具体demo"></a>具体demo</h2><ul><li><a href="https://github.com/zzugbb/js-test/tree/master/Mocha-demo">Mocha-demo</a></li></ul><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/00147203593334596b366f3fe0b409fbc30ad81a0a91c4a000">廖雪峰的官方网站-mocha</a></li><li><a href="https://github.com/ruanyf/jstraining/blob/master/demos/README.md#mocha">JavaScript 全栈工程师培训教程-Mocha-阮一峰</a></li><li><a href="https://www.jianshu.com/p/52b8aabe51dc">javascript单元测试-mocha</a></li><li><a href="https://mochajs.org/">mocha-官网</a></li><li><a href="https://www.chaijs.com/">chai-官网</a></li></ul>]]></content>
<summary type="html">
<p>前端开发过程中,测试有着非常重要的角色, 分为 <code>单元测试</code>, <code>功能测试</code>, 等等,本文主要记录对 <code>单元测试框架-Mocha</code> 的学习。</p>
</summary>
<category term="测试" scheme="http://yoursite.com/categories/%E6%B5%8B%E8%AF%95/"/>
<category term="Mocha" scheme="http://yoursite.com/tags/Mocha/"/>
<category term="单元测试" scheme="http://yoursite.com/tags/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/"/>
</entry>
<entry>
<title>Travis CI (持续集成)</title>
<link href="http://yoursite.com/passages/Travis%20CI/"/>
<id>http://yoursite.com/passages/Travis CI/</id>
<published>2019-02-26T10:00:00.000Z</published>
<updated>2020-02-06T07:49:20.423Z</updated>
<content type="html"><![CDATA[<blockquote><p><code>持续集成</code>(英语:Continuous integration,缩写 CI)是一种软件工程流程,是将所有软件工程师对于软件的工作副本持续集成到共享主线(mainline)的一种举措。</p></blockquote><span id="more"></span><h2 id="持续集成"><a href="#持续集成" class="headerlink" title="持续集成"></a>持续集成</h2><blockquote><p><code>持续集成</code>(英语:Continuous integration,缩写 CI)是一种软件工程流程,是将所有软件工程师对于软件的工作副本持续集成到共享主线(mainline)的一种举措。</p></blockquote><p><img src="https://travis-ci.org/zzugbb/my-gitbook.svg?branch=master" alt="build:passed"></p><h2 id="具体实战"><a href="#具体实战" class="headerlink" title="具体实战"></a>具体实战</h2><p><a href="https://zzugbb.github.io/my-gitbook/CI.html">gitbook 使用 Travis CI 实现自动部署</a></p><p><a href="https://zzugbb.github.io/my-gitbook/">gitbook 使用 – my-gitbook</a></p><p><a href="https://github.com/zzugbb/my-gitbook">my-gitbook</a></p>]]></content>
<summary type="html">
<blockquote>
<p><code>持续集成</code>(英语:Continuous integration,缩写 CI)是一种软件工程流程,是将所有软件工程师对于软件的工作副本持续集成到共享主线(mainline)的一种举措。</p>
</blockquote>
</summary>
<category term="工程部署" scheme="http://yoursite.com/categories/%E5%B7%A5%E7%A8%8B%E9%83%A8%E7%BD%B2/"/>
<category term="持续集成" scheme="http://yoursite.com/tags/%E6%8C%81%E7%BB%AD%E9%9B%86%E6%88%90/"/>
<category term="Travis CI" scheme="http://yoursite.com/tags/Travis-CI/"/>
</entry>
<entry>
<title>面试常见问题(一)</title>
<link href="http://yoursite.com/passages/%E9%9D%A2%E8%AF%95%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98%EF%BC%88%E4%B8%80%EF%BC%89/"/>
<id>http://yoursite.com/passages/面试常见问题(一)/</id>
<published>2019-02-26T03:00:00.000Z</published>
<updated>2020-02-06T07:49:20.488Z</updated>
<content type="html"><![CDATA[<p>前端面试的常见问题记录,闭包,继承</p><span id="more"></span><h2 id="JavaScript-闭包"><a href="#JavaScript-闭包" class="headerlink" title="JavaScript 闭包"></a>JavaScript 闭包</h2><blockquote><p><code>闭包</code> 是指有权访问另一个函数作用域中的变量的函数(能够读取其他函数内部变量的函数)。创建闭包的常见方式,就是在一个函数内部创建另一个函数。</p></blockquote><p>一个函数的返回值是另一个函数,而返回的这个函数如果调用了其父函数内部的其它变量,且返回的这个函数在外部被执行,就产生了闭包。</p><p>表现形式: 函数外部能调用函数内部定义的变量。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">makeFunc</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">var</span> name = <span class="string">"Mozilla"</span>;</span><br><span class="line"> <span class="keyword">function</span> <span class="title function_">displayName</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="title function_">alert</span>(name);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> displayName; <span class="comment">//返回的displayName函数就是闭包</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> myFunc = <span class="title function_">makeFunc</span>(); <span class="comment">//myFunc 是执行 makeFunc 时创建的 displayName 函数实例的引用</span></span><br><span class="line"><span class="title function_">myFunc</span>();</span><br></pre></td></tr></table></figure><p>注意:</p><ul><li>滥用闭包会导致内存泄露,处理方法:在退出函数之前,将不使用的局部变量全部删除。</li><li>闭包会在父函数外部,改变父函数内部变量的值。</li></ul><h3 id="闭包的用途"><a href="#闭包的用途" class="headerlink" title="闭包的用途"></a>闭包的用途</h3><p><strong>1. 封装</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> person = <span class="keyword">function</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">var</span> name = <span class="string">"default"</span>; <span class="comment">//变量作用域为函数内部,外部无法访问</span></span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> getName : <span class="keyword">function</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> name;</span><br><span class="line"> },</span><br><span class="line"> setName : <span class="keyword">function</span>(<span class="params">newName</span>) {</span><br><span class="line"> name = newName;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}();</span><br><span class="line"></span><br><span class="line"><span class="title function_">print</span>(person.<span class="property">name</span>); <span class="comment">//直接访问,结果为undefined</span></span><br><span class="line"><span class="title function_">print</span>(person.<span class="title function_">getName</span>());</span><br><span class="line">person.<span class="title function_">setName</span>(<span class="string">"abruzzi"</span>);</span><br><span class="line"><span class="title function_">print</span>(person.<span class="title function_">getName</span>());</span><br><span class="line"></span><br><span class="line">得到结果如下:</span><br><span class="line"><span class="literal">undefined</span> </span><br><span class="line"><span class="keyword">default</span> </span><br><span class="line">abruzzi</span><br></pre></td></tr></table></figure><p><strong>2. 实现类和继承</strong></p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">var</span> name = <span class="string">"default"</span>;</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> getName : <span class="keyword">function</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="keyword">return</span> name;</span><br><span class="line"> },</span><br><span class="line"> setName : <span class="keyword">function</span>(<span class="params">newName</span>) {</span><br><span class="line"> name = newName;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> <span class="title class_">Jack</span> = <span class="keyword">function</span>(<span class="params"></span>){};</span><br><span class="line"><span class="title class_">Jack</span>.<span class="property"><span class="keyword">prototype</span></span> = <span class="keyword">new</span> <span class="title class_">Person</span>(); <span class="comment">//继承自Person</span></span><br><span class="line"><span class="title class_">Jack</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">Say</span> = <span class="keyword">function</span>(<span class="params"></span>) { <span class="comment">//添加私有方法</span></span><br><span class="line"> <span class="title function_">alert</span>(<span class="string">"Hello,my name is Jack"</span>);</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> j = <span class="keyword">new</span> <span class="title class_">Jack</span>();</span><br><span class="line">j.<span class="title function_">setName</span>(<span class="string">"Jack"</span>);</span><br><span class="line"><span class="title function_">alert</span>(j.<span class="title function_">getName</span>());</span><br><span class="line">j.<span class="title class_">Say</span>();</span><br></pre></td></tr></table></figure><h2 id="JavaScript-继承"><a href="#JavaScript-继承" class="headerlink" title="JavaScript 继承"></a>JavaScript 继承</h2><ul><li>构造函数继承</li><li>原型链式继承</li><li>组合式继承(借用构造函数和原型链继承两种方式)</li><li>等等…</li></ul><h2 id="参考文档"><a href="#参考文档" class="headerlink" title="参考文档"></a>参考文档</h2><ul><li><a href="http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html">学习Javascript闭包-阮一峰</a></li><li><a href="http://www.cnblogs.com/yunfeifei/p/4019504.html">全面理解Javascript闭包和闭包的几种写法及用途</a></li><li><a href="http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html">Javascript 面向对象编程(一):封装-阮一峰</a></li><li><a href="http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html">Javascript面向对象编程(二):构造函数的继承-阮一峰</a></li><li><a href="http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance_continued.html">Javascript面向对象编程(三):非构造函数的继承-阮一峰</a></li><li><a href="https://www.imooc.com/article/20162">前端面试必备之JS继承方式总结</a></li><li><a href="https://www.cnblogs.com/humin/p/4556820.html">JS实现继承的几种方式</a></li></ul>]]></content>
<summary type="html">
<p>前端面试的常见问题记录,闭包,继承</p>
</summary>
<category term="面试" scheme="http://yoursite.com/categories/%E9%9D%A2%E8%AF%95/"/>
<category term="闭包" scheme="http://yoursite.com/tags/%E9%97%AD%E5%8C%85/"/>
<category term="继承" scheme="http://yoursite.com/tags/%E7%BB%A7%E6%89%BF/"/>
</entry>
<entry>
<title>Vue生命周期</title>
<link href="http://yoursite.com/passages/Vue%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/"/>
<id>http://yoursite.com/passages/Vue生命周期/</id>
<published>2019-02-22T07:40:00.000Z</published>
<updated>2021-03-18T01:47:05.125Z</updated>
<content type="html"><![CDATA[<p>学习 <code>vue</code> 过程中, 生命周期是其中的一个很重要的概念,简单记录。</p><span id="more"></span><h2 id="Vue-官方供图"><a href="#Vue-官方供图" class="headerlink" title="Vue 官方供图"></a>Vue 官方供图</h2><p><img src="/images/vue-lifecycle.png"/></p><h2 id="钩子函数"><a href="#钩子函数" class="headerlink" title="钩子函数"></a>钩子函数</h2><p>创建=>挂载=>更新=>销毁</p><ul><li>beforeCreate</li><li>created</li><li>beforeMount</li><li>mounted</li><li>beforeUpdate</li><li>updated</li><li>beforeDestroy</li><li>destroyed</li></ul><h3 id="beforeCreate-前"><a href="#beforeCreate-前" class="headerlink" title="beforeCreate 前"></a>beforeCreate 前</h3><p>实例创建,执行 <code>init</code> 初始化。</p><h3 id="created-前"><a href="#created-前" class="headerlink" title="created 前"></a>created 前</h3><p>进行数据观测,事件初始化,在 <code>created</code> 之前数据已经绑定,但此时没有 el 选项。</p><p>主要应用:调用数据,调用方法,调用异步函数。</p><h3 id="beforeMount-前"><a href="#beforeMount-前" class="headerlink" title="beforeMount 前"></a>beforeMount 前</h3><p>在挂载开始之前被调用:相关的 render 函数(模板)首次被调用。</p><p>通过v-for生成的html还没有被挂载到页面上</p><h3 id="mounted-前"><a href="#mounted-前" class="headerlink" title="mounted 前"></a>mounted 前</h3><p><code>vue</code> 实例对象添加 <code>$el</code> 成员,并且替换掉DOM元素</p><h3 id="beforeUpdate-amp-amp-updated"><a href="#beforeUpdate-amp-amp-updated" class="headerlink" title="beforeUpdate && updated"></a>beforeUpdate && updated</h3><p>当 vue 发现 data 中的数据发生了改变,会触发对应组件的重新渲染,先后调用 <code>beforeUpdate</code> 和 <code>updated</code> 钩子函数.</p><h3 id="beforeDestroy-amp-amp-destroyed"><a href="#beforeDestroy-amp-amp-destroyed" class="headerlink" title="beforeDestroy && destroyed"></a>beforeDestroy && destroyed</h3><p><code>beforeDestroy</code> 钩子函数在实例销毁之前调用。在这一步,实例仍然完全可用。</p><p><code>destroyed</code>钩子函数在 Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。</p><h3 id="补充-mount"><a href="#补充-mount" class="headerlink" title="补充 $mount"></a>补充 $mount</h3><p>当 vue 没有挂载 el 时,我们可以用 $mount</p>]]></content>
<summary type="html">
<p>学习 <code>vue</code> 过程中, 生命周期是其中的一个很重要的概念,简单记录。</p>
</summary>
<category term="Vue" scheme="http://yoursite.com/categories/Vue/"/>
<category term="vue" scheme="http://yoursite.com/tags/vue/"/>
<category term="生命周期" scheme="http://yoursite.com/tags/%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/"/>
</entry>
<entry>
<title>编程范式</title>
<link href="http://yoursite.com/passages/%E7%BC%96%E7%A8%8B%E6%96%B9%E5%BC%8F/"/>
<id>http://yoursite.com/passages/编程方式/</id>
<published>2019-01-30T08:40:00.000Z</published>
<updated>2019-02-11T12:01:26.070Z</updated>
<content type="html"><![CDATA[<p>日常学习工作中,经常会提到 <code>编程范式</code> , 面向对象编程, 面向过程编程, 函数式编程,响应式编程,等等,对这些内容简单记录</p><span id="more"></span><h2 id="面向过程编程"><a href="#面向过程编程" class="headerlink" title="面向过程编程"></a>面向过程编程</h2><p><code>面向过程</code> (Procedure Oriented) 是一种以过程为中心的编程思想。这些都是以什么正在发生为主要目标进行编程,不同于面向对象的是谁在受影响。与面向对象明显的不同就是封装、继承、类。</p><p>面向过程是具体的东西,是一种基础的方法,它考虑的是实际的实现, 而且面向过程是面向对象的基础。</p><p>典型代表: C</p><h2 id="面向对象编程"><a href="#面向对象编程" class="headerlink" title="面向对象编程"></a>面向对象编程</h2><p><code>面向对象程序设计</code> (Object Oriented Programming) 作为一种新方法,其本质是以建立模型体现出来的抽象思维过程和面向对象的方法。模型是用来反映现实世界中事物特征的。任何一个模型都不可能反映客观事物的一切具体特征,只能对事物特征和变化规律的一种抽象,且在它所涉及的范围内更普遍、更集中、更深刻地描述客体的特征。通过建立模型而达到的抽象是人们对客体认识的深化</p><p>面向对象的方法主要是把事物给对象化,包括其属性和行为。</p><p>典型代表: Java</p><h2 id="函数式编程"><a href="#函数式编程" class="headerlink" title="函数式编程"></a>函数式编程</h2><p><code>函数式编程</code> 是种编程方式,它将电脑运算视为函数的计算。函数编程语言最重要的基础是λ演算(lambda calculus),而且λ演算的函数可以接受函数当作输入(参数)和输出(返回值), 属于”结构化编程”的一种,主要思想是把运算过程尽量写成一系列嵌套的函数调用</p><p>和指令式编程相比,函数式编程强调函数的计算比指令的执行重要。</p><p>和过程化编程相比,函数式编程里函数的计算可随时调用。</p><p>函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。</p><p>函数式编程的一个特点就是,允许把函数本身作为 <code>参数</code> 传入另一个函数,还允许 <code>返回一个函数</code></p><p>代表: scala python (不是纯函数式编程语言)</p><h2 id="响应式编程"><a href="#响应式编程" class="headerlink" title="响应式编程"></a>响应式编程</h2><p>简称RP(Reactive Programming)</p><p><code>响应式编程</code> 是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。</p><p>例如,在命令式编程环境中,a:=b+c表示将表达式的结果赋给a,而之后改变b或c的值不会影响a。但在响应式编程中,a的值会随着b或c的更新而更新。</p><p>电子表格程序就是响应式编程的一个例子。单元格可以包含字面值或类似”=B1+C1”的公式,而包含公式的单元格的值会依据其他单元格的值的变化而变化</p><h2 id="声明式编程"><a href="#声明式编程" class="headerlink" title="声明式编程"></a>声明式编程</h2><p>告诉机器你想要的是什么 <code>what</code>,让机器想出如何去做(how)</p><h2 id="命令式编程"><a href="#命令式编程" class="headerlink" title="命令式编程"></a>命令式编程</h2><p>命令机器如何去做事情 <code>how</code> ,这样不管你想要的是什么(what),它都会按照你的命令实现。</p><h2 id="面向切面编程"><a href="#面向切面编程" class="headerlink" title="面向切面编程"></a>面向切面编程</h2><p>Aspect Oriented Programming(AOP),面向切面编程。</p><p>AOP的编程,好像就是把我们在某个方面的功能提出来与一批对象进行隔离,这样与一批对象之间降低了耦合性,可以就某个功能进行编程。</p><p>AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386819866394c3f9efcd1a454b2a8c57933e976445c0000">函数式编程-廖雪峰</a></li></ul>]]></content>
<summary type="html">
<p>日常学习工作中,经常会提到 <code>编程范式</code> , 面向对象编程, 面向过程编程, 函数式编程,响应式编程,等等,对这些内容简单记录</p>
</summary>
<category term="编程范式" scheme="http://yoursite.com/categories/%E7%BC%96%E7%A8%8B%E8%8C%83%E5%BC%8F/"/>
<category term="编程范式" scheme="http://yoursite.com/tags/%E7%BC%96%E7%A8%8B%E8%8C%83%E5%BC%8F/"/>
</entry>
</feed>