-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
202 lines (93 loc) · 357 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>this pointer</title>
<link href="/2021/11/23/this%20pointer/"/>
<url>/2021/11/23/this%20pointer/</url>
<content type="html"><![CDATA[<h5 id="今天主要是总结一下看的书的第一小节,主要是关于this指针的指向问题和new关键字的实现与bind的实现的知识点。">今天主要是总结一下看的书的第一小节,主要是关于<code>this</code>指针的指向问题和<code>new</code>关键字的实现与<code>bind</code>的实现的知识点。</h5><h3 id="this指针">this指针</h3><p><code>this</code>指针总的来说用一句话总结就是<code>谁调用就指向谁</code>。但是还是不太全面,所以我们将分以下几个部分来总结:1. 显示绑定 2. 隐式绑定 3. <code>new</code>关键字 4. 箭头函数 5. 混合的优先级</p><h4 id="显示绑定">显示绑定</h4><p>显示绑定的函数有<code>bind</code>,<code>call</code>和<code>apply</code>。他们之间没有什么大的区别,区别在于之后的传参的形式和返回的值。</p><p><code>call</code>和<code>apply</code>回立刻执行函数,而<code>bind</code>是返回绑定<code>this</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> target = {}</span><br><span class="line">fn.call(target, <span class="string">'arg1'</span>, <span class="string">'arg2'</span>);</span><br><span class="line"></span><br><span class="line">fn.apply(target, [<span class="string">'arg1'</span>, <span class="string">'arg2'</span>]);</span><br><span class="line"></span><br><span class="line">fn.bind(target, <span class="string">'arg1'</span>, <span class="string">'arg2'</span>)();</span><br></pre></td></tr></table></figure><h4 id="隐式绑定">隐式绑定</h4><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> person = {</span><br><span class="line"> name: <span class="string">'Lucas'</span>,</span><br><span class="line"> fn: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.name</span><br><span class="line"> },</span><br><span class="line"> brother: {</span><br><span class="line"> name: <span class="string">'Mike'</span>,</span><br><span class="line"> fn: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.name</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> fn1 = person.brother.fn;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(fn1());</span><br><span class="line"><span class="built_in">console</span>.log(person.fn());</span><br><span class="line"><span class="built_in">console</span>.log(person.brother.fn());</span><br></pre></td></tr></table></figure><h4 id="new关键字">new关键字</h4><p><code>new</code>关键字生成的实例中,this的指向为该对象。</p><p>关于new关键字的更多操作在之后讲。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> person = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">this</span>.name = <span class="string">'Lucas'</span>,</span><br><span class="line"> <span class="keyword">this</span>.fn = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.name</span><br><span class="line"> },</span><br><span class="line"> <span class="keyword">this</span>.brother = {</span><br><span class="line"> name: <span class="string">'Mike'</span>,</span><br><span class="line"> fn: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.name</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="built_in">console</span>.log(<span class="keyword">new</span> person().fn());</span><br><span class="line"><span class="built_in">console</span>.log(<span class="keyword">new</span> person().brother.fn());</span><br></pre></td></tr></table></figure><h4 id="箭头函数">箭头函数</h4><p>箭头函数是<code>es6</code>中的新特性,他本身没有this指针。所以this指针的指向是在形成时,其外部作用域(函数作用域或者全局作用域)的指向。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> a = {</span><br><span class="line">fn:<span class="function"><span class="params">()</span>=></span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="keyword">this</span>)</span><br><span class="line"> }</span><br><span class="line"> fn2: (<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="keyword">this</span>)</span><br><span class="line"> })()</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(a.fn())</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(a.fn2())</span><br></pre></td></tr></table></figure><h4 id="this的优先级"><code>this</code>的优先级</h4><p><code>new</code>关键字高于显示绑定高于隐式绑定,箭头函数的<code>this</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="params">a</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="keyword">this</span>.a)</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> obj1 = {</span><br><span class="line"> a: <span class="number">2</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">const</span> obj2 = {</span><br><span class="line"> a: <span class="number">3</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> bar = foo.call(obj1)</span><br><span class="line"><span class="built_in">console</span>.log(bar.call(obj2))</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><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> a = <span class="number">123</span><span class="comment">// const a = 1;</span></span><br><span class="line"><span class="keyword">const</span> foo= <span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="params">a</span> =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="keyword">this</span>.a)</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> obj1 = {</span><br><span class="line"> a: <span class="number">2</span></span><br><span class="line">}</span><br><span class="line"><span class="keyword">const</span> obj2 = {</span><br><span class="line"> a: <span class="number">3</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> bar = foo.call(obj1)</span><br><span class="line"><span class="built_in">console</span>.log(bar.call(obj2))</span><br></pre></td></tr></table></figure><p><code>const</code>声明的变量不会挂载在window对象上。</p><h3 id="new关键字实现">new关键字实现</h3><ol><li>创建新对象,将对象的<code>__proto__</code>指向函数的<code>prototype</code></li><li>将属性挂在新对象上</li><li><code>this</code>的指向指向新对象</li><li>如果没有返回对象则返回<code>this</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> _new = <span class="function"><span class="keyword">function</span>(<span class="params">fn, ...arg</span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> obj = <span class="built_in">Object</span>.create(fn.prototype); <span class="comment">//1</span></span><br><span class="line"> <span class="keyword">const</span> res = fn.apply(obj, arg); <span class="comment">//2,3</span></span><br><span class="line"> <span class="keyword">return</span> res <span class="keyword">instanceof</span> <span class="built_in">Object</span> ? res : object; <span class="comment">//4</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="bind实现">bind实现</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> _bind = <span class="built_in">Function</span>.prototype.bind || <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> me = <span class="keyword">this</span></span><br><span class="line"> <span class="keyword">var</span> context = <span class="built_in">Array</span>.prototype.shift.call(<span class="built_in">arguments</span>)</span><br><span class="line"> <span class="keyword">var</span> arg = <span class="built_in">Array</span>.prototype.slice.call(<span class="built_in">arguments</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> <span class="title">bound</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">var</span> innnerArg = <span class="built_in">Array</span>.prototype.slice.call(<span class="built_in">arguments</span>)</span><br><span class="line"> <span class="keyword">var</span> args = arg.contact(innerArg);</span><br><span class="line"> <span class="keyword">return</span> me.apply(context, args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
</entry>
<entry>
<title>Echarts Project Summary</title>
<link href="/2021/10/08/Echarts%20Project%20Summary/"/>
<url>/2021/10/08/Echarts%20Project%20Summary/</url>
<content type="html"><![CDATA[<h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p> 2021年的暑期在summer2021的活动当中找了一个开源项目,并且在学姐的建议下找一个比较大的开源团队(Apache)项目去写。最终也是捡漏捡到了Echarts的这样一个高难度的项目去写。(只有我一个人报了这个项目</p><p>现在写这篇博客的时候正是9月22日,还有几天就要期末考核了,但是我的导师还是没有review我的代码和对第二个需求的详细解答。我也很无奈,很想结项啊!!!把我的code合进去也不擦啊啊啊!</p><h2 id="需求分析"><a href="#需求分析" class="headerlink" title="需求分析"></a>需求分析</h2><p>当时接到需求的时候大概心里是有了个想法的,“关于节点自指”,其实就是节点的边信息当中的始末节点都为一个节点。有了想法就去实施,我把仓库clone下来时,我又懵了。只知道按照惯例开始往src里面找代码。</p><p><img src="https://i.loli.net/2021/10/08/ogLJvk2htVNZiEW.png" alt="image-20210922105406715.png"></p><p>在这里我利用了搜索工具,搜索了一下graph这么个关键字,找到了对应的文件夹,开始啥也不懂的乱看。这里有提到test文件夹里面的例子,其实是已经帮我们链接好了,所以我反复对比官网和代码。找到了可以改变内容的代码之后,立马跑过去问导师了,导师也给出了相应的回复,这时才慢慢走上了正道。</p><h2 id="类"><a href="#类" class="headerlink" title="类"></a>类</h2><p>突然想起来我刚刚开始看的时候是把几个类看了才开始写的。类也是面向对象最基本的思想,我涉及部分的类有Graph类、GraphNode类、GraphEdge类、List类、Line类。现在想想只有最开始把这些类搞清楚了,到后面看代码的时候才对一些方法和属性搞糊涂。</p><p>Graph类,是最基础的图类,其中有GraphNode数组和Graph Edge数组作为属性,data和edgeData两个List类。以及一些其他的方法和属性。这里最主要的就是这些。</p><figure class="highlight typescript"><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="keyword">class</span> Graph {</span><br><span class="line"> <span class="keyword">type</span>: <span class="string">'graph'</span> = <span class="string">'graph'</span>;</span><br><span class="line"></span><br><span class="line"> readonly nodes: GraphNode[] = [];</span><br><span class="line"></span><br><span class="line"> readonly edges: GraphEdge[] = [];</span><br><span class="line"></span><br><span class="line"> data: List;</span><br><span class="line"></span><br><span class="line"> edgeData: List;</span><br><span class="line"> </span><br><span class="line"> ...<span class="comment">//部分代码展示</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>GraphNode类,是图结点类</p><figure class="highlight ts"><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="keyword">class</span> GraphNode {</span><br><span class="line"></span><br><span class="line"> id: <span class="built_in">string</span>;</span><br><span class="line"></span><br><span class="line"> inEdges: GraphEdge[] = [];</span><br><span class="line"></span><br><span class="line"> outEdges: GraphEdge[] = [];</span><br><span class="line"></span><br><span class="line"> edges: GraphEdge[] = [];</span><br><span class="line"></span><br><span class="line"> hostGraph: Graph;</span><br><span class="line"></span><br><span class="line"> dataIndex: <span class="built_in">number</span> = <span class="number">-1</span>;</span><br><span class="line"> ...<span class="comment">//部分代码展示</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>GraphEdge类,是图关系类</p><figure class="highlight ts"><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="keyword">class</span> GraphEdge {</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The first node. If directed graph, it represents the source node.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> node1: GraphNode;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The second node. If directed graph, it represents the target node.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> node2: GraphNode;</span><br><span class="line"></span><br><span class="line"> dataIndex: <span class="built_in">number</span> = <span class="number">-1</span>;</span><br><span class="line"></span><br><span class="line"> hostGraph: Graph;</span><br><span class="line"> ...<span class="comment">//部分代码展示</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>List类</p><figure class="highlight ts"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> List<</span><br><span class="line"> HostModel <span class="keyword">extends</span> Model = Model,</span><br><span class="line"> Visual <span class="keyword">extends</span> DefaultDataVisual = DefaultDataVisual</span><br><span class="line">> {</span><br><span class="line"></span><br><span class="line"> readonly <span class="keyword">type</span> = <span class="string">'list'</span>;</span><br><span class="line"></span><br><span class="line"> readonly dimensions: <span class="built_in">string</span>[];</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Infomation of each data dimension, like data type.</span></span><br><span class="line"> <span class="keyword">private</span> _dimensionInfos: {[dimName: <span class="built_in">string</span>]: DataDimensionInfo};</span><br><span class="line"></span><br><span class="line"> readonly hostModel: HostModel;</span><br><span class="line"> ...<span class="comment">//部分代码展示</span></span><br><span class="line"> <span class="comment">// eslint-disable-next-line</span></span><br><span class="line"> setItemVisual<K <span class="keyword">extends</span> keyof Visual>(idx: <span class="built_in">number</span>, key: K, value: Visual[K]): <span class="built_in">void</span>;</span><br><span class="line"> setItemVisual(idx: <span class="built_in">number</span>, kvObject: Partial<Visual>): <span class="built_in">void</span>;</span><br><span class="line"> <span class="comment">// eslint-disable-next-line</span></span><br><span class="line"> setItemVisual<K <span class="keyword">extends</span> keyof Visual>(idx: <span class="built_in">number</span>, key: K | Partial<Visual>, value?: Visual[K]): <span class="built_in">void</span> {</span><br><span class="line"> <span class="keyword">const</span> itemVisual = <span class="keyword">this</span>._itemVisuals[idx] || {};</span><br><span class="line"> <span class="keyword">this</span>._itemVisuals[idx] = itemVisual;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (isObject(key)) {</span><br><span class="line"> zrUtil.extend(itemVisual, key);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> itemVisual[key <span class="keyword">as</span> <span class="built_in">string</span>] = value;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> setLayout(key: <span class="built_in">string</span>, val: <span class="built_in">any</span>): <span class="built_in">void</span>;</span><br><span class="line"> setLayout(kvObj: Dictionary<<span class="built_in">any</span>>): <span class="built_in">void</span>;</span><br><span class="line"> setLayout(key: <span class="built_in">string</span> | Dictionary<<span class="built_in">any</span>>, val?: <span class="built_in">any</span>): <span class="built_in">void</span> {</span><br><span class="line"> <span class="keyword">if</span> (isObject(key)) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">const</span> name <span class="keyword">in</span> key) {</span><br><span class="line"> <span class="keyword">if</span> (key.hasOwnProperty(name)) {</span><br><span class="line"> <span class="keyword">this</span>.setLayout(name, key[name]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">this</span>._layout[key] = val;</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"> * Get layout property.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> getLayout(key: <span class="built_in">string</span>): <span class="built_in">any</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>._layout[key];</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"> * Get layout of single data item</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> getItemLayout(idx: <span class="built_in">number</span>): <span class="built_in">any</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>._itemLayouts[idx];</span><br><span class="line"> }</span><br><span class="line">...<span class="comment">//部分代码展示</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="Bezire-curve"><a href="#Bezire-curve" class="headerlink" title="Bezire curve"></a>Bezire curve</h2><p><a href="https://www.jianshu.com/p/8f82db9556d2" target="_blank" rel="noopener">https://www.jianshu.com/p/8f82db9556d2</a></p><h2 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h2><p>实现贝塞尔曲线。</p><figure class="highlight ts"><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><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createLine</span>(<span class="params">points: <span class="built_in">number</span>[][]</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> line = <span class="keyword">new</span> ECLinePath({</span><br><span class="line"> name: <span class="string">'line'</span>,</span><br><span class="line"> subPixelOptimize: <span class="literal">true</span></span><br><span class="line"> });</span><br><span class="line"> setLinePoints(line.shape, points);</span><br><span class="line"> <span class="keyword">return</span> line;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">setLinePoints</span>(<span class="params">targetShape: ECLinePath['shape'], points: <span class="built_in">number</span>[][]</span>) </span>{</span><br><span class="line"> <span class="keyword">type</span> CurveShape = ECLinePath[<span class="string">'shape'</span>] & {</span><br><span class="line"> cpx1: <span class="built_in">number</span></span><br><span class="line"> cpy1: <span class="built_in">number</span></span><br><span class="line"> cpx2?: <span class="built_in">number</span></span><br><span class="line"> cpy2?: <span class="built_in">number</span></span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> targetShape.x1 = points[<span class="number">0</span>][<span class="number">0</span>];</span><br><span class="line"> targetShape.y1 = points[<span class="number">0</span>][<span class="number">1</span>];</span><br><span class="line"> targetShape.x2 = points[<span class="number">1</span>][<span class="number">0</span>];</span><br><span class="line"> targetShape.y2 = points[<span class="number">1</span>][<span class="number">1</span>];</span><br><span class="line"> targetShape.percent = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> cp1 = points[<span class="number">2</span>];</span><br><span class="line"> <span class="keyword">const</span> cp2 = points[<span class="number">3</span>];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (cp1) {</span><br><span class="line"> (targetShape <span class="keyword">as</span> CurveShape).cpx1 = cp1[<span class="number">0</span>];</span><br><span class="line"> (targetShape <span class="keyword">as</span> CurveShape).cpy1 = cp1[<span class="number">1</span>];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> (targetShape <span class="keyword">as</span> CurveShape).cpx1 = <span class="literal">NaN</span>;</span><br><span class="line"> (targetShape <span class="keyword">as</span> CurveShape).cpy1 = <span class="literal">NaN</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (cp2) {</span><br><span class="line"> (targetShape <span class="keyword">as</span> CurveShape).cpx2 = cp2[<span class="number">0</span>];</span><br><span class="line"> (targetShape <span class="keyword">as</span> CurveShape).cpy2 = cp2[<span class="number">1</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> Line <span class="keyword">extends</span> graphic.Group {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> _fromSymbolType: <span class="built_in">string</span>;</span><br><span class="line"> <span class="keyword">private</span> _toSymbolType: <span class="built_in">string</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">constructor</span>(<span class="params">lineData: List, idx: <span class="built_in">number</span>, seriesScope?: LineDrawSeriesScope</span>) {</span><br><span class="line"> <span class="keyword">super</span>();</span><br><span class="line"> <span class="keyword">this</span>._createLine(lineData <span class="keyword">as</span> LineList, idx, seriesScope);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> _createLine(lineData: LineList, idx: <span class="built_in">number</span>, seriesScope?: LineDrawSeriesScope) {</span><br><span class="line"> <span class="keyword">const</span> seriesModel = lineData.hostModel;</span><br><span class="line"> <span class="keyword">const</span> linePoints = lineData.getItemLayout(idx);</span><br><span class="line"> <span class="keyword">const</span> line = createLine(linePoints);</span><br><span class="line"> line.shape.percent = <span class="number">0</span>;</span><br><span class="line"> graphic.initProps(line, {</span><br><span class="line"> shape: {</span><br><span class="line"> percent: <span class="number">1</span></span><br><span class="line"> }</span><br><span class="line"> }, seriesModel, idx);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">this</span>.add(line);</span><br><span class="line"></span><br><span class="line"> each(SYMBOL_CATEGORIES, <span class="function"><span class="keyword">function</span> (<span class="params">symbolCategory</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> symbol = createSymbol(symbolCategory, lineData, idx);</span><br><span class="line"> <span class="comment">// symbols must added after line to make sure</span></span><br><span class="line"> <span class="comment">// it will be updated after line#update.</span></span><br><span class="line"> <span class="comment">// Or symbol position and rotation update in line#beforeUpdate will be one frame slow</span></span><br><span class="line"> <span class="keyword">this</span>.add(symbol);</span><br><span class="line"> <span class="keyword">this</span>[makeSymbolTypeKey(symbolCategory)] = lineData.getItemVisual(idx, symbolCategory);</span><br><span class="line"> }, <span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">this</span>._updateCommonStl(lineData, idx, seriesScope);</span><br><span class="line"> }</span><br><span class="line"> updateData(lineData: List, idx: <span class="built_in">number</span>, seriesScope: LineDrawSeriesScope) {</span><br><span class="line"> <span class="keyword">const</span> seriesModel = lineData.hostModel;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> line = <span class="keyword">this</span>.childOfName(<span class="string">'line'</span>) <span class="keyword">as</span> ECLinePath;</span><br><span class="line"> <span class="keyword">const</span> linePoints = lineData.getItemLayout(idx);</span><br><span class="line"> <span class="keyword">const</span> target = {</span><br><span class="line"> shape: {} <span class="keyword">as</span> ECLinePath[<span class="string">'shape'</span>]</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> setLinePoints(target.shape, linePoints);</span><br><span class="line"> graphic.updateProps(line, target, seriesModel, idx);</span><br><span class="line"></span><br><span class="line"> each(SYMBOL_CATEGORIES, <span class="function"><span class="keyword">function</span> (<span class="params">symbolCategory</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> symbolType = (lineData <span class="keyword">as</span> LineList).getItemVisual(idx, symbolCategory);</span><br><span class="line"> <span class="keyword">const</span> key = makeSymbolTypeKey(symbolCategory);</span><br><span class="line"> <span class="comment">// Symbol changed</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>[key] !== symbolType) {</span><br><span class="line"> <span class="keyword">this</span>.remove(<span class="keyword">this</span>.childOfName(symbolCategory));</span><br><span class="line"> <span class="keyword">const</span> symbol = createSymbol(symbolCategory, lineData <span class="keyword">as</span> LineList, idx);</span><br><span class="line"> <span class="keyword">this</span>.add(symbol);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">this</span>[key] = symbolType;</span><br><span class="line"> }, <span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">this</span>._updateCommonStl(lineData, idx, seriesScope);</span><br><span class="line"> };</span><br><span class="line"> <span class="comment">//部分代码</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在line类中调用了createLine方法,createLine方法有调用了setLinePoints方法。而原来的setLinePoints方法没有cpx2和cpy2的属性,更改之后如上,percent属性是描述线段显示的百分比。通过lineData是lineList类也是List的子类,通过getItemLayout方法获取数组。也就是setLinePoints的points参数,分别为source,curvepoint1,curvepoint2,target。这样我们就可以通过nodeEgde的setLayout方法来设定边的属性了。</p><h3 id="如何计算curvePoints的位置"><a href="#如何计算curvePoints的位置" class="headerlink" title="如何计算curvePoints的位置"></a>如何计算curvePoints的位置</h3><p>这里就需要用到一些简单的数学几何知识,因为LoopEdge的source和target为同一个目标,所以我们只需要确定curvePoint的位置就好了。我们可以取一条过圆心的线,而两个curvePoint所成线段被该线垂直平分,此时所形成的贝塞尔曲线就是我们需要的形状。</p><figure class="highlight ts"><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="function"><span class="keyword">function</span> <span class="title">getCubicControlPoint</span>(<span class="params">radToXPosi: <span class="built_in">number</span>, cpDistToCenter: <span class="built_in">number</span></span>): <span class="title">number</span>[] </span>{</span><br><span class="line"> <span class="keyword">return</span> [</span><br><span class="line"> <span class="built_in">Math</span>.cos(radToXPosi) * cpDistToCenter + centerPt[<span class="number">0</span>],</span><br><span class="line"> <span class="built_in">Math</span>.sin(radToXPosi) * cpDistToCenter + centerPt[<span class="number">1</span>]</span><br><span class="line"> ];</span><br><span class="line"> };</span><br></pre></td></tr></table></figure><p>这里就是直接计算点坐标的公式了,而这里的radToXposi是弧度为单位的,乘上长度变成了坐标。</p><p>而当我们的节点与其他节点有其他边的关系时,我们如何选取LoopEdge的中线位置来画边呢?这里是导师给出的思路。</p><ol><li><p>取该节点的相邻边,并依据边的正切值对边进行排序。 </p></li><li><p>再一次根据正切值画出每一个 section,并找出最小的 section 部分。如果最小部分 </p></li></ol><p>大于 60°,则放入 sectionlist 内,且将 availableCount 加上在这个部分可以放入的边的数。 </p><ol start="3"><li>如果可以放边的数大于需要放的 Loop 边,则在 section 中找到最大的部分,将边 </li></ol><p>放入。</p><ol start="4"><li><p>当边太多时,我们则不考虑边的交叠影响。 </p></li><li><p>放边的算法:在每个 section 中有 edgeCount 属性,如果该属性为 0,则直接跳出, </p></li></ol><p>反之继续;</p><ol start="6"><li>edgeCount 主要把 section 再次细分成几个部分。在计算部分的中线,进行计算剩 </li></ol><p>下两个点的坐标。</p><figure class="highlight ts"><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><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Graph, { GraphEdge, GraphNode } <span class="keyword">from</span> <span class="string">'../../data/Graph'</span>;</span><br><span class="line"><span class="keyword">import</span> { sub, VectorArray } <span class="keyword">from</span> <span class="string">'zrender/src/core/vector'</span>;</span><br><span class="line"><span class="keyword">import</span> { assert, bind, each, retrieve2 } <span class="keyword">from</span> <span class="string">'zrender/src/core/util'</span>;</span><br><span class="line"><span class="keyword">import</span> { GraphEdgeItemOption } <span class="keyword">from</span> <span class="string">'./GraphSeries'</span>;</span><br><span class="line"><span class="keyword">import</span> { getSymbolSize } <span class="keyword">from</span> <span class="string">'./graphHelper'</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> Radian = <span class="built_in">number</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> NodeAttrOnEdge = <span class="string">'node1'</span> | <span class="string">'node2'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">interface</span> EdgeWrap {</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Vector of the tangent line at the center node.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> tangentVec: VectorArray;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Radian of tangentVec (to x positive) of tangentVec. [-Math.PI / 2, Math.PI / 2].</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> radToXPosi: Radian;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">interface</span> SectionWrap {</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Radian of tangentVec (to x positive) of tangentVec. [-Math.PI / 2, Math.PI / 2].</span></span><br><span class="line"><span class="comment"> * Make sure radToXPosiStart <= radToXPosiEnd.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> radToXPosiStart: Radian;</span><br><span class="line"> radToXPosiEnd: Radian;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * The count of edges that assign to this section.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> edgeCount: <span class="built_in">number</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> MATH_PI = <span class="built_in">Math</span>.PI;</span><br><span class="line"><span class="keyword">const</span> MATH_2PI = MATH_PI * <span class="number">2</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * This is the radian of the intersection angle of the two control</span></span><br><span class="line"><span class="comment"> * point of a self-loop cubic bezier edge.</span></span><br><span class="line"><span class="comment"> * If the angle is bigger or smaller, the cubic curve is not pretty.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">const</span> MAX_EDGE_SECTION_RADIAN = MATH_PI - getRadianToXPositive([<span class="number">4</span>, <span class="number">5.5</span>]) * <span class="number">2</span>;</span><br><span class="line"><span class="keyword">const</span> MIN_EDGE_SECTION_RADIAN = MATH_PI / <span class="number">3</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"> * @caution This method should only be called after all</span></span><br><span class="line"><span class="comment"> * nodes and non-self-loop edges layout finished.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * @note [Self-loop edge layout strategy]:</span></span><br><span class="line"><span class="comment"> * To make it have good looking when there are muliple self-loop edges,</span></span><br><span class="line"><span class="comment"> * place them from the biggest angle (> 60 degree) one by one.</span></span><br><span class="line"><span class="comment"> * If there is no enough angles, put mulitple edges in one angle</span></span><br><span class="line"><span class="comment"> * and use different curvenesses.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * @pending Should the section angle and self-loop edge direction be able to set by user?</span></span><br><span class="line"><span class="comment"> * `curveness` can not express it.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * @pending Consider the self-loop edge might overlow the canvas.</span></span><br><span class="line"><span class="comment"> * When calculating the view transform, there is no self-loop layout info yet.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">layoutSelfLoopEdges</span>(<span class="params"></span></span></span><br><span class="line"><span class="function"><span class="params"> graph: Graph,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="comment">// Get from `getNodeGlobalScale(seriesModel)`</span></span></span></span><br><span class="line"><span class="function"><span class="params"> nodeScaleOnCoordSys: <span class="built_in">number</span></span></span></span><br><span class="line"><span class="function"><span class="params"></span>): <span class="title">void</span> </span>{</span><br><span class="line"> graph.eachNode(<span class="function"><span class="params">node</span> =></span> {</span><br><span class="line"> <span class="keyword">const</span> selfLoopEdges: GraphEdge[] = [];</span><br><span class="line"> <span class="comment">// inEdges includes outEdges if self-loop.</span></span><br><span class="line"> each(node.inEdges, <span class="function"><span class="params">edge</span> =></span> {</span><br><span class="line"> <span class="keyword">if</span> (isSelfLoopEdge(edge)) {</span><br><span class="line"> selfLoopEdges.push(edge);</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (selfLoopEdges.length) {</span><br><span class="line"> <span class="keyword">const</span> sectionList = prepareSectionList(node, selfLoopEdges.length);</span><br><span class="line"> placeSelfLoopEdges(node, sectionList, selfLoopEdges, nodeScaleOnCoordSys);</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="comment"> * @return Sections that can arrange self-loop angles. Ensure that:</span></span><br><span class="line"><span class="comment"> * `selfLoopEdgeCount <= sectionList.reduce((sum, sec) === sec.edgeCount + sum, 0)`</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">prepareSectionList</span>(<span class="params">centerNode: GraphNode, selfLoopEdgeCount: <span class="built_in">number</span></span>): <span class="title">SectionWrap</span>[] </span>{</span><br><span class="line"> <span class="keyword">const</span> adjacentEdges: EdgeWrap[] = [];</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">addAdjacentEdge</span>(<span class="params">centerNodeAttr: NodeAttrOnEdge, edge: GraphEdge</span>): <span class="title">void</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (isSelfLoopEdge(edge)) {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">const</span> tangentVec = getTangentVector(edge, centerNodeAttr);</span><br><span class="line"> <span class="keyword">const</span> radToXPosi = getRadianToXPositive(tangentVec);</span><br><span class="line"> adjacentEdges.push({ tangentVec, radToXPosi });</span><br><span class="line"> }</span><br><span class="line"> each(centerNode.inEdges, bind(addAdjacentEdge, <span class="literal">null</span>, <span class="string">'node2'</span>));</span><br><span class="line"> each(centerNode.outEdges, bind(addAdjacentEdge, <span class="literal">null</span>, <span class="string">'node1'</span>));</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Sort by radian asc.</span></span><br><span class="line"> adjacentEdges.sort(<span class="function">(<span class="params">edgeA, edgeB</span>) =></span> edgeA.radToXPosi - edgeB.radToXPosi);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> availableEdgeCount = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">const</span> sectionList: SectionWrap[] = [];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>, len = adjacentEdges.length; i < len; i++) {</span><br><span class="line"> <span class="keyword">const</span> radToXPosiStart = adjacentEdges[i].radToXPosi;</span><br><span class="line"> <span class="keyword">const</span> radToXPosiEnd = i < len - <span class="number">1</span></span><br><span class="line"> ? adjacentEdges[i + <span class="number">1</span>].radToXPosi</span><br><span class="line"> : adjacentEdges[<span class="number">0</span>].radToXPosi + MATH_2PI;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Make sure radToXPosiStart <= radToXPosiEnd.</span></span><br><span class="line"> <span class="keyword">const</span> rad2Minus1 = radToXPosiEnd - radToXPosiStart;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (rad2Minus1 >= MIN_EDGE_SECTION_RADIAN) {</span><br><span class="line"> sectionList.push({ radToXPosiStart, radToXPosiEnd, edgeCount: <span class="number">0</span> });</span><br><span class="line"> }</span><br><span class="line"> availableEdgeCount += rad2Minus1 / MIN_EDGE_SECTION_RADIAN;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (availableEdgeCount >= selfLoopEdgeCount) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> iEdge = <span class="number">0</span>; iEdge < selfLoopEdgeCount; iEdge++) {</span><br><span class="line"> <span class="comment">// Find the largest section to arrange an edge.</span></span><br><span class="line"> <span class="keyword">let</span> iSecInMax = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">let</span> secRadInMax = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> iSec = <span class="number">0</span>; iSec < sectionList.length; iSec++) {</span><br><span class="line"> <span class="keyword">const</span> thisSec = sectionList[iSec];</span><br><span class="line"> <span class="comment">// If a section is too larger than anohter section, split that large section and</span></span><br><span class="line"> <span class="comment">// arrange multiple edges in it is probably better then arrange only one edge in</span></span><br><span class="line"> <span class="comment">// the large section.</span></span><br><span class="line"> <span class="keyword">const</span> rad = (thisSec.radToXPosiEnd - thisSec.radToXPosiStart) / (thisSec.edgeCount + <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">if</span> (rad > secRadInMax) {</span><br><span class="line"> secRadInMax = rad;</span><br><span class="line"> iSecInMax = iSec;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> sectionList[iSecInMax].edgeCount++;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// In this case there are probably too many edge on a node, and intersection between</span></span><br><span class="line"> <span class="comment">// edges can not avoid. So we do not care about intersection any more.</span></span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> sectionList.length = <span class="number">0</span>;</span><br><span class="line"> sectionList.push({</span><br><span class="line"> radToXPosiStart: -MATH_PI / <span class="number">2</span>,</span><br><span class="line"> radToXPosiEnd: -MATH_PI / <span class="number">2</span> + MATH_2PI,</span><br><span class="line"> edgeCount: selfLoopEdgeCount</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> sectionList;</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"> * @return cubic bezier curve: [p1, p2, cp1, cp2]</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">placeSelfLoopEdges</span>(<span class="params"></span></span></span><br><span class="line"><span class="function"><span class="params"> centerNode: GraphNode,</span></span></span><br><span class="line"><span class="function"><span class="params"> sectionList: SectionWrap[],</span></span></span><br><span class="line"><span class="function"><span class="params"> selfLoopEdges: GraphEdge[],</span></span></span><br><span class="line"><span class="function"><span class="params"> nodeScaleOnCoordSys: <span class="built_in">number</span></span></span></span><br><span class="line"><span class="function"><span class="params"></span>): <span class="title">void</span> </span>{</span><br><span class="line"> <span class="keyword">const</span> symbolSize = getSymbolSize(centerNode);</span><br><span class="line"> <span class="keyword">const</span> centerPt = centerNode.getLayout();</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">getCubicControlPoint</span>(<span class="params">radToXPosi: <span class="built_in">number</span>, cpDistToCenter: <span class="built_in">number</span></span>): <span class="title">number</span>[] </span>{</span><br><span class="line"> <span class="keyword">return</span> [</span><br><span class="line"> <span class="built_in">Math</span>.cos(radToXPosi) * cpDistToCenter + centerPt[<span class="number">0</span>],</span><br><span class="line"> <span class="built_in">Math</span>.sin(radToXPosi) * cpDistToCenter + centerPt[<span class="number">1</span>]</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> iEdge = <span class="number">0</span>;</span><br><span class="line"> each(sectionList, <span class="function"><span class="params">section</span> =></span> {</span><br><span class="line"> <span class="keyword">const</span> secEdgeCount = section.edgeCount;</span><br><span class="line"> <span class="keyword">if</span> (!secEdgeCount) {</span><br><span class="line"> <span class="comment">// No self-loop edge arranged in this section.</span></span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> secRadStart = section.radToXPosiStart;</span><br><span class="line"> <span class="keyword">const</span> secRadEnd = section.radToXPosiEnd;</span><br><span class="line"> <span class="keyword">const</span> splitRadHalfSpan = (secRadEnd - secRadStart) / section.edgeCount / <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">const</span> edgeRadHalfSpan = <span class="built_in">Math</span>.min(splitRadHalfSpan, MAX_EDGE_SECTION_RADIAN / <span class="number">2</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// const radMid = secRadStart + secRadSpan / section.edgeCount * (iEdge - iEdgeFirstInSec);</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">let</span> iEdgeInSec = <span class="number">0</span>; iEdgeInSec < section.edgeCount; iEdgeInSec++) {</span><br><span class="line"> <span class="keyword">const</span> edge = selfLoopEdges[iEdge++];</span><br><span class="line"> <span class="keyword">const</span> cpMidRad = secRadStart + splitRadHalfSpan * (iEdgeInSec * <span class="number">2</span> + <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// This is a experimental strategy to make it look better:</span></span><br><span class="line"> <span class="comment">// If the symbol size is small, the bezier control point need to be far from the</span></span><br><span class="line"> <span class="comment">// center to make the buckle obvious, while if the symbol size is big, the control</span></span><br><span class="line"> <span class="comment">// ponit should not too far to make the buckle too significant.</span></span><br><span class="line"> <span class="comment">// So we alway make control point dist to symbol radius `100`, and enable users to</span></span><br><span class="line"> <span class="comment">// use option `curveness` to adjust it.</span></span><br><span class="line"> <span class="comment">// Becuase at present we do not layout multiple self-loop edges into single</span></span><br><span class="line"> <span class="comment">// `[cp1Rad, cp2Rad]`, we do not use option `autoCurveness`.</span></span><br><span class="line"> <span class="keyword">const</span> curveness = retrieve2(</span><br><span class="line"> edge.getModel<GraphEdgeItemOption>().get([<span class="string">'lineStyle'</span>, <span class="string">'curveness'</span>]),</span><br><span class="line"> <span class="number">0</span></span><br><span class="line"> );</span><br><span class="line"> <span class="keyword">const</span> cpDistToCenter = (symbolSize / <span class="number">2</span> + <span class="number">100</span>) * nodeScaleOnCoordSys</span><br><span class="line"> * (curveness + <span class="number">1</span>)</span><br><span class="line"> <span class="comment">// Formula:</span></span><br><span class="line"> <span class="comment">// If `cpDistToCenter = symbolSize / 2 * nodeScaleOnCoordSys / 3 * 4 / Math.cos(edgeRadHalfSpan)`,</span></span><br><span class="line"> <span class="comment">// the control point can be tangent to the symbol circle.</span></span><br><span class="line"> <span class="comment">// Hint: `distCubicMiddlePtToCenterPt / 3 * 4` get the hight of the isosceles triangle made by</span></span><br><span class="line"> <span class="comment">// control points and center point.</span></span><br><span class="line"> / <span class="number">3</span> * <span class="number">4</span> / <span class="built_in">Math</span>.cos(edgeRadHalfSpan);</span><br><span class="line"></span><br><span class="line"> edge.setLayout([</span><br><span class="line"> centerPt.slice(),</span><br><span class="line"> centerPt.slice(),</span><br><span class="line"> getCubicControlPoint(cpMidRad - edgeRadHalfSpan, cpDistToCenter),</span><br><span class="line"> getCubicControlPoint(cpMidRad + edgeRadHalfSpan, cpDistToCenter)</span><br><span class="line"> ]);</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"> assert(iEdge === selfLoopEdges.length);</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="comment"> * @return vector representing the tangant line</span></span><br><span class="line"><span class="comment"> * (from edge['node1' | 'node2'] to cp1 of the cubic bezier curve)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getTangentVector</span>(<span class="params">edge: GraphEdge, nodeAttr: NodeAttrOnEdge</span>): <span class="title">VectorArray</span> </span>{</span><br><span class="line"> <span class="comment">// points is [p1, p2] or [p1, p2, cp1].</span></span><br><span class="line"> <span class="keyword">const</span> points = edge.getLayout();</span><br><span class="line"> <span class="keyword">const</span> targetPt = points[<span class="number">2</span>] ? points[<span class="number">2</span>] : points[<span class="number">1</span>];</span><br><span class="line"> <span class="keyword">return</span> sub([], targetPt, edge[nodeAttr].getLayout());</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getRadianToXPositive</span>(<span class="params">vec: VectorArray</span>): <span class="title">Radian</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Math</span>.atan2(vec[<span class="number">1</span>], vec[<span class="number">0</span>]);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">isSelfLoopEdge</span>(<span class="params">edge: GraphEdge</span>): <span class="title">boolean</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> edge.node1 === edge.node2;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="AjustEgde"><a href="#AjustEgde" class="headerlink" title="AjustEgde"></a>AjustEgde</h3><p>在原本的需求里面还有一个adjustEgde的对于边的渲染的改变,使得symbol的坐标在节点边上而不是圆心。这里的算法思路就是利用二分法找到在线段上和节点最近的点。</p><figure class="highlight ts"><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><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> * <span class="keyword">as</span> curveTool <span class="keyword">from</span> <span class="string">'zrender/src/core/curve'</span>;</span><br><span class="line"><span class="keyword">import</span> * <span class="keyword">as</span> vec2 <span class="keyword">from</span> <span class="string">'zrender/src/core/vector'</span>;</span><br><span class="line"><span class="keyword">import</span> {getSymbolSize} <span class="keyword">from</span> <span class="string">'./graphHelper'</span>;</span><br><span class="line"><span class="keyword">import</span> Graph <span class="keyword">from</span> <span class="string">'../../data/Graph'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> v1: <span class="built_in">number</span>[] = [];</span><br><span class="line"><span class="keyword">const</span> v2: <span class="built_in">number</span>[] = [];</span><br><span class="line"><span class="keyword">const</span> v3: <span class="built_in">number</span>[] = [];</span><br><span class="line"><span class="keyword">const</span> quadraticAt = curveTool.quadraticAt;</span><br><span class="line"><span class="keyword">const</span> cubicAt = curveTool.cubicAt;</span><br><span class="line"><span class="keyword">const</span> v2DistSquare = vec2.distSquare;</span><br><span class="line"><span class="keyword">const</span> mathAbs = <span class="built_in">Math</span>.abs;</span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">intersectCurveCircle</span>(<span class="params"></span></span></span><br><span class="line"><span class="function"><span class="params"> curvePoints: <span class="built_in">number</span>[][],</span></span></span><br><span class="line"><span class="function"><span class="params"> center: <span class="built_in">number</span>[],</span></span></span><br><span class="line"><span class="function"><span class="params"> radius: <span class="built_in">number</span></span></span></span><br><span class="line"><span class="function"><span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> p0 = curvePoints[<span class="number">0</span>]; <span class="comment">// source point</span></span><br><span class="line"> <span class="keyword">const</span> p1 = curvePoints[<span class="number">1</span>]; <span class="comment">// curve point 1 </span></span><br><span class="line"> <span class="keyword">const</span> p2 = curvePoints[<span class="number">2</span>]; <span class="comment">// curve point 2 or target point</span></span><br><span class="line"> <span class="keyword">const</span> p3 = curvePoints[<span class="number">3</span>] ?? [<span class="literal">null</span>, <span class="literal">null</span>]; <span class="comment">// target point</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> d = <span class="literal">Infinity</span>;</span><br><span class="line"> <span class="keyword">let</span> t;</span><br><span class="line"> <span class="keyword">const</span> radiusSquare = radius * radius;</span><br><span class="line"> <span class="keyword">let</span> interval = <span class="number">0.1</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> bezierAt = p3[<span class="number">0</span>] && p3[<span class="number">1</span>]</span><br><span class="line"> ? cubicAt <span class="comment">// 计算三次贝塞尔值</span></span><br><span class="line"> : <span class="function"><span class="keyword">function</span> (<span class="params">p0: <span class="built_in">number</span>, p1: <span class="built_in">number</span>, p2: <span class="built_in">number</span>, p3: <span class="built_in">number</span>, t: <span class="built_in">number</span></span>): <span class="title">number</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> quadraticAt(p0, p1, p2, t); <span class="comment">//计算二次贝塞尔值</span></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> _t = <span class="number">0.1</span>; _t <= <span class="number">0.9</span>; _t += <span class="number">0.1</span>) {</span><br><span class="line"> v1[<span class="number">0</span>] = bezierAt(p0[<span class="number">0</span>], p1[<span class="number">0</span>], p2[<span class="number">0</span>], p3[<span class="number">0</span>], _t); <span class="comment">//bezire curve point of x</span></span><br><span class="line"> v1[<span class="number">1</span>] = bezierAt(p0[<span class="number">1</span>], p1[<span class="number">1</span>], p2[<span class="number">1</span>], p3[<span class="number">1</span>], _t); <span class="comment">//bezire curve point of y</span></span><br><span class="line"> <span class="keyword">const</span> diff = mathAbs(v2DistSquare(v1, center) - radiusSquare);</span><br><span class="line"> <span class="keyword">if</span> (diff < d) {</span><br><span class="line"> d = diff;</span><br><span class="line"> t = _t;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// Assume the segment is monotone,Find root through Bisection method</span></span><br><span class="line"> <span class="comment">// At most 32 iteration</span></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">32</span>; i++) {</span><br><span class="line"> <span class="comment">// const prev = t - interval;</span></span><br><span class="line"> <span class="keyword">const</span> next = t + interval;</span><br><span class="line"> <span class="comment">// v1[0] = bezierAt(p0[0], p1[0], p2[0], p3[0], prev);</span></span><br><span class="line"> <span class="comment">// v1[1] = bezierAt(p0[1], p1[1], p2[1], p3[1], prev);</span></span><br><span class="line"> v2[<span class="number">0</span>] = bezierAt(p0[<span class="number">0</span>], p1[<span class="number">0</span>], p2[<span class="number">0</span>], p3[<span class="number">0</span>], t);</span><br><span class="line"> v2[<span class="number">1</span>] = bezierAt(p0[<span class="number">1</span>], p1[<span class="number">1</span>], p2[<span class="number">1</span>], p3[<span class="number">1</span>], t);</span><br><span class="line"> v3[<span class="number">0</span>] = bezierAt(p0[<span class="number">0</span>], p1[<span class="number">0</span>], p2[<span class="number">0</span>], p3[<span class="number">0</span>], next);</span><br><span class="line"> v3[<span class="number">1</span>] = bezierAt(p0[<span class="number">1</span>], p1[<span class="number">1</span>], p2[<span class="number">1</span>], p3[<span class="number">1</span>], next);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> diff = v2DistSquare(v2, center) - radiusSquare;</span><br><span class="line"> <span class="keyword">if</span> (mathAbs(diff) < <span class="number">1e-2</span>) {</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// let prevDiff = v2DistSquare(v1, center) - radiusSquare;</span></span><br><span class="line"> <span class="keyword">const</span> nextDiff = v2DistSquare(v3, center) - radiusSquare;</span><br><span class="line"></span><br><span class="line"> interval /= <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">if</span> (diff < <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">if</span> (nextDiff >= <span class="number">0</span>) {</span><br><span class="line"> t = t + interval;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> t = t - interval;</span><br><span class="line"> }</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> (nextDiff >= <span class="number">0</span>) {</span><br><span class="line"> t = t - interval;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> t = t + interval;</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">return</span> t;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// Adjust edge to avoid</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="function"><span class="keyword">function</span> <span class="title">adjustEdge</span>(<span class="params">graph: Graph, scale: <span class="built_in">number</span></span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> tmp0: <span class="built_in">number</span>[] = [];</span><br><span class="line"> <span class="keyword">const</span> quadraticSubdivide = curveTool.quadraticSubdivide; <span class="comment">//细分二次贝塞尔曲线</span></span><br><span class="line"> <span class="keyword">const</span> cubicSubdivide = curveTool.cubicSubdivide; <span class="comment">//细分三次贝塞尔曲线</span></span><br><span class="line"> <span class="keyword">const</span> pts3: <span class="built_in">number</span>[][] = [[], [], []];</span><br><span class="line"> <span class="keyword">const</span> pts2: <span class="built_in">number</span>[][] = [[], []];</span><br><span class="line"> <span class="keyword">const</span> pts4 : <span class="built_in">number</span>[][] = [[], [], [], []];</span><br><span class="line"> <span class="keyword">const</span> v: <span class="built_in">number</span>[] = [];</span><br><span class="line"> scale /= <span class="number">2</span>;</span><br><span class="line"></span><br><span class="line"> graph.eachEdge(<span class="function"><span class="keyword">function</span> (<span class="params">edge, idx</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> linePoints = edge.getLayout();</span><br><span class="line"> <span class="keyword">const</span> fromSymbol = edge.getVisual(<span class="string">'fromSymbol'</span>);</span><br><span class="line"> <span class="keyword">const</span> toSymbol = edge.getVisual(<span class="string">'toSymbol'</span>);</span><br><span class="line"> <span class="keyword">if</span> (!linePoints.__original) {</span><br><span class="line"> linePoints.__original = [</span><br><span class="line"> vec2.clone(linePoints[<span class="number">0</span>]),</span><br><span class="line"> vec2.clone(linePoints[<span class="number">1</span>])</span><br><span class="line"> ];</span><br><span class="line"> <span class="keyword">if</span> (linePoints[<span class="number">2</span>]) {</span><br><span class="line"> linePoints.__original.push(vec2.clone(linePoints[<span class="number">2</span>]));</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (linePoints[<span class="number">3</span>]) {</span><br><span class="line"> linePoints.__original.push(vec2.clone(linePoints[<span class="number">3</span>]));</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">const</span> originalPoints = linePoints.__original;</span><br><span class="line"> <span class="comment">// Cubic curve</span></span><br><span class="line"> <span class="keyword">if</span> (linePoints[<span class="number">3</span>] != <span class="literal">null</span>) {</span><br><span class="line"> vec2.copy(pts4[<span class="number">0</span>], originalPoints[<span class="number">0</span>]);</span><br><span class="line"> vec2.copy(pts4[<span class="number">1</span>], originalPoints[<span class="number">2</span>]);</span><br><span class="line"> vec2.copy(pts4[<span class="number">2</span>], originalPoints[<span class="number">3</span>]);</span><br><span class="line"> vec2.copy(pts4[<span class="number">3</span>], originalPoints[<span class="number">1</span>]);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (fromSymbol && fromSymbol !== <span class="string">'none'</span>) {</span><br><span class="line"> <span class="keyword">const</span> symbolSize = getSymbolSize(edge.node1);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> t = intersectCurveCircle(pts4, originalPoints[<span class="number">0</span>], symbolSize * scale);</span><br><span class="line"> <span class="keyword">if</span> (t > <span class="number">0.5</span>) {</span><br><span class="line"> t = <span class="number">1</span> - t;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// Subdivide and get the second</span></span><br><span class="line"> cubicSubdivide(pts4[<span class="number">0</span>][<span class="number">0</span>], pts4[<span class="number">1</span>][<span class="number">0</span>], pts4[<span class="number">2</span>][<span class="number">0</span>], pts4[<span class="number">3</span>][<span class="number">0</span>], t, tmp0);</span><br><span class="line"> pts4[<span class="number">0</span>][<span class="number">0</span>] = tmp0[<span class="number">4</span>];</span><br><span class="line"> pts4[<span class="number">1</span>][<span class="number">0</span>] = tmp0[<span class="number">5</span>];</span><br><span class="line"> pts4[<span class="number">2</span>][<span class="number">0</span>] = tmp0[<span class="number">6</span>];</span><br><span class="line"> cubicSubdivide(pts4[<span class="number">0</span>][<span class="number">1</span>], pts4[<span class="number">1</span>][<span class="number">1</span>], pts4[<span class="number">2</span>][<span class="number">1</span>], pts4[<span class="number">3</span>][<span class="number">1</span>], t, tmp0);</span><br><span class="line"> pts4[<span class="number">0</span>][<span class="number">1</span>] = tmp0[<span class="number">4</span>];</span><br><span class="line"> pts4[<span class="number">1</span>][<span class="number">1</span>] = tmp0[<span class="number">5</span>];</span><br><span class="line"> pts4[<span class="number">2</span>][<span class="number">1</span>] = tmp0[<span class="number">6</span>];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (toSymbol && toSymbol !== <span class="string">'none'</span>) {</span><br><span class="line"> <span class="keyword">const</span> symbolSize = getSymbolSize(edge.node2);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">let</span> t = intersectCurveCircle(pts4, originalPoints[<span class="number">1</span>], symbolSize * scale);</span><br><span class="line"> <span class="keyword">if</span> (t < <span class="number">0.5</span>) {</span><br><span class="line"> t = <span class="number">1</span> - t;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// Subdivide and get the first</span></span><br><span class="line"> cubicSubdivide(pts4[<span class="number">0</span>][<span class="number">0</span>], pts4[<span class="number">1</span>][<span class="number">0</span>], pts4[<span class="number">2</span>][<span class="number">0</span>], pts4[<span class="number">3</span>][<span class="number">0</span>], t, tmp0);</span><br><span class="line"> pts4[<span class="number">1</span>][<span class="number">0</span>] = tmp0[<span class="number">1</span>];</span><br><span class="line"> pts4[<span class="number">2</span>][<span class="number">0</span>] = tmp0[<span class="number">2</span>];</span><br><span class="line"> pts4[<span class="number">3</span>][<span class="number">0</span>] = tmp0[<span class="number">3</span>];</span><br><span class="line"> cubicSubdivide(pts4[<span class="number">0</span>][<span class="number">1</span>], pts4[<span class="number">1</span>][<span class="number">1</span>], pts4[<span class="number">2</span>][<span class="number">1</span>], pts4[<span class="number">3</span>][<span class="number">1</span>], t, tmp0);</span><br><span class="line"> pts4[<span class="number">1</span>][<span class="number">1</span>] = tmp0[<span class="number">1</span>];</span><br><span class="line"> pts4[<span class="number">2</span>][<span class="number">1</span>] = tmp0[<span class="number">2</span>];</span><br><span class="line"> pts4[<span class="number">3</span>][<span class="number">1</span>] = tmp0[<span class="number">3</span>];</span><br><span class="line"> }</span><br><span class="line"> vec2.copy(linePoints[<span class="number">0</span>], pts4[<span class="number">0</span>]);</span><br><span class="line"> vec2.copy(linePoints[<span class="number">1</span>], pts4[<span class="number">3</span>]);</span><br><span class="line"> vec2.copy(linePoints[<span class="number">2</span>], pts4[<span class="number">1</span>]);</span><br><span class="line"> vec2.copy(linePoints[<span class="number">3</span>], pts4[<span class="number">2</span>]);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// Quadratic curve</span></span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (linePoints[<span class="number">2</span>] != <span class="literal">null</span>) {</span><br><span class="line"> vec2.copy(pts3[<span class="number">0</span>], originalPoints[<span class="number">0</span>]);</span><br><span class="line"> vec2.copy(pts3[<span class="number">1</span>], originalPoints[<span class="number">2</span>]);</span><br><span class="line"> vec2.copy(pts3[<span class="number">2</span>], originalPoints[<span class="number">1</span>]);</span><br><span class="line"> <span class="keyword">if</span> (fromSymbol && fromSymbol !== <span class="string">'none'</span>) {</span><br><span class="line"> <span class="keyword">const</span> symbolSize = getSymbolSize(edge.node1);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> t = intersectCurveCircle(pts3, originalPoints[<span class="number">0</span>], symbolSize * scale);</span><br><span class="line"> <span class="comment">// Subdivide and get the second</span></span><br><span class="line"> quadraticSubdivide(pts3[<span class="number">0</span>][<span class="number">0</span>], pts3[<span class="number">1</span>][<span class="number">0</span>], pts3[<span class="number">2</span>][<span class="number">0</span>], t, tmp0);</span><br><span class="line"> pts3[<span class="number">0</span>][<span class="number">0</span>] = tmp0[<span class="number">3</span>];</span><br><span class="line"> pts3[<span class="number">1</span>][<span class="number">0</span>] = tmp0[<span class="number">4</span>];</span><br><span class="line"> quadraticSubdivide(pts3[<span class="number">0</span>][<span class="number">1</span>], pts3[<span class="number">1</span>][<span class="number">1</span>], pts3[<span class="number">2</span>][<span class="number">1</span>], t, tmp0);</span><br><span class="line"> pts3[<span class="number">0</span>][<span class="number">1</span>] = tmp0[<span class="number">3</span>];</span><br><span class="line"> pts3[<span class="number">1</span>][<span class="number">1</span>] = tmp0[<span class="number">4</span>];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (toSymbol && toSymbol !== <span class="string">'none'</span>) {</span><br><span class="line"> <span class="keyword">const</span> symbolSize = getSymbolSize(edge.node2);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> t = intersectCurveCircle(pts3, originalPoints[<span class="number">1</span>], symbolSize * scale);</span><br><span class="line"> <span class="comment">// Subdivide and get the first</span></span><br><span class="line"> quadraticSubdivide(pts3[<span class="number">0</span>][<span class="number">0</span>], pts3[<span class="number">1</span>][<span class="number">0</span>], pts3[<span class="number">2</span>][<span class="number">0</span>], t, tmp0);</span><br><span class="line"> pts3[<span class="number">1</span>][<span class="number">0</span>] = tmp0[<span class="number">1</span>];</span><br><span class="line"> pts3[<span class="number">2</span>][<span class="number">0</span>] = tmp0[<span class="number">2</span>];</span><br><span class="line"> quadraticSubdivide(pts3[<span class="number">0</span>][<span class="number">1</span>], pts3[<span class="number">1</span>][<span class="number">1</span>], pts3[<span class="number">2</span>][<span class="number">1</span>], t, tmp0);</span><br><span class="line"> pts3[<span class="number">1</span>][<span class="number">1</span>] = tmp0[<span class="number">1</span>];</span><br><span class="line"> pts3[<span class="number">2</span>][<span class="number">1</span>] = tmp0[<span class="number">2</span>];</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// Copy back to layout</span></span><br><span class="line"> vec2.copy(linePoints[<span class="number">0</span>], pts3[<span class="number">0</span>]);</span><br><span class="line"> vec2.copy(linePoints[<span class="number">1</span>], pts3[<span class="number">2</span>]);</span><br><span class="line"> vec2.copy(linePoints[<span class="number">2</span>], pts3[<span class="number">1</span>]);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// Line</span></span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> vec2.copy(pts2[<span class="number">0</span>], originalPoints[<span class="number">0</span>]);</span><br><span class="line"> vec2.copy(pts2[<span class="number">1</span>], originalPoints[<span class="number">1</span>]);</span><br><span class="line"></span><br><span class="line"> vec2.sub(v, pts2[<span class="number">1</span>], pts2[<span class="number">0</span>]);</span><br><span class="line"> vec2.normalize(v, v);</span><br><span class="line"> <span class="keyword">if</span> (fromSymbol && fromSymbol !== <span class="string">'none'</span>) {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> symbolSize = getSymbolSize(edge.node1);</span><br><span class="line"></span><br><span class="line"> vec2.scaleAndAdd(pts2[<span class="number">0</span>], pts2[<span class="number">0</span>], v, symbolSize * scale);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (toSymbol && toSymbol !== <span class="string">'none'</span>) {</span><br><span class="line"> <span class="keyword">const</span> symbolSize = getSymbolSize(edge.node2);</span><br><span class="line"></span><br><span class="line"> vec2.scaleAndAdd(pts2[<span class="number">1</span>], pts2[<span class="number">1</span>], v, -symbolSize * scale);</span><br><span class="line"> }</span><br><span class="line"> vec2.copy(linePoints[<span class="number">0</span>], pts2[<span class="number">0</span>]);</span><br><span class="line"> vec2.copy(linePoints[<span class="number">1</span>], pts2[<span class="number">1</span>]);</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
</entry>
<entry>
<title>Sass</title>
<link href="/2021/09/22/Sass/"/>
<url>/2021/09/22/Sass/</url>
<content type="html"><![CDATA[<h1 id="Sass学习"><a href="#Sass学习" class="headerlink" title="Sass学习"></a>Sass学习</h1><p> 因为在Taro项目中有用到Sass,但是当时并没有学习所以就分开来写。</p><h3 id="一、安装"><a href="#一、安装" class="headerlink" title="一、安装"></a>一、安装</h3><p>因为Taro项目初始化的时候会自行安装,只要选择Sass就行了。所以这里给出官方链接。<a href="https://sass.bootcss.com/install" target="_blank" rel="noopener">https://sass.bootcss.com/install</a></p><h3 id="二、变量"><a href="#二、变量" class="headerlink" title="二、变量"></a>二、变量</h3><p>变量是存储信息并在将来重复利用的一种方式,在整个样式表中都可访问。 你可以在变量中存储颜色、字体 或任何 CSS 值,并在将来重复利用。Sass 使用 <code>$</code> 符号 作为变量的标志。</p><figure class="highlight scss"><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="variable">$font-stack</span>: Helvetica, sans-serif;</span><br><span class="line"><span class="variable">$primary-color</span>: <span class="number">#333</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">font</span>: <span class="number">100%</span> <span class="variable">$font-stack</span>;</span><br><span class="line"> <span class="attribute">color</span>: <span class="variable">$primary-color</span>;</span><br><span class="line">}</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></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">body</span> {</span><br><span class="line"> <span class="attribute">font</span>: <span class="number">100%</span> Helvetica, sans-serif;</span><br><span class="line"> <span class="attribute">color</span>: <span class="number">#333</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="三、嵌套"><a href="#三、嵌套" class="headerlink" title="三、嵌套"></a>三、嵌套</h3><p> 在编写 HTML 时,它有一个清晰的嵌套和可视化层次结构。 而 CSS 则没有。</p><p> Sass 允许嵌套 CSS 选择器,嵌套方式 与 HTML 的视觉层次结构相同。请注意,过度嵌套的规则 将导致过度限定的 CSS,这些 CSS 可能很难维护,并且 通常被认为是不好的做法。</p><p> 理解了这一点,下面就来看一个典型的网站导航的样式 示例:</p><figure class="highlight scss"><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="selector-tag">nav</span> {</span><br><span class="line"> <span class="selector-tag">ul</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">list-style</span>: none;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="selector-tag">li</span> { <span class="attribute">display</span>: inline-block; }</span><br><span class="line"></span><br><span class="line"> <span class="selector-tag">a</span> {</span><br><span class="line"> <span class="attribute">display</span>: block;</span><br><span class="line"> <span class="attribute">padding</span>: <span class="number">6px</span> <span class="number">12px</span>;</span><br><span class="line"> <span class="attribute">text-decoration</span>: none;</span><br><span class="line"> }</span><br><span class="line">}</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></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">nav</span> <span class="selector-tag">ul</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">list-style</span>: none;</span><br><span class="line">}</span><br><span class="line"><span class="selector-tag">nav</span> <span class="selector-tag">li</span> {</span><br><span class="line"> <span class="attribute">display</span>: inline-block;</span><br><span class="line">}</span><br><span class="line"><span class="selector-tag">nav</span> <span class="selector-tag">a</span> {</span><br><span class="line"> <span class="attribute">display</span>: block;</span><br><span class="line"> <span class="attribute">padding</span>: <span class="number">6px</span> <span class="number">12px</span>;</span><br><span class="line"> <span class="attribute">text-decoration</span>: none;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="四、片段"><a href="#四、片段" class="headerlink" title="四、片段"></a>四、片段</h3><p>创建部分Sass文件,其中包含一些CSS片段 ,可以将其包含在其他Sass文件中。这是模块化CSS并帮助使事情易于维护的好方法。部分文件是一个Sass文件,名称前带有一个下划线。可以将其命名为<code>_partial.scss</code>。下划线让Sass知道该文件只是部分文件,不应将其生成为CSS文件。Sass局部函数与<code>@use</code> 规则一起使用。</p><h3 id="五、模块"><a href="#五、模块" class="headerlink" title="五、模块"></a>五、模块</h3><p>不必将所有Sass都写在一个文件中。您可以根据需要将其拆分<code>@use</code>。该规则将另一个Sass文件作为<em>模块</em>加载,这意味着您可以在Sass文件中使用基于文件名的命名空间引用其变量,<a href="https://sass-lang.com/guide#topic-6" target="_blank" rel="noopener">mixins</a>和<a href="https://sass-lang.com/documentation/at-rules/function" target="_blank" rel="noopener">函数</a>。使用文件还将在编译输出中包含它生成的CSS!</p><figure class="highlight scss"><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">// _base.scss</span></span><br><span class="line"><span class="variable">$font-stack</span>: Helvetica, sans-serif;</span><br><span class="line"><span class="variable">$primary-color</span>: <span class="number">#333</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">font</span>: <span class="number">100%</span> <span class="variable">$font-stack</span>;</span><br><span class="line"> <span class="attribute">color</span>: <span class="variable">$primary-color</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight scss"><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">// styles.scss</span></span><br><span class="line">@use <span class="string">'base'</span>;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.inverse</span> {</span><br><span class="line"> <span class="attribute">background-color</span>: base.<span class="variable">$primary-color</span>;</span><br><span class="line"> <span class="attribute">color</span>: white;</span><br><span class="line">}</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></pre></td><td class="code"><pre><span class="line"><span class="selector-tag">body</span> {</span><br><span class="line"> <span class="attribute">font</span>: <span class="number">100%</span> Helvetica, sans-serif;</span><br><span class="line"> <span class="attribute">color</span>: <span class="number">#333</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.inverse</span> {</span><br><span class="line"> <span class="attribute">background-color</span>: <span class="number">#333</span>;</span><br><span class="line"> <span class="attribute">color</span>: white;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="六、混合"><a href="#六、混合" class="headerlink" title="六、混合"></a>六、混合</h3><p> CSS中的某些内容编写起来有些繁琐,尤其是使用CSS3 和存在的许多供应商前缀时。使用mixin,您可以创建要在整个站点中重复使用的CSS声明组 。您甚至可以传入值以使混入更加灵活。mixin的一个很好的用法是用于供应商前缀。这是的示例 <code>transform</code>。</p><figure class="highlight scss"><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="keyword">mixin</span> transform(<span class="variable">$property</span>) {</span><br><span class="line"> -webkit-<span class="attribute">transform</span>: <span class="variable">$property</span>;</span><br><span class="line"> -ms-<span class="attribute">transform</span>: <span class="variable">$property</span>;</span><br><span class="line"> <span class="attribute">transform</span>: <span class="variable">$property</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.box</span> { @<span class="keyword">include</span> transform(rotate(<span class="number">30deg</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></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.box</span> {</span><br><span class="line"> <span class="attribute">-webkit-transform</span>: <span class="built_in">rotate</span>(30deg);</span><br><span class="line"> <span class="attribute">-ms-transform</span>: <span class="built_in">rotate</span>(30deg);</span><br><span class="line"> <span class="attribute">transform</span>: <span class="built_in">rotate</span>(30deg);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>要创建一个mixin,请使用<code>@mixin</code>指令并为其命名。我们将其命名为mixin <code>transform</code>。我们还在<code>$property</code>括号内使用了变量 ,因此我们可以传递任何所需的变换。创建混入之后,您可以将其用作CSS 声明<code>@include</code>,以混入的名称开头。</p><h3 id="七、扩展继承"><a href="#七、扩展继承" class="headerlink" title="七、扩展继承"></a>七、扩展继承</h3><p> 这是Sass最有用的功能之一。使用<code>@extend</code>使您可以将一组CSS属性从一个选择器共享到另一个选择器。它有助于使Sass保持非常干燥。在我们的示例中,我们将使用扩展,占位符类一起使用的另一个功能,为错误,警告和成功创建一系列简单的消息传递。占位符类是一种特殊的类,仅在扩展时才打印,并且可以帮助保持编译后的CSS整洁。</p><figure class="highlight scss"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/* This CSS will print because %message-shared is extended. */</span></span><br><span class="line">%message-shared {</span><br><span class="line"> <span class="attribute">border</span>: <span class="number">1px</span> solid <span class="number">#ccc</span>;</span><br><span class="line"> <span class="attribute">padding</span>: <span class="number">10px</span>;</span><br><span class="line"> <span class="attribute">color</span>: <span class="number">#333</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// This CSS won't print because %equal-heights is never extended.</span></span><br><span class="line">%equal-heights {</span><br><span class="line"> <span class="attribute">display</span>: flex;</span><br><span class="line"> <span class="attribute">flex-wrap</span>: wrap;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.message</span> {</span><br><span class="line"> @<span class="keyword">extend</span> %message-shared;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.success</span> {</span><br><span class="line"> @<span class="keyword">extend</span> %message-shared;</span><br><span class="line"> <span class="attribute">border-color</span>: green;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.error</span> {</span><br><span class="line"> @<span class="keyword">extend</span> %message-shared;</span><br><span class="line"> <span class="attribute">border-color</span>: red;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.warning</span> {</span><br><span class="line"> @<span class="keyword">extend</span> %message-shared;</span><br><span class="line"> <span class="attribute">border-color</span>: yellow;</span><br><span class="line">}</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/* This CSS will print because %message-shared is extended. */</span></span><br><span class="line"><span class="selector-class">.message</span>, <span class="selector-class">.success</span>, <span class="selector-class">.error</span>, <span class="selector-class">.warning</span> {</span><br><span class="line"> <span class="attribute">border</span>: <span class="number">1px</span> solid <span class="number">#ccc</span>;</span><br><span class="line"> <span class="attribute">padding</span>: <span class="number">10px</span>;</span><br><span class="line"> <span class="attribute">color</span>: <span class="number">#333</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.success</span> {</span><br><span class="line"> <span class="attribute">border-color</span>: green;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.error</span> {</span><br><span class="line"> <span class="attribute">border-color</span>: red;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.warning</span> {</span><br><span class="line"> <span class="attribute">border-color</span>: yellow;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 上面的代码的作用是告诉<code>.message</code>,<code>.success</code>,<code>.error</code>,和<code>.warning</code>做人一样<code>%message-shared</code>。这意味着任何地方<code>%message-shared</code>显示来,<code>.message</code>,<code>.success</code>,<code>.error</code>,和 <code>.warning</code>也会这样做的。魔术发生在生成的CSS中,其中每个类将获得与相同的CSS属性<code>%message-shared</code>。这有助于您避免在HTML 元素上编写多个类名。</p><p> 除了Sass中的占位符类之外,您还可以扩展最简单的CSS选择器,但是使用占位符是确保不扩展嵌套在样式中其他位置的类的最简单方法,这会导致CSS中意外的选择器 。</p><p> 请注意,不会生成CSS in <code>%equal-heights</code>,因为<code>%equal-heights</code>它不会被扩展。</p><h3 id="八、操作符"><a href="#八、操作符" class="headerlink" title="八、操作符"></a>八、操作符</h3><p> 在 CSS 中经常需要做数学计算。Sass 支持一些标准的 数学运算符,例如 <code>+</code>、<code>-</code>、<code>*</code>、<code>/</code> 和 <code>%</code>。在下面的例子中,我们 将做一些简单的数学运算来计算出 <code>aside</code> & <code>article</code> 的宽度。</p><figure class="highlight scss"><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="selector-class">.container</span> {</span><br><span class="line"> <span class="attribute">width</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">article</span><span class="selector-attr">[role="main"]</span> {</span><br><span class="line"> <span class="attribute">float</span>: left;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">600px</span> / <span class="number">960px</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">aside</span><span class="selector-attr">[role="complementary"]</span> {</span><br><span class="line"> <span class="attribute">float</span>: right;</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">300px</span> / <span class="number">960px</span> * <span class="number">100%</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
</entry>
<entry>
<title>React UI娓叉煋</title>
<link href="/2021/09/22/React%20UI%E5%A8%93%E5%8F%89%E7%85%8B/"/>
<url>/2021/09/22/React%20UI%E5%A8%93%E5%8F%89%E7%85%8B/</url>
<content type="html"><![CDATA[<p> 一开始是因为老板给发的useEffect的链接去看到里面还有一篇关于React渲染机制的,因为老是看到菁程里面渲染次数问题一直没搞清楚,所以就又去看了一下,下面也会写一篇关于useEffect(其实不是特别想写因为怕是直接抄了,还是要想一下怎么用自己的理解写一篇分享吧)</p><h2 id="一个小Demo"><a href="#一个小Demo" class="headerlink" title="一个小Demo"></a>一个小Demo</h2><figure class="highlight jsx"><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="keyword">import</span> React <span class="keyword">from</span> <span class="string">'react'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> element = <span class="xml"><span class="tag"><<span class="name">div</span> <span class="attr">title</span>=<span class="string">"ele"</span>></span>This is an element.<span class="tag"></<span class="name">div</span>></span></span>;</span><br><span class="line"><span class="keyword">const</span> container = <span class="built_in">document</span>.getElementById(<span class="string">"root"</span>);</span><br><span class="line"></span><br><span class="line">ReactDOM.render(element, container);</span><br></pre></td></tr></table></figure><p>这里<code>element</code>是一个简单的<code>div</code>块,是一个<code>react</code>元素。这里区分一下DOM节点和<code>react</code>元素。<code>container</code>是获取到的DOM节点作为容器。而这里使用的还是<code>JSX</code>语法,<code>Babel</code>会将编译一下变成:</p><figure class="highlight jsx"><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">import</span> React <span class="keyword">from</span> <span class="string">'react'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> element = React.createElement(</span><br><span class="line"><span class="string">"div"</span>,</span><br><span class="line"> { <span class="attr">title</span>: <span class="string">"ele"</span> },</span><br><span class="line"> <span class="string">"This is an element"</span></span><br><span class="line">);</span><br><span class="line"><span class="keyword">const</span> container = <span class="built_in">document</span>.getElementById(<span class="string">"root"</span>);</span><br><span class="line"></span><br><span class="line">ReactDOM.render(element, container);</span><br></pre></td></tr></table></figure><p><code>createElement</code>接受的第一个参数是元素类型<code>div</code>;第二的参数是<code>attribute</code>对象,有<code>title</code>等属性;第三个参数是<code>textNode</code>。</p><p>而事实上的一个<code>react</code>元素是这样审的:</p><figure class="highlight jsx"><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="keyword">const</span> element = {</span><br><span class="line"> type: <span class="string">"div"</span>,</span><br><span class="line"> props: {</span><br><span class="line"> title: <span class="string">"ele"</span>,</span><br><span class="line"> children: <span class="string">"This is an element"</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>而在渲染时,发生了以下的传统DOM操作:</p><figure class="highlight jsx"><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">// 在 ReactDOM 渲染器内部(简化版)</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createHostInstance</span>(<span class="params">reactElement</span>) </span>{</span><br><span class="line"> <span class="keyword">let</span> domNode = <span class="built_in">document</span>.createElement(reactElement.type); </span><br><span class="line"> domNode.className = reactElement.props.className; </span><br><span class="line"> <span class="keyword">let</span> textNode = <span class="built_in">document</span>.createTextNode(<span class="string">""</span>);</span><br><span class="line"> textNode.nodeValue = reactElement.props.children;</span><br><span class="line"> domNode.appendChild(textNode);</span><br><span class="line"> <span class="keyword">return</span> domNode;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>从而将react元素变成了dom的节点。</p><p>这里很明显就出现了一个问题,如何处理<code>children</code>是需要优化的。因为<code>children</code>也有可能是一个数组对象(其他的react元素)。</p><p>例如这样的一个<code>element</code>:</p><figure class="highlight jsx"><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="keyword">const</span> element = (</span><br><span class="line"><div id=<span class="string">"foo"</span>></span><br><span class="line"> <a>bar<<span class="regexp">/a></span></span><br><span class="line"><span class="regexp"> <b /</span>></span><br><span class="line"> <<span class="regexp">/div></span></span><br><span class="line"><span class="regexp">)</span></span><br><span class="line"><span class="regexp">/</span><span class="regexp">/经过编译后</span></span><br><span class="line"><span class="regexp">const element = React.createElement(</span></span><br><span class="line"><span class="regexp"> "div",</span></span><br><span class="line"><span class="regexp"> { id: "foo" },</span></span><br><span class="line"><span class="regexp"> React.createElement("a", null, "bar"),</span></span><br><span class="line"><span class="regexp"> React.createElement("b")</span></span><br><span class="line"><span class="regexp">)</span></span><br></pre></td></tr></table></figure><p>我们开始工厂模式创造元素:</p><figure class="highlight jsx"><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="function"><span class="keyword">function</span> <span class="title">createElement</span>(<span class="params">type, props, ...children</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> type,</span><br><span class="line"> props: {</span><br><span class="line"> ...props,</span><br><span class="line"> children: children.map(<span class="function"><span class="params">child</span> =></span></span><br><span class="line"> <span class="keyword">typeof</span> child === <span class="string">"object"</span></span><br><span class="line"> ? child</span><br><span class="line"> : createTextElement(child)</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="function"><span class="keyword">function</span> <span class="title">createTextElement</span>(<span class="params">text</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> type: <span class="string">"TEXT_ELEMENT"</span>,</span><br><span class="line"> props: {</span><br><span class="line"> nodeValue: text,</span><br><span class="line"> children: [],</span><br><span class="line"> },</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>我们自己设计了两个函数,来生成元素节点或者文本节点。文本节点的<code>type</code>为”TEXT_ELEMENT“,且将children置为空数组。这样就可以区分不同的<code>child</code>了。</p><p>接下来就是<code>render</code>部分了:follow step by step.</p><figure class="highlight jsx"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">render</span>(<span class="params">element, container</span>) </span>{</span><br><span class="line"> <span class="comment">// TODO create dom nodes</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">render</span>(<span class="params">element, container</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> dom = <span class="built_in">document</span>.createElement(element.type)</span><br><span class="line"></span><br><span class="line"> container.appendChild(dom)</span><br><span class="line">}<span class="comment">// 将react元素转化为dom节点</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">render</span>(<span class="params">element, container</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> dom = <span class="built_in">document</span>.createElement(element.type)</span><br><span class="line"></span><br><span class="line"> element.props.children.forEach(<span class="function"><span class="params">child</span> =></span></span><br><span class="line"> render(child, dom)</span><br><span class="line"> )<span class="comment">// 遍历children, 递归调用</span></span><br><span class="line"></span><br><span class="line"> container.appendChild(dom)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">render</span>(<span class="params">element, container</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> dom =</span><br><span class="line"> element.type == <span class="string">"TEXT_ELEMENT"</span></span><br><span class="line"> ? <span class="built_in">document</span>.createTextNode(<span class="string">""</span>)</span><br><span class="line"> : <span class="built_in">document</span>.createElement(element.type)</span><br><span class="line"><span class="comment">//dom可能为文本节点和元素节点两类</span></span><br><span class="line"> element.props.children.forEach(<span class="function"><span class="params">child</span> =></span></span><br><span class="line"> render(child, dom)</span><br><span class="line"> )</span><br><span class="line"></span><br><span class="line"> container.appendChild(dom)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">render</span>(<span class="params">element, container</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> dom =</span><br><span class="line"> element.type == <span class="string">"TEXT_ELEMENT"</span></span><br><span class="line"> ? <span class="built_in">document</span>.createTextNode(<span class="string">""</span>)</span><br><span class="line"> : <span class="built_in">document</span>.createElement(element.type)</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">const</span> isProperty = <span class="function"><span class="params">key</span> =></span> key !== <span class="string">"children"</span> <span class="comment">//判断是不是children属性</span></span><br><span class="line"> <span class="built_in">Object</span>.keys(element.props)</span><br><span class="line"> .filter(isProperty)</span><br><span class="line"> .forEach(<span class="function"><span class="params">name</span> =></span> {</span><br><span class="line"> dom[name] = element.props[name]</span><br><span class="line"> })<span class="comment">//将除了children属性的属性赋给节点</span></span><br><span class="line"></span><br><span class="line"> element.props.children.forEach(<span class="function"><span class="params">child</span> =></span></span><br><span class="line"> render(child, dom)</span><br><span class="line"> )</span><br><span class="line"></span><br><span class="line"> container.appendChild(dom)</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在大概讲了render和元素的一些基本概念后(突然感觉跑偏了好多),react元素之间通过父子的关系形成了数的结构。</p><p>在某一时间节点调用 React 的 <code>render()</code> 方法,会创建一棵由 React 元素组成的树。在下一次 state 或 props 更新时,相同的 <code>render()</code> 方法会返回一棵不同的树。React 需要基于这两棵树之间的差别来判断如何高效的更新 UI,以保证当前 UI 与最新的树保持同步。</p><p>此算法有一些通用的解决方案,即生成将一棵树转换成另一棵树的最小操作次数。然而,即使使用<a href="http://grfia.dlsi.ua.es/ml/algorithms/references/editsurvey_bille.pdf" target="_blank" rel="noopener">最优的算法</a>,该算法的复杂程度仍为 O(n^3 ),其中 n 是树中元素的数量。</p><p>如果在 React 中使用该算法,那么展示 1000 个元素则需要 10 亿次的比较。这个开销实在是太过高昂。于是 React 在以下两个假设的基础之上提出了一套 O(n) 的启发式算法:</p><ol><li>两个不同类型的元素会产生出不同的树;</li><li>开发者可以通过设置 <code>key</code> 属性,来告知渲染哪些子元素在不同的渲染下可以保存不变;</li></ol><p>在实践中,我们发现以上假设在几乎所有实用的场景下都成立。</p><figure class="highlight jsx"><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="comment">// 第一次渲染</span></span><br><span class="line">ReactDOM.render(</span><br><span class="line"> <dialog></span><br><span class="line"> <input /></span><br><span class="line"> <<span class="regexp">/dialog>,</span></span><br><span class="line"><span class="regexp"> domContainer</span></span><br><span class="line"><span class="regexp">);</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">/</span><span class="regexp">/ 下一次渲染</span></span><br><span class="line"><span class="regexp">ReactDOM.render(</span></span><br><span class="line"><span class="regexp"> <dialog></span></span><br><span class="line"><span class="regexp"> <p>I was just added here!</</span>p> <span class="xml"><span class="tag"><<span class="name">input</span> /></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">dialog</span>></span></span>,</span><br><span class="line"> domContainer</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>react会对比元素类型,dialog ==> dialog不变,仅比对更新有改变的属性;input ==> p 发生了改变。删掉原来的节点,新建新的节点。(nothing) ==> input :需要重新创建一个 <code>input</code> 宿主实例。</p><p>在现实写代码我们不会多次调用render,而是在p标签的位置做一些手脚。</p><p>而当遇到动态列表时,我们不能确定其中的顺序总是一成不变的。</p><figure class="highlight jsx"><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="function"><span class="keyword">function</span> <span class="title">ShoppingList</span>(<span class="params">{ list }</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <form></span><br><span class="line"> {list.map(<span class="function"><span class="params">item</span> =></span> (</span><br><span class="line"> <p></span><br><span class="line"> You bought {item.name}</span><br><span class="line"> <br /></span><br><span class="line"> Enter how many <span class="keyword">do</span> you want: <span class="xml"><span class="tag"><<span class="name">input</span> /></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">p</span>></span></span></span><br><span class="line"> ))}</span><br><span class="line"> <<span class="regexp">/form></span></span><br><span class="line"><span class="regexp"> )</span></span><br><span class="line"><span class="regexp">}</span></span><br></pre></td></tr></table></figure><p>如果我们的商品列表被重新排序了,React 只会看到所有的 <code>p</code> 以及里面的 <code>input</code> 拥有相同的类型,并不知道该如何移动它们。(在 React 看来,虽然这些商品本身改变了,但是它们的顺序并没有改变。)</p><p>所以 React 会对这十个商品进行类似如下的重排序:</p><figure class="highlight jsx"><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="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i < <span class="number">10</span>; i++) {</span><br><span class="line"> <span class="keyword">let</span> pNode = formNode.childNodes[i];</span><br><span class="line"> <span class="keyword">let</span> textNode = pNode.firstChild;</span><br><span class="line"> textNode.textContent = <span class="string">'You bought '</span> + items[i].name;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>React 只会对其中的每个元素进行更新而不是将其重新排序。这样做会造成性能上的问题和潜在的 bug 。例如,当商品列表的顺序改变时,原本在第一个输入框的内容仍然会存在于现在的第一个输入框中 — 尽管事实上在商品列表里它应该代表着其他的商品!</p><p><strong>这就是为什么每次当输出中包含元素数组时,React 都会让你指定一个叫做 <code>key</code> 的属性:</strong></p><figure class="highlight jsx"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">ShoppingList</span>(<span class="params">{ list }</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <form></span><br><span class="line"> {list.map(<span class="function"><span class="params">item</span> =></span> (</span><br><span class="line"> <p key={item.productId}> You bought {item.name}</span><br><span class="line"> <br /></span><br><span class="line"> Enter how many <span class="keyword">do</span> you want: <span class="xml"><span class="tag"><<span class="name">input</span> /></span></span></span><br><span class="line"><span class="xml"> <span class="tag"></<span class="name">p</span>></span></span></span><br><span class="line"> ))}</span><br><span class="line"> <<span class="regexp">/form></span></span><br><span class="line"><span class="regexp"> )</span></span><br><span class="line"><span class="regexp">}</span></span><br></pre></td></tr></table></figure><p><code>key</code> 给予 React 判断子元素是否真正相同的能力,即使在渲染前后它在父元素中的位置不是相同的。</p><p>当 React 在 <code><form></code> 中发现 <code><p key="42"></code> ,它就会检查之前版本中的 <code><form></code> 是否同样含有 <code><p key=""42></code> 。即使 <code><form></code> 中的子元素们改变位置后,这个方法同样有效。在渲染前后当 key 仍然相同时,React 会重用先前的宿主实例,然后重新排序其兄弟元素。</p><p>需要注意的是 <code>key</code> 只与特定的父亲 React 元素相关联,比如 <code><form></code> 。React 并不会去匹配父元素不同但 key 相同的子元素。(React 并没有惯用的支持对在不重新创建元素的情况下让宿主实例在不同的父元素之间移动。)</p><p>给 <code>key</code> 赋予什么值最好呢?最好的答案就是:<strong>什么时候你会说一个元素不会改变即使它在父元素中的顺序被改变?</strong> 例如,在我们的商品列表中,商品本身的 ID 是区别于其他商品的唯一标识,那么它就最适合作为 <code>key</code> 。</p><p>最后,你也可以使用元素在数组中的下标作为 key。这个策略在元素不进行重新排序时比较合适,如果有顺序修改,diff 就会变慢。</p><p>当基于下标的组件进行重新排序时,组件 state 可能会遇到一些问题。由于组件实例是基于它们的 key 来决定是否更新以及复用,如果 key 是一个下标,那么修改顺序时会修改当前的 key,导致非受控组件的 state(比如输入框)可能相互篡改,会出现无法预期的变动。</p>]]></content>
</entry>
<entry>
<title>React Redux</title>
<link href="/2021/09/22/React%20Redux/"/>
<url>/2021/09/22/React%20Redux/</url>
<content type="html"><![CDATA[<h1 id="Connect"><a href="#Connect" class="headerlink" title="Connect()"></a><code>Connect()</code></h1><p><code>Connect()</code>是连接<code>React</code>和<code>Redux store</code>的函数。</p><p>它可以从<code>Store</code>当中拿出一些碎片的数据,传递给和它相连的组件。函数还可以发送一些<code>action</code>给<code>Store</code>。</p><p>它不会修改传递给它的组件类。而是返回一个新的,已连接的组件类,该类包含传入的组件。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">connect</span>(<span class="params">mapStateToProps?, mapDispatchToProps?, mergeProps?, options?</span>)</span></span><br></pre></td></tr></table></figure><p><code>mapStateToProps</code>和<code>mapDispatchToProps</code>分别处理的是<code>Redux Store</code>的<code>state</code>数据和<code>dispatch</code>方法。</p><p>函数返回的<code>mapStateToProps</code>和<code>mapDispatchToProps</code>分别指向组件内部的<code>stateProps</code>和<code>dispatchProps</code>。</p><h2 id="connect-参数"><a href="#connect-参数" class="headerlink" title="connect() 参数"></a><code>connect()</code> 参数</h2><p><code>connect</code> 可以接受四个不同的参数, 全部都是可选的:</p><ol><li><code>mapStateToProps?: Function</code></li><li><code>mapDispatchToProps?: Function | Object</code></li><li><code>mergeProps?: Function</code></li><li><code>options?: Object</code></li></ol><h1 id="Connect-Extracting-Data-with-mapStateToProps"><a href="#Connect-Extracting-Data-with-mapStateToProps" class="headerlink" title="Connect: Extracting Data with mapStateToProps"></a>Connect: Extracting Data with <code>mapStateToProps</code></h1><p>作为第一个传入<code>connect</code>的参数,<code>mapStateToProps</code>从<code>Store</code>选择一部分数据,传给需要的组件。</p><ul><li>当<code>store</code>的<code>state</code>数据变化的时候会调用改函数。</li><li>它接受一整个<code>store state</code>,返回一个对象包含组件需要的数据。</li></ul><h2 id="定义-mapStateToProps"><a href="#定义-mapStateToProps" class="headerlink" title="定义 mapStateToProps"></a>定义 <code>mapStateToProps</code></h2><p><code>mapStateToProps</code>应该被定义为一个函数:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">mapStateToProps</span>(<span class="params">state, ownProps?</span>)</span></span><br></pre></td></tr></table></figure><p>它应该接受一个名为<code>state</code>的第一个参数,可以选择一个称为<code>ownProps</code>的第二个参数,并返回一个包含连接组件所需数据的普通对象。</p><p>此函数应作为<code>connect</code>的第一个参数传递,并将在每次<code>Redux</code>存储状态更改时调用。如果您不想订阅存储,请传递<code>null</code>或undefined来代替<code>mapStateToProps</code>进行连接。</p><p>不管<code>mapstatetops</code>函数是使用<code>function</code>关键字<code>(function mapState(state){})</code>还是作为箭头函数<code>(constmapstate=(state)=>{}</code>编写的,它的工作方式都是一样的。</p><h3 id="Arguments"><a href="#Arguments" class="headerlink" title="Arguments"></a>Arguments</h3><ol><li><strong><code>state</code></strong></li><li><strong><code>ownProps</code> (可选的)</strong></li></ol><h4 id="state"><a href="#state" class="headerlink" title="state"></a><code>state</code></h4><p><code>mapStateToProps</code>函数的第一个参数是整个<code>Redux</code>存储状态(调用存储.<code>getState()</code>). 因此,第一个论点传统上被称为<code>state</code>。(虽然您可以给参数指定任何名称,但将其称为store是不正确的-它是“state value”,而不是“store instance”。)</p><p>至少state作为参数是应该被传入到mapStateToProps函数。</p><figure class="highlight javascript"><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="function"><span class="keyword">function</span> <span class="title">mapStateToProps</span>(<span class="params">state</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> { todos } = state</span><br><span class="line"> <span class="keyword">return</span> { <span class="attr">todoList</span>: todos.allIds }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> connect(mapStateToProps)(TodoList)</span><br></pre></td></tr></table></figure><h4 id="ownProps-optional"><a href="#ownProps-optional" class="headerlink" title="ownProps (optional)"></a><code>ownProps</code> (optional)</h4><p>如果组件需要从自己的属性中获取数据来从存储中检索数据,则可以使用第二个参数ownProps定义函数。此参数将包含给connect生成的包装器组件的所有属性。</p><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">mapStateToProps</span>(<span class="params">state, ownProps</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> { visibilityFilter } = state</span><br><span class="line"> <span class="keyword">const</span> { id } = ownProps</span><br><span class="line"> <span class="keyword">const</span> todo = getTodoById(state, id)</span><br><span class="line"></span><br><span class="line"> <span class="comment">// component receives additionally:</span></span><br><span class="line"> <span class="keyword">return</span> { todo, visibilityFilter }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// Later, in your application, a parent component renders:</span></span><br><span class="line">;<span class="xml"><span class="tag"><<span class="name">ConnectedTodo</span> <span class="attr">id</span>=<span class="string">{123}</span> /></span></span></span><br><span class="line"><span class="xml">// and your component receives props.id, props.todo, and props.visibilityFilter</span></span><br></pre></td></tr></table></figure><h3 id="Return"><a href="#Return" class="headerlink" title="Return"></a>Return</h3><p>mapToProps函数应返回一个包含组件所需数据的纯对象:</p><ul><li>Each field in the object will become a prop for your actual component</li><li>The values in the fields will be used to determine if your component needs to re-render</li></ul><figure class="highlight javascript"><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="function"><span class="keyword">function</span> <span class="title">mapStateToProps</span>(<span class="params">state</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> a: <span class="number">42</span>,</span><br><span class="line"> todos: state.todos,</span><br><span class="line"> filter: state.visibilityFilter</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// component will receive: props.a, props.todos, and props.filter</span></span><br></pre></td></tr></table></figure><h2 id="Usage-Guidelines"><a href="#Usage-Guidelines" class="headerlink" title="Usage Guidelines"></a>Usage Guidelines</h2><ol><li><h3 id="Let-mapStateToProps-Reshape-the-Data-from-the-Store"><a href="#Let-mapStateToProps-Reshape-the-Data-from-the-Store" class="headerlink" title="Let mapStateToProps Reshape the Data from the Store"></a>Let <code>mapStateToProps</code> Reshape the Data from the Store</h3></li><li><h3 id="Use-Selector-Functions-to-Extract-and-Transform-Data"><a href="#Use-Selector-Functions-to-Extract-and-Transform-Data" class="headerlink" title="Use Selector Functions to Extract and Transform Data"></a>Use Selector Functions to Extract and Transform Data</h3></li><li><h3 id="mapStateToProps-Functions-Should-Be-Fast"><a href="#mapStateToProps-Functions-Should-Be-Fast" class="headerlink" title="mapStateToProps Functions Should Be Fast"></a><code>mapStateToProps</code> Functions Should Be Fast</h3></li><li><h3 id="mapStateToProps-Functions-Should-Be-Pure-and-Synchronous"><a href="#mapStateToProps-Functions-Should-Be-Pure-and-Synchronous" class="headerlink" title="mapStateToProps Functions Should Be Pure and Synchronous"></a><code>mapStateToProps</code> Functions Should Be Pure and Synchronous</h3></li></ol><h1 id="Connect-Dispatching-Actions-with-mapDispatchToProps"><a href="#Connect-Dispatching-Actions-with-mapDispatchToProps" class="headerlink" title="Connect: Dispatching Actions with mapDispatchToProps"></a>Connect: Dispatching Actions with <code>mapDispatchToProps</code></h1><p>作为传递给connect的第二个参数,mapDispatchToProps用于将操作分派到存储区。</p><p><code>dispatch</code>是Redux Store之中唯一的函数。我们只有调用<code>store.dispatch</code>去发送一个<code>action</code>。</p><p>使用React Redux,您的组件永远不会直接访问存储区—connect会为您执行此操作。React Redux为您提供了两种让组件分派操作的方法:</p><ul><li>By default, a connected component receives <code>props.dispatch</code> and can dispatch actions itself.</li><li><code>connect</code> can accept an argument called <code>mapDispatchToProps</code>, which lets you create functions that dispatch when called, and pass those functions as props to your component.</li></ul><h2 id="Approaches-for-Dispatching"><a href="#Approaches-for-Dispatching" class="headerlink" title="Approaches for Dispatching"></a>Approaches for Dispatching</h2><h3 id="Default-dispatch-as-a-Prop"><a href="#Default-dispatch-as-a-Prop" class="headerlink" title="Default: dispatch as a Prop"></a>Default: <code>dispatch</code> as a Prop</h3><p>如果不指定connect()的第二个参数,则默认情况下,组件将接收dispatch。例如:</p><figure class="highlight javascript"><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">connect()(MyComponent)</span><br><span class="line"><span class="comment">// which is equivalent with</span></span><br><span class="line">connect(</span><br><span class="line"> <span class="literal">null</span>,</span><br><span class="line"> <span class="literal">null</span></span><br><span class="line">)(MyComponent)</span><br><span class="line"></span><br><span class="line"><span class="comment">// or</span></span><br><span class="line">connect(mapStateToProps <span class="comment">/** no second argument */</span>)(MyComponent)</span><br></pre></td></tr></table></figure><p>以这种方式连接组件后,组件将接收道具调度. 您可以使用它将操作分派到存储。</p><figure class="highlight jsx"><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="function"><span class="keyword">function</span> <span class="title">Counter</span>(<span class="params">{ count, dispatch }</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div></span><br><span class="line"> <button onClick={() => dispatch({ <span class="attr">type</span>: <span class="string">'DECREMENT'</span> })}>-<span class="xml"><span class="tag"></<span class="name">button</span>></span></span></span><br><span class="line"> <span>{count}<<span class="regexp">/span></span></span><br><span class="line"><span class="regexp"> <button onClick={() => dispatch({ type: 'INCREMENT' })}>+</</span>button></span><br><span class="line"> <button onClick={() => dispatch({ <span class="attr">type</span>: <span class="string">'RESET'</span> })}>reset<<span class="regexp">/button></span></span><br><span class="line"><span class="regexp"> </</span>div></span><br><span class="line"> )</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="Providing-A-mapDispatchToProps-Parameter"><a href="#Providing-A-mapDispatchToProps-Parameter" class="headerlink" title="Providing A mapDispatchToProps Parameter"></a>Providing A <code>mapDispatchToProps</code> Parameter</h3><p>提供mapDispatchToProps允许您指定哪一种的<code>action</code>需要被分派。它允许您提供<code>action dispatch</code>作为传参。因此,与其调用函数<code>props.dispatch(()=>increment())</code>,可以调用直接调用<code>prop.increment()</code>。你可能想这么做有几个原因。</p><h4 id="More-Declarative"><a href="#More-Declarative" class="headerlink" title="More Declarative"></a>More Declarative</h4><p>首先,将<code>dispatch</code>逻辑封装到函数中使实现更具声明性。<code>dispatch</code>一个动作并让Redux存储处理数据流是如何实现行为的,而不是它做什么。</p><p>一个很好的例子是在单击按钮时<code>dispatch</code>操作。直接连接按钮在概念上可能没有意义,按钮引用<code>dispatch</code>也没有意义。</p><figure class="highlight javascript"><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">// button needs to be aware of "dispatch"</span></span><br><span class="line"><button onClick={() => dispatch({ <span class="attr">type</span>: <span class="string">"SOMETHING"</span> })} /></span><br><span class="line"></span><br><span class="line"><span class="comment">// button unaware of "dispatch",</span></span><br><span class="line"><button onClick={doSomething} /></span><br></pre></td></tr></table></figure><p>一旦您用<code>dispatch</code>动作的函数包装了所有<code>action</code>创建者,组件就不需要分派了。因此,如果您定义自己的<code>mapDispatchToProps</code>,则连接的组件将不再接收<code>dispatch</code>。</p><h4 id="Pass-Down-Action-Dispatching-Logic-to-Unconnected-Child-Components"><a href="#Pass-Down-Action-Dispatching-Logic-to-Unconnected-Child-Components" class="headerlink" title="Pass Down Action Dispatching Logic to ( Unconnected ) Child Components"></a>Pass Down Action Dispatching Logic to ( Unconnected ) Child Components</h4><p>此外,您还可以将操作分派函数传递给子(可能是未连接的)组件。这允许更多的组件分派动作,同时让它们“不知道”Redux。</p><figure class="highlight jsx"><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">// pass down toggleTodo to child component</span></span><br><span class="line"><span class="comment">// making Todo able to dispatch the toggleTodo action</span></span><br><span class="line"><span class="keyword">const</span> TodoList = <span class="function">(<span class="params">{ todos, toggleTodo }</span>) =></span> (</span><br><span class="line"> <div></span><br><span class="line"> {todos.map(<span class="function"><span class="params">todo</span> =></span> (</span><br><span class="line"> <Todo todo={todo} onClick={toggleTodo} /></span><br><span class="line"> ))}</span><br><span class="line"> <<span class="regexp">/div></span></span><br><span class="line"><span class="regexp">)</span></span><br></pre></td></tr></table></figure><p>这就是<code>React Redux</code>的<code>connect</code>所做的——它封装了与<code>Redux store</code>对话的逻辑,让您不用担心它。这是你应该在你的实现中充分利用的。</p><h2 id="Two-Forms-of-mapDispatchToProps"><a href="#Two-Forms-of-mapDispatchToProps" class="headerlink" title="Two Forms of mapDispatchToProps"></a>Two Forms of <code>mapDispatchToProps</code></h2><p>mapDispatchToProps参数可以有两种形式。虽然函数形式允许更多的定制,但对象形式易于使用。</p><ul><li><strong>Function form</strong>: Allows more customization, gains access to <code>dispatch</code> and optionally <code>ownProps</code></li><li><strong>Object shorthand form</strong>: More declarative and easier to use</li></ul><h2 id="Defining-mapDispatchToProps-As-A-Function"><a href="#Defining-mapDispatchToProps-As-A-Function" class="headerlink" title="Defining mapDispatchToProps As A Function"></a>Defining <code>mapDispatchToProps</code> As A Function</h2><p>将<code>mapDispatchToProps</code>定义为一个函数,可以在自定义组件接收的函数以及它们如何分派操作方面提供最大的灵活性。你可以获得调度和拥有权。您可以利用这个机会编写自定义函数,以供连接的组件调用。</p><h3 id="Arguments-1"><a href="#Arguments-1" class="headerlink" title="Arguments"></a>Arguments</h3><ol><li><strong><code>dispatch</code></strong></li><li><strong><code>ownProps</code> (optional)</strong></li></ol><p><strong><code>dispatch</code></strong></p><p>将调用<code>mapDispatchToProps</code>函数,并将<code>dispatch</code>作为第一个参数。通常,通过返回在其内部调用<code>dispatch()</code>的新函数,并直接传入纯操作对象或传入操作创建者的结果来使用此方法。</p><figure class="highlight javascript"><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">const</span> mapDispatchToProps = <span class="function"><span class="params">dispatch</span> =></span> {</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> <span class="comment">// dispatching plain actions</span></span><br><span class="line"> increment: <span class="function"><span class="params">()</span> =></span> dispatch({ <span class="attr">type</span>: <span class="string">'INCREMENT'</span> }),</span><br><span class="line"> decrement: <span class="function"><span class="params">()</span> =></span> dispatch({ <span class="attr">type</span>: <span class="string">'DECREMENT'</span> }),</span><br><span class="line"> reset: <span class="function"><span class="params">()</span> =></span> dispatch({ <span class="attr">type</span>: <span class="string">'RESET'</span> })</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>您还可能希望将参数转发给<code>action creator</code>:</p><figure class="highlight javascript"><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">const</span> mapDispatchToProps = <span class="function"><span class="params">dispatch</span> =></span> {</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> <span class="comment">// explicitly forwarding arguments</span></span><br><span class="line"> onClick: <span class="function"><span class="params">event</span> =></span> dispatch(trackClick(event)), <span class="comment">//trackClick() is an anction creator</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// implicitly forwarding arguments</span></span><br><span class="line"> onReceiveImpressions: <span class="function">(<span class="params">...impressions</span>) =></span></span><br><span class="line"> dispatch(trackImpressions(impressions)) <span class="comment">//trackImpressions() is also an anction creator</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong><code>ownProps</code> ( optional )</strong></p><p>如果您的<code>mapDispatchToProps</code>函数被声明为接受两个参数,那么它将被调用,第一个参数是dispatch,传递给连接组件的属性作为第二个参数,并且在连接的组件接收到新的属性时将重新调用它。</p><p>这意味着,在组件重新呈现时,您可以在组件的属性发生更改时进行重新绑定,而不是在组件重新呈现时将新的属性重新绑定到<code>action dispatchers</code>。</p><p><strong>Binds on component mount</strong></p><figure class="highlight jsx"><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">render() {</span><br><span class="line"> <span class="keyword">return</span> <span class="xml"><span class="tag"><<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">{()</span> =></span> this.props.toggleTodo(this.props.todoId)} /></span></span><br><span class="line"><span class="xml">}</span></span><br><span class="line"></span><br><span class="line"><span class="xml">const mapDispatchToProps = dispatch => {</span></span><br><span class="line"><span class="xml"> return {</span></span><br><span class="line"><span class="xml"> toggleTodo: todoId => dispatch(toggleTodo(todoId))</span></span><br><span class="line"><span class="xml"> }</span></span><br><span class="line"><span class="xml">}</span></span><br></pre></td></tr></table></figure><p><strong>Binds on <code>props</code> change</strong></p><figure class="highlight jsx"><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">render() {</span><br><span class="line"> <span class="keyword">return</span> <span class="xml"><span class="tag"><<span class="name">button</span> <span class="attr">onClick</span>=<span class="string">{()</span> =></span> this.props.toggleTodo()} /></span></span><br><span class="line"><span class="xml">}</span></span><br><span class="line"></span><br><span class="line"><span class="xml">const mapDispatchToProps = (dispatch, ownProps) => {</span></span><br><span class="line"><span class="xml"> return {</span></span><br><span class="line"><span class="xml"> toggleTodo: () => dispatch(toggleTodo(ownProps.todoId))</span></span><br><span class="line"><span class="xml"> }</span></span><br><span class="line"><span class="xml">}</span></span><br></pre></td></tr></table></figure><h3 id="Return-1"><a href="#Return-1" class="headerlink" title="Return"></a>Return</h3><p><code>mapDispatchToProps</code>函数应返回一个纯对象:</p><ul><li>Each field in the object will become a separate prop for your own component, and the value should normally be a function that dispatches an action when called.</li><li>If you use action creators ( as oppose to plain object actions ) inside <code>dispatch</code>, it is a convention to simply name the field key the same name as the action creator:</li></ul><figure class="highlight jsx"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> increment = <span class="function"><span class="params">()</span> =></span> ({ <span class="attr">type</span>: <span class="string">'INCREMENT'</span> })</span><br><span class="line"><span class="keyword">const</span> decrement = <span class="function"><span class="params">()</span> =></span> ({ <span class="attr">type</span>: <span class="string">'DECREMENT'</span> })</span><br><span class="line"><span class="keyword">const</span> reset = <span class="function"><span class="params">()</span> =></span> ({ <span class="attr">type</span>: <span class="string">'RESET'</span> })</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> mapDispatchToProps = <span class="function"><span class="params">dispatch</span> =></span> {</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> <span class="comment">// dispatching actions returned by action creators</span></span><br><span class="line"> increment: <span class="function"><span class="params">()</span> =></span> dispatch(increment()),</span><br><span class="line"> decrement: <span class="function"><span class="params">()</span> =></span> dispatch(decrement()),</span><br><span class="line"> reset: <span class="function"><span class="params">()</span> =></span> dispatch(reset())</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><code>mapDispatchToProps</code>函数的返回将作为道具合并到连接的组件中。你可以直接调用他们,让他们<code>dispatch action</code>。</p><figure class="highlight jsx"><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="function"><span class="keyword">function</span> <span class="title">Counter</span>(<span class="params">{ count, increment, decrement, reset }</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div></span><br><span class="line"> <button onClick={decrement}>-<span class="xml"><span class="tag"></<span class="name">button</span>></span></span></span><br><span class="line"> <span>{count}<<span class="regexp">/span></span></span><br><span class="line"><span class="regexp"> <button onClick={increment}>+</</span>button></span><br><span class="line"> <button onClick={reset}>reset<<span class="regexp">/button></span></span><br><span class="line"><span class="regexp"> </</span>div></span><br><span class="line"> )</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="Defining-the-mapDispatchToProps-Function-with-bindActionCreators"><a href="#Defining-the-mapDispatchToProps-Function-with-bindActionCreators" class="headerlink" title="Defining the mapDispatchToProps Function with bindActionCreators"></a>Defining the <code>mapDispatchToProps</code> Function with <code>bindActionCreators</code></h3><p>手动的将这些函数包装起来是可笑的,所以Redux提供了一个函数去简化。</p><p><code>bindActionCreators</code> accepts two parameters:</p><ol><li>A <strong><code>function</code></strong> (an action creator) or an <strong><code>object</code></strong> (each field an action creator)</li><li><code>dispatch</code></li></ol><p><code>bindActionCreators</code>生成的包装器函数将自动转发它们的所有参数,因此您不需要手动执行此操作。</p><figure class="highlight javascript"><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">import</span> { bindActionCreators } <span class="keyword">from</span> <span class="string">'redux'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> increment = <span class="function"><span class="params">()</span> =></span> ({ <span class="attr">type</span>: <span class="string">'INCREMENT'</span> })</span><br><span class="line"><span class="keyword">const</span> decrement = <span class="function"><span class="params">()</span> =></span> ({ <span class="attr">type</span>: <span class="string">'DECREMENT'</span> })</span><br><span class="line"><span class="keyword">const</span> reset = <span class="function"><span class="params">()</span> =></span> ({ <span class="attr">type</span>: <span class="string">'RESET'</span> })</span><br><span class="line"></span><br><span class="line"><span class="comment">// binding an action creator</span></span><br><span class="line"><span class="comment">// returns (...args) => dispatch(increment(...args))</span></span><br><span class="line"><span class="keyword">const</span> boundIncrement = bindActionCreators(increment, dispatch)</span><br><span class="line"></span><br><span class="line"><span class="comment">// binding an object full of action creators</span></span><br><span class="line"><span class="keyword">const</span> boundActionCreators = bindActionCreators(</span><br><span class="line"> { increment, decrement, reset },</span><br><span class="line"> dispatch</span><br><span class="line">)</span><br><span class="line"><span class="comment">// returns</span></span><br><span class="line"><span class="comment">// {</span></span><br><span class="line"><span class="comment">// increment: (...args) => dispatch(increment(...args)),</span></span><br><span class="line"><span class="comment">// decrement: (...args) => dispatch(decrement(...args)),</span></span><br><span class="line"><span class="comment">// reset: (...args) => dispatch(reset(...args)),</span></span><br><span class="line"><span class="comment">// }</span></span><br></pre></td></tr></table></figure><p>To use <code>bindActionCreators</code> in our <code>mapDispatchToProps</code> function:</p><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { bindActionCreators } <span class="keyword">from</span> <span class="string">'redux'</span></span><br><span class="line"><span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">mapDispatchToProps</span>(<span class="params">dispatch</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> bindActionCreators({ increment, decrement, reset }, dispatch)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// component receives props.increment, props.decrement, props.reset</span></span><br><span class="line">connect(</span><br><span class="line"> <span class="literal">null</span>,</span><br><span class="line"> mapDispatchToProps</span><br><span class="line">)(Counter)</span><br></pre></td></tr></table></figure><h3 id="Manually-Injecting-dispatch"><a href="#Manually-Injecting-dispatch" class="headerlink" title="Manually Injecting dispatch"></a>Manually Injecting <code>dispatch</code></h3><p>如果提供了<code>mapDispatchToProps</code>参数,组件将不再接收默认分派。您可以通过手动将其添加到<code>mapDispatchToProps</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { bindActionCreators } <span class="keyword">from</span> <span class="string">'redux'</span></span><br><span class="line"><span class="comment">// ...</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">mapDispatchToProps</span>(<span class="params">dispatch</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> dispatch,</span><br><span class="line"> ...bindActionCreators({ increment, decrement, reset }, dispatch)</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="Defining-mapDispatchToProps-As-An-Object"><a href="#Defining-mapDispatchToProps-As-An-Object" class="headerlink" title="Defining mapDispatchToProps As An Object"></a>Defining <code>mapDispatchToProps</code> As An Object</h2><p>您已经看到,在React组件中调度Redux动作的设置过程非常相似:定义一个动作创建者,将其包装在另一个类似于的函数中<code>(…args) => dispatch(actionCreator(…args))</code>,并将该包装函数作为prop传递给您的组件。</p><p>因为这很普遍,所以<code>connect</code>支持参数的“对象简写”形式<code>mapDispatchToProps</code>:如果传递的对象中包含操作创建者而不是函数,<code>connect</code>则将<code>bindActionCreators</code>在内部自动调用您。</p><p><strong>我们建议始终使用的“对象简写”形式<code>mapDispatchToProps</code>,除非您有特定的原因自定义调度行为。</strong></p><p>注意:</p><ul><li><code>mapDispatchToProps</code>假定对象的每个字段都是动作创建者</li><li>您的组件将不再<code>dispatch</code>作为道具接收</li></ul><figure class="highlight jsx"><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">// React Redux does this for you automatically:</span></span><br><span class="line">dispatch => bindActionCreators(mapDispatchToProps, dispatch)</span><br></pre></td></tr></table></figure><p>Therefore, our <code>mapDispatchToProps</code> can simply be:</p><figure class="highlight jsx"><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="keyword">const</span> mapDispatchToProps = {</span><br><span class="line"> increment,</span><br><span class="line"> decrement,</span><br><span class="line"> reset</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>Since the actual name of the variable is up to you, you might want to give it a name like <code>actionCreators</code>, or even define the object inline in the call to <code>connect</code>:</p><figure class="highlight jsx"><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="keyword">import</span> {increment, decrement, reset} <span class="keyword">from</span> <span class="string">"./counterActions"</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> actionCreators = {</span><br><span class="line"> increment,</span><br><span class="line"> decrement,</span><br><span class="line"> reset</span><br><span class="line">}</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> connect(mapState, actionCreators)(Counter);</span><br><span class="line"><span class="comment">// or</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> connect(</span><br><span class="line"> mapState,</span><br><span class="line"> { increment, decrement, reset }</span><br><span class="line">)(Counter);</span><br></pre></td></tr></table></figure>]]></content>
</entry>
<entry>
<title>鍓嶇</title>
<link href="/2021/09/22/%E9%8D%93%E5%B6%87%EE%81%AC/"/>
<url>/2021/09/22/%E9%8D%93%E5%B6%87%EE%81%AC/</url>
<content type="html"><![CDATA[<p>这篇文章主要是来分享一下我这一年多时间以来在前端方面学习的方法和路径。</p><h2 id="什么是前端?"><a href="#什么是前端?" class="headerlink" title="什么是前端?"></a>什么是前端?</h2><p>为用户提供可交互的可视化界面。在传统的MVC式的开发当中,M为Model模型,V为View视图,C为Controller控制器。而前后端分离之后,前端主要负责的是V视图的部分。而如今前端早已不再是只能开发web方向了,如今它也具有数据可视化,垮端技术,中后台技术等方向。</p><h2 id="如何学习前端?"><a href="#如何学习前端?" class="headerlink" title="如何学习前端?"></a>如何学习前端?</h2><p>其实如何前端这个话题和如何学习是一个道理,我们其实只要掌握了学习的方法,用来学习什么都。</p><ol><li>独立解决问题的能力。</li><li>独立思考能力。</li><li>英语阅读能力。</li></ol><p>独立解决问题主要在于怎么提高自己的搜商。在如今互联网发达的时代,很多东西都是可以自己找到问题的答案的。那么难点就在于如何抽象出来问题,和提炼搜索内容。同样的问题可能有不同的关键字那么出来的结果就可能不一样。</p><p>独立思考能力,这一点也不用多说,凡事只有自己多思考过了才能成为自己的东西。我们在除了光去查去看了之后也要多实践。有时候看了也只是看了,多动手去写写代码。</p><p>而英语阅读能力也很重要在于英文文献的阅读,有很多时候我们中文的搜索解决不了我们的问题,这个时候我们就可以用英文去搜索并且阅读英文的文献。再者国外很多技术都比国内发展更好一些,所以要了解比较新的技术也需要去阅读英文。</p><p>其实以上说的这些点也不局限于前端的学习,而更多是通用的现代学习方法。</p><h2 id="前端三大基石"><a href="#前端三大基石" class="headerlink" title="前端三大基石"></a>前端三大基石</h2><p>HTML</p><p>HTML的全称为超文本标记语言,是一种标记语言。它包括一系列标签.通过这些标签可以将网络上的文档格式统一,使分散的Internet资源连接为一个逻辑整体。HTML文本是由HTML命令组成的描述性文本,HTML命令可以说明文字,图形、动画、声音、表格、链接。</p><p>CSS</p><p>层叠样式表(英文全称:Cascading Style Sheets)是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的计算机语言。CSS不仅可以静态地修饰网页,还可以配合各种脚本语言动态地对网页各元素进行格式化。</p><p>Javascript</p><p>JavaScript(简称“JS”) 是一种具有函数优先的轻量级,解释型或即时编译型的编程语言。虽然它是作为开发Web页面的脚本语言而出名,但是它也被用到了很多非浏览器环境中,JavaScript 基于原型编程、多范式的动态脚本语言,并且支持面向对象、命令式和声明式(如函数式编程)风格。</p><p>Javascript衍生的学习内容就十分的多,介于JavaScript的弱类型的语言,微软推出了对应的强类型语言TypeScript。</p><p>CSS的预处理的编译也有许多Less和SCSS都是可以去学一学,在开发更大型的项目的时候使用更好。</p><p>关于前端的框架来说,三大热门的框架React、Vue和Angular。这三个框架是基于Javascript的Web开发框架。了解这些内容之前我们应该要学习DOM和CSSOM等内容,Javascript是如何操控DOM元素的。</p><p>这里就又要问一个问题了,你们为什么学习前端?就业?写项目?感兴趣?</p><p>为什么要问这个问题呢?其实就是一个时间成本的问题。其实大家在学了HTML之后,学习Vue要更容易上手,因为它的视图和模块区分的更明显,还有就是是它的开发团队当中有许多的中国人,中文文档阅读起来也是十分方便且中文文档的质量也十分的高。十分推荐只是用来写项目的同学去学习,相比于React框架来说时间成本要低很多。</p><p>那么更想以前端就业的同学来说学习React和Vue 也是都要去学习和了解的框架。React相对于Vue来说需要了解class组件和它对应的声明周期。当然在16年后?他们也推出了React Hooks。从class组件变成了函数组件。用函数的思想去写组件可以使更多的组件抽取更加容易。</p><p>除了基本的React和Vue框架,也有对应的包去学习。Router实现路由跳转,Redux实现状态的管理。在比较简单的项目当中,不推荐使用Redux。刚刚开始学习写项目时候,我不建议去使用别人写好的组件。例如Antd这个比较知名的阿里前端开发的开源组件库。</p><p>当我们需要开发小程序的时候推荐一些框架。Taro框架是现在可以支持React和Vue的开发一个比较丰富的框架。但是现在Taro框架还是不太稳定,bug还挺多的。</p><p>当然这里说的都是一些关于前端web开发的部分,在实现可视化和中后台的方面还没有特别深入了解,也就不好多说什么了。我也最近才刚刚开始学习nodejs一些简单的服务搭建的。</p><h2 id="计算机基础"><a href="#计算机基础" class="headerlink" title="计算机基础"></a>计算机基础</h2><p>计算机基础是一个要成为专业的程序猿必备的技能了,也不管你在哪个领域里面所需要知道和了解的。</p><p>第一个就是C语言的学习,了解到其实我们院20级的管工的同学并没有C语言这门课,还是推荐大家在学习数据结构的时候把C语言的结构体,指针等概念了解清楚。</p><p>数据结构和算法</p><p>数据结构也是比较基础的一门课,链表,队列,堆栈,数组,串,二叉树等概念是我们专业所学习的,但是还有像图等我们专业都不会讲解,可以看看熊回香老师的那本书,也是写的很好的。在加上算法,书里面讲到的比较基础的算法有查找和排序,查找有二分法,二叉排序树,嘻哈表。排序有直接插入,选择排序,推排序,冒泡排序,快速排序,归并排序,桶排序等。这些排序和查找最后考试也是都会考的。</p><p>我们专业在数据结构这方面出的代码设计题会比较简单,导致你不需要动手去实践已知的一些算法,可能只需要逻辑上理解就够了,而我们要知道逻辑上面的理解和能真正把代码写出来是两回事。我自己也是吃了这方面的亏,自己刷题的时候也是知道怎么去完成,但是代码多多少少都会出现一点bug。</p><p>虽然前端对算法的要求部不是特别高,但是也不是没有要求的,所以多刷题多总结就没什么错了。</p><p>计算机网络</p><p>计算机网络我们学院开设的课程主要集中于在应用层之下了,而我们实际的网络开发,更多的需要的知识是应用层的,http协议就是应用层的主要协议。这个大家可以看老师推荐的教材或者《图解HTTP》这本书。</p><p>剩余的操作系统和计算机组成原理里面,还是推荐大家可以多多学习操作系统,机组的话可能更多的偏向硬件一些,学起来可能回比较枯燥乏味。</p>]]></content>
</entry>
<entry>
<title>鑷€傚簲灞呬腑</title>
<link href="/2021/09/22/%E9%91%B7%EE%81%88%E2%82%AC%E5%82%9A%E7%B0%B2%E7%81%9E%E5%91%AC%E8%85%91/"/>
<url>/2021/09/22/%E9%91%B7%EE%81%88%E2%82%AC%E5%82%9A%E7%B0%B2%E7%81%9E%E5%91%AC%E8%85%91/</url>
<content type="html"><![CDATA[<h1 id="关于网页布局中的水平垂直居中"><a href="#关于网页布局中的水平垂直居中" class="headerlink" title="关于网页布局中的水平垂直居中"></a>关于网页布局中的水平垂直居中</h1><h3 id="一、首先来分享最简单的flex布局中如何居中"><a href="#一、首先来分享最简单的flex布局中如何居中" class="headerlink" title="一、首先来分享最简单的flex布局中如何居中"></a>一、首先来分享最简单的flex布局中如何居中</h3><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="selector-class">.father</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 class="comment">/*水平居中*/</span></span><br><span class="line"> <span class="attribute">align-items</span>: center;<span class="comment">/*垂直居中*/</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 这里father指的是夫元素的盒子,对父元素进行设置<code>display: flex;</code>其中的子元素就会变成项目,父元素本身就成为了flex容器。利用flex的一些特性就可以进行居中的布局。</p><p> 关于更详细的flex布局,这里有一个链接:<a href="http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html?utm_source=tuicool" target="_blank" rel="noopener">http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html?utm_source=tuicool</a></p><h3 id="二、”display-inline-block”中如何实现居中"><a href="#二、”display-inline-block”中如何实现居中" class="headerlink" title="二、”display:inline-block”中如何实现居中"></a>二、”display:inline-block”中如何实现居中</h3><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">.father</span>{</span><br><span class="line"> <span class="attribute">text-align</span>: center;<span class="comment">/*水平居中*/</span></span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.son</span>{</span><br><span class="line"> <span class="attribute">display</span>:inline-block;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 当block变成inline-block时,多个div在一个父元素的容器中,<code>margin: 0 auto;</code>就不再有作用。目前我找到的方法只有在父元素中设置<code>text-align: center;</code>使这些div居中。百度中这么解释到,“我们的行内元素就相当于一行之内的文字了”,我也只能这么理解了。对于div中的文字,我们只能再使用<code>text-align: start;</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><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">.father</span>{</span><br><span class="line"> <span class="attribute">width</span>:auto;</span><br><span class="line"> <span class="attribute">height</span>:<span class="number">200px</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.father</span><span class="selector-pseudo">:after</span>{</span><br><span class="line"> <span class="attribute">display</span>:inline-block;</span><br><span class="line"> <span class="attribute">height</span>:<span class="number">100%</span>;</span><br><span class="line"> <span class="attribute">font-size</span>:<span class="number">0</span>;</span><br><span class="line"> <span class="attribute">content</span>: <span class="string">""</span>;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.son</span>{</span><br><span class="line"> <span class="attribute">display</span>:inline-block;</span><br><span class="line"> <span class="attribute">vertical-align</span>: middle;<span class="comment">/*垂直居中*/</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 这一串css代码是用来inline-block当中的垂直居中问题,可以用于head当中,因为大多时候head定宽,用一个伪元素设置其高度为100%时,将父元素撑开,子元素就垂直居中啦!也适用于多行文字!</p><h6 id="当然如果head之中只有一行文字,在父元素中设置height与line-height相等时,也可以垂直居中,只是会出现一些小问题。比如只是文字居中而div没有居中。(如果div高和head高不相等)"><a href="#当然如果head之中只有一行文字,在父元素中设置height与line-height相等时,也可以垂直居中,只是会出现一些小问题。比如只是文字居中而div没有居中。(如果div高和head高不相等)" class="headerlink" title="当然如果head之中只有一行文字,在父元素中设置height与line-height相等时,也可以垂直居中,只是会出现一些小问题。比如只是文字居中而div没有居中。(如果div高和head高不相等)"></a>当然如果head之中只有一行文字,在父元素中设置height与line-height相等时,也可以垂直居中,只是会出现一些小问题。比如只是文字居中而div没有居中。(如果div高和head高不相等)</h6><h3 id="三、“display:block”一个block的居中"><a href="#三、“display:block”一个block的居中" class="headerlink" title="三、“display:block”一个block的居中"></a>三、“display:block”一个block的居中</h3><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">.son</span>{</span><br><span class="line"> <span class="attribute">margin</span>: <span class="number">0</span> auto;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 这一串代码十分简洁,十分容易记住,但是一定要找到使用场合。在一个父元素只有一个子元素时,此代码可以时该元素自适应的居中,比较常用于head套用,page整体布局中。</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">.father</span>{</span><br><span class="line"> <span class="attribute">height</span>:<span class="number">100px</span>;</span><br><span class="line"> <span class="attribute">line-height</span>:<span class="number">100px</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 不多说了,注意只能用于单行文字。会使子元素高度变大。</p><h3 id="四、“display-table”的居中"><a href="#四、“display-table”的居中" class="headerlink" title="四、“display: table”的居中"></a>四、“display: table”的居中</h3><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></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.father</span>{</span><br><span class="line"> <span class="attribute">display</span>:table;</span><br><span class="line">}</span><br><span class="line"><span class="selector-class">.son</span>{</span><br><span class="line"> <span class="attribute">display</span>:table-cell;</span><br><span class="line"> <span class="attribute">vertical-align</span>: middle;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 这种方法适用性不强,因为大多数display属性为block,inlin-block或者flex。再次使用display时可能会改变一些属性。</p><h3 id="五、定位"><a href="#五、定位" class="headerlink" title="五、定位"></a>五、定位</h3><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 class="selector-class">.father</span>{</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">500px</span>;</span><br><span class="line"> <span class="attribute">height</span>: <span class="number">300px</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-class">.son</span>{</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">100px</span>;</span><br><span class="line"> <span class="attribute">height</span>: <span class="number">100px</span>;</span><br><span class="line"> <span class="attribute">position</span>: absolute;</span><br><span class="line"> <span class="attribute">top</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">bottom</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">left</span>: <span class="number">0</span>;</span><br><span class="line"> <span class="attribute">margin</span>: auto;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 该方法用于son宽高已知!</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><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.father</span>{</span><br><span class="line"> <span class="attribute">width</span>: <span class="number">500px</span>;</span><br><span class="line"> <span class="attribute">height</span>: <span class="number">300px</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-class">.son</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">translateX</span>(-50%) <span class="built_in">translateY</span>(-50%);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 该方法用于son宽高未知!</p><h6 id="总的来说自适应居中的方法就这些了,如果想看到更多的居中方式可以点击这里访问李雪莲学姐做的总结!!"><a href="#总的来说自适应居中的方法就这些了,如果想看到更多的居中方式可以点击这里访问李雪莲学姐做的总结!!" class="headerlink" title="总的来说自适应居中的方法就这些了,如果想看到更多的居中方式可以点击这里访问李雪莲学姐做的总结!!"></a>总的来说自适应居中的方法就这些了,如果想看到更多的居中方式可以点击这里访问李雪莲学姐做的总结!!</h6><p> <a href="https://lilixuelian.github.io/2019/05/22/center/" target="_blank" rel="noopener">https://lilixuelian.github.io/2019/05/22/center/</a> </p>]]></content>
</entry>
<entry>
<title>闃叉姈鑺傛祦</title>
<link href="/2021/09/22/%E9%97%83%E5%8F%89%E5%A7%88%E9%91%BA%E5%82%9B%E7%A5%A6/"/>
<url>/2021/09/22/%E9%97%83%E5%8F%89%E5%A7%88%E9%91%BA%E5%82%9B%E7%A5%A6/</url>
<content type="html"><![CDATA[<p> 其实在了解防抖和节流的作用是什么了之后就实现起来会比较容易</p><h2 id="防抖"><a href="#防抖" class="headerlink" title="防抖"></a>防抖</h2><p>防抖是防止短时间内一直调用一个函数,在n秒后执行函数,在n秒内多次触发事件,则重新开始计时。</p><figure class="highlight javascript"><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="keyword">let</span> request = <span class="function">(<span class="params">val</span>) =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"request: "</span> + val);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">debounce</span>(<span class="params">fn, delay</span>)</span>{</span><br><span class="line"> <span class="keyword">let</span> timeout;</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>{</span><br><span class="line"> clearTimeout(timeout);</span><br><span class="line"> timeout = setTimeout(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> fn.apply(<span class="keyword">this</span>, <span class="built_in">arguments</span>);</span><br><span class="line"> }, delay);</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> inputEle = <span class="built_in">document</span>.getElementById(<span class="string">"input"</span>);</span><br><span class="line"><span class="keyword">let</span> debounceInput = debounce(request, <span class="number">500</span>);</span><br><span class="line"></span><br><span class="line">inputEle.addEventListener(<span class="string">"keyup"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">e</span>)</span>{</span><br><span class="line"> debounceInput(e.target.value);</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 javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> request = <span class="function">(<span class="params">val</span>) =></span> {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"request: "</span> + val);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">throttle</span>(<span class="params">fn, delay</span>)</span>{</span><br><span class="line"> <span class="keyword">let</span> timer;</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">if</span>(!timer) {</span><br><span class="line"> fn.apply(<span class="keyword">this</span>,<span class="built_in">arguments</span>);</span><br><span class="line"> timer = setTimeout(<span class="function"><span class="params">()</span>=></span>{</span><br><span class="line"> clearTimeout(timer);</span><br><span class="line"> time = <span class="literal">null</span>;</span><br><span class="line"> },delay)</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>然而让我考虑了好久这里为什么要使用apply方法去执行。我查到的原因就是因为request函数的参数个数未知性,应该直接传入arguments的参数对象。还可以改成fn(…arguments)。</p>]]></content>
</entry>
<entry>
<title>瀛ょ嫭鏄熺悆--Taro妗嗘灦鎬荤粨</title>
<link href="/2021/09/22/%E7%80%9B%E3%82%87%E5%AB%AD%E9%8F%84%E7%86%BA%E6%82%86--Taro%E5%A6%97%E5%97%98%E7%81%A6%E9%8E%AC%E8%8D%A4%E7%B2%A8/"/>
<url>/2021/09/22/%E7%80%9B%E3%82%87%E5%AB%AD%E9%8F%84%E7%86%BA%E6%82%86--Taro%E5%A6%97%E5%97%98%E7%81%A6%E9%8E%AC%E8%8D%A4%E7%B2%A8/</url>
<content type="html"><![CDATA[<h1 id="孤独星球–Taro框架总结"><a href="#孤独星球–Taro框架总结" class="headerlink" title="孤独星球–Taro框架总结"></a>孤独星球–Taro框架总结</h1><p> 大一下学期用Taro框架写了QQ的小程序–孤独星球,项目链接在这里。<a href="https://github.com/The-Planet-of-Loneline/project" target="_blank" rel="noopener">https://github.com/The-Planet-of-Loneline/project</a></p><p> 项目分为白天和黑夜两个部分,白天是同组的刘安完成的,技术含量也比较高;黑夜和登录部分就是由我完成的。接下来就说一下Taro里面的一些细节。</p><h3 id="一、项目结构"><a href="#一、项目结构" class="headerlink" title="一、项目结构"></a>一、项目结构</h3><p> 因为一开始没有去参照学姐学长做的客栈的框架,所以这个项目的框架比较乱,一些组件的页面的位置也存放的不正确。希望以后的项目能够把公共组件和私有组件分开,组件和页面分开以形成更明晰的结构。以下是参照木犀客栈的结构:</p><figure class="highlight jboss-cli"><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="params">--src</span></span><br><span class="line"><span class="params">--assets</span> <span class="string">//</span>存放图片</span><br><span class="line"><span class="params">--png</span></span><br><span class="line"><span class="params">--svg</span></span><br><span class="line"><span class="params">--components</span> <span class="string">//</span>存放组件</span><br><span class="line"><span class="params">--common</span> <span class="string">//</span>公用组件</span><br><span class="line"><span class="params">--index</span> <span class="string">//</span>私有组件</span><br><span class="line"><span class="params">--pages</span> <span class="string">//</span>页面</span><br><span class="line"><span class="params">--index</span></span><br><span class="line"><span class="params">--index</span>.jsx</span><br><span class="line"><span class="params">--service</span><span class="string">//Fech</span> API</span><br><span class="line"><span class="params">--Fech</span>.jsx</span><br><span class="line"><span class="params">--app</span>.jsx <span class="string">//</span>配置</span><br><span class="line"><span class="params">--app</span>.scss <span class="string">//</span>样式</span><br><span class="line"><span class="params">--index</span>.html <span class="string">//</span>接口</span><br></pre></td></tr></table></figure><p>一般来说一个项目的结构就如上所示了。</p><h3 id="二、Taro内置组件"><a href="#二、Taro内置组件" class="headerlink" title="二、Taro内置组件"></a>二、Taro内置组件</h3><p> 刚刚开始写静态页面的时候使用错了组件,还是用的HTML的标签<code><div> <span></code>等。要注意以下代码的含义:</p><figure class="highlight jsx"><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="keyword">import</span> Taro, { Component } <span class="keyword">from</span> <span class="string">'@tarojs/taro'</span></span><br><span class="line"><span class="keyword">import</span> { View, Text,Image } <span class="keyword">from</span> <span class="string">'@tarojs/components'</span></span><br></pre></td></tr></table></figure><p> Taro里面有内置的组件使用,<code><View> <Text></code>等类似于HTML中的标签使用。要注意的是,HTML中使用的class选择器,class关键字要改变成classname,因为关键字的保留class类。</p><p>这里的import也是webpack的方法吧,引入你需要的组件例如黑夜的头部和底部:</p><figure class="highlight jsx"><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="keyword">import</span> Head <span class="keyword">from</span> <span class="string">'../component/Head'</span></span><br><span class="line"><span class="keyword">import</span> Footer <span class="keyword">from</span> <span class="string">'../component/Footer'</span></span><br></pre></td></tr></table></figure><p>一定要from正确的路径<code>'../'</code>是返回上一级目录,也可以返回多次。</p><h3 id="三、Taro中的输入框"><a href="#三、Taro中的输入框" class="headerlink" title="三、Taro中的输入框"></a>三、Taro中的输入框</h3><p> Taro中的输入框也是Taro当中的内置组件也分为<code>input</code>和<code>textarea</code>,但是要大写<code><Input /> <Textarea /></code>,这里顺便提一下Taro里面所有组件开头都要大写。</p><p> 输入框输入值的时候<code>value</code>要空,且还有监听事件函数<code>onInput</code>,<code>onChange</code>也可以。但是比较坑的事,<code>onInput</code>函数对于<code>Input</code>和<code>Textarea</code>不同。当时产品组给我提的要求是控制行数限制,这里也要说一下<code>Textarea</code>的特性,有换行的监听函数。但是由于<code>onInput</code>对于<code>Textarea</code>的<code>value</code>的改变不能显示于<code>Textarea</code>,而可以显示于<code>Input</code>。最后也是需求改成了字数限制。</p><figure class="highlight jsx"><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"><Textarea </span><br><span class="line">className=<span class="string">'write'</span> </span><br><span class="line">value={Value} </span><br><span class="line">onInput={<span class="keyword">this</span>.handleInputChange.bind(<span class="keyword">this</span>)} </span><br><span class="line">onFocus={<span class="keyword">this</span>.handleInput.bind(<span class="keyword">this</span>)}</span><br><span class="line">onBlur={<span class="keyword">this</span>.handleback.bind(<span class="keyword">this</span>)} </span><br><span class="line">showConfirmBar={<span class="literal">false</span>}</span><br><span class="line">maxlength={<span class="number">75</span>}</span><br><span class="line">autoFocus={<span class="literal">true</span>}</span><br><span class="line">><span class="xml"><span class="tag"></<span class="name">Textarea</span>></span></span></span><br></pre></td></tr></table></figure><p> 组件的写法可以这样换行以更醒目的看见,太长不方便查看。但是一些<code>View</code>好像就不行。</p><h3 id="四、API"><a href="#四、API" class="headerlink" title="四、API"></a>四、API</h3><p> 写整个项目前最重要的就是沟通,和产品沟通和后端沟通。没有沟通好的后果就是白天好像重新写页面的结构。还好因为黑夜也不难,所以没有做好沟通也影响不大。其中我觉得比较重要的是分页这个部分。因为要考虑到页面的实际需求来看分页的形式和需不需要分页。参考<code>swaggerUI</code>是一个很重要的东西,一定要反复比对。</p><figure class="highlight jsx"><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">onReachBottom(){</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.state.history.length % <span class="number">5</span> == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">this</span>.setState({</span><br><span class="line"> page: <span class="keyword">this</span>.state.page + <span class="number">1</span></span><br><span class="line"> }, () => {</span><br><span class="line"> Fetch(<span class="string">`secret/history?page=<span class="subst">${<span class="keyword">this</span>.state.page}</span>`</span>,</span><br><span class="line"> {},</span><br><span class="line"> <span class="string">'GET'</span>).then(<span class="function"><span class="params">res</span> =></span> {</span><br><span class="line"> <span class="keyword">this</span>.setState({</span><br><span class="line"> history: <span class="keyword">this</span>.state.history.concat(res.history)</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></pre></td></tr></table></figure><p> 这里是一个后端的分页方法,需要的事我每一次请求时发送一个页面数字给后端,他再返回给我对应数字的内容。这种分页方法个人感觉比较适合网页,而不适合小程序去写。所以我加了限定条件只有显示内容为5个时候才会进行下一次的请求。</p><p> API的路径一定要对,我举例困扰我很久的删除功能。</p><figure class="highlight jsx"><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">handleDelete(){</span><br><span class="line"> Fetch(<span class="string">`secret/delete/:secret_id/?secretId=<span class="subst">${<span class="keyword">this</span>.props.Debunkid}</span>`</span>,</span><br><span class="line"> {},</span><br><span class="line"> <span class="string">'DELETE'</span>).then(<span class="function"><span class="params">res</span> =></span> { </span><br><span class="line"> Taro.showToast({</span><br><span class="line"> title: <span class="string">'删除成功'</span>,</span><br><span class="line"> icon: <span class="string">'none'</span></span><br><span class="line"> })</span><br><span class="line"> <span class="keyword">this</span>.props.onCloseDelete() </span><br><span class="line"> Taro.reLaunch({</span><br><span class="line"> url:<span class="string">`/pages/Mine/Mine`</span></span><br><span class="line"> }) </span><br><span class="line"> })</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p> 这里因为我少了一个<code>/</code>导致我应该不能与后端连接,但是开发者工具可以我也就没有想太多。牢记!!</p><h3 id="五、QQ授权和分享"><a href="#五、QQ授权和分享" class="headerlink" title="五、QQ授权和分享"></a>五、QQ授权和分享</h3><p> QQ授权和分享是要过审核必须写的一个API,我们也是事后才写的。</p><figure class="highlight jsx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><Button open-type=<span class="string">'getUserInfo'</span> className=<span class="string">'login'</span> onClick={<span class="keyword">this</span>.power}>登录<<span class="regexp">/Button></span></span><br></pre></td></tr></table></figure><figure class="highlight jsx"><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">power () {</span><br><span class="line"> Taro.getSetting({</span><br><span class="line"> success: <span class="function">(<span class="params">res</span>) =></span> {</span><br><span class="line"> <span class="keyword">this</span>.setState({ <span class="attr">powered</span>:res.authSetting[<span class="string">'scope.userInfo'</span>]})</span><br><span class="line"> <span class="keyword">if</span> (res.authSetting[<span class="string">'scope.userInfo'</span>]) {</span><br><span class="line"> <span class="keyword">this</span>.onHandleLogin()</span><br><span class="line"> }</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 jsx"><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">Taro.showShareMenu({</span><br><span class="line"> showShareItems: [<span class="string">'qq'</span>, <span class="string">'qzone'</span>, <span class="string">'wechatFriends'</span>, <span class="string">'wechatMoment'</span>]</span><br><span class="line"> })</span><br></pre></td></tr></table></figure><p>第一二个代码块是处理授权的部分,第三个是分享。</p>]]></content>
</entry>
<entry>
<title>瀛﹁€岄〉闈㈡€荤粨</title>
<link href="/2021/09/22/%E7%80%9B%EF%B9%81%E2%82%AC%E5%B2%84%E3%80%89%E9%97%88%E3%88%A1%E2%82%AC%E8%8D%A4%E7%B2%A8/"/>
<url>/2021/09/22/%E7%80%9B%EF%B9%81%E2%82%AC%E5%B2%84%E3%80%89%E9%97%88%E3%88%A1%E2%82%AC%E8%8D%A4%E7%B2%A8/</url>
<content type="html"><![CDATA[<h1 id="关于HTML和CSS的总结"><a href="#关于HTML和CSS的总结" class="headerlink" title="关于HTML和CSS的总结"></a>关于HTML和CSS的总结</h1><h6 id="在这两周时间,我写了静态的学而网页并进行了一些修改。在学姐学长的帮助和指导之下,我对网页的一些整体布局有所了解,以下为一些自己在写学而时犯下的错误。"><a href="#在这两周时间,我写了静态的学而网页并进行了一些修改。在学姐学长的帮助和指导之下,我对网页的一些整体布局有所了解,以下为一些自己在写学而时犯下的错误。" class="headerlink" title="在这两周时间,我写了静态的学而网页并进行了一些修改。在学姐学长的帮助和指导之下,我对网页的一些整体布局有所了解,以下为一些自己在写学而时犯下的错误。"></a>在这两周时间,我写了静态的学而网页并进行了一些修改。在学姐学长的帮助和指导之下,我对网页的一些整体布局有所了解,以下为一些自己在写学而时犯下的错误。</h6><h4 id="HEADER-PART"><a href="#HEADER-PART" class="headerlink" title="HEADER PART"></a>HEADER PART</h4><p>1.布局方式不要混用(其实适用于很多地方),<code>flex</code> <code>inline-block</code> 和<code>float</code>最好不要混合使用。</p><p>2.尽量减少div的使用。学会思考<code>span</code>和<code>div</code>的使用情况。<code>span</code>作为行内元素,可以用来标记一些行内特殊的元素;<code>div</code>作为块元素,更好的区分出每一个区域。有时候会用很多个<code>div</code>,变成<code>inline-block</code>的样子是因为在行内中出现了不同的功能区。</p><p>3.消除间隙。由于行内元素都是有间隙的所以一般需要消除间隙,例如图片与搜索框之间。</p><p>4.搜索框的写法,一般是用一个大的<code>div</code>把<code>input</code>和图片包裹起来,设置<code>div</code>的<code>border</code>的颜色来展示边框。</p><p>5.实现<code>:hover</code>之后,要确保前后元素的大小一致,这样才美观。</p><h4 id="MIDDLE-PART"><a href="#MIDDLE-PART" class="headerlink" title="MIDDLE PART"></a>MIDDLE PART</h4><p>1.整体布局,用一个<code>div</code>来使多个中间部分水平居中。</p><p>2.在整个页面中最好只采取一种布局方式。</p><p>3.<code>position:sticky</code>可以适用于更多的场合,也更符合如今的审美需求。</p><p>4.<code>input</code>的样式用CSS来改变</p><h4 id="FOOTER-PART"><a href="#FOOTER-PART" class="headerlink" title="FOOTER PART"></a>FOOTER PART</h4><p>1.注意字符间距</p><p>2.<code>body</code>的<code>margin</code>为0或者<code>padding</code>为0;</p>]]></content>
</entry>
<entry>
<title>React Hook</title>
<link href="/2021/09/22/React%20Hook/"/>
<url>/2021/09/22/React%20Hook/</url>
<content type="html"><![CDATA[<h1 id="React-Hook"><a href="#React-Hook" class="headerlink" title="React Hook"></a>React Hook</h1><h2 id="📌-State-Hook"><a href="#📌-State-Hook" class="headerlink" title="📌 State Hook"></a>📌 State Hook</h2><p>“Hook是react 16.8的新增特性。它可以让你在不编写class的情况下使用state。”这是React官网</p><p>对Hook最直接的解释。不使用class而是普通的函数去封装组件或者页面。</p><figure class="highlight jsx"><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="keyword">import</span> React, { useState } <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Example</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="comment">// 声明一个新的叫做 “count” 的 state 变量</span></span><br><span class="line"> <span class="keyword">const</span> [count, setCount] = useState(<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div></span><br><span class="line"> <p>You clicked {count} times<<span class="regexp">/p></span></span><br><span class="line"><span class="regexp"> <button onClick={() => setCount(count + 1)}></span></span><br><span class="line"><span class="regexp"> Click me</span></span><br><span class="line"><span class="regexp"> </</span>button></span><br><span class="line"> <<span class="regexp">/div></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp">}</span></span><br></pre></td></tr></table></figure><p>这里我们引入并解构出useState方法来声明一个Hook当中的state变量。 <code>const [count, setCount] = useState(0);</code>这一个语句中useState的唯一参数为声明的state的初始值,例如这里的count为一个数字,并且初始值为0。setCount则像setState方法一样去改变state的值。</p><p><strong><code>useState</code> 方法的返回值是什么?</strong> 返回值为:当前 state 以及更新 state 的函数。这就是我们写 <code>const [count, setCount] = useState()</code> 的原因。这与 class 里面 <code>this.state.count</code> 和 <code>this.setState</code> 类似,唯一区别就是你需要成对的获取它们。</p><p>下面展示同一个class封装的组件。</p><figure class="highlight jsx"><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="class"><span class="keyword">class</span> <span class="title">Example</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span></span>{</span><br><span class="line"> <span class="keyword">constructor</span>(){</span><br><span class="line"> <span class="keyword">super</span>();</span><br><span class="line"> <span class="keyword">this</span>.state = {</span><br><span class="line"> count: <span class="number">0</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> click() {</span><br><span class="line"> <span class="keyword">const</span> {count} = <span class="keyword">this</span>.state</span><br><span class="line"> <span class="keyword">this</span>.setState({</span><br><span class="line"> count: count + <span class="number">1</span></span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div></span><br><span class="line"> <p>You clicked {<span class="keyword">this</span>.state.count} times<<span class="regexp">/p></span></span><br><span class="line"><span class="regexp"> <button onClick={this.click.bind(this)}></span></span><br><span class="line"><span class="regexp"> Click me</span></span><br><span class="line"><span class="regexp"> </</span>button></span><br><span class="line"> <<span class="regexp">/div></span></span><br><span class="line"><span class="regexp"> ); </span></span><br><span class="line"><span class="regexp">}</span></span><br></pre></td></tr></table></figure><p>大体来说两者可以完成同一个功能就是记下按钮被点击的次数。我们可以明显观察到hook的使用变量的改变和显示都比class要简单很多。</p><h4 id="声明多个state变量"><a href="#声明多个state变量" class="headerlink" title="声明多个state变量"></a>声明多个state变量</h4><figure class="highlight jsx"><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="function"><span class="keyword">function</span> <span class="title">ExampleWithManyStates</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="comment">// 声明多个 state 变量!</span></span><br><span class="line"> <span class="keyword">const</span> [age, setAge] = useState(<span class="number">42</span>);</span><br><span class="line"> <span class="keyword">const</span> [fruit, setFruit] = useState(<span class="string">'banana'</span>);</span><br><span class="line"> <span class="keyword">const</span> [todos, setTodos] = useState([{ <span class="attr">text</span>: <span class="string">'Learn Hooks'</span> }]);</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><h4 id="那么,什么是-Hook"><a href="#那么,什么是-Hook" class="headerlink" title="那么,什么是 Hook?"></a>那么,什么是 Hook?</h4><p>Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用 —— 这使得你不使用 class 也能使用 React。</p><p>React 内置了一些像 <code>useState</code> 这样的 Hook。你也可以创建你自己的 Hook 来复用不同组件之间的状态逻辑。我们会先介绍这些内置的 Hook。</p><h2 id="⚡️-Effect-Hook"><a href="#⚡️-Effect-Hook" class="headerlink" title="⚡️ Effect Hook"></a>⚡️ Effect Hook</h2><p>你之前可能已经在 React 组件中执行过数据获取、订阅或者手动修改过 DOM。我们统一把这些操作称为“副作用”,或者简称为“作用”。</p><p><strong><code>useEffect</code> 就是一个 Effect Hook,给函数组件增加了操作副作用的能力。它跟 class 组件中的 <code>componentDidMount</code>、<code>componentDidUpdate</code> 和 <code>componentWillUnmount</code> 具有相同的用途,只不过被合并成了一个 API。</strong></p><figure class="highlight jsx"><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="keyword">import</span> React, { useState, useEffect } <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Example</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> [count, setCount] = useState(<span class="number">0</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 相当于 componentDidMount 和 componentDidUpdate:</span></span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="comment">// 使用浏览器的 API 更新页面标题</span></span><br><span class="line"> <span class="built_in">document</span>.title = <span class="string">`You clicked <span class="subst">${count}</span> times`</span>;</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div></span><br><span class="line"> <p>You clicked {count} times<<span class="regexp">/p></span></span><br><span class="line"><span class="regexp"> <button onClick={() => setCount(count + 1)}></span></span><br><span class="line"><span class="regexp"> Click me</span></span><br><span class="line"><span class="regexp"> </</span>button></span><br><span class="line"> <<span class="regexp">/div></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp">}</span></span><br></pre></td></tr></table></figure><figure class="highlight jsx"><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="class"><span class="keyword">class</span> <span class="title">Example</span> <span class="keyword">extends</span> <span class="title">React</span>.<span class="title">Component</span></span>{</span><br><span class="line"> <span class="keyword">constructor</span>(){</span><br><span class="line"> <span class="keyword">super</span>();</span><br><span class="line"> <span class="keyword">this</span>.state = {</span><br><span class="line"> count: <span class="number">0</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> componentDidMount(){</span><br><span class="line"> <span class="built_in">document</span>.title = <span class="string">`You clicked <span class="subst">${<span class="keyword">this</span>.state.count}</span> times`</span>;</span><br><span class="line"> }</span><br><span class="line"> componentDidUpdate(){</span><br><span class="line"> <span class="built_in">document</span>.title = <span class="string">`You clicked <span class="subst">${<span class="keyword">this</span>.state.count}</span> times`</span>;</span><br><span class="line"> }</span><br><span class="line"> click() {</span><br><span class="line"> <span class="keyword">const</span> {count} = <span class="keyword">this</span>.state</span><br><span class="line"> <span class="keyword">this</span>.setState({</span><br><span class="line"> count: count + <span class="number">1</span></span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <div></span><br><span class="line"> <p>You clicked {<span class="keyword">this</span>.state.count} times<<span class="regexp">/p></span></span><br><span class="line"><span class="regexp"> <button onClick={this.click.bind(this)}></span></span><br><span class="line"><span class="regexp"> Click me</span></span><br><span class="line"><span class="regexp"> </</span>button></span><br><span class="line"> <<span class="regexp">/div></span></span><br><span class="line"><span class="regexp"> ); </span></span><br><span class="line"><span class="regexp">}</span></span><br></pre></td></tr></table></figure><p>当你调用 <code>useEffect</code> 时,就是在告诉 React 在完成对 DOM 的更改后运行你的“副作用”函数。由于副作用函数是在组件内声明的,所以它们可以访问到组件的 props 和 state。默认情况下,React 会在每次渲染后调用副作用函数 —— <strong>包括</strong>第一次渲染的时候。(useEffect会在每一次页面渲染时调用。)</p><p>副作用函数还可以通过返回一个函数来指定如何“清除”副作用。例如,在下面的组件中使用副作用函数来订阅好友的在线状态,并通过取消订阅来进行清除操作:</p><figure class="highlight jsx"><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">import</span> React, { useState, useEffect } <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">FriendStatus</span>(<span class="params">props</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> [isOnline, setIsOnline] = useState(<span class="literal">null</span>);</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">handleStatusChange</span>(<span class="params">status</span>) </span>{</span><br><span class="line"> setIsOnline(status.isOnline);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);</span><br><span class="line"> };</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (isOnline === <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">'Loading...'</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> isOnline ? <span class="string">'Online'</span> : <span class="string">'Offline'</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在这个示例中,React 会在组件销毁时取消对 <code>ChatAPI</code> 的订阅,然后在后续渲染时重新执行副作用函数。</p><figure class="highlight jsx"><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><br><span class="line">componentDidMount(){</span><br><span class="line"> ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);</span><br><span class="line">}</span><br><span class="line">componentWillUnmount(){</span><br><span class="line"> ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);</span><br><span class="line">}</span><br><span class="line">....</span><br></pre></td></tr></table></figure><h3 id="通过跳过-Effect-进行性能优化"><a href="#通过跳过-Effect-进行性能优化" class="headerlink" title="通过跳过 Effect 进行性能优化"></a>通过跳过 Effect 进行性能优化</h3><p>在某些情况下,每次渲染后都执行清理或者执行 effect 可能会导致性能问题。在 class 组件中,我们可以通过在 <code>componentDidUpdate</code> 中添加对 <code>prevProps</code> 或 <code>prevState</code> 的比较逻辑解决:</p><figure class="highlight jsx"><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">componentDidUpdate(prevProps, prevState) {</span><br><span class="line"> <span class="keyword">if</span> (prevState.count !== <span class="keyword">this</span>.state.count) {</span><br><span class="line"> <span class="built_in">document</span>.title = <span class="string">`You clicked <span class="subst">${<span class="keyword">this</span>.state.count}</span> times`</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这是很常见的需求,所以它被内置到了 <code>useEffect</code> 的 Hook API 中。如果某些特定值在两次重渲染之间没有发生变化,你可以通知 React <strong>跳过</strong>对 effect 的调用,只要传递数组作为 <code>useEffect</code> 的第二个可选参数即可:</p><figure class="highlight jsx"><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">useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="built_in">document</span>.title = <span class="string">`You clicked <span class="subst">${count}</span> times`</span>;</span><br><span class="line">}, [count]); <span class="comment">// 仅在 count 更改时更新</span></span><br></pre></td></tr></table></figure><p>上面这个示例中,我们传入 <code>[count]</code> 作为第二个参数。这个参数是什么作用呢?如果 <code>count</code> 的值是 <code>5</code>,而且我们的组件重渲染的时候 <code>count</code> 还是等于 <code>5</code>,React 将对前一次渲染的 <code>[5]</code> 和后一次渲染的 <code>[5]</code> 进行比较。因为数组中的所有元素都是相等的(<code>5 === 5</code>),React 会跳过这个 effect,这就实现了性能的优化。</p><p>当渲染时,如果 <code>count</code> 的值更新成了 <code>6</code>,React 将会把前一次渲染时的数组 <code>[5]</code> 和这次渲染的数组 <code>[6]</code> 中的元素进行对比。这次因为 <code>5 !== 6</code>,React 就会再次调用 effect。如果数组中有多个元素,即使只有一个元素发生变化,React 也会执行 effect。</p><p>对于有清除操作的 effect 同样适用:</p><figure class="highlight jsx"><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">useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">handleStatusChange</span>(<span class="params">status</span>) </span>{</span><br><span class="line"> setIsOnline(status.isOnline);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);</span><br><span class="line"> };</span><br><span class="line">}, [props.friend.id]); <span class="comment">// 仅在 props.friend.id 发生变化时,重新订阅</span></span><br></pre></td></tr></table></figure><p>未来版本,可能会在构建时自动添加第二个参数。</p><h2 id="✌️-Hook-使用规则"><a href="#✌️-Hook-使用规则" class="headerlink" title="✌️ Hook 使用规则"></a>✌️ Hook 使用规则</h2><p>Hook 就是 JavaScript 函数,但是使用它们会有两个额外的规则:</p><ul><li><p>只能在<strong>函数最外层</strong>调用 Hook。不要在循环、条件判断或者子函数中调用。</p></li><li><p>只能在 <strong>React 的函数组件</strong>中调用 Hook。不要在其他 JavaScript 函数中调用。(还有一个地方可以调用 Hook —— 就是自定义的 Hook 中,我们稍后会学习到。)</p></li><li><p>React 的函数组件是这样的:</p><figure class="highlight jsx"><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">const</span> Example = <span class="function">(<span class="params">props</span>) =></span> {</span><br><span class="line"> <span class="comment">// 你可以在这使用 Hook</span></span><br><span class="line"> <span class="keyword">return</span> <span class="xml"><span class="tag"><<span class="name">div</span> /></span>;</span></span><br><span class="line"><span class="xml">}</span></span><br></pre></td></tr></table></figure><p>或是这样:</p><figure class="highlight jsx"><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="function"><span class="keyword">function</span> <span class="title">Example</span>(<span class="params">props</span>) </span>{</span><br><span class="line"> <span class="comment">// 你可以在这使用 Hook</span></span><br><span class="line"> <span class="keyword">return</span> <span class="xml"><span class="tag"><<span class="name">div</span> /></span>;</span></span><br><span class="line"><span class="xml">}</span></span><br></pre></td></tr></table></figure><p>你之前可能把它们叫做“无状态组件”。但现在我们为它们引入了使用 React state 的能力,所以我们更喜欢叫它”函数组件”。</p><p>Hook 在 class 内部是<strong>不</strong>起作用的。但你可以使用它们来取代 class 。</p></li></ul><h2 id="💡-自定义-Hook"><a href="#💡-自定义-Hook" class="headerlink" title="💡 自定义 Hook"></a>💡 自定义 Hook</h2><p>前面,我们介绍了一个叫 <code>FriendStatus</code> 的组件,它通过调用 <code>useState</code> 和 <code>useEffect</code> 的 Hook 来订阅一个好友的在线状态。假设我们想在另一个组件里重用这个订阅逻辑。</p><p>首先,我们把这个逻辑抽取到一个叫做 <code>useFriendStatus</code> 的自定义 Hook 里:</p><figure class="highlight jsx"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> React, { useState, useEffect } <span class="keyword">from</span> <span class="string">'react'</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">useFriendStatus</span>(<span class="params">friendID</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> [isOnline, setIsOnline] = useState(<span class="literal">null</span>);</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">handleStatusChange</span>(<span class="params">status</span>) </span>{</span><br><span class="line"> setIsOnline(status.isOnline);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> useEffect(<span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);</span><br><span class="line"> };</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> isOnline;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>它将 <code>friendID</code> 作为参数,并返回该好友是否在线:</p><p>现在我们可以在两个组件中使用它:</p><figure class="highlight jsx"><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="function"><span class="keyword">function</span> <span class="title">FriendStatus</span>(<span class="params">props</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> isOnline = useFriendStatus(props.friend.id);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (isOnline === <span class="literal">null</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="string">'Loading...'</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> isOnline ? <span class="string">'Online'</span> : <span class="string">'Offline'</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">FriendListItem</span>(<span class="params">props</span>) </span>{</span><br><span class="line"> <span class="keyword">const</span> isOnline = useFriendStatus(props.friend.id);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> (</span><br><span class="line"> <li style={{ <span class="attr">color</span>: isOnline ? <span class="string">'green'</span> : <span class="string">'black'</span> }}></span><br><span class="line"> {props.friend.name}</span><br><span class="line"> <<span class="regexp">/li></span></span><br><span class="line"><span class="regexp"> );</span></span><br><span class="line"><span class="regexp">}</span></span><br></pre></td></tr></table></figure><p>每个组件间的 state 是完全独立的。Hook 是一种复用<em>状态逻辑</em>的方式,它不复用 state 本身。事实上 Hook 的每次<em>调用</em>都有一个完全独立的 state —— 因此你可以在单个组件中多次调用同一个自定义 Hook。</p><p>自定义 Hook 更像是一种约定而不是功能。如果函数的名字以 “<code>use</code>” 开头并调用其他 Hook,我们就说这是一个自定义 Hook。</p>]]></content>
</entry>
<entry>
<title>JS Chapter 6</title>
<link href="/2021/09/22/JS%20Chapter%206/"/>
<url>/2021/09/22/JS%20Chapter%206/</url>
<content type="html"><![CDATA[<h2 id="Generator"><a href="#Generator" class="headerlink" title="Generator"></a>Generator</h2><p>先看三段代码</p><figure class="highlight javascript"><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">try</span>{</span><br><span class="line"> <span class="keyword">var</span> ninjas = syncGetJSON(<span class="string">"ninjas.json"</span>);</span><br><span class="line"> <span class="keyword">var</span> missions = syncGetJSON(ninjas[<span class="number">0</span>].missionsUrl);</span><br><span class="line"> <span class="keyword">var</span> missionDetails = syncGetJSON(mission[<span class="number">0</span>].detailsUrl);</span><br><span class="line"> <span class="comment">//Study the mission description</span></span><br><span class="line">}<span class="keyword">catch</span>(e){</span><br><span class="line"> <span class="comment">//Oh no, we weren't able to get the mission details</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight javascript"><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">getJSON(<span class="string">"ninjas.json"</span>,<span class="function"><span class="keyword">function</span>(<span class="params">err,ninjas</span>)</span>{</span><br><span class="line"> <span class="keyword">if</span>(err){</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Error fetching list of ninjas"</span>,err);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> getJSON(ninjas[<span class="number">0</span>].missionsUrl,<span class="function"><span class="keyword">function</span>(<span class="params">err,missions</span>)</span>{</span><br><span class="line"> <span class="keyword">if</span>(err){</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Error locating ninja missions"</span>,err);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> getJSON(mission[<span class="number">0</span>].detailsUrl,<span class="function"><span class="keyword">function</span>(<span class="params">err,missionDetails</span>)</span>{</span><br><span class="line"> <span class="keyword">if</span>(err){</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"Error locating mission details"</span>,err);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//Study the intel plan</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 javascript"><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">async</span>(<span class="function"><span class="keyword">function</span>*(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">try</span>{</span><br><span class="line"> <span class="keyword">var</span> ninjas = syncGetJSON(<span class="string">"ninjas.json"</span>);</span><br><span class="line"> <span class="keyword">var</span> missions = syncGetJSON(ninjas[<span class="number">0</span>].missionsUrl);</span><br><span class="line"> <span class="keyword">var</span> missionDetails = syncGetJSON(mission[<span class="number">0</span>].detailsUrl);</span><br><span class="line"> <span class="comment">//Study the mission description</span></span><br><span class="line">}<span class="keyword">catch</span>(e){</span><br><span class="line"> <span class="comment">//Oh no, we weren't able to get the mission details</span></span><br><span class="line">}</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p>第一段代码问题:从服务器获得数据是一个长期运行的操作,因为<code>JavaScript</code>是依赖单线程模式,我们会锁住我们的<code>UI</code>直到这整个代码运行结束。这导致了无法反应的应用和使用户失望。</p><figure class="highlight javascript"><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"><span class="function"><span class="keyword">function</span>* <span class="title">WeaponGenerator</span>(<span class="params"></span>)</span>{</span><br><span class="line"><span class="keyword">yield</span> <span class="string">"Katana"</span>;</span><br><span class="line"><span class="keyword">yield</span> <span class="string">"Wakizashi"</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">const</span> weaponsIterator = WeaponGenerator();</span><br><span class="line"><span class="keyword">const</span> result1 = weaponsIterator.next();</span><br><span class="line">assert(<span class="keyword">typeof</span> result1 === <span class="string">"object"</span> && result1.value === <span class="string">"katana"</span> && !result1.done,<span class="string">"Katana recevied!"</span>);</span><br><span class="line"><span class="keyword">const</span> result2 = weaponsIterator.next();</span><br><span class="line">assert(<span class="keyword">typeof</span> result2 === <span class="string">"object"</span> && result2.value === <span class="string">"wakizashi"</span> && !result2.done,<span class="string">"wakizashi recevied!"</span>);</span><br><span class="line"><span class="keyword">const</span> result3 = weaponsIterator.next();</span><br><span class="line">assert(<span class="keyword">typeof</span> result3 === <span class="string">"object"</span> && result3.value === <span class="literal">undefined</span> && result3.done,<span class="string">"There are no more results!"</span>);</span><br></pre></td></tr></table></figure><p><code>WeaponGenerator</code>是构造器,<code>weaponsIterator.next()</code>会返回一个对象,如果传入值则<code>yield</code>被替换为改值,对象有两个属性<code>value</code>和<code>done</code>,当第三次返回对象时<code>done</code>的值为<code>true</code>。</p><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span>* <span class="title">WarriorGenerator</span>(<span class="params"></span>)</span>{</span><br><span class="line"><span class="keyword">yield</span> <span class="string">"Katana"</span>;</span><br><span class="line"><span class="keyword">yield</span>* NinjaGenerator();</span><br><span class="line"><span class="keyword">yield</span> <span class="string">"Wakizashi"</span>;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">function</span>* <span class="title">NinjaGenerator</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">yield</span> <span class="string">"Hattori"</span>;</span><br><span class="line"> <span class="keyword">yield</span> <span class="string">"Yoshi"</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">let</span> warrior <span class="keyword">of</span> WarriorGenerator()){</span><br><span class="line"> assert(warrior !== <span class="literal">null</span>, warrior);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>类似于链表的结构。</p><figure class="highlight javascript"><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="function"><span class="keyword">function</span>* <span class="title">NinjaGenerator</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">try</span>{</span><br><span class="line"> <span class="keyword">yield</span> <span class="string">"Hattori"</span>;</span><br><span class="line"> fail(<span class="string">"The expected exception didn't occur"</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">catch</span>(e){</span><br><span class="line"> assert(e === <span class="string">"Catch this!"</span>,<span class="string">"Aha! We caught an exception"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">const</span> ninjaIterator = NinjaGenrator();</span><br><span class="line"><span class="keyword">const</span> result1 = ninjaIterator().next();</span><br><span class="line">assert(result1.value === <span class="string">"Hattori"</span>, <span class="string">"We got Hattori"</span>);</span><br><span class="line">ninjaIterator.throw(<span class="string">"Catch this!"</span>);</span><br></pre></td></tr></table></figure><p>这里是说有throw这个方法</p><figure class="highlight javascript"><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="function"><span class="keyword">function</span>* <span class="title">NinjaGenerator</span>(<span class="params">action</span>)</span>{</span><br><span class="line"> <span class="keyword">const</span> imposter = <span class="keyword">yield</span> (<span class="string">"Hattori"</span> + action);</span><br><span class="line"> assert(imposter === <span class="string">"Hanzo"</span>,<span class="string">"The generator has been infiltrated"</span>);</span><br><span class="line"> <span class="keyword">yield</span> (<span class="string">"Yoshi ("</span> + imposter + <span class="string">") "</span> + action);</span><br><span class="line">}</span><br><span class="line"><span class="keyword">const</span> ninjaIterator = NinjaGenerator(<span class="string">"skulk"</span>);</span><br><span class="line"><span class="keyword">const</span> result1 = ninjaIterator.next();</span><br><span class="line">assert(result1.value === <span class="string">"Hattori skulk"</span>, <span class="string">"Hattori is skulking"</span>);</span><br><span class="line"><span class="keyword">const</span> result2 = ninjaIterator.next(<span class="string">"Hanzo"</span>);</span><br><span class="line">assert(result2.value === <span class="string">"Yoshi (Hanzo) skulk"</span>, <span class="string">"We have an imposter!"</span>);</span><br></pre></td></tr></table></figure><h2 id="Promise"><a href="#Promise" class="headerlink" title="Promise"></a>Promise</h2><p>来搬一个别人的博客<a href="https://www.jianshu.com/p/1b63a13c2701" target="_blank" rel="noopener">https://www.jianshu.com/p/1b63a13c2701</a></p>]]></content>
</entry>
<entry>
<title>Redux</title>
<link href="/2021/09/22/Redux/"/>
<url>/2021/09/22/Redux/</url>
<content type="html"><![CDATA[<h1 id="Redux"><a href="#Redux" class="headerlink" title="Redux"></a>Redux</h1><h2 id="什么时候需要-Redux"><a href="#什么时候需要-Redux" class="headerlink" title="什么时候需要 Redux"></a>什么时候需要 Redux</h2><p>首先明确一点,Redux 是一个有用的架构,但不是非用不可。事实上,大多数情况,你可以不用它,只用 React 就够了。</p><p>简单说,如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加复杂性。Redux 的适用场景:多交互、多数据源。</p><p>从组件角度看,如果你的应用有以下场景,可以考虑使用 Redux。</p><ul><li>某个组件的状态,需要共享</li><li>某个状态需要在任何地方都可以拿到</li><li>一个组件需要改变全局状态</li><li>一个组件需要改变另一个组件的状态</li></ul><h2 id="基本概念和-API"><a href="#基本概念和-API" class="headerlink" title="基本概念和 API"></a>基本概念和 API</h2><h3 id="Store"><a href="#Store" class="headerlink" title="Store"></a>Store</h3><p>Store 就是保存数据的地方,你可以把它看成一个容器。整个应用只能有一个 Store。</p><p>Redux 提供<code>createStore</code>这个函数,用来生成 Store。</p><blockquote><figure class="highlight javascript"><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="keyword">import</span> { createStore } <span class="keyword">from</span> <span class="string">'redux'</span>;</span><br><span class="line"><span class="keyword">const</span> store = createStore(fn);</span><br></pre></td></tr></table></figure></blockquote><p>上面代码中,<code>createStore</code>函数接受另一个函数作为参数,返回新生成的 Store 对象。</p><h3 id="State"><a href="#State" class="headerlink" title="State"></a>State</h3><p><code>Store</code>对象包含所有数据。如果想得到某个时点的数据,就要对 Store 生成快照。这种时点的数据集合,就叫做 State。</p><p>当前时刻的 State,可以通过<code>store.getState()</code>拿到。</p><blockquote><figure class="highlight javascript"><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">import</span> { createStore } <span class="keyword">from</span> <span class="string">'redux'</span>;</span><br><span class="line"><span class="keyword">const</span> store = createStore(fn);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> state = store.getState();</span><br></pre></td></tr></table></figure></blockquote><p>Redux 规定, 一个 State 对应一个 View。只要 State 相同,View 就相同。你知道 State,就知道 View 是什么样,反之亦然。</p><h3 id="Action"><a href="#Action" class="headerlink" title="Action"></a>Action</h3><p>State 的变化,会导致 View 的变化。但是,用户接触不到 State,只能接触到 View。所以,State 的变化必须是 View 导致的。Action 就是 View 发出的通知,表示 State 应该要发生变化了。</p><p>Action 是一个对象。其中的<code>type</code>属性是必须的,表示 Action 的名称。</p><blockquote><figure class="highlight javascript"><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">const</span> action = {</span><br><span class="line"> type: <span class="string">'ADD_TODO'</span>,</span><br><span class="line"> payload: <span class="string">'Learn Redux'</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure></blockquote><p>上面代码中,Action 的名称是<code>ADD_TODO</code>,它携带的信息是字符串<code>Learn Redux</code>。</p><p>可以这样理解,Action 描述当前发生的事情。改变 State 的唯一办法,就是使用 Action。它会运送数据到 Store。</p><h3 id="Action-Creator"><a href="#Action-Creator" class="headerlink" title="Action Creator"></a>Action Creator</h3><p>View 要发送多少种消息,就会有多少种 Action。如果都手写,会很麻烦。可以定义一个函数来生成 Action,这个函数就叫 Action Creator。</p><blockquote><figure class="highlight javascript"><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">const</span> ADD_TODO = <span class="string">'添加 TODO'</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">addTodo</span>(<span class="params">text</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> type: ADD_TODO,</span><br><span class="line"> text</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> action = addTodo(<span class="string">'Learn Redux'</span>);</span><br></pre></td></tr></table></figure></blockquote><p>上面代码中,<code>addTodo</code>函数就是一个 Action Creator。</p><h3 id="store-dispatch"><a href="#store-dispatch" class="headerlink" title="store.dispatch()"></a>store.dispatch()</h3><p><code>store.dispatch()</code>是 View 发出 Action 的唯一方法。</p><blockquote><figure class="highlight javascript"><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="keyword">import</span> { createStore } <span class="keyword">from</span> <span class="string">'redux'</span>;</span><br><span class="line"><span class="keyword">const</span> store = createStore(fn);</span><br><span class="line"></span><br><span class="line">store.dispatch({</span><br><span class="line"> type: <span class="string">'ADD_TODO'</span>,</span><br><span class="line"> payload: <span class="string">'Learn Redux'</span></span><br><span class="line">});</span><br></pre></td></tr></table></figure></blockquote><p>上面代码中,<code>store.dispatch</code>接受一个 Action 对象作为参数,将它发送出去。</p><p>结合 Action Creator,这段代码可以改写如下。</p><blockquote><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">store.dispatch(addTodo(<span class="string">'Learn Redux'</span>));</span><br></pre></td></tr></table></figure></blockquote><h2 id="Reducer"><a href="#Reducer" class="headerlink" title="Reducer"></a>Reducer</h2><p>Store 收到 Action 以后,必须给出一个新的 State,这样 View 才会发生变化。这种 State 的计算过程就叫做 Reducer。</p><p>Reducer 是一个函数,它接受 Action 和当前 State 作为参数,返回一个新的 State。</p><blockquote><figure class="highlight javascript"><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">const</span> reducer = <span class="function"><span class="keyword">function</span> (<span class="params">state, action</span>) </span>{</span><br><span class="line"> <span class="comment">// ...</span></span><br><span class="line"> <span class="keyword">return</span> new_state;</span><br><span class="line">};</span><br></pre></td></tr></table></figure></blockquote><p>整个应用的初始状态,可以作为 State 的默认值。下面是一个实际的例子。</p><blockquote><figure class="highlight javascript"><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="keyword">const</span> defaultState = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">const</span> reducer = <span class="function">(<span class="params">state = defaultState, action</span>) =></span> {</span><br><span class="line"> <span class="keyword">switch</span> (action.type) {</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'ADD'</span>:</span><br><span class="line"> <span class="keyword">return</span> state + action.payload;</span><br><span class="line"> <span class="keyword">default</span>: </span><br><span class="line"> <span class="keyword">return</span> state;</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> state = reducer(<span class="number">1</span>, {</span><br><span class="line"> type: <span class="string">'ADD'</span>,</span><br><span class="line"> payload: <span class="number">2</span></span><br><span class="line">});</span><br></pre></td></tr></table></figure></blockquote><p>上面代码中,<code>reducer</code>函数收到名为<code>ADD</code>的 Action 以后,就返回一个新的 State,作为加法的计算结果。其他运算的逻辑(比如减法),也可以根据 Action 的不同来实现。</p><p>实际应用中,Reducer 函数不用像上面这样手动调用,<code>store.dispatch</code>方法会触发 Reducer 的自动执行。为此,Store 需要知道 Reducer 函数,做法就是在生成 Store 的时候,将 Reducer 传入<code>createStore</code>方法。</p><blockquote><figure class="highlight javascript"><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="keyword">import</span> { createStore } <span class="keyword">from</span> <span class="string">'redux'</span>;</span><br><span class="line"><span class="keyword">const</span> store = createStore(reducer);</span><br></pre></td></tr></table></figure></blockquote><p>上面代码中,<code>createStore</code>接受 Reducer 作为参数,生成一个新的 Store。以后每当<code>store.dispatch</code>发送过来一个新的 Action,就会自动调用 Reducer,得到新的 State。</p><p>为什么这个函数叫做 Reducer 呢?因为它可以作为数组的<code>reduce</code>方法的参数。请看下面的例子,一系列 Action 对象按照顺序作为一个数组。</p><blockquote><figure class="highlight javascript"><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="keyword">const</span> actions = [</span><br><span class="line"> { <span class="attr">type</span>: <span class="string">'ADD'</span>, <span class="attr">payload</span>: <span class="number">0</span> },</span><br><span class="line"> { <span class="attr">type</span>: <span class="string">'ADD'</span>, <span class="attr">payload</span>: <span class="number">1</span> },</span><br><span class="line"> { <span class="attr">type</span>: <span class="string">'ADD'</span>, <span class="attr">payload</span>: <span class="number">2</span> }</span><br><span class="line">];</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> total = actions.reduce(reducer, <span class="number">0</span>); <span class="comment">// 3</span></span><br></pre></td></tr></table></figure></blockquote><p>上面代码中,数组<code>actions</code>表示依次有三个 Action,分别是加<code>0</code>、加<code>1</code>和加<code>2</code>。数组的<code>reduce</code>方法接受 Reducer 函数作为参数,就可以直接得到最终的状态<code>3</code>。</p><h3 id="纯函数"><a href="#纯函数" class="headerlink" title="纯函数"></a>纯函数</h3><p>什么是纯函数?<a href="https://www.jianshu.com/p/a5a6d4399d69" target="_blank" rel="noopener">https://www.jianshu.com/p/a5a6d4399d69</a> </p><p>由于 Reducer 是纯函数,就可以保证同样的State,必定得到同样的 View。但也正因为这一点,Reducer 函数里面不能改变 State,必须返回一个全新的对象,请参考下面的写法。</p><blockquote><figure class="highlight javascript"><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"><span class="comment">// State 是一个对象</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">reducer</span>(<span class="params">state, action</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Object</span>.assign({}, state, { thingToChange });</span><br><span class="line"> <span class="comment">// 或者</span></span><br><span class="line"> <span class="keyword">return</span> { ...state, ...newState };</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// State 是一个数组</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">reducer</span>(<span class="params">state, action</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> [...state, newItem];</span><br><span class="line">}</span><br></pre></td></tr></table></figure></blockquote><p>最好把 State 对象设成只读。你没法改变它,要得到新的 State,唯一办法就是生成一个新对象。这样的好处是,任何时候,与某个 View 对应的 State 总是一个不变的对象。</p><h3 id="store-subscribe"><a href="#store-subscribe" class="headerlink" title="store.subscribe()"></a>store.subscribe()</h3><p>Store 允许使用<code>store.subscribe</code>方法设置监听函数,一旦 State 发生变化,就自动执行这个函数。</p><blockquote><figure class="highlight javascript"><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">import</span> { createStore } <span class="keyword">from</span> <span class="string">'redux'</span>;</span><br><span class="line"><span class="keyword">const</span> store = createStore(reducer);</span><br><span class="line"></span><br><span class="line">store.subscribe(listener);</span><br></pre></td></tr></table></figure></blockquote><p>显然,只要把 View 的更新函数(对于 React 项目,就是组件的<code>render</code>方法或<code>setState</code>方法)放入<code>listen</code>,就会实现 View 的自动渲染。</p><p><code>store.subscribe</code>方法返回一个函数,调用这个函数就可以解除监听。</p><blockquote><figure class="highlight javascript"><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="keyword">let</span> unsubscribe = store.subscribe(<span class="function"><span class="params">()</span> =></span></span><br><span class="line"> <span class="built_in">console</span>.log(store.getState())</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">unsubscribe();</span><br></pre></td></tr></table></figure></blockquote><h2 id="Store-的实现"><a href="#Store-的实现" class="headerlink" title="Store 的实现"></a>Store 的实现</h2><p>上一节介绍了 Redux 涉及的基本概念,可以发现 Store 提供了三个方法。</p><blockquote><ul><li>store.getState()</li><li>store.dispatch()</li><li>store.subscribe()</li></ul></blockquote><blockquote><figure class="highlight javascript"><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="keyword">import</span> { createStore } <span class="keyword">from</span> <span class="string">'redux'</span>;</span><br><span class="line"><span class="keyword">let</span> { subscribe, dispatch, getState } = createStore(reducer);</span><br></pre></td></tr></table></figure></blockquote><p><code>createStore</code>方法还可以接受第二个参数,表示 State 的最初状态。这通常是服务器给出的。</p><blockquote><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> store = createStore(todoApp, <span class="built_in">window</span>.STATE_FROM_SERVER)</span><br></pre></td></tr></table></figure></blockquote><p>上面代码中,<code>window.STATE_FROM_SERVER</code>就是整个应用的状态初始值。注意,如果提供了这个参数,它会覆盖 Reducer 函数的默认初始值。</p><p>下面是<code>createStore</code>方法的一个简单实现,可以了解一下 Store 是怎么生成的。</p><blockquote><figure class="highlight javascript"><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">const</span> createStore = <span class="function">(<span class="params">reducer</span>) =></span> {</span><br><span class="line"> <span class="keyword">let</span> state;</span><br><span class="line"> <span class="keyword">let</span> listeners = [];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> getState = <span class="function"><span class="params">()</span> =></span> state;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> dispatch = <span class="function">(<span class="params">action</span>) =></span> {</span><br><span class="line"> state = reducer(state, action);</span><br><span class="line"> listeners.forEach(<span class="function"><span class="params">listener</span> =></span> listener());</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> subscribe = <span class="function">(<span class="params">listener</span>) =></span> {</span><br><span class="line"> listeners.push(listener);</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="params">()</span> =></span> {</span><br><span class="line"> listeners = listeners.filter(<span class="function"><span class="params">l</span> =></span> l !== listener);</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> dispatch({});</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> { getState, dispatch, subscribe };</span><br><span class="line">};</span><br></pre></td></tr></table></figure></blockquote><h2 id="Reducer-的拆分"><a href="#Reducer-的拆分" class="headerlink" title="Reducer 的拆分"></a>Reducer 的拆分</h2><p>Reducer 函数负责生成 State。由于整个应用只有一个 State 对象,包含所有数据,对于大型应用来说,这个 State 必然十分庞大,导致 Reducer 函数也十分庞大。</p><p>请看下面的例子。</p><blockquote><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> chatReducer = <span class="function">(<span class="params">state = defaultState, action = {}</span>) =></span> {</span><br><span class="line"> <span class="keyword">const</span> { type, payload } = action;</span><br><span class="line"> <span class="keyword">switch</span> (type) {</span><br><span class="line"> <span class="keyword">case</span> ADD_CHAT:</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Object</span>.assign({}, state, {</span><br><span class="line"> chatLog: state.chatLog.concat(payload)</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">case</span> CHANGE_STATUS:</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Object</span>.assign({}, state, {</span><br><span class="line"> statusMessage: payload</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">case</span> CHANGE_USERNAME:</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Object</span>.assign({}, state, {</span><br><span class="line"> userName: payload</span><br><span class="line"> });</span><br><span class="line"> <span class="keyword">default</span>: <span class="keyword">return</span> state;</span><br><span class="line"> }</span><br><span class="line">};</span><br></pre></td></tr></table></figure></blockquote><p>上面代码中,三种 Action 分别改变 State 的三个属性。</p><blockquote><ul><li>ADD_CHAT:<code>chatLog</code>属性</li><li>CHANGE_STATUS:<code>statusMessage</code>属性</li><li>CHANGE_USERNAME:<code>userName</code>属性</li></ul></blockquote><p>这三个属性之间没有联系,这提示我们可以把 Reducer 函数拆分。不同的函数负责处理不同属性,最终把它们合并成一个大的 Reducer 即可。</p><blockquote><figure class="highlight javascript"><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="keyword">const</span> chatReducer = <span class="function">(<span class="params">state = defaultState, action = {}</span>) =></span> {</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> chatLog: chatLog(state.chatLog, action),</span><br><span class="line"> statusMessage: statusMessage(state.statusMessage, action),</span><br><span class="line"> userName: userName(state.userName, action)</span><br><span class="line"> }</span><br><span class="line">};</span><br></pre></td></tr></table></figure></blockquote><p>上面代码中,Reducer 函数被拆成了三个小函数,每一个负责生成对应的属性。</p><p>这样一拆,Reducer 就易读易写多了。而且,这种拆分与 React 应用的结构相吻合:一个 React 根组件由很多子组件构成。这就是说,子组件与子 Reducer 完全可以对应。</p><p>Redux 提供了一个<code>combineReducers</code>方法,用于 Reducer 的拆分。你只要定义各个子 Reducer 函数,然后用这个方法,将它们合成一个大的 Reducer。</p><blockquote><figure class="highlight javascript"><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">import</span> { combineReducers } <span class="keyword">from</span> <span class="string">'redux'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> chatReducer = combineReducers({</span><br><span class="line"> chatLog,</span><br><span class="line"> statusMessage,</span><br><span class="line"> userName</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> todoApp;</span><br></pre></td></tr></table></figure></blockquote><p>上面的代码通过<code>combineReducers</code>方法将三个子 Reducer 合并成一个大的函数。</p><p>这种写法有一个前提,就是 State 的属性名必须与子 Reducer 同名。如果不同名,就要采用下面的写法。</p><blockquote><figure class="highlight javascript"><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="keyword">const</span> reducer = combineReducers({</span><br><span class="line"> a: doSomethingWithA,</span><br><span class="line"> b: processB,</span><br><span class="line"> c: c</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="function"><span class="keyword">function</span> <span class="title">reducer</span>(<span class="params">state = {}, action</span>) </span>{</span><br><span class="line"> <span class="keyword">return</span> {</span><br><span class="line"> a: doSomethingWithA(state.a, action),</span><br><span class="line"> b: processB(state.b, action),</span><br><span class="line"> c: c(state.c, action)</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></blockquote><p>总之,<code>combineReducers()</code>做的就是产生一个整体的 Reducer 函数。该函数根据 State 的 key 去执行相应的子 Reducer,并将返回结果合并成一个大的 State 对象。</p><h2 id="计数器"><a href="#计数器" class="headerlink" title="计数器"></a>计数器</h2><p>下面我们来看一个最简单的实例。</p><blockquote><figure class="highlight jsx"><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="keyword">const</span> Counter = <span class="function">(<span class="params">{ value }</span>) =></span> (</span><br><span class="line"> <h1>{value}<<span class="regexp">/h1></span></span><br><span class="line"><span class="regexp">);</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">const render = () => {</span></span><br><span class="line"><span class="regexp"> ReactDOM.render(</span></span><br><span class="line"><span class="regexp"> <Counter value={store.getState()}/</span>>,</span><br><span class="line"> <span class="built_in">document</span>.getElementById(<span class="string">'root'</span>)</span><br><span class="line"> );</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">store.subscribe(render);</span><br><span class="line">render</span><br></pre></td></tr></table></figure></blockquote><p>上面是一个简单的计数器,唯一的作用就是把参数<code>value</code>的值,显示在网页上。Store 的监听函数设置为<code>render</code>,每次 State 的变化都会导致网页重新渲染。</p><p>下面加入一点变化,为<code>Counter</code>添加递增和递减的 Action。</p><blockquote><figure class="highlight jsx"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> Counter = <span class="function">(<span class="params">{ value, onIncrement, onDecrement }</span>) =></span> (</span><br><span class="line"> <div></span><br><span class="line"> <h1>{value}<<span class="regexp">/h1></span></span><br><span class="line"><span class="regexp"> <button onClick={onIncrement}>+</</span>button></span><br><span class="line"> <button onClick={onDecrement}>-<span class="xml"><span class="tag"></<span class="name">button</span>></span></span></span><br><span class="line"> <<span class="regexp">/div></span></span><br><span class="line"><span class="regexp">);</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">const reducer = (state = 0, action) => {</span></span><br><span class="line"><span class="regexp"> switch (action.type) {</span></span><br><span class="line"><span class="regexp"> case 'INCREMENT': return state + 1;</span></span><br><span class="line"><span class="regexp"> case 'DECREMENT': return state - 1;</span></span><br><span class="line"><span class="regexp"> default: return state;</span></span><br><span class="line"><span class="regexp"> }</span></span><br><span class="line"><span class="regexp">};</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">const store = createStore(reducer);</span></span><br><span class="line"><span class="regexp"></span></span><br><span class="line"><span class="regexp">const render = () => {</span></span><br><span class="line"><span class="regexp"> ReactDOM.render(</span></span><br><span class="line"><span class="regexp"> <Counter</span></span><br><span class="line"><span class="regexp"> value={store.getState()}</span></span><br><span class="line"><span class="regexp"> onIncrement={() => store.dispatch({type: 'INCREMENT'})}</span></span><br><span class="line"><span class="regexp"> onDecrement={() => store.dispatch({type: 'DECREMENT'})}</span></span><br><span class="line"><span class="regexp"> /</span>>,</span><br><span class="line"> <span class="built_in">document</span>.getElementById(<span class="string">'root'</span>)</span><br><span class="line"> );</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">render();</span><br><span class="line">store.subscribe(render);</span><br></pre></td></tr></table></figure></blockquote>]]></content>
</entry>
<entry>
<title>JS Chapter 7</title>
<link href="/2021/09/22/JS%20Chapter%207/"/>
<url>/2021/09/22/JS%20Chapter%207/</url>
<content type="html"><![CDATA[<h2 id="Object-orientation-with-prototypes"><a href="#Object-orientation-with-prototypes" class="headerlink" title="Object orientation with prototypes"></a>Object orientation with prototypes</h2><p>虽然在之后avascript或者其一些框架的使用中,原型和原型链的概念很少被提到。但是原型作为JavaScript的基本的重要概念之一,也是需要被我们掌握的。</p><h3 id="原型的概念"><a href="#原型的概念" class="headerlink" title="原型的概念"></a>原型的概念</h3><p>书上给出的概念 A prototype is an object to which the search for a particular property can be delegated to.</p><p>首先最简单的缩句理解prototype就是一个对象,对象有一些特殊的属性。</p><h3 id="Understanding-protototypes"><a href="#Understanding-protototypes" class="headerlink" title="Understanding protototypes"></a>Understanding protototypes</h3><p>我们可以先创造一个对象,对象里面包含一些字面对象得标记</p><figure class="highlight javascript"><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="keyword">let</span> obj = {</span><br><span class="line">prop1: <span class="number">1</span>,</span><br><span class="line">prop2: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{},</span><br><span class="line">prop3: {}</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>我们也可以进行一些修改删除操作,也可以添加一个完全新的属性:</p><figure class="highlight javascript"><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">obj.prop1 = <span class="number">1</span>;</span><br><span class="line">obj.prop1 = [];</span><br><span class="line"><span class="keyword">delete</span> obj.prop2;</span><br><span class="line">obj.prop4 = <span class="string">"Hello"</span>;</span><br></pre></td></tr></table></figure><p>最后object的内容是这样的:</p><figure class="highlight javascript"><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><br><span class="line">prop1:[],</span><br><span class="line">prop3:{},</span><br><span class="line">prop4:<span class="string">"Hello"</span></span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>当在开发软件时,我们会希望减少代码的冗余量,尽可能的去重复利用一些代码,其中我们可以利用Javascript中继承的特性。</p><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> yoshi = {<span class="attr">skulk</span>: <span class="literal">true</span>};</span><br><span class="line"><span class="keyword">const</span> hattori = {<span class="attr">sneak</span>: <span class="literal">true</span>};</span><br><span class="line"><span class="keyword">const</span> kuma = {<span class="attr">creep</span>: <span class="literal">true</span>};</span><br><span class="line">assert(<span class="string">"skulk"</span> <span class="keyword">in</span> yoshi, <span class="string">"Yoshi can skulk"</span>);</span><br><span class="line">assert(!(<span class="string">"sneak"</span> <span class="keyword">in</span> yoshi), <span class="string">"Yoshi cannot sneak"</span>);</span><br><span class="line">assert(!(<span class="string">"creep"</span> <span class="keyword">in</span> yoshi), <span class="string">"Yoshi cannot creep"</span>);</span><br><span class="line"><span class="built_in">Object</span>.setPrototypeOf(yoshi, hattori);<span class="comment">//把hattori设为yoshi的原型</span></span><br><span class="line">assert(<span class="string">"sneak"</span> <span class="keyword">in</span> yoshi, <span class="string">"Yoshi can now sneak"</span>);</span><br><span class="line">assert(!(<span class="string">"creep"</span> <span class="keyword">in</span> hattori), <span class="string">"Hattori cannot creep"</span>);</span><br><span class="line"><span class="built_in">Object</span>.setPrototypeOf(hattori, kuma);<span class="comment">//把kuma设为hattori的原型</span></span><br><span class="line">assert(<span class="string">"creep"</span> <span class="keyword">in</span> yoshi, <span class="string">"Hattori can now creep"</span>);</span><br><span class="line">assert(<span class="string">"creep"</span> <span class="keyword">in</span> hattori, <span class="string">"Yoshi can also creep"</span>);</span><br></pre></td></tr></table></figure><p>画一下这个一条原型链。[[prototype]]</p><h3 id="Object-construction-and-prototypes"><a href="#Object-construction-and-prototypes" class="headerlink" title="Object construction and prototypes"></a>Object construction and prototypes</h3><p>我们首先使用JavaScript当中的new关键字来完成原型链的构成</p><figure class="highlight javascript"><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="function"><span class="keyword">function</span> <span class="title">Ninja</span>(<span class="params"></span>)</span>{</span><br><span class="line">Ninja.prototype.swingSword = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</span><br><span class="line"><span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="keyword">const</span> ninja1 = Ninja();</span><br><span class="line">assert(ninja1 === <span class="literal">undefined</span>,<span class="string">"No instance of Ninja created."</span>);</span><br><span class="line"><span class="keyword">const</span> ninja2 = <span class="keyword">new</span> Ninja();</span><br><span class="line">assert(ninja2 && ninja2.swingSword && ninja2.swingSword(),<span class="string">"Instance exists and method is callable."</span>);</span><br></pre></td></tr></table></figure><p>Ninja这个函数对象当中我们创建了一个函数在他的原型当中,这个原型对象当中有constructor指向他自己(Ninja)和一个swingSword函数。当我们使用new关键字时,其实一共有四个步骤:</p><ol><li>new了之后,在内存中申请一块空闲的空间,存储创建的新的对象。</li><li>在函数最顶端有一个理论上的空对象即this:把this设置为当前的对象。</li><li>执行构造函数把this对象中的数据填满:设置对象的属性和方法的值。</li><li>最后一步有一个隐式的return this; 把this这个对象返回。</li></ol><h4 id="instance-properties"><a href="#instance-properties" class="headerlink" title="instance properties"></a>instance properties</h4><p>这里我们用this参数来完成Ninja函数</p><figure class="highlight javascript"><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"><span class="function"><span class="keyword">function</span> <span class="title">Ninja</span>(<span class="params"></span>)</span>{</span><br><span class="line"><span class="keyword">this</span>.swung = <span class="literal">false</span>;</span><br><span class="line"><span class="keyword">this</span>.swingSword = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</span><br><span class="line"><span class="keyword">return</span> !<span class="keyword">this</span>.swung;</span><br><span class="line">};</span><br><span class="line">}</span><br><span class="line">Ninja.prototype.swingSword = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.swung;</span><br><span class="line">};</span><br><span class="line"><span class="keyword">const</span> ninja = <span class="keyword">new</span> Ninja();</span><br><span class="line">assert(ninja.swingSword(), <span class="string">"Called the instance method, not the prototype method."</span>);</span><br></pre></td></tr></table></figure><p>上面提到的new关键字的实际四个步骤,这里的ninja其实就是指向ninja本身的this对象。ninja本身会有swung和swingSword属性,和他存在一个原型指向ninja的原型。ninja原型之中也会有一个swingSword方法,但是我们在调用swingSword方法可以看到返回的值为true而不是false本身,因为当我们调用swingSword时,ninja会在其本身去寻找有没有这个swingSword方法,当swingSword不存在时,才再开始在其原型中寻找函数。比如,我们会在一些数组对象Array或者字符串对象String使用一些方法时,sort,map等,我们并没有直接在这些对象之中定义,而是他们继承了Array和String的原型,而去他的原型当中寻找这些方法。</p><figure class="highlight javascript"><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">Ninja.prototype = {</span><br><span class="line">pierce: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>当执行到该句时,Ninja的原型会指向新的这个对象包含pierce函数。</p><figure class="highlight javascript"><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="function"><span class="keyword">function</span> <span class="title">Ninja</span>(<span class="params"></span>)</span>{}</span><br><span class="line"><span class="keyword">const</span> ninja = <span class="keyword">new</span> Ninja();</span><br><span class="line">assert(<span class="keyword">typeof</span> ninja === <span class="string">"object"</span>, <span class="string">"The type of the instance is object."</span>);</span><br><span class="line">assert(ninja <span class="keyword">instanceof</span> Ninja, <span class="string">"instanceof identifies the constructor."</span>);</span><br><span class="line">assert(ninja.constructor === Ninja, <span class="string">"The ninja object was created by the Ninja function"</span>);</span><br></pre></td></tr></table></figure><p>从这几行代码可以得出ninja是一个的对象,也是Ninja得一个实例,而ninja的原型里面的constructor指向的Ninja</p><figure class="highlight javascript"><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="function"><span class="keyword">function</span> <span class="title">Ninja</span>(<span class="params"></span>)</span>{}</span><br><span class="line"><span class="keyword">const</span> ninja = <span class="keyword">new</span> Ninja();</span><br><span class="line"><span class="keyword">const</span> ninja2 = <span class="keyword">new</span> ninja.constructor();</span><br><span class="line">assert(ninja2 <span class="keyword">instanceof</span> Ninja, <span class="string">"It's a Ninja!"</span>);</span><br><span class="line">assert(ninja !== ninja2,<span class="string">"But not the same Ninja"</span>);</span><br></pre></td></tr></table></figure><p>我们通过ninja.constructor来构建一个新的对象,而ninja2也是一个Ninja的实例。</p><h3 id="Achieving-inheritance"><a href="#Achieving-inheritance" class="headerlink" title="Achieving inheritance"></a>Achieving inheritance</h3><figure class="highlight javascript"><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="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params"></span>)</span>{};</span><br><span class="line">Person.prototype.dance = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{};</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Ninja</span>(<span class="params"></span>)</span>{};</span><br><span class="line">Ninja.prototype = <span class="keyword">new</span> Person();</span><br><span class="line"><span class="keyword">const</span> ninja = <span class="keyword">new</span> Ninja();</span><br><span class="line">assert(ninja <span class="keyword">instanceof</span> Ninja, <span class="string">"ninja receives functionality from the Ninja prototype"</span>);</span><br><span class="line">assert(ninja <span class="keyword">instanceof</span> Person, <span class="string">"...and the Person prototype"</span>);</span><br><span class="line">assert(ninja <span class="keyword">instanceof</span> <span class="built_in">Object</span>, <span class="string">"...and the Object prototype"</span>);</span><br><span class="line">assert(<span class="keyword">typeof</span> ninja.dance === <span class="string">"function"</span>,<span class="string">"..and can dance!"</span>)</span><br></pre></td></tr></table></figure><p>这里是一个原型链的继承,ninja是Ninja的实例也是Person的实例也是一个对象实例。</p><h3 id="Using-JavaScript-“classes”-in-ES6"><a href="#Using-JavaScript-“classes”-in-ES6" class="headerlink" title="Using JavaScript “classes” in ES6"></a>Using JavaScript “classes” in ES6</h3><p>我们实际在开发过程中,我们会经常使用ES6中的新特性classes。</p><figure class="highlight javascript"><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="class"><span class="keyword">class</span> <span class="title">Ninja</span></span>{</span><br><span class="line"> <span class="keyword">constructor</span>(name){</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> walk(){</span><br><span class="line"> <span class="keyword">return</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">swingSword(){</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">}</span><br><span class="line"><span class="comment">// ninja.prototype.swingSword = (){ return true};</span></span><br><span class="line"><span class="keyword">static</span> dance(){</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">}</span><br><span class="line"><span class="keyword">var</span> ninja = <span class="keyword">new</span> Ninja(<span class="string">"Yoshi"</span>);</span><br><span class="line">assert(ninja.swingSword(),<span class="string">"and he can swing a sword"</span>);</span><br></pre></td></tr></table></figure><figure class="highlight javascript"><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="class"><span class="keyword">class</span> <span class="title">Person</span></span>{</span><br><span class="line"><span class="keyword">constructor</span>(name){</span><br><span class="line"><span class="keyword">this</span>.name = name;</span><br><span class="line">}</span><br><span class="line">dance(){</span><br><span class="line"><span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Ninja</span> <span class="keyword">extends</span> <span class="title">Person</span></span>{</span><br><span class="line"> <span class="keyword">constructor</span>(name,weapon){</span><br><span class="line"> <span class="keyword">super</span>(name);</span><br><span class="line"> <span class="keyword">this</span>.weapon = weapon;</span><br><span class="line"> }</span><br><span class="line"> wieldWeapon(){</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
</entry>
<entry>
<title>JS Chapter 5</title>
<link href="/2021/09/22/JS%20Chapter%205/"/>
<url>/2021/09/22/JS%20Chapter%205/</url>
<content type="html"><![CDATA[<h2 id="Closure"><a href="#Closure" class="headerlink" title="Closure"></a>Closure</h2><h3 id="一、概念"><a href="#一、概念" class="headerlink" title="一、概念"></a>一、概念</h3><h6 id="A-closure-is-the-combination-of-a-function-and-the-lexical-environment-within-which-that-function-was-declared"><a href="#A-closure-is-the-combination-of-a-function-and-the-lexical-environment-within-which-that-function-was-declared" class="headerlink" title="A closure is the combination of a function and the lexical environment within which that function was declared."></a>A closure is the combination of a function and the lexical environment within which that function was declared.</h6><h3 id="二、Lexical-Environment(词法环境)"><a href="#二、Lexical-Environment(词法环境)" class="headerlink" title="二、Lexical Environment(词法环境)"></a>二、Lexical Environment(词法环境)</h3><p> 这个链接详细介绍了什么是词法环境。<a href="https://segmentfault.com/a/1190000015172796" target="_blank" rel="noopener">https://segmentfault.com/a/1190000015172796</a> </p><h3 id="三、区分的两个概念"><a href="#三、区分的两个概念" class="headerlink" title="三、区分的两个概念"></a>三、区分的两个概念</h3><p> 一开始看闭包这个部分的时候一直没有搞懂为什么不能在外部变量访问内部变量的问题,其实是我把两个概念给搞混了。</p><p> 为什么不能访问内部变量这个问题很简单,就是局部变量的生存周期与函数的调用时一样,一旦函数调用完毕,这些局部变量就不在存在了。</p><figure class="highlight javascript"><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">let</span> outter = <span class="number">1</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> (<span class="params"></span>)</span>{</span><br><span class="line"><span class="keyword">let</span> inner = <span class="number">2</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p> 而我一开始困惑了很久,就是为什么<code>a.b</code>,这样的就可以访问呢? 那我搞混的两个概念就是<strong>局部变量</strong>和<strong>对象的属性或者方法</strong>。</p><p> 局部变量就是上面所说的,那么对象的属性或方法来举例子:</p><figure class="highlight javascript"><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="keyword">let</span> a = <span class="keyword">new</span> <span class="built_in">Object</span>();<span class="comment">//a是一个对象</span></span><br><span class="line">a.b = <span class="number">2</span>;</span><br><span class="line">alert(a.b);</span><br></pre></td></tr></table></figure><h3 id="四、小桃花穿越故事"><a href="#四、小桃花穿越故事" class="headerlink" title="四、小桃花穿越故事"></a>四、小桃花穿越故事</h3><p>先举一个简单的例子</p><figure class="highlight javascript"><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="function"><span class="keyword">function</span> <span class="title">t1</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">var</span> age = <span class="number">20</span>;</span><br><span class="line"> <span class="function"><span class="keyword">function</span> <span class="title">t2</span>(<span class="params"></span>)</span>{</span><br><span class="line"> alert(age);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> t2;</span><br><span class="line"> }</span><br><span class="line"><span class="keyword">var</span> tmp = t1();</span><br><span class="line">tmp();<span class="comment">//----------------------------20</span></span><br></pre></td></tr></table></figure><p> 大部分的语言,t1被调用执行,则申请内存,并把其局部变量age, push入栈,t1函数执行完毕,内部的局部变量,随着函数的退出而销毁.因此age = 20 的局部变量已经消失了;<br> 但是在js中,age = 20 这个变量,却被t2捕捉,即使t1执行完毕,通过t2仍然可以访问t2依然可以访问该变量。这也是实现上面的访问局部变量。</p><p> 再来看一下,这个情形的过程,引入js闭包的知识点。<br> 在js中,t1执行过程中又生成了t2,而作用域上来说,t2能访问到age = 20,于是age = 20 不会消失,而是与返回的t1函数形成了一个环境包,这个包是t2的<strong>(把其周围的变量环境形成了封闭的环境包 共同返回)</strong>,即使t1执行完毕,通过t2仍然可以访问t1依然可以访问该变量,这就是闭包!!!<br><strong>小桃花穿越</strong></p><figure class="highlight javascript"><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="function"><span class="keyword">function</span> <span class="title">closure</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">var</span> sister = <span class="string">'大桃花'</span>;</span><br><span class="line"> <span class="keyword">var</span> me = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</span><br><span class="line"> alert(sister);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> me;</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">place</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">var</span> sister = <span class="string">'清朝大福晋'</span>;</span><br><span class="line"> <span class="keyword">var</span> girl = closure();</span><br><span class="line"> girl();</span><br><span class="line">}</span><br><span class="line">place();<span class="comment">//------------------------------大桃花</span></span><br></pre></td></tr></table></figure><h3 id="五、闭包计数器"><a href="#五、闭包计数器" class="headerlink" title="五、闭包计数器"></a>五、闭包计数器</h3><p>闭包来维护一个别人污染不到的变量 做计数器</p><figure class="highlight javascript"><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">var</span> fn = (<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">var</span> cnt = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">return</span> ++cnt;</span><br><span class="line"> }</span><br><span class="line"> })();</span><br><span class="line">alert(fn());<span class="comment">//------------------1</span></span><br><span class="line">alert(fn());<span class="comment">//------------------2</span></span><br><span class="line">alert(fn());<span class="comment">//------------------3</span></span><br></pre></td></tr></table></figure><p>这里放一个经典的案例就也不搬过来了。<a href="https://blog.csdn.net/Tacks/article/details/78704922" target="_blank" rel="noopener">https://blog.csdn.net/Tacks/article/details/78704922</a></p><h2 id="Stack-Heap"><a href="#Stack-Heap" class="headerlink" title="Stack Heap"></a>Stack Heap</h2><p>一开始了解的stack栈就是<strong>上进上出 先入后出</strong>这样子,也不想搬运别人博客了就放一个链接<a href="https://www.jianshu.com/p/90808ed34b86" target="_blank" rel="noopener">https://www.jianshu.com/p/90808ed34b86</a></p><p>heap堆之前了解并不多来搬运一下博客链接吧。<a href="https://blog.csdn.net/qian3223/article/details/82424757" target="_blank" rel="noopener">https://blog.csdn.net/qian3223/article/details/82424757</a></p><h2 id="Types-of-JavaScript-variables"><a href="#Types-of-JavaScript-variables" class="headerlink" title="Types of JavaScript variables"></a>Types of JavaScript variables</h2><p> <code>var</code>关键字是JavaScript创造开始时的一部分,然而<code>let</code>和<code>const</code>关键字的在ES6版本中更新的产物。</p><h3 id="变量易变性(variables-mutability)"><a href="#变量易变性(variables-mutability)" class="headerlink" title="变量易变性(variables mutability)"></a>变量易变性(variables mutability)</h3><p> 如果我们按照变量区分他们,<code>const</code>则与剩余的两个有很大区别。所有以<code>const</code>声明的变量都是不可改变的。那么以剩下两个关键字声明的变量都可以反复改变很多次的值。</p><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> firstConst = <span class="string">"samurai"</span>;</span><br><span class="line">assert(firstConst === <span class="string">"samurai"</span>,<span class="string">"firstConst is a samruai"</span>);</span><br><span class="line"><span class="keyword">try</span>{</span><br><span class="line">firstConst = <span class="string">"ninja"</span>;</span><br><span class="line"> fail(<span class="string">"Shouldn't be here"</span>);</span><br><span class="line">}<span class="keyword">catch</span>(e){</span><br><span class="line"> pass(<span class="string">"An exception has occurred"</span>);</span><br><span class="line">}</span><br><span class="line">assert(firstConst === <span class="string">"samurai"</span>,<span class="string">"firstCount is still a samuerai"</span>);</span><br><span class="line"><span class="keyword">const</span> secondConst = {};</span><br><span class="line">secondConst.weapon = <span class="string">"wakizashi"</span>;</span><br><span class="line">assert(secondConst.weapon === <span class="string">"wakizashi"</span>,<span class="string">"We can add new properties"</span>);</span><br><span class="line"><span class="keyword">const</span> thirdConst = [];</span><br><span class="line">assert(thirdConst.length === <span class="number">0</span>, <span class="string">"No items in our array"</span>);</span><br><span class="line">thirdConst.push(<span class="string">"Yoshi"</span>);</span><br><span class="line">assert(thirdConst.length === <span class="number">1</span>, <span class="string">"The array has changed"</span>);</span><br></pre></td></tr></table></figure><p> 首先,我们声明且初始化了<code>firstConst</code>变量为<code>samurai</code>,我们继续给他赋一个全新的值<code>ninja</code>,因为<code>firstConst</code>是一个常量,所以我们<code>ninja</code>赋值失败。所以,<code>JavaScript</code>的引擎会丢出一个<code>exception</code>事件,我们用到<code>fail</code>和<code>pass</code>方法(这两者和<code>assert</code>类似)来测试<code>exception</code>事件是否发生了。如果<code>exception</code>发生了,<code>catch</code>语句会被激活,然后<code>pass</code>语句也就被执行了。反之,<code>fail</code>语句就会被执行。</p><p> 再而,我们声明一个空对象<code>secondConst</code>和空数组<code>thirdCosnt</code>。我们已经知道了不能改变常量的值,但是我们可以给它增添属性。</p><h3 id="变量声明关键字和词法作用域"><a href="#变量声明关键字和词法作用域" class="headerlink" title="变量声明关键字和词法作用域"></a>变量声明关键字和词法作用域</h3><p> 不同关键字声明有不同的作用域,这一部分比较简单,总的来说,就是<code>var</code>无论在哪儿声明都是以最近的函数作用域或者全局作用域,而<code>const</code>和<code>let</code>可以为块作用域。</p><figure class="highlight javascript"><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="function"><span class="keyword">function</span>(<span class="params"></span>)</span>{</span><br><span class="line"> <span class="keyword">var</span> local = <span class="string">''</span>;</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">var</span> i = <span class="number">0</span>;i < <span class="number">10</span>;i++);</span><br><span class="line"> assert(i == <span class="number">10</span>,<span class="string">"i is ten"</span>);</span><br><span class="line">}</span><br><span class="line">assert(<span class="keyword">typeof</span> i === <span class="string">"undefined"</span>,<span class="string">"We cannot see function variables outside of a function"</span>);</span><br></pre></td></tr></table></figure><h3 id="在词法作用域中的寄存(状态提升)"><a href="#在词法作用域中的寄存(状态提升)" class="headerlink" title="在词法作用域中的寄存(状态提升)"></a>在词法作用域中的寄存(状态提升)</h3><p> 在<code>JavaScript</code>中,代码的执行分为两个阶段。第一阶段为<code>JavaScript</code>引擎会把所有声明变量和函数声明在当前的词法环境内提前。第二阶段为执行阶段,由函数调用执行或者赋值时开始。其中,<code>var</code> <code>function</code> 只是对变量声明,没有赋值操作。</p>]]></content>
</entry>
</search>