-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.xml
More file actions
1220 lines (1027 loc) · 122 KB
/
index.xml
File metadata and controls
1220 lines (1027 loc) · 122 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
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>老崔博客</title>
<link>http://ijs.me/</link>
<description>Recent content on 老崔博客</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Thu, 24 Sep 2020 21:38:58 +0800</lastBuildDate>
<atom:link href="http://ijs.me/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>前端路由原理</title>
<link>http://ijs.me/2020/09/24/spa-router/</link>
<pubDate>Thu, 24 Sep 2020 21:38:58 +0800</pubDate>
<guid>http://ijs.me/2020/09/24/spa-router/</guid>
<description>现在我们稍微复杂一点的单页面应用(SPA),都需要路由, vue-router 也是 Vue 全家桶的标配之一。vue-router 默认 hash 模式,如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。
网页 url 组成部分:
// http://127.0.0.1:8881/01-hash.html?a=100&amp;b=20#/aaa/bbb location.protocol // 'http:' location.hostname // '127.0.0.1' location.host // '127.0.0.1:8881' location.port // '8881' location.pathname // '/01-hash.html' location.search // '?a=100&amp;b=20' location.hash // '#/aaa/bbb' hash 模式 hash 的特点:
hash 变化会触发网页跳转,即浏览器的前进、后退 hash 变化不会刷新页面,SPA 必需的特点 hash 永远不会提交到 server 端(前端自生自灭) &lt;p&gt;hash test&lt;p&gt; &lt;button id=&quot;btn1&quot;&gt;修改 hash&lt;/button&gt; &lt;script&gt; // hash 变化,包括: // a.</description>
</item>
<item>
<title>详解 Vue 原理</title>
<link>http://ijs.me/2020/09/01/explain-vue-principle/</link>
<pubDate>Tue, 01 Sep 2020 06:32:40 +0800</pubDate>
<guid>http://ijs.me/2020/09/01/explain-vue-principle/</guid>
<description>组件化和 MVVM 模式 组件化其实很久以前就有的概念,Vue 也是把这个概念借鉴了过来,允许我们使用小型、独立和通常可复用的组件构建大型应用。传统组件,只是静态渲染,更新还要依赖于操作 DOM,而 Vue 和 React 这种现代话框架则是采用数据驱动视图的方式,Vue 是采用 MVVM 模式来实现,React 是通过 setState 来实现的。所谓数据驱动视图就是我们不再直接操作 Dom,想改页面上的什么东西,直接更改 Vue 或 React 里的数据就行了,Vue 和 React 框架本身根据数据来帮我们重新渲染视图,这使得我们的开发更加关注于数据和业务逻辑,降低程序开发的复杂度,使得出现了很多富客户端应用,所谓富客户端就是页面的功能非常复杂,具有很强交互性来给客户提供更高和更全方位的体验。
Vue 的 MVVM 模式如下图所示:View 就是视图,也就是页面上的 DOM。Model 就是模型,可以理解为 Vue 组件里面的 Data,或者 Vuex 里面的数据。这两者之间通过 ViewModel 这一层来做关联,比如监听事件,通过 ViewModel 这一层,我们在 Model 修改时,就能执行页面渲染。而 View 这一层里面比如点击事件,各种 Dom 事件触发时就能修改 Model 这一层里面的数据。这就是数据驱动视图,不用直接操作视图,而是通过修改数据来操作的。MVVM 第一个 M 对应着Model,第二个字母 V 对应着 View,最后两个字母 VM 对应着 ViewModel。
Vue 响应式 监听 data 变化 我们知道 Vue 组件 data 的数据一旦变化,立刻触发视图的更新。首先我们要如何知道 data 是发生了变化呢?实现数据驱动视图的第一步就是当 data 发生了变化,我们怎样第一时间知道?</description>
</item>
<item>
<title>VS Code 搜索排除</title>
<link>http://ijs.me/2019/08/07/vscode-search-exclude/</link>
<pubDate>Wed, 07 Aug 2019 11:39:03 +0800</pubDate>
<guid>http://ijs.me/2019/08/07/vscode-search-exclude/</guid>
<description>我们在使用 VS Code 的全局搜索时,比如全局搜索一个前端项目,竟然会带上打包后的 /dist, /node_modules 等目录一起搜索,这样会带来很多无关的搜索结果,而且还会让 VS Code 程序卡死,我们可以使用 VS Code 的搜索排除功能来解决这个问题。
我们可以以一个项目为中心来决定搜索时排除哪些文件夹,打开 Workspace 的 settings.json 文件,在该文件中加入下列内容:
{ // 搜索排除 &quot;search.exclude&quot;: { &quot;**/.git&quot;: true, &quot;**/node_modules&quot;: true, &quot;**/bower_components&quot;: true, &quot;**/tmp&quot;: true }, } 然后确保您没有关闭搜索排除功能。 在搜索区域中,展开“要排除的文件”输入框,并确保选中齿轮图标。
再次搜索时,就会发现搜索结果干净了,没有干扰结果啦。</description>
</item>
<item>
<title>setTimeout(fn, 0) 意味着什么</title>
<link>http://ijs.me/2019/05/16/settimeout-fn-0/</link>
<pubDate>Thu, 16 May 2019 23:56:25 +0800</pubDate>
<guid>http://ijs.me/2019/05/16/settimeout-fn-0/</guid>
<description>当你定义 setTimeout 那一刻起(不管时间是不是0),JS 并不会直接去执行这段代码,而是把它扔到一个事件队列里面,当页面中所有同步任务都干完了以后,才会去执行事件队列里面的代码。</description>
</item>
<item>
<title>为 MacTeX 配置中文支持</title>
<link>http://ijs.me/2019/04/03/mactex-chinese/</link>
<pubDate>Wed, 03 Apr 2019 23:44:13 +0800</pubDate>
<guid>http://ijs.me/2019/04/03/mactex-chinese/</guid>
<description>MacTeX 自带了名为 TeXShop 的编辑器,我们打开 TeXShop,然后打开偏好设置,把编码改为 UTF-8,
然后切换到排版,把默认指令选为“采用键入的指令”,
我们在写带有中文的文档时,在 .tex 文档中加入 \usepackage{xeCJK} 就能处理中文了。</description>
</item>
<item>
<title>Node.js 所用的模块规范 -- CommonJS 规范</title>
<link>http://ijs.me/2019/04/01/node.js-modules-commonjs/</link>
<pubDate>Mon, 01 Apr 2019 22:43:42 +0800</pubDate>
<guid>http://ijs.me/2019/04/01/node.js-modules-commonjs/</guid>
<description>我们先来看一个例子,新建一个 01_run.js 文件:
console.log(&quot;This is a test.&quot;); 在终端中打开该文件所在目录,执行调试 node --inspect-brk 01_run.js,然后在 Chrome 浏览器打开地址 chrome://inspect/,就可以看到我们的文件的 Target,点击 inspect,在打开的调试工具窗口中就可以看到实际执行的代码为:
(function(exports, require, module, __filename, __dirname) { console.log(&quot;This is a test.&quot;); }); 外面包裹的函数都是 Node.js 内部帮我们做的,exports 参数代表模块的输出, require 表示需要引用别的模块时调用的 function, module 代表模块本身,module 里面还有一个exports 属性, __filename 就是该文件的路径(绝对路径), __dirname 是该文件所在文件夹的路径(绝对路径)。
exports 参数是 module.exports 的简写,当 exports 在文件中被当作变量赋值时,则该简写就不成立了,参考 exports shortcut。
module.exports.hello = true; // Exported from require of module exports = { hello: false }; // Not exported, only available in the module CommonJS 规范:</description>
</item>
<item>
<title>Ant Design 同一个页面内多个表单校验冲突解决</title>
<link>http://ijs.me/2019/02/15/ant-design-two-form/</link>
<pubDate>Fri, 15 Feb 2019 19:50:32 +0800</pubDate>
<guid>http://ijs.me/2019/02/15/ant-design-two-form/</guid>
<description>遇到这样一种场景,某个页面比较复杂,页面本身是一个表单,然后 Modal 里是另外一个表单,如果我们写在同一个组件里。在表单校验时就会发生两个表单会同时校验的问题。
这时我们需要把一个表单抽离出来成一个独立的组件。然后主页面和弹窗之间的数据通信可以通过 props 来解决。
例如:
class Modal extends Component { handleModalSubmit = e =&gt; { e.preventDefault() this.props.form.validateFields((err, values) =&gt; { values.id = this.props.id if (!err) { request(``).then(res =&gt; { }) } }) } render() { return ( &lt;Form onSubmit={this.handleModalSubmit}&gt; &lt;/Form&gt; } } const WrappedModal = Form.create()(Modal) class MainPage extends Component { render() { return ( &lt;Form onSubmit={this.handleSubmit}&gt; &lt;Modal title='弹窗表单' visible={this.state.visible} onCancel={this.handleCancel}&gt; &lt;WrappedModal id={this.state.id} /&gt; &lt;/Modal&gt; &lt;/Form&gt; ) } } const WrappedMainPage = Form.</description>
</item>
<item>
<title>博客切回 HTTP 访问(已重新切回 HTTPS)</title>
<link>http://ijs.me/2019/02/14/blog-http/</link>
<pubDate>Thu, 14 Feb 2019 11:53:10 +0800</pubDate>
<guid>http://ijs.me/2019/02/14/blog-http/</guid>
<description>我的博客是搭建在 GitHub Pages 上的,并且使用了 Custom domain(自定义域名),一开始我在仓库的 Settings 里勾选了 Enforce HTTPS,这样即使你在浏览器里输入 ijs.me,也会自动访问 https://ijs.me。GitHub 为我们提供了免费的证书,用的是 Let’s Encrypt 提供的免费证书,免费证书有效期比较短,每隔几个月会更新一次。
我的网站引用了一些 Cloudflare 上的 CSS 和 JS 文件,Cloudflare 在国外访问速度较快,但是在国内速度就太慢了,我就把用的这几个 Cloudflare 上的 CSS 和 JS 文件放到了七牛上,我用的是七牛免费的 HTTP 流量。在 HTTPS 网站上引用这些 HTTP 开头的文件 URL 会遇到已阻止载入混合活动内容错误,导致 CSS 和 JS 文件加载失败。
所以为了方便,我把网站取消了 Enforce HTTPS,使用 HTTPS 如果是自己的证书还要担心证书到期问题,用 HTTP 访问网站更方便。
经过实测,我们在博客文章里做的一些网站站内的一些内链,原先为 HTTPS 开头的,也需要改为 HTTP,否则该文章会自动用 HTTPS 访问,引用的一些第三方网站的 HTTPS URL 则不受影响。
2020 年 8 月最新更新:已重新切回 HTTPS HTTPS 是大势所趋,Chrome 浏览器针对 HTTP 网址已提示不安全。所以为图床购买了 HTTPS 流量。</description>
</item>
<item>
<title>HTTP 强缓存和协商缓存</title>
<link>http://ijs.me/2019/02/12/http-cache/</link>
<pubDate>Tue, 12 Feb 2019 15:33:53 +0800</pubDate>
<guid>http://ijs.me/2019/02/12/http-cache/</guid>
<description>强缓存 我们从浏览器向服务器发请求时,浏览器再次向同样的接口发送请求时,会首先根据上次请求的 Response Headers 的 cache-control 和 expires 判断是否命中强缓存,若命中则直接从缓存中获取请求结果,不再真的发请求到服务器。
如果 cache-control 与 expires 同时存在的话,cache-control 的优先级高于 expires。
协商缓存 若没有命中强缓存,就会发一个请求到服务器,验证协商缓存是否命中。根据 Last-Modified 和 ETag 来判断是否命中协商缓存。
1、Last-Modified,If-Modified-Since 浏览器第一次跟服务器请求一个资源,服务器在返回这个资源的同时,在 respone 的 header 加上 Last-Modified 的 header,这个 header 表示这个资源在服务器上的最后修改时间。
浏览器再次跟服务器请求这个资源时,在 request 的 header 上加上 If-Modified-Since 的 header,这个 header 的值就是上一次请求时返回的 Last-Modified 的值。
服务器再次收到资源请求时,根据浏览器传过来 If-Modified-Since 和资源在服务器上的最后修改时间判断资源是否有变化,如果没有变化则返回 304 Not Modified,但是不会返回资源内容;如果有变化,就正常返回资源内容。当服务器返回 304 Not Modified 的响应时,response header 中不会再添加 Last-Modified 的 header,因为既然资源没有变化,那么 Last-Modified 也就不会改变,这是服务器返回 304 时的 response header。
2、ETag、If-None-Match Etag是由服务器生成的每个资源的唯一标识字符串,只要资源有变化就这个值就会改变。
If-None-Match的 header 会将上次返回的Etag发送给服务器,询问该资源的Etag是否有更新,有变动就会发送新的资源回来。与 Last-Modified 不一样的是,当服务器返回 304 Not Modified 的响应时,由于 ETag 重新生成过,response header 中还会把这个 ETag 返回,即使这个 ETag 跟之前的没有变化。</description>
</item>
<item>
<title>JavaScript 生成时间戳及其在网络请求中的应用</title>
<link>http://ijs.me/2019/02/03/javascript-timestamp/</link>
<pubDate>Sun, 03 Feb 2019 22:47:07 +0800</pubDate>
<guid>http://ijs.me/2019/02/03/javascript-timestamp/</guid>
<description>我们知道,使用强缓存时,浏览器不会发送请求到服务端,根据设置的缓存时间浏览器一直从缓存中获取资源,在这期间若资源产生了变化,浏览器就在缓存期内就一直得不到最新的资源(这就是很多情况下服务器上资源已经更新了,我们在浏览器中却拿不到最新的资源的原因),那么如何防止这种事情发生呢?
我们可以通过在请求路径后加上时间戳,来更新页面中引用的资源路径,让浏览器主动放弃缓存,加载新资源。
加时间戳后的请求 URL 类似于 https://a.com/action/api/url?timestamp=1549954762183,其中 ?timestamp=1549954762183 就是我们加的请求参数,1549954762183 是生成的时间戳,那么如何生成时间戳呢?
大概有以下三种方式:
let timestamp1 = Date.parse(new Date()) // 精确到秒 let timestamp2 = new Date().valueOf() // 精确到毫秒 let timestamp3 = new Date().getTime() // 精确到毫秒 加上时间戳后,每次的请求路径就不同了,所以每次都相当于是一个新请求,不会受之前强缓存的影响。
关于强缓存和协商缓存机制可以参考这篇文章:HTTP 强缓存和协商缓存</description>
</item>
<item>
<title>macOS 上的那些神器</title>
<link>http://ijs.me/2019/01/23/macos-artifact/</link>
<pubDate>Wed, 23 Jan 2019 19:51:02 +0800</pubDate>
<guid>http://ijs.me/2019/01/23/macos-artifact/</guid>
<description>Paste 剪贴板工具,Paste 为您保存您的历史拷贝内容,让你可以随时快速粘贴之前拷贝的内容,界面和系统融为一体,仿佛内置应用,支持快捷键。
Dash 文档离线查看工具,支持的语言非常全。
Magnet 分屏神器,尤其适合双屏人士,支持快速在两个屏幕之间移动窗口等。
Expressions 写正则表达式神器,上面写正则,下面可以验证是否正确,旁边侧栏就是各种正则符号的文档。</description>
</item>
<item>
<title>React Router 组件切换时滚动条重置到页面顶部</title>
<link>http://ijs.me/2019/01/21/react-router-scroll-restoration/</link>
<pubDate>Mon, 21 Jan 2019 18:09:15 +0800</pubDate>
<guid>http://ijs.me/2019/01/21/react-router-scroll-restoration/</guid>
<description>我们在使用 React Router V4 时可以发现在路由切换时滚动条的位置没有变化,进入一个新的页面后滚动条还是在上页时的位置,这显然不符合我们阅读网页的习惯。
在早期的 React Router 版本是提供开箱即用的滚动到顶部重置支持的。因为现在浏览器开始支持了 HTML5 引入的 history.pushState() 方法,浏览器开始处理默认的滚动条状态,并且不同的应用对是否滚动到顶部有不同的需求。所以我们需要自己来根据需求来实现。
现在我们来实现在路由切换时滚动条重置到页面顶部。
我们在项目中的工具文件夹里新建一个 /src/utils/ScrollToTop.js
import React, { Component } from 'react' import { withRouter } from 'react-router-dom' class ScrollToTop extends Component { componentDidUpdate(prevProps) { if (this.props.location.pathname !== prevProps.location.pathname) { window.scrollTo(0, 0); } } render() { return this.props.children; } } export default withRouter(ScrollToTop); 然后在我们的路由文件里引入 ScrollToTop 组件,并用 ScrollToTop 组件把我们的路由包裹一层,这样就实现了当路由切换时滚动条自动重置到页面顶部。</description>
</item>
<item>
<title>macOS 下编写 C 和 C++</title>
<link>http://ijs.me/2019/01/19/macos-c-cpp/</link>
<pubDate>Sat, 19 Jan 2019 23:01:56 +0800</pubDate>
<guid>http://ijs.me/2019/01/19/macos-c-cpp/</guid>
<description>安装微软官方推出的 VSCode 插件 C/C++,该插件提供了代码格式化,自动补全等功能。</description>
</item>
<item>
<title>使用七牛云作为博客图床配合 PicGo 上传图片</title>
<link>http://ijs.me/2019/01/15/qiniu-blog-picgo/</link>
<pubDate>Tue, 15 Jan 2019 14:58:50 +0800</pubDate>
<guid>http://ijs.me/2019/01/15/qiniu-blog-picgo/</guid>
<description>博客图床 我的博客是搭建在 GitHub Pages 上,GitHub Pages 对每个站点默认最大空间不能超过 1 GB,而且把图片放到 GitHub Pages 里访问速度也不是非常快,还要担心有天图片放太多导致容量不够用。所以我们需要图床服务来单独放置我们的图片。
七牛云是国内非常优秀的云存储服务商,我们把图片放到七牛云上访问速度也非常快,这对读者阅读我们的博客体验也会更好。
首先我们需要注册一个七牛云账号。
实名认证 注册完成后我们需要首先实名认证才能新建存储空间,我们个人用户申请个人认证就好了,认证方式可以选支付宝或者银行转账认证,支付宝认证需要登录个人支付宝授权七牛访问您的认证信息,授权后耐心等待至认证结束, 中途不要主动关闭页面。然后填写个人信息,提交后等待审核。进入待审核状态后,会提示“您的身份认证信息已提交, 七牛将在 3 个工作日内完成审核,审核结果将通过邮件和短信通知您。”
我大概等了 30 分钟就认证通过了。
实名认证后,您可获得更多免费额度:10GB 永久存储空间,10GB/月 HTTP 国内流量,10GB/月 HTTP 海外流量等等。
新建图床 首先我们在对象存储栏目里新建一个存储空间,存储区域根据你的需要选一个,访问控制选为公开空间。
公开空间,可通过文件对象的 URL 直接访问。如果要使用七牛云存储的镜像存储功能,请设置空间的属性为公有。
私有空间,文件对象的访问则必须获得拥有者的授权才能访问。
公开和私有仅对空间的读文件生效,修改、删除、写入等对空间的操作均需要拥有者的授权才能进行操作。
绑定域名 七牛融合 CDN 测试域名(以 clouddn.com/qiniucdn.com/qiniudn.com/qnssl.com/qbox.me 结尾),每个域名每日限总流量 10GB,每个测试域名自创建起 30 个自然日后系统会自动回收,仅供测试使用。
所以我们需要绑定我们自己的域名,绑定加速的域名必须先完成在中国大陆的 ICP 备案。
在绑定域名页加速域名字段填写一个你已备案的域名的二级域名,比如 cdn.xxx.com,覆盖范围我选了全球。
点击创建然后会提示你:
加速域名 cdn.xxx.com 添加成功!配置部署中。 需要到域名解析服务商完成 CNAME 绑定,绑定后加速服务正式生效。如何配置 CNAME CNAME: cdn.xxx.com.qiniudns.com
我们去我们购买域名的服务提供商控制台的域名解析里添加解析记录:
添加好 CNAME 记录后,我们去七牛云的融合 CDN -&gt; 域名管理可以看到我们绑定的域名,现在状态为处理中,一般 10 分钟左右就成功了,等域名状态变为成功后域名就可以使用了。</description>
</item>
<item>
<title>mozjpeg 编译错误解决</title>
<link>http://ijs.me/2019/01/14/mozjpeg-pre-build-compile-error-fix/</link>
<pubDate>Mon, 14 Jan 2019 14:57:46 +0800</pubDate>
<guid>http://ijs.me/2019/01/14/mozjpeg-pre-build-compile-error-fix/</guid>
<description>在对某个项目执行 npm install 时出现如下错误:
&gt; mozjpeg@4.1.1 postinstall /Users/dezhu/Code/wrw/node_modules/mozjpeg &gt; node lib/install.js ⚠ The `/Users/dezhu/Code/wrw/node_modules/mozjpeg/vendor/cjpeg` binary doesn't seem to work correctly ⚠ mozjpeg pre-build test failed ℹ compiling from source ✖ Error: autoreconf -fiv &amp;&amp; ./configure --disable-shared --prefix=&quot;/Users/dezhu/Code/wrw/node_modules/mozjpeg/vendor&quot; --bindir=&quot;/Users/dezhu/Code/wrw/node_modules/mozjpeg/vendor&quot; --libdir=&quot;/Users/dezhu/Code/wrw/node_modules/mozjpeg/vendor&quot; &amp;&amp; make --jobs=12 &amp;&amp; make install --jobs=12 Command failed: autoreconf -fiv /bin/sh: autoreconf: command not found at ChildProcess.exithandler (child_process.js:294:12) at ChildProcess.emit (events.js:182:13) at maybeClose (internal/child_process.js:962:16) at Process.ChildProcess._handle.onexit (internal/child_process.js:251:5) 经过搜索,发现可以通过如下方式解决。
首先更新 Xcode Command Line Tools 到最新版本,然后执行下面这几条命令:</description>
</item>
<item>
<title>Kindle 自定义字体</title>
<link>http://ijs.me/2019/01/12/kindle-font/</link>
<pubDate>Sat, 12 Jan 2019 23:54:07 +0800</pubDate>
<guid>http://ijs.me/2019/01/12/kindle-font/</guid>
<description>最近把 Kindle 用 USB 数据线连接电脑,发现 Kindle 根目录下多了一个 fonts 文件夹,好奇点进去,发现一个 Readme.txt 文件夹,打开发现是 Kindle 自定义字体的说明:
您现在可以将自己喜欢的字体安装到 Kindle 上,从而在阅读电子书时选用。
您安装的字体必须是 OpenType (OTF) 或 TrueType (TTF) 字体,而其他字体格式均不支持。此外,字体通常以字体集的形式可用,且每种字体可能包含数个不同的文件,分别为不同的字体样式。例如,常规、斜体、粗体,粗斜体等每种样式各为一个文件。我们建议您安装字体集所含的全部文件以获得最佳阅读体验。受支持的字体文件应具有以下扩展名之一:.ttf、.otf 或 .ttc 。
字体安装的具体步骤如下:
若字体以压缩文件(如 ZIP 文件)格式打包,请用您喜欢的文件解压程序将文件解压缩
将字体文件复制到 Kindle 上的“fonts”文件夹
将 Kindle 从电脑上断开连接
除 Kindle 字体外,您现在还可以选择自定义字体,从【显示设置】(Aa) 菜单中操作即可
从【显示设置】(Aa) 菜单中选择了自定义字体后,Kindle 将以该字体显示多数电子书的内容。如果某部书的内容不能以该字体显示,Kindle 将使用系统默认字体。这种情况发生的原因可能是该字体不支持书中的文字或该字体已损坏。
这意味着 Kindle 用户不需要越狱就可以享受到自定义字体啦,Kindle 默认只提供四种字体,及其有限,原生支持自定义字体对广大 Kindle 用户来说无疑是一大福利。
进一步搜索发现 Kindle 设备自 2018 年 6 月份更新的 5.9.6 版本固件就开始支持自定义字体,只是我一直没发现。
这里我着重推荐使用免费开源的思源宋体,我们直接下载 ZIP 包,注意文件较大,推荐使用迅雷下载。思源宋体比默认的宋体要舒服很多,而且思源宋体这样的衬线字体识别度高是及其适合阅读的。</description>
</item>
<item>
<title>聊一聊互联网寒冬</title>
<link>http://ijs.me/2019/01/11/winter-of-internet/</link>
<pubDate>Fri, 11 Jan 2019 23:59:20 +0800</pubDate>
<guid>http://ijs.me/2019/01/11/winter-of-internet/</guid>
<description>最近京城互联网届变得人心惶惶,不断爆出互联网公司大规模裁员,不仅是不赚钱的小公司,就连那些巨头也在裁员了,美其名曰优化。
从百度指数和 Google Trends 也可以看出最近“裁员”关键字的搜索量大增,当然这也与这几年网民数量增加有一点关系。
下图是百度指数 2010-12-27 ~ 2019-01-07 “裁员”一词的搜索指数:
下图是 Google Trends 2004 年至今“裁员”一词的热度:
从 Google Trends 可以看出最近这波裁员热度目前尚未超过 2008 年那次,但是恐慌容易传染,看着一些企业裁员了,本来不需要裁员的那些公司,有的也跟风裁员了。大家对未来的信心不足,行业容易像多米诺骨牌似的发生崩塌。
人们总是在繁荣中过于乐观,在寒冬中过于悲观。
资本从来都是只会锦上添花,而不会雪中送炭。
任何时候都要学会居安思危。
互联网无惧泡沫,任何一次泡沫破裂,推到重来,都意味着巨大的机遇。</description>
</item>
<item>
<title>2019 年初的 Angular</title>
<link>http://ijs.me/2019/01/08/angular-beginning-of-2019/</link>
<pubDate>Tue, 08 Jan 2019 23:58:25 +0800</pubDate>
<guid>http://ijs.me/2019/01/08/angular-beginning-of-2019/</guid>
<description>上手门槛 Angular 确实是前端三大框架 Angular, React, Vue 中使用门槛最高的,Angular 默认使用 TypeScript,这意味着你写 Angular 首先要熟悉 TypeScript 的语法。而且 Angular 官方提供的 Angular CLI 非常强大,命令众多,这同时也意味着有一点学习门槛。
使用人数 现在是 2019 年 1 月,Angular 的最新版本是 7.2.0,我们可以看到 @angular/core 在 npm 上的周下载量达到 1,725,765,Angular 的 1 版本 AngularJS 在 npm 上的周下载量也有 348,934,react 的周下载量高达 3,386,941,对比之下 vue 的周下载量只有 640,672,Angular 和 React 在 npm 上的下载量要远远超过 Vue 的。当然这和 Vue 的使用者不少是直接用 &lt;script&gt; 引入,并未使用命令行工具(CLI)有关。但是 npm 上的下载量也能说明 Angular 还是很受大家欢迎的。
UI 组件库 如果你喜欢谷歌的 Material Design 风格,那么使用 Angular 就可以享受到谷歌官方推出的 Angular Material 组件库。并且非常流行的 Ant Design 也有 Angular 的组件实现 NG-ZORRO。</description>
</item>
<item>
<title>Node.js 概念及优势</title>
<link>http://ijs.me/2019/01/03/what-node.js/</link>
<pubDate>Thu, 03 Jan 2019 23:58:26 +0800</pubDate>
<guid>http://ijs.me/2019/01/03/what-node.js/</guid>
<description>Node.js 是构建在 Chrome&rsquo;s V8 JavaScript 引擎上的运行时,Node.js 并不是一门语言,JavaScript 才是语言,而 Node.js 是一个 JavaScript runtime,类似于 Java 语言的 JRE,是一个运行时。
阻塞:I/O 时进程休眠等待 I/O 完成后进行下一步。
非阻塞 I/O:I/O 时函数立即返回,进程不等待 I/O 完成。
事件驱动:
I/O 等异步操作结束后的通知,发射一个事件,然后调用相应的事件处理程序。
内部实现是用观察者模式实现的。
使用场景:
Web 场景,高并发,I/O 密集。
I/O 密集:文件操作、网络操作、数据库相关操作。
那么什么是 CPU 密集呢?如果程序大部分时间用来做压缩、解压、加密、解密这些操作就称之为 CPU 密集。
Node.js 在处理高并发,I/O 密集场景性能优势明显。
高并发简单地说就是在单位时间内访问量特别大就是高并发,高并发解决办法:
增加机器数
增加每台机器的 CPU 数 &ndash; 多核
那么在公司中主要用 Node.js 做什么呢?
Web Server
本地代码构建,如 webpack</description>
</item>
<item>
<title>2019 新年展望</title>
<link>http://ijs.me/2019/01/01/new-year-2019/</link>
<pubDate>Tue, 01 Jan 2019 23:55:37 +0800</pubDate>
<guid>http://ijs.me/2019/01/01/new-year-2019/</guid>
<description>每天都要进步一点,不允许每天重复,不能穷忙,低头拉车的同时也要抬头看路。</description>
</item>
<item>
<title>zsh 遇到 permission 警告信息</title>
<link>http://ijs.me/2018/12/20/zsh-permission/</link>
<pubDate>Thu, 20 Dec 2018 22:45:49 +0800</pubDate>
<guid>http://ijs.me/2018/12/20/zsh-permission/</guid>
<description>今天在一台新的电脑上安装 zsh 和 oh-my-zsh 时遇到刚打开时出现如下警告信息:
[oh-my-zsh] Insecure completion-dependent directories detected: drwxr-xr-x 3 501 admin 96 8 13 14:09 /usr/local/share/zsh drwxr-xr-x 6 501 admin 192 8 13 14:23 /usr/local/share/zsh/site-functions lrwxr-xr-x 1 501 admin 39 8 13 14:18 /usr/local/share/zsh/site-functions/_brew -&gt; ../../../Homebrew/completions/zsh/_brew lrwxr-xr-x 1 501 admin 44 8 13 14:18 /usr/local/share/zsh/site-functions/_brew_cask -&gt; ../../../Homebrew/completions/zsh/_brew_cask lrwxr-xr-x 1 501 admin 56 8 13 14:23 /usr/local/share/zsh/site-functions/_git -&gt; ../../../Cellar/git/2.18.0/share/zsh/site-functions/_git [oh-my-zsh] For safety, we will not load completions from these directories until [oh-my-zsh] you fix their permissions and ownership and restart zsh.</description>
</item>
<item>
<title>Node.js 进程与线程</title>
<link>http://ijs.me/2018/12/16/node.js-thread-process/</link>
<pubDate>Sun, 16 Dec 2018 23:56:46 +0800</pubDate>
<guid>http://ijs.me/2018/12/16/node.js-thread-process/</guid>
<description>进程:计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位。比如打开音乐播放器,浏览器,系统把音乐播放器,浏览器程序加载到内存中,我们称执行中的程序叫做进程。
多进程:启动多个进程,多个进程可以一块执行多个任务。CPU 使用调度算法快速进行切换。
线程:进程中一个相对独立的,可调度的执行单元,与同属一个进程的线程共享进程的资源。
多线程:启动一个进程,在一个进程内启动多个线程,这样,多个线程也可以一块执行多个任务。
JavaScript 是单线程的,Node.js 也是单线程的,单线程只是针对主进程,I/O 操作系统底层多线程调度。所以我们说 Node.js 是单线程的,并不是说 Node.js 做所有事情都是单线程,像 I/O 操作是交给操作系统底层去做的。单线程并不是单进程,Node.js 通过 cluster 集群来利用多核 CPU 的能力。</description>
</item>
<item>
<title>前后端联调因 cookie 问题导致 Tomcat 容器报错从而接口返回 500 错误</title>
<link>http://ijs.me/2018/12/11/tomcat-cookies-500/</link>
<pubDate>Tue, 11 Dec 2018 23:54:52 +0800</pubDate>
<guid>http://ijs.me/2018/12/11/tomcat-cookies-500/</guid>
<description>最近接手了一个别人写的系统,发现所有有和后端接口交互的页面接口都会返回 500 错误。
经过一番排查,最终发现这个系统最近加了个登陆逻辑,这个登陆是有和后端交互的,这个系统登陆当时是这样处理的,前端向后端发请求,后端返回一些字段,前端根据这些字段来设置 cookie,其中后端返回的一个字段为中文,而前后端都没对中文做处理,导致 cookie 的格式不对,所有的接口再向后端发请求时,Tomcat 容器那里会报 cookie 错误,导致请求返回 500。其实应该后端设置 cookie 的,前端设置 cookie 还得一个一个得设置。
原因是 cookie 中不该有中文,有中文等特殊字符 Tomcat 容器那里会报 cookie 错误,可以把中文编码下再保存成 cookie,前后端都可以编码,JS 这里的处理是通过 encodeURIComponent(URIstring)对 URL 进行编码,decodeURIComponent() 函数可对 encodeURIComponent() 函数编码的 URI 进行解码。</description>
</item>
<item>
<title>CocoaPods 使用清华源</title>
<link>http://ijs.me/2018/12/07/cocoapods-tsinghua/</link>
<pubDate>Fri, 07 Dec 2018 23:51:42 +0800</pubDate>
<guid>http://ijs.me/2018/12/07/cocoapods-tsinghua/</guid>
<description>首先我们根据官网方法安装 CocoaPods:
sudo gem install cocoapods 然后:
cd ~/.cocoapods/repos pod repo remove master git clone https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git master 最后进入自己的工程,在自己工程的podFile第一行加上:
source 'https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git' 使用 pod repo 可以查看 URL 字段判断当前自己用的哪个源。</description>
</item>
<item>
<title>解决因含有恶意代码的 flatmap-stream 包被删导致项目安装依赖错误</title>
<link>http://ijs.me/2018/12/06/yarn-flatmap-stream/</link>
<pubDate>Thu, 06 Dec 2018 17:23:02 +0800</pubDate>
<guid>http://ijs.me/2018/12/06/yarn-flatmap-stream/</guid>
<description>最近同事在开发一个之前的 React 项目时,发现安装一个 cookie npm 包会报错,然后我紧接着发现那个项目无论安装什么包都会报错,把项目的 node_modules 目录删除后重新 yarn install 时也会报相同的错误:
error http://registry.npm.taobao.org/flatmap-stream/download/flatmap-stream-0.1.1.tgz: Extracting tar content of undefined failed, the file appears to be corrupt: &quot;Unexpected end of data&quot; 看到错误相信,想到最近 event-stream 引入了含有恶意代码的 flatmap-stream 盗取用户的比特币的新闻。于是查看项目中是否有引入 flatmap-stream 这个包:
yarn why flatmap-stream 可以看到包的依赖顺序为 npm-run-all#ps-tree#event-stream#flatmap-stream,最终是npm-run-all这个包用到了flatmap-stream 这个包,而这个包因某个版本含有病毒被 NPM 官方删除了。所以会导致下载时 404 错误。
注意如果你同事那里有报错,而你的电脑上安装依赖时没有报错,可能时因为你电脑上有 Yarn 的缓存,可以先清空 Yarn 的缓存:
yarn cache clean 然后删除项目的 node_modules 目录,再重新 yarn install 时就会报和你同事相同的 flatmap-stream 错误了。
再删除 node_modules 之前,我看了一下 node_modules 下的 flatmap-stream 包下面内容,并没有发现恶意代码,估计之前病毒作者只在某个版本下的 index.</description>
</item>
<item>
<title>Git 重命名分支</title>
<link>http://ijs.me/2018/12/05/git-rename-branch/</link>
<pubDate>Wed, 05 Dec 2018 19:13:45 +0800</pubDate>
<guid>http://ijs.me/2018/12/05/git-rename-branch/</guid>
<description> 假定现在的分支名称为 oldName,想要修改为 newName
本地分支重命名 git branch -m oldName newName 远程分支重命名 1、重命名远程分支对应的本地分支
git branch -m oldName newName 2、删除远程分支
git push --delete origin oldName 3、把本地分支上传并且把本地分支与远程分支关联
git push --set-upstream origin newName </description>
</item>
<item>
<title>在手机端打开 PC 端启动的本地项目</title>
<link>http://ijs.me/2018/11/30/phone-localhost/</link>
<pubDate>Fri, 30 Nov 2018 19:38:04 +0800</pubDate>
<guid>http://ijs.me/2018/11/30/phone-localhost/</guid>
<description>查看局域网 IP ifconfig en0
显示网卡 en0 的信息,找到 inet 字段,这个字段后面的 ip 地址就是你的局域网的 ip:
然后可以在 PC 上启动你的项目,PC 上的打开地址比如是 http://localhost:3000/,就可以在移动端浏览器输入你的局域网 ip 地址跟上端口号就可以打开 PC 端启动的项目了,比如我这里移动端应该打开的网址是 http://192.168.0.147:3000/,注意你的电脑和手机应该链接同一个 ip,否则不是在同一个局域网内导致打不开网址。</description>
</item>
<item>
<title>当引入的主 JS 文件加载失败时引入备用的 JS 文件</title>
<link>http://ijs.me/2018/11/29/include-alternative-js/</link>
<pubDate>Thu, 29 Nov 2018 22:15:22 +0800</pubDate>
<guid>http://ijs.me/2018/11/29/include-alternative-js/</guid>
<description> onerror 方法 判断对象是否存在 </description>
</item>
<item>
<title>在 VS Code 中使用 Prettier 来格式化前端代码</title>
<link>http://ijs.me/2018/11/16/prettier-code-formatter/</link>
<pubDate>Fri, 16 Nov 2018 19:18:34 +0800</pubDate>
<guid>http://ijs.me/2018/11/16/prettier-code-formatter/</guid>
<description>我们平时写代码经常需要保持一定的风格,而 Prettier 可以很好的帮我们格式化 JavaScript / TypeScript / CSS,Prettier 甚至支持格式化 SCSS 代码,而我们如果使用官方的 sass-convert 往往会遇到这个工具自身的兼容性问题。
首先我们在 VS Code 里安装 Prettier, 然后我们进行一些个性化配置,打开 VS Code 的配置文件 settings.json,然后在其中加入下面内容:
&quot;editor.formatOnSave&quot;: true, &quot;prettier.jsxSingleQuote&quot;: true, &quot;prettier.semi&quot;: false, &quot;prettier.proseWrap&quot;: &quot;preserve&quot; 然后每次保存的时候就会自动格式化代码了,你也可以通过 CMD + Shift + P -&gt; Format Document 来手动进行格式化代码。
之前发现 Prettier 在格式化 JSX 代码时,有些 HTML 标签比如 &lt;p&gt; 标签里的内容有时会分为两行显示,这样直接把内容换行会导致显示多一个空格的问题,后来经过一番搜索发现 settings.json 里加一句 &quot;prettier.proseWrap&quot;: &quot;preserve&quot; 就好了,意为原本是否换行保持不变。</description>
</item>
<item>
<title>Git 理解工作区、暂存区、版本库和 stage unstage 状态</title>
<link>http://ijs.me/2018/11/14/git-workspace-staging-area-and-local-repository-stage-unstage/</link>
<pubDate>Wed, 14 Nov 2018 12:01:59 +0800</pubDate>
<guid>http://ijs.me/2018/11/14/git-workspace-staging-area-and-local-repository-stage-unstage/</guid>
<description>首先我们来理解下 Git 工作区、暂存区和版本库概念
工作区:就是你在电脑里能看到的目录。 暂存区:英文叫 stage, 或 index。一般存放在 &ldquo;.git 目录下&rdquo; 下的 index 文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。 版本库:工作区有一个隐藏目录.git,这个不算工作区,而是 Git 的版本库。 </description>
</item>
<item>
<title>iTerm2 + oh-my-zsh + agnoster 打造完美终端</title>
<link>http://ijs.me/2018/11/13/iterm2-oh-my-zsh-agnoster/</link>
<pubDate>Tue, 13 Nov 2018 16:07:03 +0800</pubDate>
<guid>http://ijs.me/2018/11/13/iterm2-oh-my-zsh-agnoster/</guid>
<description>安装 iTerm2 首先我们安装 iTerm2,去 iTerm2 官网 下载安装即可。
切换默认终端为 zsh 首先通过 cat /etc/shells 来查看当前系统可以使用哪些 shell:
# List of acceptable shells for chpass(1). # Ftpd will not allow users to connect who are not using # one of these shells. /bin/bash /bin/csh /bin/ksh /bin/sh /bin/tcsh /bin/zsh 通过 echo $SHELL 命令可以查看当前正在使用的 shell。
如果当前的 shell 不是 zsh,可以通过 chsh -s /bin/zsh 来把 shell 切换为 zsh,终端重启之后将生效。
安装 oh-my-zsh 根据 GitHub 上的 oh-my-zsh 仓库说明的方法安装即可:
sh -c &quot;$(curl -fsSL https://raw.</description>
</item>
<item>
<title>巧用 setTimeout 进行排序</title>
<link>http://ijs.me/2018/11/06/settimeout-sort/</link>
<pubDate>Tue, 06 Nov 2018 23:57:41 +0800</pubDate>
<guid>http://ijs.me/2018/11/06/settimeout-sort/</guid>
<description>原理:把数组每一项的值当作 setTimeout 的时间参数,根据数值大小延迟不同的时间输出值(或放到新数组里),达到排序目的。</description>
</item>
<item>
<title>在 macOS 系统上配置 LaTeX 环境</title>
<link>http://ijs.me/2018/10/28/macos-latex-setup/</link>
<pubDate>Sun, 28 Oct 2018 23:56:46 +0800</pubDate>
<guid>http://ijs.me/2018/10/28/macos-latex-setup/</guid>
<description>由于 MacTeX 提供的编辑器比较简单,所以我们使用 VS Code 来编写 LaTeX。
VS Code 的 LaTeX Workshop 扩展 我们需要安装 VS Code 的扩展 LaTeX Workshop,LaTeX Workshop 为我们在 VS Code 里编写 LaTeX 提供了一个完整的工具集,包括以 PDF 格式查看,LaTeX 代码高亮,语法提示,LaTeX 文件格式化等。</description>
</item>
<item>
<title>在 React Router 的 Link 中用 query state 和 search 三种方式传参数的差异</title>
<link>http://ijs.me/2018/10/19/react-router-link-query-state-search/</link>
<pubDate>Fri, 19 Oct 2018 16:29:45 +0800</pubDate>
<guid>http://ijs.me/2018/10/19/react-router-link-query-state-search/</guid>
<description>我们在页面间跳转时,经常需要传一些参数到下一个页面,我们可以在 Link 中携带一些参数到下一个页面,发现网上的一些文章有些错误,官方文档也没有很详细的说明,根据尝试,做出以下区分:
query &lt;Link to={{pathname: `/project`, query: function a() {return 'name=test'}}}&gt;项目&lt;/Link&gt; query 支持所有的 JS 基本数据类型:字符串(String)、数字(Number)、布尔(Boolean)、空值(Null)、未定义(Undefined)、Symbol和引用数据类型:对象(Object)、数组(Array)、函数(Function),在新页面刷新后,传来的数据不复存在,不用 query 这个标识符随便起一个名字(除了 state 和 search)和 query 作用完全相同,query 不会把数据加到 URL 上。
在新页面可以通过 this.props.location.query 拿到 function a() {return 'name=test'}。
state &lt;Link to={{pathname: `/project`, state:{name: 'test'}}}&gt;项目&lt;/Link&gt; state 支持除 Symbol 和函数之外的所有数据类型包括基本数据类型:字符串(String)、数字(Number)、布尔(Boolean)、空值(Null)、未定义(Undefined)和引用数据类型:对象(Object)、数组(Array),在新页面刷新后数据还存在,state 不会把数据加到 URL 上。
在新页面可以通过 this.props.location.state 拿到 {name: 'test'}。
search &lt;Link to={{pathname: `/project`, search: 'name=test'}}&gt;项目&lt;/Link&gt; search 只支持字符串,在新页面刷新后数据还存在,会把数据加到 URL 上,URL 上的数据前面会加 ?,类似于 https://a.com/project?name=test。
在新页面可以通过 this.props.location.search 拿到 'name=test'。</description>
</item>
<item>
<title>CSS Modules 及其在 React 中实践</title>
<link>http://ijs.me/2018/10/18/css-modules/</link>
<pubDate>Thu, 18 Oct 2018 23:59:00 +0800</pubDate>
<guid>http://ijs.me/2018/10/18/css-modules/</guid>
<description>CSS 样式问题 在样式开发过程中,有两个问题比较突出:
全局污染 —— CSS 文件中的选择器是全局生效的,不同文件中的同名选择器,根据 build 后生成文件中的先后顺序,后面的样式会将前面的覆盖;
选择器复杂 —— 为了避免上面的问题,我们在编写样式的时候不得不小心翼翼,类名里会带上限制范围的标识,变得越来越长,多人开发时还很容易导致命名风格混乱,一个元素上使用的选择器个数也可能越来越多。
Create React App 支持 CSS Modules 为了让我们使用 Create React App 创建的项目支持 CSS Modules,我们需要把 CSS 文件的命名中加上 module 类似 [name].module.css,然后实际编译后的类名会被加上一个 hash 值,变成了这样的格式 [filename]\_[classname]\_\_[hash],这保证了它的唯一性。
如果你使用了 SCSS 或者别的预处理器,也需要为相应的预处理器扩展名前面加上 module,类似于 [name].module.scss or [name].module.sass。
比如我们现在新建一个 Button.module.css 文件:
.error { background-color: red; } 然后在组件文件里按照如下方式使用我们定义的样式:
import React, { Component } from 'react'; import styles from './Button.module.css'; // Import css modules stylesheet as styles class Button extends Component { render() { // reference as a js object return &lt;button className={styles.</description>
</item>
<item>
<title>Go 语言的 main 和 init 函数</title>
<link>http://ijs.me/2018/10/17/go-main-init-function/</link>
<pubDate>Wed, 17 Oct 2018 15:42:29 +0800</pubDate>
<guid>http://ijs.me/2018/10/17/go-main-init-function/</guid>
<description>Go 里面有两个保留的函数:init 函数(能够应用于所有的 package)和 main 函数(只能应用于 package main)。这两个函数在定义时不能有任何的参数和返回值。虽然一个 package 里面可以写任意多个 init 函数,但这无论是对于可读性还是以后的可维护性来说,我们都强烈建议用户在一个 package 中每个文件只写一个 init 函数。
Go 程序会自动调用 init() 和 main(),所以你不需要在任何地方调用这两个函数。每个 package 中的 init 函数都是可选的,但 package main 就必须包含一个 main 函数。
每一个可独立运行的 Go 程序,必定包含一个 package main,在这个 main 包中必定包含一个入口函数 main,而这个函数既没有参数,也没有返回值。
程序的初始化和执行都起始于 main 包。如果 main 包还导入了其它的包,那么就会在编译时将它们依次导入。有时一个包会被多个包同时导入,那么它只会被导入一次(例如很多包可能都会用到 fmt 包,但它只会被导入一次,因为没有必要导入多次)。当一个包被导入时,如果该包还导入了其它的包,那么会先将其它包导入进来,然后再对这些包中的包级常量和变量进行初始化,接着执行 init 函数(如果有的话),依次类推。等所有被导入的包都加载完毕了,就会开始对 main 包中的包级常量和变量进行初始化,然后执行 main 包中的 init 函数(如果存在的话),最后执行 main 函数。下图详细地解释了整个执行过程:
main 函数引入包初始化流程图</description>
</item>
<item>
<title>C 语言指针变量</title>
<link>http://ijs.me/2018/10/16/c-pointer-variable/</link>
<pubDate>Tue, 16 Oct 2018 16:32:10 +0800</pubDate>
<guid>http://ijs.me/2018/10/16/c-pointer-variable/</guid>
<description>指针的概念 我们知道,计算机中所有的数据都必须放在内存中,为了正确访问这些数据,我们必须为每个字节编上号码,每个字节的编号是唯一的,根据编号可以准确的找到某个内存。
我们将内存中字节的编号称为地址(Address)或指针(Pointer)。地址从 0 开始一次增加,以十六进制表示,C 语言输出十六进制形式为 %#X。
一切都是地址 CPU 访问内存时需要的是地址,而不是变量名和函数名!变量名和函数名只是地址的一种助记符,当源文件被编译和链接成可执行程序后,它们都会被替换成地址。编译和链接过程的一项重要任务就是找到这些名称所对应的地址。
需要注意的是,虽然变量名、函数名、字符串名和数组名在本质上是一样的,它们都是地址的助记符,但在编写代码的过程中,我们认为变量名表示的是数据本身,而函数名、字符串名和数组名表示的是代码块或数据块的首地址。
定义指针变量 数据在内存中的地址也称为指针,如果一个变量存储了一份数据的指针,我们就称它为指针变量。
在C语言中,允许用一个变量来存放指针,这种变量称为指针变量。指针变量的值就是某份数据的地址。
定义指针变量与定义普通变量非常类似,不过要在变量名前面加星号*,格式为:
datatype *name; 或者
datatype *name = value; * 表示这是一个指针变量,datatype 表示该指针变量所指向的数据的类型。例如:
int *p1; p1 是一个指向 int 类型数据的指针变量,至于 p1 究竟指向哪一份数据,应该由赋予它的值决定。再如:
int a = 100, b = 200; int *p_a = &amp;a; p_a = &amp;b; p_a 需要的一个地址,a 前面必须要加取地址符 &amp;,否则是不对的。
* 是一个特殊符号,表明一个变量是指针变量,定义 p1、p2 时必须带 *。而给 p1、p2 赋值时,因为已经知道了它是一个指针变量,就没必要多此一举再带上 *,后边可以像使用普通变量一样来使用指针变量。也就是说,定义指针变量时必须带 *,给指针变量赋值时不能带 *。
p_a 的类型是 int*, 而不是 int。</description>
</item>
<item>
<title>React 代码规范</title>
<link>http://ijs.me/2018/10/15/react-code-guide/</link>
<pubDate>Mon, 15 Oct 2018 23:59:32 +0800</pubDate>
<guid>http://ijs.me/2018/10/15/react-code-guide/</guid>
<description>根据编码实践总结出如下编写 React 代码规范:
所有的语句不应加分号,React 使用 JSX 语法,因为不管加不加分号最终 Babel 转译成 ES5 时都会加上分号,而加分号还需分别什么时候加什么时候不加,所以现在 React 项目推崇不加分号;
组件名、JS 文件名使用大驼峰命名法,以英文意思为依据,如 LoginControl;
JS 变量名命名采用小驼峰命名法,如 currentDay;
JS 函数命名采用小驼峰命名法,如 fetchData();
CSS class 命名采用短横线命名法,如 commits-detail;
所有的 CSS 均使用 SCSS 编写,如果某个块只需要一个 CSS 属性,也可以把 CSS 直接加到 JS 文件里,如 style={{ marginBottom: 15 }} ,注意在 JSX 里写 CSS 需要把属性名的的短横线变成小驼峰命名法;
代码缩进均使用两个空格缩进,务必把编辑器的 Tab 键设置为两个空格;
state or 类属性?与渲染 UI 直接相关的使用 state,只是组件内的变量可用类属性如 this.age = 18;
后端返回对象判空方法: Object.keys(this.state.result).length !== 0 然后使用三目运算符决定是否渲染 UI 或者显示 Loading 效果;</description>
</item>
<item>
<title>Git 忽略已经提交的文件</title>
<link>http://ijs.me/2018/10/10/git-update-index/</link>
<pubDate>Wed, 10 Oct 2018 23:54:59 +0800</pubDate>
<guid>http://ijs.me/2018/10/10/git-update-index/</guid>
<description>对于已经提交的文件,即使我们把这个文件(或文件夹)加到了 .gitignore 里,Git还是会追踪该文件。
所以我们可以用如下这条命令来取消追踪 PATH 文件:
git update-index --assume-unchanged PATH PATH为要忽略的文件夹或文件,文件夹的末尾需要加 / 。</description>
</item>
<item>
<title>解决 VS Code 终端启动时 nvm 提示 prefix option 错误</title>
<link>http://ijs.me/2018/10/09/vs-code-terminal-nvm-complaining-prefix-option/</link>
<pubDate>Tue, 09 Oct 2018 11:05:28 +0800</pubDate>
<guid>http://ijs.me/2018/10/09/vs-code-terminal-nvm-complaining-prefix-option/</guid>
<description>升级 macOS Mojave 新系统后,发现在 VS Code 启动终端时,每次都会提示 &ldquo;prefix&rdquo; 错误:
nvm is not compatible with the npm config &quot;prefix&quot; option: currently set to &quot;/usr/local&quot; Run `npm config delete prefix` or `nvm use --delete-prefix v8.9.1 --silent` to unset it 解决办法:
首先需要找到老的 node_modules 的位置:
ls -la /usr/local/bin | grep npm 终端会列出路径:
lrwxr-xr-x 1 mac admin 46 8 29 15:40 npx -&gt; /usr/local/lib/node_modules/npm/bin/npx-cli.js 然后我们删除这些文件:
rm -R /usr/local/bin/npm /usr/local/lib/node_modules/npm/bin/npm-cli.js 随后发现终端又报另一个兼容性问题,因为我在使用 nvm 之前用 Homebrew 安装过 node,所以我们需要删除之前使用 Homebrew 安装的 node:</description>
</item>
<item>
<title>Create React App 2.0 新特性</title>
<link>http://ijs.me/2018/10/06/create-react-app-2.0-new-feature/</link>
<pubDate>Sat, 06 Oct 2018 23:58:29 +0800</pubDate>
<guid>http://ijs.me/2018/10/06/create-react-app-2.0-new-feature/</guid>
<description> 更新到 2.0 版本 Create React App 我们从 1.x 版本更新到 2.0 版本,只需要重新安装即可:
yarn global add create-react-app </description>
</item>
<item>
<title>Java 语言基础</title>
<link>http://ijs.me/2018/10/05/java-foundation/</link>
<pubDate>Fri, 05 Oct 2018 23:59:27 +0800</pubDate>
<guid>http://ijs.me/2018/10/05/java-foundation/</guid>
<description> Java 版本 Java 主要分为三个版本:
Java SE Java SE(即 Java Platform, Standard Edition)是 Java 的标准版,主要用于桌面应用程序的开发,同时也是 Java 的基础、JDBC(Java 数据库连接性)操作、I/O(输入/输出)网络通信、多线程等技术。 Java EE Java EE(即 Java Platform, Enterprise Edition)是 Java 的企业版,主要用于开发企业级分布式网络程序,如电子商务网站和 ERP(企业资源规划)系统,其核心是 EJB(企业 Java 组件模型)。 Java ME Java ME 主要应用于嵌入式系统开发。 </description>
</item>
<item>
<title>修改 VS Code 内置终端字体</title>
<link>http://ijs.me/2018/09/28/vs-code-terminal-fontfamily/</link>
<pubDate>Fri, 28 Sep 2018 15:18:24 +0800</pubDate>
<guid>http://ijs.me/2018/09/28/vs-code-terminal-fontfamily/</guid>
<description>我的终端使用的是 Zsh,并且配置了 Zsh 的一个主题,这个主题需要安装字体来支持箭头效果,在 iTerm2 中我设置了这个字体,但是 VS Code 里这个箭头还是显示乱码,解决方法:
打开 VS Code 的 settings.json 文件,加入下面一行,我那个主题用的是 Meslo LG M for Powerline 字体:
&quot;terminal.integrated.fontFamily&quot;: &quot;Meslo LG M for Powerline&quot;, 这样 VS Code 内置的终端就能正确显示 Zsh 主题的箭头了。</description>
</item>
<item>
<title>升级 macOS Mojave 后部分软件(如 VS Code)字体变虚 及应用白边解决办法</title>
<link>http://ijs.me/2018/09/26/macos-mojave-font/</link>
<pubDate>Wed, 26 Sep 2018 14:19:34 +0800</pubDate>
<guid>http://ijs.me/2018/09/26/macos-mojave-font/</guid>
<description>字体变虚 升级 macOS Mojave 新系统后,苹果默认关闭了子像素抗锯齿,导致字体变细锯齿增多。像 VS Code 之类的代码编辑器显示的字体效果会变细变模糊很多,我一开始通过把编辑器的字体加粗来暂时解决,可是这样侧边栏之类的字体还是看着过细,可以通过如下方式来解决这个问题。
解决字体渲染过细,打开终端,输入:
defaults write -g CGFontRenderingFontSmoothingDisabled -bool NO 回车,然后重启应用就发现字体变回升级之前的效果了,不再需要手动为编辑器的字体加粗。
应用白边 第三方深色 UI 应用顶部有一条白边,打开终端,输入:defaults write -app 应用名 NSRequiresAquaSystemAppearance -bool No 回车,如:
defaults write -app Google\ Chrome NSRequiresAquaSystemAppearance -bool No 针对有空格的应用名,如 Visual Studio Code,应使用 \ 来分割:Visual\ Studio\ Code
之后重启对应应用即可 (该指令相当于让应用强行使用深色模式 UI,如果应用 /系统本身是浅色的,就没必要执行这个指令)</description>
</item>
<item>
<title>Create React App 通过 Proxy 在本地跨域请求 API</title>
<link>http://ijs.me/2018/09/20/create-react-app-proxy/</link>
<pubDate>Thu, 20 Sep 2018 13:47:52 +0800</pubDate>
<guid>http://ijs.me/2018/09/20/create-react-app-proxy/</guid>
<description>我们通过 create-react-app 新建项目在本地开发时,通常需求请求数据 API,而数据 API 大多数是会遇到跨域问题的,在线上生产环境我们可以通过 Nginx 配置反向代理到我们 build 之后的项目目录,可是在本地应该怎么解决跨域问题了,当然我们在本地也可以配置 Nginx 反向代理了,但是我们的 create-react-app 在本地开发时已经开了一个端口启动了一个 devServer 了,所以我们配置 Nginx 反向代理的话就需要再配置一个端口,把这个端口的反向代理到 create-react-app 启动的这个端口上,以前的一篇文章 Nginx 解决本地开发启动 Server 跨域问题 详细讲了这种方法,这种方法比较繁琐,而且还可能会遇到问题。
create-react-app 为我们提供一个可配置的 proxy 选项,我们只需要在 package.json 文件里加入这个字段并正确配置就可以了。
当我们所有的请求都只是请求同一个域名的 API 时,我们这样写:
&quot;proxy&quot;: &quot;https://api-domain.com&quot; 比如我们使用 fetch 发请求时,devServer 就会把本地的请求都代理到 proxy 指定的域名 https://api-domain.com 上,那么如果我们项目请求 API 有多个域名怎么办呢?
如果需要区分多个 API,我们 proxy 的值需要是个对象:
&quot;proxy&quot;: { &quot;/aapi&quot;: { &quot;target&quot;: &quot;https://a.api-domain.com&quot;, &quot;secure&quot;: false, &quot;changeOrigin&quot;: true }, &quot;/bapi&quot;: { &quot;target&quot;: &quot;https://b.api-domain.com&quot;, &quot;secure&quot;: false, &quot;changeOrigin&quot;: true } } 由于我们的 API 是 HTTPS 协议的,所以我们每个 API 配置需要加这两个字段:</description>
</item>
<item>
<title>Go 环境配置</title>
<link>http://ijs.me/2018/09/19/go-environment/</link>
<pubDate>Wed, 19 Sep 2018 13:34:41 +0800</pubDate>
<guid>http://ijs.me/2018/09/19/go-environment/</guid>
<description>Go 安装 首先我们来安装 Go,Go 有多种方法安装:
源码安装 Go 1.5 彻底移除 C 代码,Runtime、Compiler、Linker 均由 Go 编写,实现自举,所以我们不再需要先安装 C 编译器,直接去官网找到相应的 goVERSION.src.tar.gz 下载源码,解压到 $HOME 目录,然后执行:
cd go/src ./all.bash 然后我们需要设置环境变量,可以把下面的命令写进 .bashrc 或者 .zshrc 里面:
export GOPATH=$HOME/gopath export PATH=$PATH:$HOME/go/bin:$GOPATH/bin Go标准包安装 但是我们最好通过 Go 标准包安装,直接下载响应系统的安装包,直接点下一步就行了。
第三方工具安装 我们也可以通过 Homebrew 之类的第三方工具安装:
brew update &amp;&amp; brew upgrade brew install go GOPATH 和工作空间 GOPATH 从 go 1.8 开始,GOPATH 环境变量现在有一个默认值,在 Unix 上默认为 $HOME/go,如果 $HOME 目录下没有 go 这个目录则新建。
$GOPATH 目录约定有三个子目录:
src 存放源代码(比如:.</description>
</item>
<item>
<title>JS 双感叹号 (!!) 作用</title>
<link>http://ijs.me/2018/09/18/js-exclamation-point/</link>
<pubDate>Tue, 18 Sep 2018 16:21:23 +0800</pubDate>
<guid>http://ijs.me/2018/09/18/js-exclamation-point/</guid>
<description>我们在 JS 代码中看到 !!a 这样两个感叹号代表什么呢?第一个感叹号为把变量取反转化成 boolean 类型,null、undefined 和空字符串取反之前本身可以视为 false,其余都为 true。第二个感叹号把第一个取反操作再取反,来得到变量原本应该表达的 true 或者 false。
这样写主要是为了把任意类型的数据转换成 boolean 数据类型。
比如我们在和后端 API 进行交互式,经常需要判断数据是否为空,这时就可以这样写:
if (!!a) { // a 非空时才执行的代码 } 而不必写各种臃肿的判断条件了。</description>
</item>
<item>
<title>修改并发布 npm 包</title>
<link>http://ijs.me/2018/09/13/modify-node-modules-package/</link>
<pubDate>Thu, 13 Sep 2018 14:54:58 +0800</pubDate>
<guid>http://ijs.me/2018/09/13/modify-node-modules-package/</guid>
<description>如果我们要修改引用的某个 npm 包该怎么做呢,如果直接去修改 node_modules 下的代码,因为我们不应该把 node_modules 目录传到 Git 上,所以我们改了别人安装依赖时还是没修改过的代码。合理的做法是什么呢?
我们首先应该在 GitHub 上 fork 一份要修改的源代码,然后 clone 到我们本地,进行我们所需的修改,把修改提交到 GitHub 上,由于 npm 可以直接从 GitHub 上安装包,所以我们可以执行 npm install https://github.com/&lt;username&gt;/&lt;repository&gt;/tarball/master 来安装。另外我们还可以把我们修改后的包发布到 npm 上,这样别人也可以直接从 npm 源安装。
由于我们通常会把源换成淘宝源来获取更快的安装速度,所以我们要发布包的话需要先把源改回到官方源:
npm config set registry https://registry.npmjs.org/ 然后如果你已经有 npm 账户了,执行 npm login 来登录;如果没有账户,就执行 npm adduser 来创建账户。
可以执行 npm whoami 来查看你是用哪个账户登录的。
我们的 package.json 里的 name 字段表示包名,需要我们取一个别人没有用过的包名,并且不能和别人的太像,修改好代码后执行 npm publish 来发布你的包,这时你就可以在 https://www.npmjs.com 搜索到你刚发布的包了,并且过一会儿也可以在 淘宝 NPM 镜像源 上搜索到你发布的包了,可以像其他人发布的包那样正常使用。
我们发布完我们的包后,可以把 npm 源改回淘宝源:
npm config set registry https://registry.</description>
</item>
<item>
<title>React Router V4 在 URL 中 传递和获取 '?sort=name' 形式的值</title>
<link>http://ijs.me/2018/09/10/react-router-v4-get-parameter-search/</link>
<pubDate>Mon, 10 Sep 2018 17:02:23 +0800</pubDate>
<guid>http://ijs.me/2018/09/10/react-router-v4-get-parameter-search/</guid>
<description>有时我们需要在 Link 传递的 URL 中加入类似 ?sort=name 的参数, 来组成这样的 URL: a.com?sort=name。
问号 ? 后加参数的形式,这样不占用我们 URL 中的变量,而又有刷新后参数还在的优点。
由于 this.props.location.query 在 React Router v4 中不再存在,所以需要使用 this.props.location.search,然后使用 query-string 来自己解析参数。
我们在父级页面中这样使用 Link 来传来参数,
&lt;Link to={{ pathname: '/courses', search: '?sort=name' }}/&gt; 然后安装 query-string:
yarn add query-string 在子页面中解析传来的参数:
import queryString from 'query-string' class New extends Component { constructor(props) { super(props); let urlParams = queryString.parse(this.props.location.search) } // ... } 这样我们就拿到了 URL 中的参数对象。</description>
</item>
<item>
<title>为 create-react-app 项目添加 Sass 支持</title>
<link>http://ijs.me/2018/09/02/create-react-app-sass/</link>
<pubDate>Sun, 02 Sep 2018 23:34:25 +0800</pubDate>
<guid>http://ijs.me/2018/09/02/create-react-app-sass/</guid>
<description>首先安装 node-sass-chokidar:
yarn add node-sass-chokidar 然后在 package.json 中加入下面两条执行脚本:
&quot;build-css&quot;: &quot;node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/&quot;, &quot;watch-css&quot;: &quot;npm run build-css &amp;&amp; node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/ --watch --recursive&quot;, watch-css 会监控 src 目录下的所有的 .scss 文件,然后会把每一个 .scss 文件生成一个对应的 .css 文件,我们可以在组件中 import 对应的 .css 文件。另外我们需要在 .gitignore 文件中忽略 src 目录及其子目录下的 .css 文件 src/**/*.css。
安装 npm-run-all 来同时执行 npm start 和 watch-css:
yarn add npm-run-all 最后在 package.json 中删掉 start 和 build 这两条脚本,加入下面四条脚本(我的项目已 yarn eject):</description>
</item>
<item>
<title>解决 macOS 下 Vim 的 退格键(backspace)不能用的问题</title>
<link>http://ijs.me/2018/09/01/vim-macos-backspace/</link>
<pubDate>Sat, 01 Sep 2018 22:12:13 +0800</pubDate>
<guid>http://ijs.me/2018/09/01/vim-macos-backspace/</guid>
<description>发现升级到 Vim 8 之后,我是在 iTerm2 里打开的终端里的 Vim,发现退格键不能正常使用了,解决方法如下,我们要在 Vim 的配置文件 .vimrc 中加入下面两项配置:
set nocompatible set backspace=indent,eol,start 然后在终端执行 source ~/.vimrc 使修改的配置立即生效。这样就解决了退格键不起作用的问题。
Vim 是 vi 编辑器的加强版,增加了很多功能,默认 set compatible 是与 vi 兼容,为了兼容失去了很多 Vim 扩展的功能。set nocompatible 是关闭兼容模式,由于这个选项是最基础的配置,会连带很多其它选项的变动。</description>
</item>
<item>
<title>Nginx 解决本地开发启动 Server 跨域问题</title>
<link>http://ijs.me/2018/08/31/react-nginx-server-cors/</link>
<pubDate>Fri, 31 Aug 2018 23:54:43 +0800</pubDate>
<guid>http://ijs.me/2018/08/31/react-nginx-server-cors/</guid>
<description>当我们本地使用开发项目启动了一个 server 后依然打算用 Nginx 反向代理解决 API 跨越问题时,可以这样做:比如我们本地项目的 server 启动的端口是 8000,没有跨域请求 API 时,我们直接在本地访问 http://localhost:8000/ 来访问我们的项目,当我们遇到跨域问题该怎么办呢,我们在服务器上一般通过 Nginx 反向代理到我们项目 build 之后的路径上,那么在我们本地应该怎么做呢?我们在本地 Nginx 可以再监听一个额外的端口,比如 8001,把这个端口的 / 请求代理到我们的 http://localhost:8000/ 上,把 /api 请求代理到我们的 API 域名上,Nginx 配置如下:
server { listen 8001; server_name localhost; location / { proxy_pass http://localhost:8000; } location /api/ { proxy_pass http://api-domain.com; } } 这样我们平时开发就访问 http://localhost:8001/ 来查看我们的项目。
当我们使用 webpack 或者 webpack 基础上构建的脚手架时,更好的办法是使用 proxy 字段来在本地解决 API 跨域的问题,比如我的另一篇文章 Create React App 通过 Proxy 在本地跨域请求 API 介绍了使用 create-react-app 这个使用了 webpack 的脚手架配置 API 代理的方法。</description>
</item>
<item>
<title>Git 修改提交的用户名、邮箱和远程仓库地址</title>
<link>http://ijs.me/2018/08/23/git-modify-username-email-remote-url/</link>
<pubDate>Thu, 23 Aug 2018 23:40:58 +0800</pubDate>
<guid>http://ijs.me/2018/08/23/git-modify-username-email-remote-url/</guid>
<description>Git 修改当前项目的用户名的命令:git config user.name 你的目标用户名;
Git 修改当前项目提交邮箱的命令:git config user.email 你的目标邮箱名;
改完后进入项目的 .git 文件夹,我们可以发现 config 文件已经加上了我们设置的 user 信息,我们也可以编辑这个文件来修改用户名和密码。
Git 修改全局的用户名和邮箱的命令为:
git config --global user.name 你的目标用户名; git config --global user.email 你的目标邮箱名; 也可以编辑全局的 .gitconfig 文件 vi ~/.gitconfig 来修改。</description>
</item>
<item>
<title>zsh 终端快捷键</title>
<link>http://ijs.me/2018/08/22/zsh-terminal-shortcut/</link>
<pubDate>Wed, 22 Aug 2018 22:56:22 +0800</pubDate>
<guid>http://ijs.me/2018/08/22/zsh-terminal-shortcut/</guid>
<description>⌃ + u:清空当前行 ⌃ + a:移动到行首 ⌃ + e:移动到行尾 ⌃ + f:向前移动 ⌃ + b:向后移动 ⌃ + p:上一条命令 ⌃ + n:下一条命令 ⌃ + r:搜索历史命令 ⌃ + y:召回最近用命令删除的文字 ⌃ + h:删除光标之前的字符 ⌃ + d:删除光标所指的字符 ⌃ + w:删除光标之前的单词 ⌃ + k:删除从光标到行尾的内容 ⌃ + t:交换光标和之前的字符
⌘ + Click:可以打开文件,文件夹和链接
⌘ + n:新建窗口
⌘ + t:新建标签页
⌘ + w:关闭当前页
⌘ + 数字 &amp; ⌘ + 方向键:切换标签页
⌥⌘ + 数字:切换窗口</description>
</item>
<item>
<title>调试 React Native</title>
<link>http://ijs.me/2018/08/21/debug-react-native/</link>
<pubDate>Tue, 21 Aug 2018 15:32:42 +0800</pubDate>
<guid>http://ijs.me/2018/08/21/debug-react-native/</guid>
<description>我们写 JavaScript 通常通过 console.log 来打印一些信息调试我们的程序,那么使用 React Native 开发移动 App 应该如何调试呢?
如果我们是在 Xcode 中启动的模拟器,那么我们写的 console.log('test') 实际上是被打印到 Xcode 的 Debug 日志里,直接在 Xcode 里就能看到。
如果我们是通过 react-native run-ios 来启动模拟器,在程序中写 console.log('test'),我们要怎么看到打印的信息呢?
我们可以在模拟器界面,按 Command + D,点击 Debug JS Remotely,就会在浏览器里打开一个新的调试页面,在这个调试页面的 Console 里可以看到我们打印的信息。
或者可以使用 console.warn() 直接在 App 内打印调试信息。</description>
</item>
<item>
<title>Mac Linux 查看端口占用情况及关闭端口</title>
<link>http://ijs.me/2018/08/20/mac-linux-query-kill-port/</link>
<pubDate>Mon, 20 Aug 2018 19:14:56 +0800</pubDate>
<guid>http://ijs.me/2018/08/20/mac-linux-query-kill-port/</guid>
<description>查看端口占用情况 lsof -i:端口号 比如:
lsof -i:8081 输出如下:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME node 44195 mac 20u IPv6 0xc2056b16e4568339 0t0 TCP *:sunproxyadmin (LISTEN) node 44195 mac 28u IPv6 0xc2056b16e456ab79 0t0 TCP localhost:sunproxyadmin-&gt;localhost:56335 (ESTABLISHED) ReactNati 45104 mac 8u IPv6 0xc2056b16e456a5b9 0t0 TCP localhost:56335-&gt;localhost:sunproxyadmin (ESTABLISHED) ReactNati 45104 mac 12u IPv6 0xc2056b16e456a5b9 0t0 TCP localhost:56335-&gt;localhost:sunproxyadmin (ESTABLISHED) 关闭端口 kill -9 44195 kill -9 45104 执行上门两条命令,</description>
</item>
<item>
<title>Git 子模块踩过的坑</title>
<link>http://ijs.me/2018/08/17/git-submodule/</link>
<pubDate>Fri, 17 Aug 2018 09:12:00 +0800</pubDate>
<guid>http://ijs.me/2018/08/17/git-submodule/</guid>
<description>Git 子模块允许你将一个 Git 仓库当作另外一个Git仓库的子目录。这允许你克隆另外一个仓库到你的项目中并且保持你的提交相对独立。
我在一台电脑上配置好了 Git 子目录,也把 Git 子目录生成的配置文件 .gitmodules 提交到了 Github 上,当我在另一台电脑上 clone 下来上层目录时,确发现子模块不起作用。
解决方法如下就是我们需要把根目录下(我这里是 blog)以前生成的 .gitmodules 删掉,然后把子目录(我这里是 public) 从 .gitignore 文件里删除,然后重新添加 Git 子模块,最后把子模块的目录(public)添加到上层目录下的 .gitignore 文件里:
比如我的博客系统的目录是 blog 目录,而生成的博客网站是 blog 目录下的 public 目录,我们已经在 Github 上建立了这两个远程仓库时,我们首先把上层目录 blog 对应的仓库 clone 到本地,我的博客系统是 hugo,当我运行 hugo 命令时,会在 blog 目录下生成一个 public 目录,这个下的文件需要提交到另外一个仓库来当作博客的根目录。这个 public 目录我们是不提交到 Github 上的
我们删除以前生成的 .gitmodules 文件,把 public 从 blog 目录下的 .gitignore 文件里删掉,然后使用以下命令重新添加子模块:
git submodule add -b master git@github.com:cuidezhu/cuidezhu.github.io.git public 然后把子模块的目录(public)添加到上层目录下的 .gitignore 文件里,这样我们就配置好子模块了,下次我们添加文章后重新运行 hugo 命令,就会重新出现 public 文件夹。</description>
</item>
<item>
<title>数字每三个数添加一个逗号</title>
<link>http://ijs.me/2018/08/14/number-add-comma/</link>
<pubDate>Tue, 14 Aug 2018 23:55:31 +0800</pubDate>
<guid>http://ijs.me/2018/08/14/number-add-comma/</guid>
<description>function addCommaNumber(num) { let newStr = &quot;&quot;; let numStr = num.toString(); let count = 1 for (let i = numStr.length - 1; i &gt;= 0; i--) { if (count % 3 === 0 &amp;&amp; i !== 0) { newStr = ',' + numStr.charAt(i) + newStr; } else { newStr = numStr.charAt(i) + newStr; } count++; } return newStr; } </description>
</item>
<item>
<title>更改 Git 远程仓库地址</title>
<link>http://ijs.me/2018/08/13/change-git-remote-url/</link>
<pubDate>Mon, 13 Aug 2018 00:09:13 +0800</pubDate>
<guid>http://ijs.me/2018/08/13/change-git-remote-url/</guid>
<description> 我们有时候需要更改 Git 仓库的远程地址,该如何操作呢?通常有下面几种方式:
先删后加 git remote rm origin git remote add origin git@xxx </description>
</item>
<item>
<title>微信小程序开发指南</title>
<link>http://ijs.me/2018/08/07/miniprogram-dev/</link>
<pubDate>Tue, 07 Aug 2018 20:43:14 +0800</pubDate>
<guid>http://ijs.me/2018/08/07/miniprogram-dev/</guid>
<description>开发环境 首先我们去 微信公众平台 注册一个小程序账号,按照要求填写信息即可,这里我注册的是个人账号。然后用我们注册好的账号登陆微信公众平台,点击右侧菜单栏的设置,然后选择开发设置,这里我们可以看到开发者ID下面有AppID(小程序ID),复制你的小程序ID那串字符。
然后我们去下载 微信开发者工具,选择你系统对应的版本即可。安装好打开开发工具,点小程序项目来新建一个小程序项目,然后选择项目目录,把上一步你复制的AppID粘贴到AppID表单里,填写项目名称,选择默认的建立普通快速启动模版即可,确定信息无误点击确定。这时我们就进入微信小程序开发页面了,下次我们再打开微信开发者工具时,就可以看到我们这次新建的这个小程序,直接点击进入即可。
项目结构 打开项目,我们可以看到左侧一个 Hello World 的界面,右侧是我们的项目代码。我们可以先随便去 pages/index/index.wxml 修改一下代码,Ctrl + S 保存,就可以看到左侧的页面跟着刷新了,展示出我们的修改。.wxml 文件对应的是我们普通的 .html 文件,结构大致是类似的,只是标签名有所不同,而 .wxss 文件对应的就是我们普通的 .css 文件。</description>
</item>
<item>
<title>JavaScript 跨域问题解决方法</title>
<link>http://ijs.me/2018/08/05/javascript-cross-domain-solution/</link>
<pubDate>Sun, 05 Aug 2018 21:19:21 +0800</pubDate>
<guid>http://ijs.me/2018/08/05/javascript-cross-domain-solution/</guid>
<description>只要协议,域名,端口有任何一个不同,都被当作跨域。
以下情况会出现跨域:
协议不同,http://a.com 和 https://a.com </description>
</item>
<item>
<title>JS 获取 URL 中 GET 参数的值(正则法和 location.search 法)</title>
<link>http://ijs.me/2018/08/03/js-url-get-params/</link>
<pubDate>Fri, 03 Aug 2018 19:43:08 +0800</pubDate>
<guid>http://ijs.me/2018/08/03/js-url-get-params/</guid>
<description> 正则法 location.search 法 function getSearch() { let url = location.search; let theRequest = new Object(); if (url.indexOf(&quot;?&quot;) != -1) { let str = url.substr(1); strs = str.split(&quot;&amp;&quot;); for(var i = 0; i &lt; strs.length; i ++) { theRequest[strs[i].split(&quot;=&quot;)[0]] = unescape(strs[i].split(&quot;=&quot;)[1]); } } return theRequest; } </description>
</item>
<item>
<title>使用 Webpack 从零开始手动搭建 React 环境</title>
<link>http://ijs.me/2018/08/02/webpack-react-environment/</link>
<pubDate>Thu, 02 Aug 2018 23:30:36 +0800</pubDate>
<guid>http://ijs.me/2018/08/02/webpack-react-environment/</guid>
<description>新建一个项目的文件夹,打开终端,进入我们新建的文件夹目录,我们使用 npm init 来初始化一个 npm 项目,按照提示填写项目相关信息,然后它会根据你填的信息生成一个 package.json 文件。
我们的项目需要用到 Webpack 和 React,这里我们用 webpack 的版本 3.9.1,我们首先安装下这两个包:
npm i webpack@3.9.1 react npm i 是 npm install 的别名,其它 npm install 的别名有 isntall, add,npm install 的后缀的意思可以看 官方文档:
npm install saves any specified packages into dependencies by default. Additionally, you can control where and how they get saved with some additional flags:
-P, &ndash;save-prod: Package will appear in your dependencies. This is the default unless -D or -O are present.</description>
</item>
<item>
<title>Flutter 入门教程</title>
<link>http://ijs.me/2018/07/31/flutter-getting-started-tutorial/</link>
<pubDate>Tue, 31 Jul 2018 23:43:37 +0800</pubDate>
<guid>http://ijs.me/2018/07/31/flutter-getting-started-tutorial/</guid>
<description>Flutter 是谷歌推出的一款开发移动端 App 的框架,支持 Android,iOS,和谷歌未来的新系统 Fuchsia。Flutter 解决了 React Native 的性能问题,现在学习 Flutter 正当其时,用一套代码即可支持多平台应用,为我们带来了开发效率的极大提升。
Flutter 是用 Dart 语言写的,坊间相传 Dart 开发组就在 Flutter 团队旁边,所以 Flutter 团队为了方便才用 Dart 的,其实主要是因为 Dart 语言的高性能,Dart 支持即时编译(just-in-time compilation)和预先编译(ahead-of-time Compilation),即时编译使 Flutter 能在 App 运行时直接重新编译,热加载(Hot Reloading)带来了开发效率的提高;预先编译意味着你的 App 使用的库和函数等直接编译为原生的 ARM 代码,这时发布版的 App 运行效率更高和可预测, 所以 Dart 非常适合移动开发。而且 Dart 有静态类型,随着项目规模的增大,可以帮助你更好的追踪 Bug 和管理代码。
安装 Dart SDK 与 Flutter 捆绑在一起,不需要单独安装 Dart。我本机的系统是 macOS,如果你是别的系统,可以去官网查看安装方法。
首先我们去官网下载最新的安装包,当前是 v0.5.1-beta 版,然后解压到你想要的文件夹中,我是解压到了自己的家目录 ~ 下。
然后把 flutter 永久性加入到环境变量(PATH)中,打开命令行,我使用的是 iTerm2 + zsh,查看你的 flutter 的解压路径 pwd,然后 vim $HOME/.</description>
</item>
<item>
<title>最少硬币找零问题</title>
<link>http://ijs.me/2018/07/30/minimum-coin-change-problem/</link>
<pubDate>Mon, 30 Jul 2018 23:47:06 +0800</pubDate>
<guid>http://ijs.me/2018/07/30/minimum-coin-change-problem/</guid>
<description>有面额为d1&hellip;dn的硬币,和要找零的钱数,找出所需最小硬币个数的方案,例如,美国有一下面额(硬币):d1=1, d2=5, d3=10, d4 = 25, 如果要找36美分的零钱,所需最少硬币是[1, 10, 25],即满足如下输出:
const minCoinChange = new minCoinChange([1, 5, 10, 25]) console.log(minCoinChange(36)) // [1, 10, 25] const minCoinChange2 = new MinCoinChange([1, 3, 4]) console.log(minCoinChange2.makeChange(6)) // [3, 3] 此题为动态规划的典型题目</description>
</item>
<item>
<title>对比两个 JS 对象是否相等</title>
<link>http://ijs.me/2018/07/28/compare-two-js-object/</link>
<pubDate>Sat, 28 Jul 2018 23:42:47 +0800</pubDate>
<guid>http://ijs.me/2018/07/28/compare-two-js-object/</guid>
<description>我们知道 JS 对象引用数据类型,存储的是对象在内存中的地址,故下面两个对象是不相等的:
let obj = {name: 1} let obj1 = {name: 1} console.log(obj == obj1) //false 那么我们怎么比较两个对象是否相等呢?还有如果对象内的属性值还有对象呢,我们应当递归处理这种情况。
let obj = {name: 1, other: {title: 'react'}} let obj1 = {name: 1, other: {title: 'react'}} function compareObj(obj1, obj2) { if (obj1 == obj2) { return true } if (Object.keys(obj1).length !== Object.keys(obj2).length) { return false } for(let k in obj1) { if (typeof obj1[k] == 'object') { return compareObj(obj1[k], obj2[k]) } else if (obj1[k] !</description>
</item>
<item>
<title>JavaScript 函数柯里化(Curry)</title>
<link>http://ijs.me/2018/07/27/javascript-function-curry/</link>
<pubDate>Fri, 27 Jul 2018 18:41:39 +0800</pubDate>
<guid>http://ijs.me/2018/07/27/javascript-function-curry/</guid>
<description>const add = function(x) { return function(y) { return x + y + 3 } } const add = x =&gt; y =&gt; x+y+3 const res = add(2)(4) console.log('res is', res) </description>
</item>
<item>
<title>React 服务端渲染(SSR)</title>
<link>http://ijs.me/2018/07/24/react-server-side-rendering/</link>
<pubDate>Tue, 24 Jul 2018 21:38:00 +0800</pubDate>
<guid>http://ijs.me/2018/07/24/react-server-side-rendering/</guid>
<description>服务端渲染有利于首屏加载速度和搜索引擎优化(SEO)。
babel-node 因为 Node 环境原生不支持 JSX,首先我们使用 babel-node 让 Node 环境支持 JSX:
yarn add babel-cli 然后我们在 package.json 里用 babel-node 来替代 Node,&rdquo;scripts&rdquo; 字段里加入下面一行:
&quot;scripts&quot;: { &quot;server&quot;: &quot;NODE_ENV=test nodemon --exec babel-node server/server.js&quot;, } 现在我们的 Node 环境已经支持 es6 了,那么怎么支持 JSX 呢?我们在项目根目录下新建个 babel 的配置文件 .babelrc,然后把我们的 package.json 文件下的 babel 的配置复制到 .babelrc 文件中:
{ &quot;presets&quot;: [ &quot;react-app&quot; ], &quot;plugins&quot;: [ &quot;transform-decorators-legacy&quot;, [ &quot;import&quot;, { &quot;libraryName&quot;: &quot;antd-mobile&quot;, &quot;style&quot;: &quot;css&quot; } ] ] } renderToString() 然后我们把 src/index.</description>
</item>
<item>
<title>redux-thunk 中间件的实现</title>
<link>http://ijs.me/2018/07/22/redux-thunk-middleware-implementation/</link>
<pubDate>Sun, 22 Jul 2018 22:05:08 +0800</pubDate>
<guid>http://ijs.me/2018/07/22/redux-thunk-middleware-implementation/</guid>
<description> 同步中间件 通过 redux 暴露出的 applyMiddleware,我们可以得到一个新的 dispatch. 所以 applyMiddleware 的实际效果可以看做是:dispatch =&gt; newdispatch
异步中间件 对于异步的情况,我们拿 redux-thunk 为例,它会对传入的 action 进行判断,如果是 function 的话。则去把我们的 action 执行,这个执行的就是我们的 delay 代码。然后在最里面执行 dispatch()。所以我们的箭头又重新回到最上面,这一次就相当于同步的使用了。
redux-thunk 允许我们的 action 创建函数 return 一个函数而不是一个 action, 经常用来延迟 dispatch 某个 action。redux-thunk 本身代码非常简单,下面我们来实现一下:
const thunk = ({ dispatch, getState }) =&gt; next =&gt; action =&gt; { // 如果是函数,执行一下,参数是dispatch和getState if (typeof action === &quot;function&quot;) { return action(dispatch, getState) } // 默认什么都没干 return next(action) } export default thunk </description>
</item>
<item>
<title>函数式编程</title>
<link>http://ijs.me/2018/07/21/functional-programming/</link>
<pubDate>Sat, 21 Jul 2018 12:09:18 +0800</pubDate>
<guid>http://ijs.me/2018/07/21/functional-programming/</guid>
<description>函数式编程是一种编程典范,最重要的是函数可以当参数,函数也可以当返回值。比如下面这个例子:
function hello() { console.log('hello, I love react') } function WrapperHello(fn) { return function() { console.log('before say hello') fn() console.log('after say hello') } } hello = WrapperHello(hello) hello() 上面这句 hello = WrapperHello(hello) 把 hello() 这个函数装饰了一次,这种设计模式称为装饰器模式,这也是 React 中的高阶组件(HOC)实现的基础。</description>
</item>
<item>
<title>React 高阶组件和装饰器</title>
<link>http://ijs.me/2018/07/20/react-higher-order-components-and-decorator/</link>
<pubDate>Fri, 20 Jul 2018 19:56:36 +0800</pubDate>
<guid>http://ijs.me/2018/07/20/react-higher-order-components-and-decorator/</guid>
<description>高阶组件 高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件。但高阶组件本身并不是React API,它只是一种模式。
下面我们来实现一个高阶组件:
function WrapperHello(Comp) { class WrapComp extends React.Component { render() { return ( &lt;div&gt; &lt;p&gt;这是 HOC 高阶组件特有的元素&lt;/p&gt; &lt;Comp {...this.props}&gt;&lt;/Comp&gt; &lt;/div&gt; ) } } return WrapComp } class Hello extends React.Component { render() { return &lt;h2&gt;Hello, I love React&amp;Redux&lt;/h2&gt; } } Hello = WrapperHello(Hello) 装饰器写法 我们把 Hello = WrapperHello(Hello) 改为装饰器的写法就是下面这样:
function WrapperHello(Comp) { class WrapComp extends React.Component { render() { return ( &lt;div&gt; &lt;p&gt;这是 HOC 高阶组件特有的元素&lt;/p&gt; &lt;Comp {.</description>
</item>
<item>
<title>实现 react-redux</title>
<link>http://ijs.me/2018/07/18/react-redux-implementation/</link>
<pubDate>Wed, 18 Jul 2018 20:45:52 +0800</pubDate>
<guid>http://ijs.me/2018/07/18/react-redux-implementation/</guid>
<description>前面的文章 迷你 Redux 实现 我们实现了一个简单的 Redux, 那么我们怎么在 React 项目里使用我们自制的 Redux 呢?我们可以显式传递 Store,但更优雅的方式是使用 react-redux,这篇文章会实现我们自己的 react-redux。
显式传递 Store 我们可以手动用 subscribe 订阅 ReactDOM.render 来将把 redux 和 react 结合起来,将 Store 集成到 UI 中最合乎直觉逻辑的做法是显式地将它作为属性在组件树中向下传递。例如下面的 index.js 文件中渲染一个 App 组件并传递 Store:
import React from &quot;react&quot; import ReactDOM from &quot;react-dom&quot; import App from &quot;./components/App&quot; import { counter } from &quot;./index.redux&quot; const store = createStore(counter) const render = () =&gt; ReactDOM.render(&lt;App store={store} /&gt;, document.getElementById(&quot;root&quot;)) store.subscribe(render) render() 在这个文件中,我们使用 counter 这个 reducer 处理函数来创建了一个 store,当 App 组件渲染完毕后,Store 会作为属性传递给它。每次 Store 发生变化后,render 函数就会被触发执行,这样就可以使用新的 State 数据高效地更新 UI 了。</description>
</item>
<item>
<title>React 原理深入解析(附源码)</title>
<link>http://ijs.me/2018/07/15/react-source-code-analysis/</link>
<pubDate>Sun, 15 Jul 2018 09:51:10 +0800</pubDate>
<guid>http://ijs.me/2018/07/15/react-source-code-analysis/</guid>
<description>JSX 我们现在一般使用 JSX 来写 React 代码,实际上我们的 JSX 最终会把编译成普通的 JavaScript 代码,我们可以在 Babel 里看下转化后的代码:
我们可以看到经过 Babel 编译后,React 实际上是调用 createElement() 函数 来创建元素的。
React.createElement() 我们可以看下 React 源码中的 react/packages/react/src/ReactElement.js 文件,找到createElement() 函数,createElement() 接收三个参数,分别是元素的类型,属性,和子元素:
/** * Create and return a new ReactElement of the given type. * See https://reactjs.org/docs/react-api.html#createelement */ export function createElement(type, config, children) { let propName // Reserved names are extracted const props = {} let key = null let ref = null let self = null let source = null if (config !</description>
</item>
<item>
<title>迷你 Redux 实现</title>
<link>http://ijs.me/2018/07/14/mini-redux-implemention/</link>
<pubDate>Sat, 14 Jul 2018 20:04:01 +0800</pubDate>
<guid>http://ijs.me/2018/07/14/mini-redux-implemention/</guid>
<description>redux 主要由三部分组成:action, reduer, store,
Action Action 是用户自己定义的,用来描述发生了什么, action 的 type 字段是必须的,其它字段可以自己定义:
const action = { type: 'ADD_TODO', }; Reducer Reducer 也是由用户负责编写的,Reducers 指定了应用状态的变化如何响应 actions 并发送到 store 的,记住 actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state。
function todoApp(state = initialState, action) { switch (action.type) { case ADD_TODO: return state + 1 default: return state } } Store redux 只有一个单一的 Store, 用户通过 createStore() 来创建 store,createStore() 接受一个 reducer 函数作为参数, 我们使用 combineReducers() 将多个 reducer 合并成为一个。
createStore() 的第二个参数是可选的, 用于设置 state 初始状态。这对开发同构应用时非常有用,服务器端 redux 应用的 state 结构可以与客户端保持一致, 那么客户端可以将从网络接收到的服务端 state 直接用于本地数据初始化。</description>
</item>
<item>
<title>单向数据绑定 VS 双向数据绑定</title>
<link>http://ijs.me/2018/07/13/one-way-data-binding-vs-two-way-data-binding/</link>
<pubDate>Fri, 13 Jul 2018 19:19:13 +0800</pubDate>
<guid>http://ijs.me/2018/07/13/one-way-data-binding-vs-two-way-data-binding/</guid>
<description> 单向数据绑定 React 的数据是单向绑定的,不像 Vue 支持双向绑定。相应的 React 中的数据流也是单向的,这也是 React 提倡的一点,单向数据绑定能够避免状态管理复杂度上升时产生的各种问题。试想一下在双向数据绑定中:如果一个 model 的变化会引起另一个 model 变化,那么当 view 变化时,就可能引起对应 model 以及另一个 model 的变化,依次地,可能会引起另一个 view 的变化。直至你搞不清楚到底发生了什么。state 在什么时候,由于什么原因,如何变化已然不受控制。 当系统变得错综复杂的时候,想重现问题或者添加新功能就会变得举步维艰。单向数据绑定可以让应用变得更加可预测且容易理解。
单向数据绑定的优点:
所有状态的改变可记录、可跟踪,源头易追溯; 所有数据只有一份,组件数据只有唯一的入口和出口,使得程序更直观更容易理解,有利于应用的可维护性; 一旦数据变化,就去更新页面(data-页面),但是没有(页面-data); 如果用户在页面上做了变动,那么就手动收集起来(双向是自动),合并到原有的数据中。 双向绑定 = 单向绑定 + UI事件监听
单向数据绑定的缺点:
HTML代码渲染完成,无法改变,有新数据,就须把旧HTML代码去掉,整合新数据和模板重新渲染; 代码量上升,数据流转过程变长,出现很多类似的样板代码; 同时由于对应用状态独立管理的严格要求(单一的全局store),在处理局部状态较多的场景时(如用户输入交互较多的“富表单型”应用 TodoMVC等),会显得啰嗦及繁琐。 双向数据绑定 双向数据绑定带来了双向数据流,数据模型(Module)和视图(View)之间的双向绑定,无论数据变化,或是用户操作,都能带来互相的变动,自动更新,适用于UI控件中(通常是类表单操作)。
双向数据绑定优点:
用户在视图上的修改会自动同步到数据模型中去,数据模型中值的变化也会立刻同步到视图中去; 无需进行和单向数据绑定的那些CRUD(Create,Retrieve,Update,Delete)操作; 在表单交互较多的场景下,会简化大量业务无关的代码。 双向数据绑定缺点:
无法追踪局部状态的变化; “暗箱操作”,增加了出错时 debug 的难度; 由于组件数据变化来源入口变得可能不止一个,数据流转方向易紊乱,若再缺乏“管制”手段,血崩。 </description>
</item>
<item>
<title>五种方式实现三栏布局(两边固定宽度,中间自适应)</title>
<link>http://ijs.me/2018/07/11/html-css-three-column-layout/</link>
<pubDate>Wed, 11 Jul 2018 23:15:41 +0800</pubDate>
<guid>http://ijs.me/2018/07/11/html-css-three-column-layout/</guid>
<description>三栏布局是网页中常见的布局,即两边固定宽度,中间自适应,下面我们用五种不同的方式来实现这种布局。
&lt;!DOCTYPE html&gt; &lt;html lang=&quot;en&quot;&gt; &lt;head&gt; &lt;meta charset=&quot;UTF-8&quot;&gt; &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt; &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;ie=edge&quot;&gt; &lt;title&gt;Document&lt;/title&gt; &lt;style&gt; html * { margin: 0; padding: 0; } .layout { margin-top: 20px; } .layout:first-child { margin-top: 0; } .layout div { min-height: 150px; } &lt;/style&gt; &lt;/head&gt; &lt;body&gt; &lt;!-- float 浮动解决方案 --&gt; &lt;section class=&quot;layout float&quot;&gt; &lt;style&gt; .layout.float .left { float: left; width: 300px; background: red; } .layout.float .right { float: right; width: 300px; background: blue; } .</description>
</item>
<item>
<title>Apply, Call 和 Bind</title>
<link>http://ijs.me/2018/07/04/apply-call-bind/</link>
<pubDate>Wed, 04 Jul 2018 23:58:57 +0800</pubDate>
<guid>http://ijs.me/2018/07/04/apply-call-bind/</guid>
<description>在 JavaScript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向。
let obj = { name: 'jack' } function func() { console.log(this.name); } func.call(obj); // &quot;jack&quot; call 方法的第一个参数是作为函数上下文的对象,这里把 obj 作为参数传给了 func,此时函数里的 this 便指向了 obj 对象。此处 func 函数里其实相当于
function func() { console.log(obj.name); } call 和 apply 作用相同,只是接收的参数不一样
function.apply(thisArg, [argsArray]) function.call(thisArg, arg1, arg2, ...) bind() 也可以改变 this 的指向,bind() 方法会创建一个新函数,当这个新函数被调用时,它的 this 值是传递给 bind() 的第一个参数, 它的参数是 bind() 的其他参数和其原本的参数。
apply, call 和 bind 三者有相似之处,
都是用来改变函数的this对象的指向的。 第一个参数都是this要指向的对象。 都可以利用后续参数传参。 var xw={ name: &quot;小王&quot;, gender: &quot;男&quot;, age: 24, say: function() { alert(this.</description>
</item>
<item>
<title>JavaScript 函数防抖 Debounce 实现原理</title>
<link>http://ijs.me/2018/07/02/javascript-function-debounce/</link>
<pubDate>Mon, 02 Jul 2018 23:20:48 +0800</pubDate>
<guid>http://ijs.me/2018/07/02/javascript-function-debounce/</guid>
<description>考虑这样一个场景,我们有一个搜索框,需要在用户输入内容时列出搜索结果,我们可以用 oninput 事件来做这件事情。
oninput 和 onchange 不同之处在于 oninput 事件在 input 值发生变化是立即触发, onchange 在元素失去焦点时触发。