-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
451 lines (270 loc) · 304 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>何庆畅的个人博客|ChangerHe's Blog</title>
<subtitle>Keep Hungry, Keep Foolish.</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://blog.changerhe.cn/"/>
<updated>2018-08-12T10:44:17.509Z</updated>
<id>http://blog.changerhe.cn/</id>
<author>
<name>ChangerHe</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>kafka的基本概念和安装步骤</title>
<link href="http://blog.changerhe.cn/2018/08/02/kafka%E7%9A%84%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5%E5%92%8C%E5%AE%89%E8%A3%85%E6%AD%A5%E9%AA%A4/"/>
<id>http://blog.changerhe.cn/2018/08/02/kafka的基本概念和安装步骤/</id>
<published>2018-08-02T15:52:52.000Z</published>
<updated>2018-08-12T10:44:17.509Z</updated>
<content type="html"><![CDATA[<h2 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h2><p>Kafka是一个分布式的、可分区的、可复制的消息系统。它提供了普通消息系统的功能,但具有自己独特的设计。</p><h2 id="基本的消息系统术语"><a href="#基本的消息系统术语" class="headerlink" title="基本的消息系统术语"></a>基本的消息系统术语</h2><p>Kafka将消息以topic为单位进行归纳。</p><p>将向Kafka topic发布消息的程序成为producers.</p><p>将预订topics并消费消息的程序成为consumer.</p><p>Kafka以集群的方式运行,可以由一个或多个服务组成,每个服务叫做一个broker.</p><p>producers通过网络将消息发送到Kafka集群,集群向消费者提供消息</p><h2 id="topic和logs"><a href="#topic和logs" class="headerlink" title="topic和logs"></a>topic和logs</h2><p>一个topic是一组消息的归纳, 对每个topic, kafuka对它的日志进行了分区</p><p><img src="http://www.linuxidc.com/upload/2014_07/140721072031171.png" alt=""></p><p>每个分区都由一系列有序的、不可变的消息组成,这些消息被连续的追加到分区中。分区中的每个消息都有一个连续的序列号叫做offset,用来在分区中唯一的标识这个消息。</p><p>在一个可配置的时间内, kafuka集群保留所有发布的消息, 不管这些消息有没有被消费, 比如, 如果消息的保存策略被设置为2天, 那么在一个消息被发布的两天时间内, 它都是可以被消费的. 之后它将被丢弃以释放空间.</p><p>kafuka的性能是和数据量无关的常量级的, 所以保留太多的数据并不是问题</p><p>实际上每个consumer唯一需要维护的数据是消息在日志中的位置, 也就是offset, 这个offset有consumer来维护; 一般情况下随着consumer不断的读取消息, 这个offset的值不断增加, 但其实consumer可以以任意的顺序读取消息, 比如它可以把offset设置为一个旧的值来重读之前的消息</p><h2 id="分布式"><a href="#分布式" class="headerlink" title="分布式"></a>分布式</h2><p>每个分区在kafuka集群的若干服务中都有副本, 这样有些持有副本的服务可以共同处理数据和请求, 副本数量是可以配置的, 副本使kafuka具备了容错能力</p><p>每个分区都由一个服务器作为leader, 零或若干服务器作为follwers, leader负责处理消息的读和写, follwer则去复制leader, 如果leader down了, follwer中的一台则会自动成为leader, 集群中的每个服务都会同事扮演两个角色: 作为它所持有的一部分分区的leader, 同事作为其他分区的follwers, 这样集群就会有较好的负载均衡</p><h2 id="producers"><a href="#producers" class="headerlink" title="producers"></a>producers</h2><p>producer将消息发布到它指定的topic中, 并负责决定发布到哪个分区</p><h2 id="consumers"><a href="#consumers" class="headerlink" title="consumers"></a>consumers</h2><p>本质上kafuka只支持topic, 每个consumer属于一个consumer group, 反过来说, 每个group可以有多个consumer, 发送到topic的消息, 只会被订阅此topic的每个group中的consumer消费</p><p>如果所有的consumer都具有相同的group, 这种情况和</p><h2 id="kafka安装"><a href="#kafka安装" class="headerlink" title="kafka安装"></a>kafka安装</h2><p>下载kafka/zookeeper</p><p>解压</p><figure class="highlight plain"><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">tar zxf kafka_2.11-0.11.0.3.tgz</span><br><span class="line">tar zxf zookeeper-3.4.13.tar.gz</span><br></pre></td></tr></table></figure><p>进入zookeeper, 复制zoo.cfg</p><figure class="highlight plain"><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">cd zookeeper-3.4.13</span><br><span class="line">cp conf/zoo_sample.cfg conf/zoo.cfg</span><br></pre></td></tr></table></figure><p>启动zookeeper</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">bin/zkServer.sh start</span><br></pre></td></tr></table></figure><p>进入kafka<br><figure class="highlight plain"><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><br><span class="line">cd kafka_2.11-0.11.0.3</span><br></pre></td></tr></table></figure></p><p>编辑config中的server.properties</p><p>修改</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vi config/server.properties</span><br></pre></td></tr></table></figure><p>listeners为当前的host加端口</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">listeners=PLAINTEXT://192.168.1.120:9092</span><br></pre></td></tr></table></figure><p>启动kafka, 并使其在后台运行</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">bin/kafka-server-start.sh config/server.properties &</span><br></pre></td></tr></table></figure><p>此时两个服务就启动好了, 使用telnet测试一下</p><figure class="highlight plain"><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">telnet 192.168.1.120 9092</span><br><span class="line">telnet 192.168.1.120 2181</span><br></pre></td></tr></table></figure><p>启动测试producer服务</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">bin/kafka-console-producer.sh --broker-list 192.168.1.120:9092 --topic test</span><br></pre></td></tr></table></figure><p>我们再开启另一个端口, 启动consumer测试服务</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">bin/kafka-console-consumer.sh --zookeeper 192.168.1.120:2181 --topic test</span><br></pre></td></tr></table></figure><p>此时我们通过producer中发送的任意请求, 都可以在consumer的测试服务中获取到对应信息</p>]]></content>
<summary type="html">
Kafka是一个分布式的、可分区的、可复制的消息系统。它提供了普通消息系统的功能,但具有自己独特的设计。
</summary>
<category term="kafka" scheme="http://blog.changerhe.cn/tags/kafka/"/>
</entry>
<entry>
<title>React-Native之工程打包</title>
<link href="http://blog.changerhe.cn/2018/05/20/React-Native%E4%B9%8B%E5%B7%A5%E7%A8%8B%E6%89%93%E5%8C%85/"/>
<id>http://blog.changerhe.cn/2018/05/20/React-Native之工程打包/</id>
<published>2018-05-20T12:11:03.000Z</published>
<updated>2018-08-12T11:04:34.709Z</updated>
<content type="html"><![CDATA[<h1 id="android"><a href="#android" class="headerlink" title="android"></a>android</h1><p>生成秘钥</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000</span><br></pre></td></tr></table></figure><p>1、使用keytool命令生成证书:<br>-genkey </p><p>-alias my-key-alias(别名)</p><p>-keypass 123456(别名密码)</p><p>-keyalg RSA(算法)</p><p>-keysize 2048(密钥长度)</p><p>-validity 10000(有效期,天单位)</p><p>-keystore D:/keys/tomcat.keystore(指定生成证书的位置和证书名称)</p><p>-storepass 123456(获取keystore信息的密码)</p><p>这条命令会要求你输入密钥库(keystore)和对应密钥的密码,然后设置一些发行相关的信息。最后它会生成一个叫做my-release-key.keystore的密钥库文件。</p><h2 id="设置gradle变量"><a href="#设置gradle变量" class="headerlink" title="设置gradle变量"></a>设置gradle变量</h2><p>把my-release-key.keystore文件放到你工程中的android/app文件夹下。</p><p>2.编辑~/.gradle/gradle. properties或../android/gradle.properties(一个是全局gradle.properties,一个是项目中的gradle.properties,大家可以根据需要进行修改) ,加入如下代码:</p><figure class="highlight plain"><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">MYAPP_RELEASE_STORE_FILE=your keystore filename </span><br><span class="line">MYAPP_RELEASE_KEY_ALIAS=your keystore alias </span><br><span class="line">MYAPP_RELEASE_STORE_PASSWORD=***** </span><br><span class="line">MYAPP_RELEASE_KEY_PASSWORD=*****</span><br></pre></td></tr></table></figure><p>提示:用正确的证书密码、alias以及key密码替换掉 *。</p><h2 id="在gradle配置文件中添加签名配置"><a href="#在gradle配置文件中添加签名配置" class="headerlink" title="在gradle配置文件中添加签名配置"></a>在gradle配置文件中添加签名配置</h2><p>编辑 android/app/build.gradle文件添加如下代码:</p><figure class="highlight plain"><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">android { </span><br><span class="line"> ... </span><br><span class="line"> defaultConfig { ... } </span><br><span class="line"> signingConfigs { </span><br><span class="line"> release { </span><br><span class="line"> storeFile file(MYAPP_RELEASE_STORE_FILE) </span><br><span class="line"> storePassword MYAPP_RELEASE_STORE_PASSWORD </span><br><span class="line"> keyAlias MYAPP_RELEASE_KEY_ALIAS </span><br><span class="line"> keyPassword MYAPP_RELEASE_KEY_PASSWORD </span><br><span class="line"> } </span><br><span class="line"> } </span><br><span class="line"> buildTypes { </span><br><span class="line"> release { </span><br><span class="line"> ... </span><br><span class="line"> signingConfig signingConfigs.release </span><br><span class="line"> } </span><br><span class="line"> } </span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>主要点在于<code>signConfigs</code>的配置</p><h2 id="通过rn命令生成bundle文件"><a href="#通过rn命令生成bundle文件" class="headerlink" title="通过rn命令生成bundle文件"></a>通过rn命令生成bundle文件</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">React-native bundle --entry-file index.Android.js --bundle-output ./android/app/src/main/assets/index.android.jsbundle --platform android --assets-dest ./android/app/src/main/res/ --dev false</span><br></pre></td></tr></table></figure><p>–entry-file Path to the root JS file, either absolute or relative to JS root [required] (入口文件)</p><p>–platform Either “iOS” or “Android”(平台)</p><p>–transformer Specify a custom transformer to be used (absolute path) [default: “/Users/babytree-mbp13/projects/xcodeProjects/AwesomeProject/node_modules/React-native/packager/transformer.js”]</p><p>–dev If false, warnings are disabled and the bundle is minified [default: true] (是否为开发环境, 正式环境为false, 正式环境则禁用掉warning且压缩bundle)</p><p>–prepack If true, the output bundle will use the Prepack format. [default: false]</p><p>–bridge-config File name of a a JSON export of __fbBatchedBridgeConfig. Used by Prepack. Ex. ./bridgeconfig.json</p><p>–bundle-output File name where to store the resulting bundle, ex. /tmp/groups.bundle [required]</p><p>–bundle-encoding Encoding the bundle should be written in (<a href="https://nodejs.org/api/buffer.html#buffer_buffer)" target="_blank" rel="noopener">https://nodejs.org/api/buffer.html#buffer_buffer)</a>. [default: “utf8”]</p><p>–sourcemap-output File name where to store the sourcemap file for resulting bundle, ex. /tmp/groups.map</p><p>–assets-dest Directory name where to store assets referenced in the bundle</p><p>–verbose Enables logging [default: false]</p><h2 id="编译apk"><a href="#编译apk" class="headerlink" title="编译apk"></a>编译apk</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cd android && ./gradlew assembleRelease</span><br></pre></td></tr></table></figure><h1 id="ios"><a href="#ios" class="headerlink" title="ios"></a>ios</h1><p>需要使用apple开发者账号, 并生成秘钥并进行app证书签名, 步骤较复杂, 博主暂未走通, 所以就不赘述了…</p>]]></content>
<summary type="html">
React-Native之工程打包
</summary>
<category term="React-Native" scheme="http://blog.changerhe.cn/categories/React-Native/"/>
<category term="React-Native" scheme="http://blog.changerhe.cn/tags/React-Native/"/>
</entry>
<entry>
<title>React-Native之react-navigation(v2)</title>
<link href="http://blog.changerhe.cn/2018/04/19/React-Native%E4%B9%8Breact-navigation(v2)/"/>
<id>http://blog.changerhe.cn/2018/04/19/React-Native之react-navigation(v2)/</id>
<published>2018-04-19T14:16:09.000Z</published>
<updated>2018-08-12T11:01:37.564Z</updated>
<content type="html"><![CDATA[<h2 id="createStackNavigator"><a href="#createStackNavigator" class="headerlink" title="createStackNavigator"></a>createStackNavigator</h2><p>使用<code>createStackNavigator</code>来创建页面的跳转栈路径进行追踪</p><h3 id="通过createStackNavigator来对路由进行配置"><a href="#通过createStackNavigator来对路由进行配置" class="headerlink" title="通过createStackNavigator来对路由进行配置"></a>通过createStackNavigator来对路由进行配置</h3><figure class="highlight plain"><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">const RootStack = createStackNavigator({</span><br><span class="line"> // 第一个对象用于对页面的路由表进行配置</span><br><span class="line"> Home: HomeScreen,</span><br><span class="line"> Details: DetailsScreen</span><br><span class="line">}, {</span><br><span class="line"> // 通过第二个参数来对页面进行精细化配置</span><br><span class="line"> // 配置页面进入的路由</span><br><span class="line"> initialRouteName: 'Home'</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line">export default class App extends React.Component {</span><br><span class="line"> render() {</span><br><span class="line"> return <RootStack /></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="路由页面跳转"><a href="#路由页面跳转" class="headerlink" title="路由页面跳转"></a>路由页面跳转</h3><p>页面的路由跳转可以通过多种方式, 其中一种最简单粗暴的方法就是通过<code>onPress</code>方法</p><figure class="highlight plain"><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">onPress = {</span><br><span class="line"> () => {</span><br><span class="line"> // 跳转其实就是调用父组件中navigator对象中的navigate方法</span><br><span class="line"> return this.props.navigation.navigate('Details')</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>上面是一个跳转到<code>Details</code>页面的方式, 还有其他几种方法</p><figure class="highlight plain"><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><br><span class="line">this.props.navigation.goBack()</span><br><span class="line">// 回到堆栈中的最顶层</span><br><span class="line">this.props.navigation.popToTop()</span><br></pre></td></tr></table></figure><p>另一点需要注意的是, 因为<code>react navigation</code>的机制问题, 当前页面中跳转当前页面, 是没有任何反应的</p><h3 id="路由的页面传参"><a href="#路由的页面传参" class="headerlink" title="路由的页面传参"></a>路由的页面传参</h3><p>通过对<code>navigate</code>方法传递第二个参数的方式, 可以实现页面跳转的参数传递</p><figure class="highlight plain"><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">this.props.navigation.navigate('Details', {</span><br><span class="line"> itemId: 86,</span><br><span class="line"> otherParam: 'anything you want here',</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p>同样的, 接收参数也是需要使用类似的方式</p><figure class="highlight plain"><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">const itemId = navigation.getParam('itemId', 'NO-ID');</span><br><span class="line">const otherParam = navigation.getParam('otherParam', 'some default value');</span><br></pre></td></tr></table></figure><p>通过<code>navigation</code>的<code>getParam</code>方法进行参数的接收, 第一个参数为参数名称, 第二个参数为默认值</p><h3 id="为页面增加页面参数"><a href="#为页面增加页面参数" class="headerlink" title="为页面增加页面参数"></a>为页面增加页面参数</h3><p>为页面增加参数可以直接使用<code>navigationOptions</code>, 对其进行赋值即可</p><figure class="highlight plain"><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">static navigationOptions = {</span><br><span class="line"> title: 'Detail'</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>同样的, 我们也可以使用函数的方式对title进行赋值</p><figure class="highlight plain"><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">static navigationOptions = ({navigation}) => {</span><br><span class="line"> return {</span><br><span class="line"> title: navigation.getParam('otherParam', 'a nested title')</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>由于这个特性, 我们就可以很方便地对页面的标题进行设置了, 比如说, 当我们点击某个按钮的时候</p><figure class="highlight plain"><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">onPress={</span><br><span class="line"> () => {</span><br><span class="line"> return this.props.navigation.setParams({</span><br><span class="line"> otherParam: 'changed'</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>点击之后重新设置了navigation中的参数</p><h3 id="为页面的标题增加自定义的样式"><a href="#为页面的标题增加自定义的样式" class="headerlink" title="为页面的标题增加自定义的样式"></a>为页面的标题增加自定义的样式</h3><p>直接为<code>navigationOptions</code>额外传递参数即可</p><figure class="highlight plain"><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><br><span class="line">headerStyle: {</span><br><span class="line"> backgroundColor: '#f4511e',</span><br><span class="line">},</span><br><span class="line">// 头部的标题颜色</span><br><span class="line">headerTintColor: '#fff',</span><br><span class="line">// 头部标题的样式</span><br><span class="line">headerTitleStyle: {</span><br><span class="line"> fontWeight: 'bold',</span><br><span class="line">},</span><br></pre></td></tr></table></figure><p>一般情况下, 我们的标题的样式在整个项目工程中是一样的, 所以此时我们可以直接在根路由中去为页面整体做样式的设置</p><figure class="highlight plain"><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">const RootStack = createStackNavigator({</span><br><span class="line"> Home: HomeScreen, // 通过createStackNavigator来进行页面的路由配置</span><br><span class="line"> Details: DetailsScreen</span><br><span class="line">}, {</span><br><span class="line"> initialRouteName: 'Home', // 初始默认的路由</span><br><span class="line"> navigationOptions: {</span><br><span class="line"> headerStyle: {</span><br><span class="line"> backgroundColor: '#f4511e',</span><br><span class="line"> },</span><br><span class="line"> headerTintColor: '#fff',</span><br><span class="line"> headerTitleStyle: {</span><br><span class="line"> fontWeight: 'bold',</span><br><span class="line"> },</span><br><span class="line"> },</span><br><span class="line">});</span><br></pre></td></tr></table></figure><h3 id="自定义跳转的标题图标"><a href="#自定义跳转的标题图标" class="headerlink" title="自定义跳转的标题图标"></a>自定义跳转的标题图标</h3><p>对于页面的标题, 图标, 按钮等功能, 我们都可以对其进行定制, 下面是定制我们的标题的样式的例子</p><figure class="highlight plain"><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><br><span class="line">class LogoTitle extends React.Component {</span><br><span class="line"> render() {</span><br><span class="line"> return (<Image</span><br><span class="line"> source={require('./assets/delete.png')}</span><br><span class="line"> style={{</span><br><span class="line"> width: 30,</span><br><span class="line"> height: 30</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">static navigationOptions = {</span><br><span class="line"> headerTitle: <LogoTitle />,</span><br><span class="line"> // 同样的, 对标题左侧和右侧, 也是一样可以进行设置的</span><br><span class="line"> headerRight: (</span><br><span class="line"> <Button</span><br><span class="line"> onPress={() => alert('This is a button!')}</span><br><span class="line"> title="Info"</span><br><span class="line"> color="#000"</span><br><span class="line"> /></span><br><span class="line"> ),</span><br><span class="line"> headerLeft: (</span><br><span class="line"> <Button</span><br><span class="line"> onPress={() => alert('This is a button!')}</span><br><span class="line"> title="Info"</span><br><span class="line"> color="#000"</span><br><span class="line"> /></span><br><span class="line"> ),</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="页面的标题向页面传参方式"><a href="#页面的标题向页面传参方式" class="headerlink" title="页面的标题向页面传参方式"></a>页面的标题向页面传参方式</h3><p>页面标题向页面内的传参方式稍复杂, 需要定义一个中间参数, 通过每次对中间参数函数的方式去调用页面内的函数</p><p>需要注意的是, 此时标题的<code>navigationOptions</code>必须为函数, 否则无法实现此功能</p><figure class="highlight plain"><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">const navigaionOptions = ({navigaion}) => {</span><br><span class="line"> const params = navigation.state.params || {}</span><br><span class="line"> return {</span><br><span class="line"> headerTitle: <LogoTitle />,</span><br><span class="line"> headerRight: (</span><br><span class="line"> <Button</span><br><span class="line"> onPress={params.increaseCount}</span><br><span class="line"> title="add one"</span><br><span class="line"> color="#000"</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">// state不需要放在constructor里面?</span><br><span class="line">state = {</span><br><span class="line"> count = 0</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// 在页面声明周期初始化的时候, 初始化设置increaseCount这个变量, 用于对页面进行初始化配置</span><br><span class="line">componentWillMount() {</span><br><span class="line"> this.props.navigation.setParams({</span><br><span class="line"> increaseCount: this._increaseCount</span><br><span class="line"> })</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">_increaseCount = () => {</span><br><span class="line"> this.setState({</span><br><span class="line"> count: this.state.count + 1</span><br><span class="line"> })</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="全屏模态框"><a href="#全屏模态框" class="headerlink" title="全屏模态框"></a>全屏模态框</h3><p>全屏模态框会暂时阻止原来页面的交互流程, 而直接开始模态框中的交互</p><p>我们对页面分为两个部分, 一个是页面分类, 另一个是模态框的分类</p><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">const MainStack = createStackNavigator({</span><br><span class="line"> Home: HomeScreen, // 通过createStackNavigator来进行页面的路由配置</span><br><span class="line"> Details: DetailsScreen</span><br><span class="line">}, {</span><br><span class="line"> initialRouteName: 'Home', // 初始默认的路由</span><br><span class="line"> navigationOptions: {</span><br><span class="line"> headerStyle: {</span><br><span class="line"> backgroundColor: '#f4511e',</span><br><span class="line"> },</span><br><span class="line"> headerTintColor: '#fff',</span><br><span class="line"> headerTitleStyle: {</span><br><span class="line"> fontWeight: 'bold',</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">const RootStack = createStackNavigator(</span><br><span class="line"> {</span><br><span class="line"> // 页面堆栈</span><br><span class="line"> Main: {</span><br><span class="line"> screen: MainStack,</span><br><span class="line"> },</span><br><span class="line"> // 模态框堆栈</span><br><span class="line"> MyModal: {</span><br><span class="line"> screen: ModalScreen,</span><br><span class="line"> },</span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> mode: 'modal',</span><br><span class="line"> headerMode: 'none',</span><br><span class="line"> }</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line">export default class App extends React.Component {</span><br><span class="line"> render() {</span><br><span class="line"> return <RootStack/>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这样配置好之后, 需要使用modal全屏页面的时候, 直接调用跳转逻辑即可</p><figure class="highlight plain"><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><br><span class="line"><Button</span><br><span class="line"> title = "Go to Modal"</span><br><span class="line"> onPress = {</span><br><span class="line"> () => this.props.navigation.navigate('MyModal')</span><br><span class="line"> }</span><br><span class="line">/></span><br></pre></td></tr></table></figure><h2 id="tab导航"><a href="#tab导航" class="headerlink" title="tab导航"></a>tab导航</h2><p>tab导航的定义方式很简单, 通过从react-navigation中引入不同的配置函数即可</p><figure class="highlight plain"><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">import {createBottomTabNavigator} from 'react-navigation';</span><br><span class="line"></span><br><span class="line">// 定义页面的tab堆栈</span><br><span class="line">const TabStack = createBottomTabNavigator({</span><br><span class="line"> // 定义的键值对中, 键名默认为tab的名称, 可在页面中定义title来覆盖这个名称</span><br><span class="line"> Home111: HomeScreen, </span><br><span class="line"> Details: SettingsScreen</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line">// 同样的, 将这个堆栈从app根组件中渲染即可</span><br><span class="line">export default class App extends React.Component {</span><br><span class="line"> render() {</span><br><span class="line"> return <TabStack/>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="抽屉导航"><a href="#抽屉导航" class="headerlink" title="抽屉导航"></a>抽屉导航</h2>]]></content>
<summary type="html">
react-navigation是react-native生态圈中比较重要的组件之一, 提供给了react-native应用原生的页面跳转能力
</summary>
<category term="React-Native" scheme="http://blog.changerhe.cn/categories/React-Native/"/>
<category term="React-Native" scheme="http://blog.changerhe.cn/tags/React-Native/"/>
</entry>
<entry>
<title>Eslint配置条件参考</title>
<link href="http://blog.changerhe.cn/2018/04/15/Eslint%E9%85%8D%E7%BD%AE%E6%9D%A1%E4%BB%B6%E5%8F%82%E8%80%83/"/>
<id>http://blog.changerhe.cn/2018/04/15/Eslint配置条件参考/</id>
<published>2018-04-15T15:11:34.000Z</published>
<updated>2018-08-12T10:55:37.701Z</updated>
<content type="html"><![CDATA[<figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> "no-alert": 0,//禁止使用alert confirm prompt</span><br><span class="line"> "no-array-constructor": 2,//禁止使用数组构造器</span><br><span class="line"> "no-bitwise": 0,//禁止使用按位运算符</span><br><span class="line"> "no-caller": 1,//禁止使用arguments.caller或arguments.callee</span><br><span class="line"> "no-catch-shadow": 2,//禁止catch子句参数与外部作用域变量同名</span><br><span class="line"> "no-class-assign": 2,//禁止给类赋值</span><br><span class="line"> "no-cond-assign": 2,//禁止在条件表达式中使用赋值语句</span><br><span class="line"> "no-console": 2,//禁止使用console</span><br><span class="line"> "no-const-assign": 2,//禁止修改const声明的变量</span><br><span class="line"> "no-constant-condition": 2,//禁止在条件中使用常量表达式 if(true) if(1)</span><br><span class="line"> "no-continue": 0,//禁止使用continue</span><br><span class="line"> "no-control-regex": 2,//禁止在正则表达式中使用控制字符</span><br><span class="line"> "no-debugger": 2,//禁止使用debugger</span><br><span class="line"> "no-delete-var": 2,//不能对var声明的变量使用delete操作符</span><br><span class="line"> "no-div-regex": 1,//不能使用看起来像除法的正则表达式/=foo/</span><br><span class="line"> "no-dupe-keys": 2,//在创建对象字面量时不允许键重复 {a:1,a:1}</span><br><span class="line"> "no-dupe-args": 2,//函数参数不能重复</span><br><span class="line"> "no-duplicate-case": 2,//switch中的case标签不能重复</span><br><span class="line"> "no-else-return": 2,//如果if语句里面有return,后面不能跟else语句</span><br><span class="line"> "no-empty": 2,//块语句中的内容不能为空</span><br><span class="line"> "no-empty-character-class": 2,//正则表达式中的[]内容不能为空</span><br><span class="line"> "no-empty-label": 2,//禁止使用空label</span><br><span class="line"> "no-eq-null": 2,//禁止对null使用==或!=运算符</span><br><span class="line"> "no-eval": 1,//禁止使用eval</span><br><span class="line"> "no-ex-assign": 2,//禁止给catch语句中的异常参数赋值</span><br><span class="line"> "no-extend-native": 2,//禁止扩展native对象</span><br><span class="line"> "no-extra-bind": 2,//禁止不必要的函数绑定</span><br><span class="line"> "no-extra-boolean-cast": 2,//禁止不必要的bool转换</span><br><span class="line"> "no-extra-parens": 2,//禁止非必要的括号</span><br><span class="line"> "no-extra-semi": 2,//禁止多余的冒号</span><br><span class="line"> "no-fallthrough": 1,//禁止switch穿透</span><br><span class="line"> "no-floating-decimal": 2,//禁止省略浮点数中的0 .5 3.</span><br><span class="line"> "no-func-assign": 2,//禁止重复的函数声明</span><br><span class="line"> "no-implicit-coercion": 1,//禁止隐式转换</span><br><span class="line"> "no-implied-eval": 2,//禁止使用隐式eval</span><br><span class="line"> "no-inline-comments": 0,//禁止行内备注</span><br><span class="line"> "no-inner-declarations": [2, "functions"],//禁止在块语句中使用声明(变量或函数)</span><br><span class="line"> "no-invalid-regexp": 2,//禁止无效的正则表达式</span><br><span class="line"> "no-invalid-this": 2,//禁止无效的this,只能用在构造器,类,对象字面量</span><br><span class="line"> "no-irregular-whitespace": 2,//不能有不规则的空格</span><br><span class="line"> "no-iterator": 2,//禁止使用__iterator__ 属性</span><br><span class="line"> "no-label-var": 2,//label名不能与var声明的变量名相同</span><br><span class="line"> "no-labels": 2,//禁止标签声明</span><br><span class="line"> "no-lone-blocks": 2,//禁止不必要的嵌套块</span><br><span class="line"> "no-lonely-if": 2,//禁止else语句内只有if语句</span><br><span class="line"> "no-loop-func": 1,//禁止在循环中使用函数(如果没有引用外部变量不形成闭包就可以)</span><br><span class="line"> "no-mixed-requires": [0, false],//声明时不能混用声明类型</span><br><span class="line"> "no-mixed-spaces-and-tabs": [2, false],//禁止混用tab和空格</span><br><span class="line"> "linebreak-style": [0, "windows"],//换行风格</span><br><span class="line"> "no-multi-spaces": 1,//不能用多余的空格</span><br><span class="line"> "no-multi-str": 2,//字符串不能用\换行</span><br><span class="line"> "no-multiple-empty-lines": [1, {"max": 2}],//空行最多不能超过2行</span><br><span class="line"> "no-native-reassign": 2,//不能重写native对象</span><br><span class="line"> "no-negated-in-lhs": 2,//in 操作符的左边不能有!</span><br><span class="line"> "no-nested-ternary": 0,//禁止使用嵌套的三目运算</span><br><span class="line"> "no-new": 1,//禁止在使用new构造一个实例后不赋值</span><br><span class="line"> "no-new-func": 1,//禁止使用new Function</span><br><span class="line"> "no-new-object": 2,//禁止使用new Object()</span><br><span class="line"> "no-new-require": 2,//禁止使用new require</span><br><span class="line"> "no-new-wrappers": 2,//禁止使用new创建包装实例,new String new Boolean new Number</span><br><span class="line"> "no-obj-calls": 2,//不能调用内置的全局对象,比如Math() JSON()</span><br><span class="line"> "no-octal": 2,//禁止使用八进制数字</span><br><span class="line"> "no-octal-escape": 2,//禁止使用八进制转义序列</span><br><span class="line"> "no-param-reassign": 2,//禁止给参数重新赋值</span><br><span class="line"> "no-path-concat": 0,//node中不能使用__dirname或__filename做路径拼接</span><br><span class="line"> "no-plusplus": 0,//禁止使用++,--</span><br><span class="line"> "no-process-env": 0,//禁止使用process.env</span><br><span class="line"> "no-process-exit": 0,//禁止使用process.exit()</span><br><span class="line"> "no-proto": 2,//禁止使用__proto__属性</span><br><span class="line"> "no-redeclare": 2,//禁止重复声明变量</span><br><span class="line"> "no-regex-spaces": 2,//禁止在正则表达式字面量中使用多个空格 /foo bar/</span><br><span class="line"> "no-restricted-modules": 0,//如果禁用了指定模块,使用就会报错</span><br><span class="line"> "no-return-assign": 1,//return 语句中不能有赋值表达式</span><br><span class="line"> "no-script-url": 0,//禁止使用javascript:void(0)</span><br><span class="line"> "no-self-compare": 2,//不能比较自身</span><br><span class="line"> "no-sequences": 0,//禁止使用逗号运算符</span><br><span class="line"> "no-shadow": 2,//外部作用域中的变量不能与它所包含的作用域中的变量或参数同名</span><br><span class="line"> "no-shadow-restricted-names": 2,//严格模式中规定的限制标识符不能作为声明时的变量名使用</span><br><span class="line"> "no-spaced-func": 2,//函数调用时 函数名与()之间不能有空格</span><br><span class="line"> "no-sparse-arrays": 2,//禁止稀疏数组, [1,,2]</span><br><span class="line"> "no-sync": 0,//nodejs 禁止同步方法</span><br><span class="line"> "no-ternary": 0,//禁止使用三目运算符</span><br><span class="line"> "no-trailing-spaces": 1,//一行结束后面不要有空格</span><br><span class="line"> "no-this-before-super": 0,//在调用super()之前不能使用this或super</span><br><span class="line"> "no-throw-literal": 2,//禁止抛出字面量错误 throw "error";</span><br><span class="line"> "no-undef": 1,//不能有未定义的变量</span><br><span class="line"> "no-undef-init": 2,//变量初始化时不能直接给它赋值为undefined</span><br><span class="line"> "no-undefined": 2,//不能使用undefined</span><br><span class="line"> "no-unexpected-multiline": 2,//避免多行表达式</span><br><span class="line"> "no-underscore-dangle": 1,//标识符不能以_开头或结尾</span><br><span class="line"> "no-unneeded-ternary": 2,//禁止不必要的嵌套 var isYes = answer === 1 ? true : false;</span><br><span class="line"> "no-unreachable": 2,//不能有无法执行的代码</span><br><span class="line"> "no-unused-expressions": 2,//禁止无用的表达式</span><br><span class="line"> "no-unused-vars": [2, {"vars": "all", "args": "after-used"}],//不能有声明后未被使用的变量或参数</span><br><span class="line"> "no-use-before-define": 2,//未定义前不能使用</span><br><span class="line"> "no-useless-call": 2,//禁止不必要的call和apply</span><br><span class="line"> "no-void": 2,//禁用void操作符</span><br><span class="line"> "no-var": 0,//禁用var,用let和const代替</span><br><span class="line"> "no-warning-comments": [1, { "terms": ["todo", "fixme", "xxx"], "location": "start" }],//不能有警告备注</span><br><span class="line"> "no-with": 2,//禁用with</span><br><span class="line"></span><br><span class="line"> "array-bracket-spacing": [2, "never"],//是否允许非空数组里面有多余的空格</span><br><span class="line"> "arrow-parens": 0,//箭头函数用小括号括起来</span><br><span class="line"> "arrow-spacing": 0,//=>的前/后括号</span><br><span class="line"> "accessor-pairs": 0,//在对象中使用getter/setter</span><br><span class="line"> "block-scoped-var": 0,//块语句中使用var</span><br><span class="line"> "brace-style": [1, "1tbs"],//大括号风格</span><br><span class="line"> "callback-return": 1,//避免多次调用回调什么的</span><br><span class="line"> "camelcase": 2,//强制驼峰法命名</span><br><span class="line"> "comma-dangle": [2, "never"],//对象字面量项尾不能有逗号</span><br><span class="line"> "comma-spacing": 0,//逗号前后的空格</span><br><span class="line"> "comma-style": [2, "last"],//逗号风格,换行时在行首还是行尾</span><br><span class="line"> "complexity": [0, 11],//循环复杂度</span><br><span class="line"> "computed-property-spacing": [0, "never"],//是否允许计算后的键名什么的</span><br><span class="line"> "consistent-return": 0,//return 后面是否允许省略</span><br><span class="line"> "consistent-this": [2, "that"],//this别名</span><br><span class="line"> "constructor-super": 0,//非派生类不能调用super,派生类必须调用super</span><br><span class="line"> "curly": [2, "all"],//必须使用 if(){} 中的{}</span><br><span class="line"> "default-case": 2,//switch语句最后必须有default</span><br><span class="line"> "dot-location": 0,//对象访问符的位置,换行的时候在行首还是行尾</span><br><span class="line"> "dot-notation": [0, { "allowKeywords": true }],//避免不必要的方括号</span><br><span class="line"> "eol-last": 0,//文件以单一的换行符结束</span><br><span class="line"> "eqeqeq": 2,//必须使用全等</span><br><span class="line"> "func-names": 0,//函数表达式必须有名字</span><br><span class="line"> "func-style": [0, "declaration"],//函数风格,规定只能使用函数声明/函数表达式</span><br><span class="line"> "generator-star-spacing": 0,//生成器函数*的前后空格</span><br><span class="line"> "guard-for-in": 0,//for in循环要用if语句过滤</span><br><span class="line"> "handle-callback-err": 0,//nodejs 处理错误</span><br><span class="line"> "id-length": 0,//变量名长度</span><br><span class="line"> "indent": [2, 4],//缩进风格</span><br><span class="line"> "init-declarations": 0,//声明时必须赋初值</span><br><span class="line"> "key-spacing": [0, { "beforeColon": false, "afterColon": true }],//对象字面量中冒号的前后空格</span><br><span class="line"> "lines-around-comment": 0,//行前/行后备注</span><br><span class="line"> "max-depth": [0, 4],//嵌套块深度</span><br><span class="line"> "max-len": [0, 80, 4],//字符串最大长度</span><br><span class="line"> "max-nested-callbacks": [0, 2],//回调嵌套深度</span><br><span class="line"> "max-params": [0, 3],//函数最多只能有3个参数</span><br><span class="line"> "max-statements": [0, 10],//函数内最多有几个声明</span><br><span class="line"> "new-cap": 2,//函数名首行大写必须使用new方式调用,首行小写必须用不带new方式调用</span><br><span class="line"> "new-parens": 2,//new时必须加小括号</span><br><span class="line"> "newline-after-var": 2,//变量声明后是否需要空一行</span><br><span class="line"> "object-curly-spacing": [0, "never"],//大括号内是否允许不必要的空格</span><br><span class="line"> "object-shorthand": 0,//强制对象字面量缩写语法</span><br><span class="line"> "one-var": 1,//连续声明</span><br><span class="line"> "operator-assignment": [0, "always"],//赋值运算符 += -=什么的</span><br><span class="line"> "operator-linebreak": [2, "after"],//换行时运算符在行尾还是行首</span><br><span class="line"> "padded-blocks": 0,//块语句内行首行尾是否要空行</span><br><span class="line"> "prefer-const": 0,//首选const</span><br><span class="line"> "prefer-spread": 0,//首选展开运算</span><br><span class="line"> "prefer-reflect": 0,//首选Reflect的方法</span><br><span class="line"> "quotes": [1, "single"],//引号类型 `` "" ''</span><br><span class="line"> "quote-props":[2, "always"],//对象字面量中的属性名是否强制双引号</span><br><span class="line"> "radix": 2,//parseInt必须指定第二个参数</span><br><span class="line"> "id-match": 0,//命名检测</span><br><span class="line"> "require-yield": 0,//生成器函数必须有yield</span><br><span class="line"> "semi": [2, "always"],//语句强制分号结尾</span><br><span class="line"> "semi-spacing": [0, {"before": false, "after": true}],//分号前后空格</span><br><span class="line"> "sort-vars": 0,//变量声明时排序</span><br><span class="line"> "space-after-keywords": [0, "always"],//关键字后面是否要空一格</span><br><span class="line"> "space-before-blocks": [0, "always"],//不以新行开始的块{前面要不要有空格</span><br><span class="line"> "space-before-function-paren": [0, "always"],//函数定义时括号前面要不要有空格</span><br><span class="line"> "space-in-parens": [0, "never"],//小括号里面要不要有空格</span><br><span class="line"> "space-infix-ops": 0,//中缀操作符周围要不要有空格</span><br><span class="line"> "space-return-throw-case": 2,//return throw case后面要不要加空格</span><br><span class="line"> "space-unary-ops": [0, { "words": true, "nonwords": false }],//一元运算符的前/后要不要加空格</span><br><span class="line"> "spaced-comment": 0,//注释风格要不要有空格什么的</span><br><span class="line"> "strict": 2,//使用严格模式</span><br><span class="line"> "use-isnan": 2,//禁止比较时使用NaN,只能用isNaN()</span><br><span class="line"> "valid-jsdoc": 0,//jsdoc规则</span><br><span class="line"> "valid-typeof": 2,//必须使用合法的typeof的值</span><br><span class="line"> "vars-on-top": 2,//var必须放在作用域顶部</span><br><span class="line"> "wrap-iife": [2, "inside"],//立即执行函数表达式的小括号风格</span><br><span class="line"> "wrap-regex": 0,//正则表达式字面量用小括号包起来</span><br><span class="line"> "yoda": [2, "never"]//禁止尤达条件</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
Eslint配置条件参考
</summary>
<category term="Eslint" scheme="http://blog.changerhe.cn/tags/Eslint/"/>
</entry>
<entry>
<title>React-Native之动画</title>
<link href="http://blog.changerhe.cn/2018/04/02/React-Native%E4%B9%8B%E5%8A%A8%E7%94%BB/"/>
<id>http://blog.changerhe.cn/2018/04/02/React-Native之动画/</id>
<published>2018-04-02T11:53:12.000Z</published>
<updated>2018-08-12T11:06:46.658Z</updated>
<content type="html"><![CDATA[<h2 id="动画组成"><a href="#动画组成" class="headerlink" title="动画组成"></a>动画组成</h2><p>react-native提供了两个互补的动画系统: 用于全局的布局动画(LayoutAnimation), 和用于创建更精细交互的动画(Animated)</p><h3 id="animated"><a href="#animated" class="headerlink" title="animated"></a>animated</h3><p>Animated旨在以声明的形式来定义动画的输入与输出,在其中建立一个可配置的变化函数,然后使用简单的start/stop方法来控制动画按顺序执行。<br>Animated仅封装了四个可以动画化的组件:<code>View</code>、<code>Text</code>、<code>Image</code>和<code>ScrollView</code><br>不过可以使用<code>Animated.createAnimatedComponent()</code>来封装你自己的组件。</p><p>下面是一个简单的透明渐变动画的例子</p><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">// FadeInView.js</span><br><span class="line">import React, { Component } from 'react';</span><br><span class="line">import {</span><br><span class="line"> Animated,</span><br><span class="line">} from 'react-native';</span><br><span class="line"></span><br><span class="line">export default class FadeInView extends Component {</span><br><span class="line"> constructor(props) {</span><br><span class="line"> super(props);</span><br><span class="line"> this.state = {</span><br><span class="line"> // 透明度初始值设为0</span><br><span class="line"> fadeAnim: new Animated.Value(0),</span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line"> componentDidMount() {</span><br><span class="line"> // 随时间变化而执行的动画类型 </span><br><span class="line"> Animated.timing(</span><br><span class="line"> // 动画中的变量值</span><br><span class="line"> this.state.fadeAnim,</span><br><span class="line"> {</span><br><span class="line"> // 透明度最终变为1,即完全不透明</span><br><span class="line"> toValue: 1,</span><br><span class="line"> // 变化动画的总执行时间</span><br><span class="line"> duration: 3000</span><br><span class="line"> }</span><br><span class="line"> ).start(); // 开始执行动画</span><br><span class="line"> }</span><br><span class="line"> render() {</span><br><span class="line"> return (</span><br><span class="line"> // 可动画化的视图组件</span><br><span class="line"> <Animated.View</span><br><span class="line"> style={{</span><br><span class="line"> ...this.props.style,</span><br><span class="line"> // 将透明度指定为动画变量值</span><br><span class="line"> opacity: this.state.fadeAnim,</span><br><span class="line"> }}</span><br><span class="line"> ></span><br><span class="line"> {this.props.children}</span><br><span class="line"> </Animated.View></span><br><span class="line"> );</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>然后通过引入该组件, 并传入对应的style样式及子组件的方式就可以开始进行使用了</p><p>总体来说, 简单的动画就是用Animated.Value指定初始值, 此时要new一个对象,然后在Animated.timing中设置结束值,其他的交给React native让它自动创建,我们只需要调用start开始动画即可。</p><h2 id="常用的动画类"><a href="#常用的动画类" class="headerlink" title="常用的动画类"></a>常用的动画类</h2><h3 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h3><p>static decay(value, config) 阻尼,将一个值根据阻尼系数动画到 0</p><p>static timing(value, config 根据时间函数来处理,常见的比如线性,加速开始减速结束等等,支持自定义时间函数</p><p>static spring(value, config) 弹性动画</p><p>static add(a, b) 将两个Animated.value相加,返回一个新的</p><p>static multiply(a, b) 将两个Animated.value相乘,返回一个新的</p><p>static modulo(a, modulus),将a对modulus取余,类似操作符%</p><p>static delay(time)延迟一段时间</p><p>static sequence(animations) 依次开始一组动画,后一个在前一个结束后才会开始,如果其中一个动画中途停止,则整个动画组停止</p><p>static parallel(animations, config?),同时开始一组动画,默认一个动画中途停止,则全都停止。可以通过设置stopTogether来重写这一特性</p><p>static stagger(time, animations),一组动画可以同时执行,但是会按照延迟依次开始</p><p>static event(argMapping, config?),利用手势,Scroll来手动控制动画的状态</p><p>static createAnimatedComponent(Component),自定义的让某一个Component支持动画</p><h3 id="属性"><a href="#属性" class="headerlink" title="属性"></a>属性</h3><p>Value,类型是AnimatedValue,驱动基本动画</p><p>AnimatedValueXY,类型是AnimatedValueXY,驱动二维动画</p><h4 id="AnimatedValue类型"><a href="#AnimatedValue类型" class="headerlink" title="AnimatedValue类型"></a>AnimatedValue类型</h4><p>一个AnimatedValue一次可以驱动多个可动画属性,但是一个AnimatedValue一次只能由一个机制驱动。比如,一个Value可以同时动画View的透明度和位置,但是一个Value一次只能采用线性时间函数</p><h4 id="方法-1"><a href="#方法-1" class="headerlink" title="方法"></a>方法</h4><p>constructor(value) 构造器</p><p>setValue(value) 直接设置值,会导致动画终止</p><p>setOffset(offset) 设置当前的偏移量</p><p>flattenOffset() 将偏移量合并到最初值中,并把偏移量设为0,</p><p>addListener(callback) ,removeListener(id),removeAllListeners(),增加一个异步的动画监听者</p><p>stopAnimation(callback?) 终止动画,并在动画结束后执行callback</p><p>interpolate(config) 插值,在更新可动画属性前用插值函数对当前值进行变换</p><p>animate(animation, callback) 通常在React Native内部使用</p><p>stopTracking(),track(tracking) 通常在React Native内部使用</p><h5 id="AnimatedValueXY"><a href="#AnimatedValueXY" class="headerlink" title="AnimatedValueXY"></a>AnimatedValueXY</h5><p>和AnimatedValue类似,用在二维动画</p><h5 id="interpolate"><a href="#interpolate" class="headerlink" title="interpolate"></a>interpolate</h5><p>所以一般时间, 我们创建动画的基本流程是:</p><ol><li>在state中使用一个变量来存储我们new出来的动画的对象, 并赋予其初始值</li></ol><figure class="highlight plain"><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">tate = {</span><br><span class="line"> anim: new Animated.Value(0)</span><br><span class="line">};</span><br></pre></td></tr></table></figure><ol><li>当需要调用这个动画对象的时候, 我们使用动画对象的对应动画参数来进行调用</li></ol><figure class="highlight plain"><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">nimated.timing(</span><br><span class="line"> // 传入起始状态下的动画对象</span><br><span class="line"> this.state.anim, </span><br><span class="line"> // 传入结束状态的值, 当然, 这个值是可以变化的</span><br><span class="line"> // 通过变化的结束值, 就可以很方便地进行动画的循环了</span><br><span class="line"> { toValue: this.state.currentAlpha }</span><br><span class="line">).start();</span><br></pre></td></tr></table></figure><ol><li>对页面需要进行控制的动画对象进行处理, 目前可以处理的组件有: <code>Text</code>, <code>View</code>, <code>Image</code>, <code>ScrollView</code> , 我们将其写为<code>Animated</code>对象下面的属性形式以使动画正常生效</li></ol><figure class="highlight plain"><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"><Animated.Text style={{</span><br><span class="line"> // 当前组件的透明度参数, 直接设置为此对象值, 则代表直接获取到了此对象的value</span><br><span class="line"> opacity: this.state.anim, </span><br><span class="line"> // 这个和css3中的transform是一样的 </span><br><span class="line"> // 因为只有一个值在变, 所以我们这里需要为对应的内容设置范围值</span><br><span class="line"> transform: [</span><br><span class="line"> { </span><br><span class="line"> // 我们使用anim中的interpolate函数来进行页面数值的转换</span><br><span class="line"> translateY: this.state.anim.interpolate({</span><br><span class="line"> // 输入值的范围</span><br><span class="line"> inputRange: [0, 1],</span><br><span class="line"> // 输出值的范围</span><br><span class="line"> outputRange: [60, 0] //线性插值,0对应60,0.5对应30,1对应0</span><br><span class="line"> }),</span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> // 同样的, 缩放值也是与anim的value一致</span><br><span class="line"> scale: this.state.anim</span><br><span class="line"> },</span><br><span class="line"> ],</span><br><span class="line">}}></span><br></pre></td></tr></table></figure><p>一般作为一个变量, 我们会将其转换为范围值来对页面的样式进行控制</p>]]></content>
<summary type="html">
React-Native之动画
</summary>
<category term="React-Native" scheme="http://blog.changerhe.cn/categories/React-Native/"/>
<category term="React-Native" scheme="http://blog.changerhe.cn/tags/React-Native/"/>
</entry>
<entry>
<title>ReactNative的mac初始环境配置</title>
<link href="http://blog.changerhe.cn/2018/03/05/ReactNative%E7%9A%84mac%E5%88%9D%E5%A7%8B%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/"/>
<id>http://blog.changerhe.cn/2018/03/05/ReactNative的mac初始环境配置/</id>
<published>2018-03-05T15:43:27.000Z</published>
<updated>2018-08-12T10:41:42.113Z</updated>
<content type="html"><![CDATA[<h1 id="基本的环境安装"><a href="#基本的环境安装" class="headerlink" title="基本的环境安装"></a>基本的环境安装</h1><p>首先, 我们使用mac, 当然少不了安装它的开发工具xcode啦, xcode是mac下的ios客户端app开发利器, 我们如果不知道电脑中是否安装了xcode, 可以通过在vim中输入以下的内容进行检查</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xcode-select --install</span><br></pre></td></tr></table></figure><p>当我们正常安装了Xcode的时候会报错, 提示我们xcode已经正常安装, 但是当我们没有安装的时候, 这行命令就会帮我们进行安装xcode了</p><p>其次, 使用苹果开发, homebrew也是一必备利器, 我们需要使用它来安装watchman和flow</p><p>watchman是facebook的一个开源项目, 用它来监视文件并且记录文件的改动情况</p><p>flow是一个JavaScript静态类型检查器,用于找出JavaScript代码中的类型错误</p><p>最后, 我们需要安装一个<code>yarn</code>作为替代<code>npm</code>的工具, 来进行安装应用, 并设置yarn的默认安装路径为淘宝镜像, 设置好之后我们就可以直接通过使用yarn命令从淘宝国内站点请求到我们需要的数据了</p><figure class="highlight plain"><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">yarn config set registry https://registry.npm.taobao.org --global</span><br><span class="line">yarn config set disturl https://npm.taobao.org/dist --global</span><br></pre></td></tr></table></figure><p>安装完这些之后, 就可以先安装一个react-native脚手架出来玩一下啦</p><p>我们使用之前全局安装的react-native命令对脚手进行自动安装</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">react-native init MyAwesomeProject</span><br></pre></td></tr></table></figure><p>当我们需要指定版本的时候, 可以在后面加上一个<code>--version</code>参数, 后面加上版本号就可以安装对应版本的react-native工程了</p><p>安装好之后, 万事俱备只欠东风了, 现在我们进入到项目工程中, 把项目跑起来<br><figure class="highlight plain"><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">cd MyAwesomeProject</span><br><span class="line">react-native run-ios</span><br></pre></td></tr></table></figure></p><h2 id="注意-可能很多同学会和我一样在这里运行之后就只能看到一个ios的首界面了"><a href="#注意-可能很多同学会和我一样在这里运行之后就只能看到一个ios的首界面了" class="headerlink" title="注意, 可能很多同学会和我一样在这里运行之后就只能看到一个ios的首界面了"></a>注意, 可能很多同学会和我一样在这里运行之后就只能看到一个ios的首界面了</h2><p>为什么呢? 原因是因为最新版的react-native需要安装下载boost库, 而因为这个库过大, 所以很容易就导致下载出现问题</p><p>解决方案有两种, 第一是选择降级方案, 选择一个低版本的react-native进行安装, 当然, 这样做会牺牲掉一部分对最新版本特性的体验了</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">react-native init MyApp --version 0.44.3</span><br></pre></td></tr></table></figure><p>第二种方案是选择科学上网来将需要的内容下下来, 并复制到需要的地方</p><p>这里提供一个网上的大神提供的<img src="https://pan.baidu.com/s/1kV5iVzD" alt="下载地址"><br>在这里我们需要将下载内容替换一下</p>]]></content>
<summary type="html">
首先, 我们使用mac, 当然少不了安装它的开发工具xcode啦, xcode是mac下的ios客户端app开发利器, 我们如果不知道电脑中是否安装了xcode, 可以通过在vim中输入以下的内容进行检查
</summary>
</entry>
<entry>
<title>SASS学习进阶</title>
<link href="http://blog.changerhe.cn/2018/03/04/testForMac/"/>
<id>http://blog.changerhe.cn/2018/03/04/testForMac/</id>
<published>2018-03-04T11:37:41.000Z</published>
<updated>2018-03-04T11:40:10.039Z</updated>
<content type="html"><![CDATA[<h1 id="sass学习进阶"><a href="#sass学习进阶" class="headerlink" title="sass学习进阶"></a>sass学习进阶</h1><h2 id="if语句"><a href="#if语句" class="headerlink" title="@if语句"></a>@if语句</h2><p>@if是一个SassScript,它可以根据条件来处理样式快,如果条件为true则返回一个样式块,反之false返回另一个样式块。在sass中除了@if单独使用以外,还可以配合@else if 和@else 一起使用。<br><figure class="highlight plain"><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">@mixin blockOrHidden($boolean: true){</span><br><span class="line">@if $boolean{</span><br><span class="line">@debug "$boolean is #{$boolean}"; //@debug指令用于调试</span><br><span class="line">display: block;</span><br><span class="line">}</span><br><span class="line">@else {</span><br><span class="line">@debug "$boolean is #{$boolean}"; //@debug指令用于调试</span><br><span class="line">display: none;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">.block {</span><br><span class="line">@include blockOrHidden;</span><br><span class="line">}</span><br><span class="line">.hidden {</span><br><span class="line">@include blockOrHidden(false);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>编译出的css为<br><figure class="highlight plain"><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">.block {</span><br><span class="line">display: block;</span><br><span class="line">}</span><br><span class="line">.hidden {</span><br><span class="line">display: none;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h2 id="for循环"><a href="#for循环" class="headerlink" title="for循环"></a>for循环</h2><p>在制作网格系统的时候,我们都需要使用到.col1~.col12这样的类名,在css中需要一个个去写,但是在sass 中可以很容易地使用@for循环来完成。<br>for循环有两种实现方式<br><figure class="highlight plain"><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">@for $i from <start> through <end></span><br><span class="line">//$i表示变量 start表示起始值 end表示结束值</span><br><span class="line">@for $i form <start> to <end></span><br><span class="line">//二者区别是,关键字through表示包括end这个数,而to表示不包括end这个数</span><br></pre></td></tr></table></figure></p><p>@for循环在网格系统生成每个格子的class代码<br><figure class="highlight plain"><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">$grid-prefix: span;</span><br><span class="line">$grid-width: 60px;</span><br><span class="line">$grid-gutter: 20px;</span><br><span class="line">%grid {</span><br><span class="line">float: left;</span><br><span class="line">margin-left: $grid-gutter /2;</span><br><span class="line">margin-right: $grid-gutter /2;</span><br><span class="line">}</span><br><span class="line">@for $i form 1 through 12 {</span><br><span class="line">.#{$grid-prefix}#{$i}{</span><br><span class="line">width: $grid-width * $i + $grid-gutter * ($i - 1);</span><br><span class="line">@extend %grid;</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>编译出的css为<br><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">.span1, .span2, .span3, .span4, .span5, .span6, .span7, .span8, .span9, .span10, .span11, .span12 {</span><br><span class="line">float: left;</span><br><span class="line">margin-left: 10px;</span><br><span class="line">margin-right: 10px;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">.span1 {</span><br><span class="line">width: 60px;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">.span2 {</span><br><span class="line">width: 140px;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">.span3 {</span><br><span class="line">width: 220px;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">.span4 {</span><br><span class="line">width: 300px;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">.span5 {</span><br><span class="line">width: 380px;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">.span6 {</span><br><span class="line">width: 460px;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">.span7 {</span><br><span class="line">width: 540px;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">.span8 {</span><br><span class="line">width: 620px;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">.span9 {</span><br><span class="line">width: 700px;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">.span10 {</span><br><span class="line">width: 780px;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">.span11 {</span><br><span class="line">width: 860px;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">.span12 {</span><br><span class="line">width: 940px;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>将上面的实例做一些修改,将@for through方式换成@for to::<br><figure class="highlight plain"><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">@for $i from 1 to 13 {</span><br><span class="line">.#{$grid-prefix}#{$i}{</span><br><span class="line">width: $grid-width * $i + $grid-gutter * ($i - 1);</span><br><span class="line">@extend %grid;</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h2 id="while循环"><a href="#while循环" class="headerlink" title="@while循环"></a>@while循环</h2><p>@while指令也需要SassScript表达式,并且会生成不同的代码块,直到表达式值为false时停止循环。<br><figure class="highlight plain"><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">$types: 4;</span><br><span class="line">$type-width: 20px;</span><br><span class="line">@while $types > 0{ //等价于while( types = 4 , types > 0);</span><br><span class="line">.while-#{$types}{ //等价于.while-types{</span><br><span class="line">width: $types-width + $types; //等价于width: 20px - types;</span><br><span class="line">}</span><br><span class="line">$types: $types - 1; //等价于 4--;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h2 id="each循环"><a href="#each循环" class="headerlink" title="@each循环"></a>@each循环</h2><p>@each循环就是去遍历一个列表,然后从列表中取出对应的值。<br>@each命令的形式:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">@each $var in <list></span><br></pre></td></tr></table></figure></p><p>$var 是一个变量名,list是一个列表,用于进行引用。<br><figure class="highlight plain"><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">$list: adam john wynn mason kuroir; //列出列表,供下面进行引用</span><br><span class="line">@mixin author-images {</span><br><span class="line">@each $author in $list {</span><br><span class="line">.photo-#{$author}{</span><br><span class="line">background: url("images/avatars/#{$author}.png") no-repeat;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">.author-bio {</span><br><span class="line">@include author-images;</span><br><span class="line">}</span><br><span class="line">//编译出的css为</span><br><span class="line">.author-bio .photo-adam {</span><br><span class="line">background: url("/images/avatars/adam.png") no-repeat; }</span><br><span class="line">.author-bio .photo-john {</span><br><span class="line">background: url("/images/avatars/john.png") no-repeat; }</span><br><span class="line">.author-bio .photo-wynn {</span><br><span class="line">background: url("/images/avatars/wynn.png") no-repeat; }</span><br><span class="line">.author-bio .photo-mason {</span><br><span class="line">background: url("/images/avatars/mason.png") no-repeat; }</span><br><span class="line">.author-bio .photo-kuroir {</span><br><span class="line">background: url("/images/avatars/kuroir.png") no-repeat; }</span><br></pre></td></tr></table></figure></p><h1 id="sass函数"><a href="#sass函数" class="headerlink" title="sass函数"></a>sass函数</h1><h2 id="字符串函数"><a href="#字符串函数" class="headerlink" title="字符串函数"></a>字符串函数</h2><p>sass的字符串函数主要包括两个<br><figure class="highlight plain"><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">unquote($string);</span><br><span class="line">//删除字符串中的引号,如果字符串中没有引号,将返回原始字符串。注:unquote()函数只能删除字符串最前和最后的引号,无法删除字符串中间的引号。</span><br><span class="line">quote($string);</span><br><span class="line">//给字符串添加引号,如果字符串中间有引号或空格时,需要用单引号或者双引号括起,否则编译时会报错。</span><br></pre></td></tr></table></figure></p><h2 id="字符串函数To-upper-case-和To-lower-case"><a href="#字符串函数To-upper-case-和To-lower-case" class="headerlink" title="字符串函数To-upper-case()和To-lower-case()"></a>字符串函数To-upper-case()和To-lower-case()</h2><figure class="highlight plain"><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">To-upper-case():将字符串的小写字母转换成大写字母</span><br><span class="line">To-lower-case():将字符串的啊写字母转换成小写字母</span><br></pre></td></tr></table></figure><h2 id="数字函数"><a href="#数字函数" class="headerlink" title="数字函数"></a>数字函数</h2><figure class="highlight plain"><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">percentage($value):将一个不带单位的数转换成百分比值;</span><br><span class="line">round($value):将数值四舍五入,转换成一个最接近的整数; 0.4999视为0</span><br><span class="line">ceil($value):将大于自己的小数转换成下一位整数; 0.0001视为1</span><br><span class="line">floor($value):将一个数去除他的小数部分; 0.0001视为0</span><br><span class="line">abs($value):返回一个数的绝对值;</span><br><span class="line">min($numbers…):找出几个数值之间的最小值;</span><br><span class="line">max($numbers…):找出几个数值之间的最大值;</span><br><span class="line">random(): 获取随机数</span><br></pre></td></tr></table></figure><h2 id="列表函数"><a href="#列表函数" class="headerlink" title="列表函数"></a>列表函数</h2><p>列表函数主要包括一些对列表参数的函数使用,主要包括以下几种:<br><figure class="highlight plain"><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">length($list):返回一个列表的长度值; //括号内的值算一个</span><br><span class="line">nth($list, $n):返回一个列表中指定的某个标签值,$n表示第几个</span><br><span class="line">join($list1, $list2, [$separator]):将两个列给连接在一起,变成一个列表;</span><br><span class="line">append($list1, $val, [$separator]):将某个值放在列表的最后;</span><br><span class="line">zip($lists…):将几个列表结合成一个多维的列表;</span><br><span class="line">index($list, $value):返回一个值在列表中的位置值。以1开始</span><br></pre></td></tr></table></figure></p><h2 id="Introspection函数"><a href="#Introspection函数" class="headerlink" title="Introspection函数"></a>Introspection函数</h2><p>Introspection函数包括了几个判断型函数:<br><figure class="highlight plain"><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">type-of($value):返回一个值的类型</span><br><span class="line">unit($number):返回一个值的单位</span><br><span class="line">unitless($number):判断一个值是否带有单位</span><br><span class="line">comparable($number-1, $number-2):判断两个值是否可以做加、减和合并</span><br></pre></td></tr></table></figure></p><h2 id="sass-Maps函数"><a href="#sass-Maps函数" class="headerlink" title="sass Maps函数"></a>sass Maps函数</h2><p>借助于map功能,为同一量下,多个有名字的变量进行处理。<br><figure class="highlight plain"><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">map-get($map,$key):根据给定的 key 值,返回 map 中相关的值。</span><br><span class="line">map-merge($map1,$map2):将两个 map 合并成一个新的 map。</span><br><span class="line">map-remove($map,$key):从 map 中删除一个 key,返回一个新 map。</span><br><span class="line">map-keys($map):返回 map 中所有的 key。</span><br><span class="line">map-values($map):返回 map 中所有的 value。</span><br><span class="line">map-has-key($map,$key):根据给定的 key 值判断 map 是否有对应的 value 值,如果有返回 true,否则返回 false。</span><br><span class="line">keywords($args):返回一个函数的参数,这个参数可以动态的设置 key 和 value。</span><br></pre></td></tr></table></figure></p><h1 id="sass的-规则"><a href="#sass的-规则" class="headerlink" title="sass的@规则"></a>sass的@规则</h1><p>sass支持所有css3的@规则,以及一些sass专属的规则,也被成为指令。这些规则在sass 中具有不同的功效。</p><h2 id="import规则"><a href="#import规则" class="headerlink" title="@import规则"></a>@import规则</h2><p>sass扩展了css的@import规则,使其能够引入scss和sass文件。所有引入的scss文件和sass文件都会被合并输出一个单一的css文件。被导入的文件中所定义的变量或mixins都可以在主文件中使用。<br>sass会在当前目录下寻找其他sass文件,也可以通过:load_paths选项或在命令行中使用–load-path 选项来制定额外的搜索目录。<br>@import根据文件名引入。默认情况下,它会寻找sass文件并直接引入,但是在少数几种情况下,它会被编译成css的@import规则:<br><figure class="highlight plain"><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">如果文件的扩展名是 .css。</span><br><span class="line">如果文件名以 http:// 开头。</span><br><span class="line">如果文件名是 url()。</span><br><span class="line">如果 @import 包含了任何媒体查询(media queries)。</span><br></pre></td></tr></table></figure></p><p>如果上述情况都没有出现,且扩展名是.sass或者是.scss,则该名称的sass<br>或scss文件就会被引入。</p><h2 id="media规则"><a href="#media规则" class="headerlink" title="@media规则"></a>@media规则</h2><p>sass中的@media规则和css中的使用规则类似,但它有另外一个功能,可以嵌套在css规则中。有点类似于JS中的冒泡功能一样。如果使用@media指令,他将冒泡到外面。<br><figure class="highlight plain"><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">.sidebar {</span><br><span class="line">width: 300px;</span><br><span class="line">@media screen and (orientation: landscape){</span><br><span class="line">width: 500px;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">//编译结果</span><br><span class="line">.sidebar {</span><br><span class="line">width: 300px;</span><br><span class="line">@media screen and (orientation: landscape){</span><br><span class="line">.sidebar{</span><br><span class="line">width: 500px;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h2 id="extend规则"><a href="#extend规则" class="headerlink" title="@extend规则"></a>@extend规则</h2><p>sass中的@extend是用来扩展选择器或占位符(类似于继承)</p><h2 id="at-root规则"><a href="#at-root规则" class="headerlink" title="@at-root规则"></a>@at-root规则</h2><p>@at-root规则从字面上解释就是跳出根元素。当你选择器嵌套多层之后,想让某个选择器跳出,此时就可以使用@at-root。<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">.a {</span><br><span class="line">color: red;</span><br><span class="line">.b {</span><br><span class="line">color: orange;</span><br><span class="line">.c {</span><br><span class="line">color:yellow;</span><br><span class="line">@at-root .d {</span><br><span class="line">color: green;</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">.a {</span><br><span class="line">color: red;</span><br><span class="line">}</span><br><span class="line">.a .b{</span><br><span class="line">color: orange;</span><br><span class="line">}</span><br><span class="line">.a .b .c {</span><br><span class="line">color:yellow;</span><br><span class="line">}</span><br><span class="line">.d {</span><br><span class="line">color: green;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h2 id="debug规则"><a href="#debug规则" class="headerlink" title="@debug规则"></a>@debug规则</h2><p>@debug在sass中是用来调试的,当你在sass的源码中使用了@debug规则之后,sass代码在编译出错时,在命令终端会输出你设置的提示bug:<br><figure class="highlight plain"><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">@debug 10em + 12em;</span><br><span class="line">//输出内容</span><br><span class="line">Line 1 DEBUG: 22em;</span><br></pre></td></tr></table></figure></p><h2 id="warn规则"><a href="#warn规则" class="headerlink" title="@warn规则"></a>@warn规则</h2><p>@warn 和@debug 类似,用来帮助我们很好的调试sass。</p><h2 id="error"><a href="#error" class="headerlink" title="@error"></a>@error</h2><p>@error 和@debug、@warn 类似,用来帮助我们很好的调试sass。</p>]]></content>
<summary type="html">
sass学习进阶 @if语句 @if是一个SassScript,它可以根据条件来处理样式快,如果条件为true则返回一个样式块,反之false返回另一个样式块。在sass中除了@if单独使用以外,还可以配合@else if 和@else 一起使用。
</summary>
<category term="SASS 学习笔记" scheme="http://blog.changerhe.cn/categories/SASS-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
<category term="SASS" scheme="http://blog.changerhe.cn/tags/SASS/"/>
</entry>
<entry>
<title>Charles抓包工具的基本使用</title>
<link href="http://blog.changerhe.cn/2018/02/06/Charles%E6%8A%93%E5%8C%85%E5%B7%A5%E5%85%B7%E7%9A%84%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/"/>
<id>http://blog.changerhe.cn/2018/02/06/Charles抓包工具的基本使用/</id>
<published>2018-02-06T13:23:42.000Z</published>
<updated>2018-08-12T10:47:39.477Z</updated>
<content type="html"><![CDATA[<h2 id="charles-常用功能"><a href="#charles-常用功能" class="headerlink" title="charles 常用功能"></a>charles 常用功能</h2><ol><li>抓取移动设备的http请求</li></ol><blockquote><p>输入ifconfig查看本机ip地址</p></blockquote><blockquote><p>打开<code>proxy > proxy settings</code>, 设置移动设备连接到电脑的端口(默认8888)</p></blockquote><blockquote><p>使用手机连接到与电脑相同的局域网, 并将无线局域网设置为手动代理, 输入我们在charles上设置的端口号, 即可实现对手机上请求的监听</p></blockquote><p>需要注意的是, 我们第一次通过手机连接电脑上的charles的时候, charles会显示安全提示, 我们需要点击接受才能够继续对手机进行请求监听</p><p>如果不想每次新设备都要设置一次监听的话, 可以在<code>proxy > access control settings</code>中, 设置通用的ip range为<code>0.0.0.0/0</code>, 表示允许所有的ip进入端口进行条数</p><ol><li>过滤不需要的网络包</li></ol><blockquote><p>选择<code>proxy > recording settings</code></p></blockquote><h2 id="包名过滤"><a href="#包名过滤" class="headerlink" title="包名过滤"></a>包名过滤</h2><p>使用<code>sequence</code>中的filter功能, 可以对包名进行过滤, 即可得到我们想要的内容</p><p>使用<code>structor</code>中域名文件夹, 可以查看到当前域名下面的所有的包信息</p><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><ol><li>手机上和电脑上均不能开启shadowsocks或者蓝灯等proxy软件, 否则抓不到包!!!</li></ol><h2 id="macos-解决https无法抓包问题"><a href="#macos-解决https无法抓包问题" class="headerlink" title="macos 解决https无法抓包问题"></a>macos 解决https无法抓包问题</h2><p>在Charles中,转到<code>帮助</code>菜单,然后选择<code>SSL代理>安装Charles Root证书</code>。钥匙串访问将打开。点击所有证书, 找到<code>Charles Proxy ...</code>条目,然后双击以获取相关信息。展开<code>信任</code>部分,在“使用此证书时”旁边,将其从<code>使用系统默认值</code>更改为<code>始终信任</code>。然后关闭证书信息窗口,系统将提示您输入管理员密码以更新系统信任设置。</p>]]></content>
<summary type="html">
Charles其实是一款代理服务器,通过过将自己设置成系统(电脑或者浏览器)的网络访问代理服务器,然后截取请求和请求结果达到分析抓包的目的。该软件是用Java写的,能够在Windows,Mac,Linux上使用。安装Charles的时候要先装好Java环境。
</summary>
<category term="Charles" scheme="http://blog.changerhe.cn/tags/Charles/"/>
</entry>
<entry>
<title>百度地图JSapi使用总结</title>
<link href="http://blog.changerhe.cn/2018/01/02/%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BEJSapi%E4%BD%BF%E7%94%A8/"/>
<id>http://blog.changerhe.cn/2018/01/02/百度地图JSapi使用/</id>
<published>2018-01-02T14:55:12.000Z</published>
<updated>2018-08-12T10:52:52.970Z</updated>
<content type="html"><![CDATA[<h1 id="百度地图的基本使用"><a href="#百度地图的基本使用" class="headerlink" title="百度地图的基本使用"></a>百度地图的基本使用</h1><blockquote><p>注册百度账号</p></blockquote><blockquote><p>申请成为百度开发者</p></blockquote><blockquote><p>获取服务密钥(ak)</p></blockquote><p>注意: 百度对外接口的坐标系为BD09坐标系,并不是GPS采集的真实经纬度,在使用百度地图JavaScript API服务前,需先将非百度坐标通过坐标转换接口转换成百度坐标。 坐标转换、批量坐标转换示例详见JavaScript API示例。</p><h1 id="添加地图控件"><a href="#添加地图控件" class="headerlink" title="添加地图控件"></a>添加地图控件</h1><table><thead><tr><th>控件</th><th>类名</th><th>简介</th></tr></thead><tbody><tr><td>抽象基类</td><td>Control</td><td>所有控件均继承此类的方法、属性。通过此类您可实现自定义控件</td></tr><tr><td>平移缩放控件</td><td>NavigationControl</td><td>PC端默认位于地图左上方,它包含控制地图的平移和缩放的功能。移动端提供缩放控件,默认位于地图右下方</td></tr><tr><td>缩略地图</td><td>OverviewMapControl</td><td>默认位于地图右下方,是一个可折叠的缩略地图</td></tr><tr><td>比例尺</td><td>ScaleControl</td><td>默认位于地图左下方,显示地图的比例关系</td></tr><tr><td>地图类型</td><td>MapTypeControl</td><td>默认位于地图右上方</td></tr><tr><td>定位</td><td>GeolocationControl</td><td>针对移动端开发,默认位于地图左下方</td></tr></tbody></table><p>可以使用Map.addControl()方法向地图添加控件。<br>可以使用Map.removeControl()方法为地图移除控件。</p><h2 id="地图初始化"><a href="#地图初始化" class="headerlink" title="地图初始化"></a>地图初始化</h2><figure class="highlight plain"><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">// 传入对应的dom节点标签id名称, 用于挂在对应的百度地图显示区块</span><br><span class="line">var map = new BMap.Map("container"); </span><br><span class="line">// 传入中心点及基础缩放比例</span><br><span class="line">map.centerAndZoom(new BMap.Point(116.404, 39.915), 11); </span><br><span class="line">// 增加地图控件</span><br><span class="line">map.addControl(new BMap.NavigationControl()); // 平移缩放控件</span><br><span class="line">map.addControl(new BMap.ScaleControl()); // 比例尺控件</span><br><span class="line">map.addControl(new BMap.OverviewMapControl()); // 缩略图控件</span><br><span class="line">map.addControl(new BMap.MapTypeControl()); </span><br><span class="line">map.setCurrentCity("北京"); // 仅当设置城市信息时,MapTypeControl的切换功能才能可用</span><br></pre></td></tr></table></figure><h2 id="控制控件位置"><a href="#控制控件位置" class="headerlink" title="控制控件位置"></a>控制控件位置</h2><p>初始化控件时,可提供一个可选参数,其中的anchor和offset属性共同控制控件在地图上的位置。 anchor表示控件的停靠位置,即控件停靠在地图的哪个角。当地图尺寸发生变化时,控件会根据停靠位置的不同来调整自己的位置。</p><table><thead><tr><th>anchor值</th><th>位置说明</th></tr></thead><tbody><tr><td>BMAP_ANCHOR_TOP_LEFT</td><td>表示控件定位于地图的左上角</td></tr><tr><td>BMAP_ANCHOR_TOP_RIGHT</td><td>表示控件定位于地图的右上角</td></tr><tr><td>BMAP_ANCHOR_BOTTOM_LEFT</td><td>表示控件定位于地图的左下角</td></tr><tr><td>BMAP_ANCHOR_BOTTOM_RIGHT</td><td>表示控件定位于地图的右下角</td></tr></tbody></table><h2 id="控件位置偏移"><a href="#控件位置偏移" class="headerlink" title="控件位置偏移"></a>控件位置偏移</h2><p>除了指定停靠位置外,还可以通过偏移量来指示控件距离地图边界有多少像素。如果两个控件的停靠位置相同,那么控件可能会重叠在一起,这时就可以通过偏移值使二者分开显示。</p><p>如下示例为:将比例尺放置在地图的左下角,由于API默认会有版权信息,因此需要添加一些偏移值以防止控件重叠。</p><figure class="highlight plain"><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">var opts = {offset: new BMap.Size(150, 5)}</span><br><span class="line">map.addControl(new BMap.ScaleControl(opts));</span><br></pre></td></tr></table></figure><p>除此之外, 控件外观也是可以更改的</p><figure class="highlight plain"><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">var opts = {type: BMAP_NAVIGATION_CONTROL_SMALL} </span><br><span class="line">map.addControl(new BMap.NavigationControl(opts)); // 调整平移缩放控件为显示小型平移缩放控件</span><br></pre></td></tr></table></figure><h2 id="自定义控件"><a href="#自定义控件" class="headerlink" title="自定义控件"></a>自定义控件</h2><h3 id="定义一个自定义控件的构造函数并继承Control"><a href="#定义一个自定义控件的构造函数并继承Control" class="headerlink" title="定义一个自定义控件的构造函数并继承Control"></a>定义一个自定义控件的构造函数并继承Control</h3><p>定义自定义控件的构造函数,并在构造函数中提供defaultAnchor和defaultOffset两个属性,以便API正确定位控件位置,接着让其继承于Control。在下面的示例中我们定义一个名为ZoomControl的控件,每一次点击将地图放大两个级别。它具有文本标识,而不是平移缩放控件中使用的图形图标。</p><figure class="highlight plain"><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">// 定义一个控件类,即function </span><br><span class="line">function ZoomControl(){ </span><br><span class="line"> // 设置默认停靠位置和偏移量 </span><br><span class="line"> this.defaultAnchor = BMAP_ANCHOR_TOP_LEFT; </span><br><span class="line"> this.defaultOffset = new BMap.Size(10, 10); </span><br><span class="line">} </span><br><span class="line">// 通过JavaScript的prototype属性继承于BMap.Control </span><br><span class="line">ZoomControl.prototype = new BMap.Control();</span><br></pre></td></tr></table></figure><h3 id="初始化自定义控件"><a href="#初始化自定义控件" class="headerlink" title="初始化自定义控件"></a>初始化自定义控件</h3><p>设置自定义控件构造函数的prototype属性为Control的实例,以便继承控件基类。</p><p>当调用map.addControl()方法添加自定义控件时,API会调用该对象的initialize()方法用来初始化控件,您需要实现此方法并在其中创建控件所需的DOM元素,并添加DOM事件。所有自定义控件中的DOM元素最终都应该添加到地图容器(即地图所在的DOM元素)中去,地图容器可以通过map.getContainer()方法获得。最后initialize()方法需要返回控件容器的DOM元素。</p><figure class="highlight plain"><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">// 自定义控件必须实现initialize方法,并且将控件的DOM元素返回 </span><br><span class="line">// 在本方法中创建个div元素作为控件的容器,并将其添加到地图容器中 </span><br><span class="line">ZoomControl.prototype.initialize = function(map){ </span><br><span class="line"> // 创建一个DOM元素 </span><br><span class="line"> var div = document.createElement("div"); </span><br><span class="line"> // 添加文字说明 </span><br><span class="line"> div.appendChild(document.createTextNode("放大2级")); </span><br><span class="line"> // 设置样式 </span><br><span class="line"> div.style.cursor = "pointer"; </span><br><span class="line"> div.style.border = "1px solid gray"; </span><br><span class="line"> div.style.backgroundColor = "white"; </span><br><span class="line"> // 绑定事件,点击一次放大两级 </span><br><span class="line"> div.onclick = function(e){ </span><br><span class="line"> map.zoomTo(map.getZoom() + 2); </span><br><span class="line"> } </span><br><span class="line"> // 添加DOM元素到地图中 </span><br><span class="line"> map.getContainer().appendChild(div); </span><br><span class="line"> // 将DOM元素返回 </span><br><span class="line"> return div; </span><br><span class="line"> }</span><br></pre></td></tr></table></figure><h3 id="添加自定义控件"><a href="#添加自定义控件" class="headerlink" title="添加自定义控件"></a>添加自定义控件</h3><p>添加自定义控件与添加其他控件方法一致,调用map.addControl()方法即可。</p><figure class="highlight plain"><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><br><span class="line">var myZoomCtrl = new ZoomControl(); </span><br><span class="line">// 添加到地图当中 </span><br><span class="line">map.addControl(myZoomCtrl);</span><br></pre></td></tr></table></figure><h1 id="个性化地图配置"><a href="#个性化地图配置" class="headerlink" title="个性化地图配置"></a>个性化地图配置</h1><p>目前地图的样式个性化可以通过官方的默认样式进行设置, 也可以通过个性地图编辑工具对地图的样式进行编辑, 然后生成地图的样式json, 后通过JavaScript api的方法调用生效</p><h2 id="模版选择方式"><a href="#模版选择方式" class="headerlink" title="模版选择方式"></a>模版选择方式</h2><blockquote><p>选择模板: 从开放平台选择各种不同的风格模板之一</p></blockquote><blockquote><p>设置地图样式</p></blockquote><figure class="highlight plain"><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">var mapStyle={ style : "*模板英文名称*" } </span><br><span class="line">map.setMapStyle(mapStyle);</span><br></pre></td></tr></table></figure><p>如下图, 当我们需要设置下图的风格</p><p><img src="http://mapopen-pub-jsapi.bj.bcebos.com/img/jsimg5.jpg" alt=""></p><figure class="highlight plain"><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">var mapStyle={ style : "mapbox" } </span><br><span class="line">map.setMapStyle(mapStyle);</span><br></pre></td></tr></table></figure><h2 id="个性化编辑方式"><a href="#个性化编辑方式" class="headerlink" title="个性化编辑方式"></a>个性化编辑方式</h2><p>见百度地图开发文档</p><h1 id="在地图上进行标注"><a href="#在地图上进行标注" class="headerlink" title="在地图上进行标注"></a>在地图上进行标注</h1><p>所有叠加或覆盖到地图的内容,我们统称为地图覆盖物。覆盖物拥有自己的地理坐标,当拖动或缩放地图时,它们会相应的移动。</p><p>覆盖物主要分为:标注(点标注、矢量图形(包括折线、多边形、圆))、信息窗口、图层。</p><h2 id="提供的覆盖物"><a href="#提供的覆盖物" class="headerlink" title="提供的覆盖物"></a>提供的覆盖物</h2><p>可以使用map.addOverlay方法向地图添加覆盖物,使用map.removeOverlay方法移除覆盖物,注意此方法不适用于InfoWindow。</p><table><thead><tr><th>覆盖物</th><th>类名</th><th>说明</th></tr></thead><tbody><tr><td>抽象基类</td><td>Overlay</td><td>所有的覆盖物均继承此类的方法</td></tr><tr><td>点</td><td>Marker</td><td>表示地图上的点,可自定义标注的图标</td></tr><tr><td>文本</td><td>Label</td><td>表示地图上的文本标注,您可以自定义标注的文本内容</td></tr><tr><td>折线</td><td>Polyline</td><td>表示地图上的折线</td></tr><tr><td>多边形</td><td>Polygon</td><td>表示地图上的多边形。多边形类似于闭合的折线,另外您也可以为其添加填充颜色</td></tr><tr><td>圆</td><td>Circle</td><td>表示地图上的圆</td></tr><tr><td>信息窗口</td><td>InfoWindow</td><td>信息窗口也是一种特殊的覆盖物,它可以展示更为丰富的文字和多媒体信息。注意:同一时刻只能有一个信息窗口在地图上打开</td></tr><tr><td>地面叠加层</td><td>GoundOverlay</td><td>表示叠加在地图上的图片,图片的链接、大小、位置等属性可以自定义</td></tr><tr><td>海量点</td><td>PointCollection</td><td>针对点的数量很大的情况,可以使用海量点进行展示</td></tr><tr><td>自定义覆盖物</td><td>自定义</td><td>支持通过继承覆盖物基类Overlay,自定义覆盖物</td></tr></tbody></table><h2 id="标注点"><a href="#标注点" class="headerlink" title="标注点"></a>标注点</h2><p>Marker是一个用来往地图上添加点标记的类。使用它将任何你希望用户看到的兴趣点标注在地图上。</p><p>API提供了默认图标样式,也可以通过Icon类来指定自定义图标。Marker的构造函数的参数为Point和MarkerOptions(可选)。</p><p>注意:当使用自定义图标时,标注的地理坐标点将位于标注所用图标的中心位置,可通过Icon的offset属性修改标定位置。</p><h3 id="向地图添加标注"><a href="#向地图添加标注" class="headerlink" title="向地图添加标注"></a>向地图添加标注</h3><figure class="highlight plain"><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">var map = new BMap.Map("container"); </span><br><span class="line">var point = new BMap.Point(116.404, 39.915); </span><br><span class="line">map.centerAndZoom(point, 15); </span><br><span class="line">var marker = new BMap.Marker(point); // 创建标注 </span><br><span class="line">map.addOverlay(marker); // 将标注添加到地图中</span><br></pre></td></tr></table></figure><h3 id="定义标注图标"><a href="#定义标注图标" class="headerlink" title="定义标注图标"></a>定义标注图标</h3><p>通过Icon类可实现自定义标注的图标,下面示例通过参数MarkerOptions的icon属性进行设置,您也可以使用marker.setIcon()方法。</p><figure class="highlight plain"><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">var map = new BMap.Map("container"); </span><br><span class="line">var point = new BMap.Point(116.404, 39.915); </span><br><span class="line">map.centerAndZoom(point, 15); // 编写自定义函数,创建标注 </span><br><span class="line">function addMarker(point, index){ // 创建图标对象 </span><br><span class="line"> var myIcon = new BMap.Icon("markers.png", new BMap.Size(23, 25), { </span><br><span class="line"> // 指定定位位置。 </span><br><span class="line"> // 当标注显示在地图上时,其所指向的地理位置距离图标左上 </span><br><span class="line"> // 角各偏移10像素和25像素。您可以看到在本例中该位置即是 </span><br><span class="line"> // 图标中央下端的尖角位置。 </span><br><span class="line"> anchor: new BMap.Size(10, 25), </span><br><span class="line"> // 设置图片偏移。 </span><br><span class="line"> // 当您需要从一幅较大的图片中截取某部分作为标注图标时,您 </span><br><span class="line"> // 需要指定大图的偏移位置,此做法与css sprites技术类似。 </span><br><span class="line"> imageOffset: new BMap.Size(0, 0 - index * 25) // 设置图片偏移 </span><br><span class="line"> }); </span><br><span class="line"> // 创建标注对象并添加到地图 </span><br><span class="line"> var marker = new BMap.Marker(point, {icon: myIcon}); </span><br><span class="line"> map.addOverlay(marker); </span><br><span class="line">} </span><br><span class="line">// 随机向地图添加10个标注 </span><br><span class="line">var bounds = map.getBounds(); </span><br><span class="line">var lngSpan = bounds.maxX - bounds.minX; </span><br><span class="line">var latSpan = bounds.maxY - bounds.minY; </span><br><span class="line">for (var i = 0; i < 10; i ++) { </span><br><span class="line"> var point = new BMap.Point(bounds.minX + lngSpan * (Math.random() * 0.7 + 0.15), </span><br><span class="line"> bounds.minY + latSpan * (Math.random() * 0.7 + 0.15)); </span><br><span class="line"> addMarker(point, i); </span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="监听标注事件"><a href="#监听标注事件" class="headerlink" title="监听标注事件"></a>监听标注事件</h3><p>事件方法与Map事件机制相同。</p><figure class="highlight plain"><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">marker.addEventListener("click", function(){ </span><br><span class="line"> alert("您点击了标注"); </span><br><span class="line">});</span><br></pre></td></tr></table></figure><h3 id="可拖拽的标注"><a href="#可拖拽的标注" class="headerlink" title="可拖拽的标注"></a>可拖拽的标注</h3><p><code>marker</code>的<code>enableDragging</code>和<code>disableDragging</code>方法可用来开启和关闭标注的拖拽功能。默认情况下标注不支持拖拽,您需要调用marker.enableDragging()方法来开启拖拽功能。在标注开启拖拽功能后,您可以监听标注的dragend事件来捕获拖拽后标注的最新位置。</p><figure class="highlight plain"><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">marker.enableDragging(); </span><br><span class="line">marker.addEventListener("dragend", function(e){ </span><br><span class="line"> alert("当前位置:" + e.point.lng + ", " + e.point.lat); </span><br><span class="line">})</span><br></pre></td></tr></table></figure><h2 id="标注折线"><a href="#标注折线" class="headerlink" title="标注折线"></a>标注折线</h2><p>Polyline表示地图上的折线覆盖物。它包含一组点,并将这些点连接起来形成折线。 Polyline使用详情请见类参考。</p><h3 id="添加折线"><a href="#添加折线" class="headerlink" title="添加折线"></a>添加折线</h3><p>折线在地图上绘制为一系列直线段。可以自定义这些线段的颜色、粗细和透明度。颜色可以是十六进制数字形式(比如:#ff0000)或者是颜色关键字(比如:red)。<br>Polyline的绘制需要浏览器支持矢量绘制功能。在Internet Explorer中,地图使用VML绘制折线;在其他浏览器中使用SVG或者Canvas。</p><p>以下代码段会在两点之间创建6像素宽的蓝色折线:</p><figure class="highlight plain"><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">var polyline = new BMap.Polyline([</span><br><span class="line"> new BMap.Point(116.399, 39.910),</span><br><span class="line"> new BMap.Point(116.405, 39.920)</span><br><span class="line"> ],</span><br><span class="line"> {strokeColor:"blue", strokeWeight:6, strokeOpacity:0.5}</span><br><span class="line"> );</span><br><span class="line">map.addOverlay(polyline);</span><br></pre></td></tr></table></figure><h1 id="增加信息窗口"><a href="#增加信息窗口" class="headerlink" title="增加信息窗口"></a>增加信息窗口</h1><p>所有叠加或覆盖到地图的内容,我们统称为地图覆盖物。覆盖物拥有自己的地理坐标,当您拖动或缩放地图时,它们会相应的移动。</p><p>覆盖物主要分为:标注(点标注、矢量图形(包括折线、多边形、圆))、信息窗口、图层。</p><h2 id="提供的信息窗口"><a href="#提供的信息窗口" class="headerlink" title="提供的信息窗口"></a>提供的信息窗口</h2><p>InfoWindow:信息窗口。也是一种特殊的覆盖物,它可以展示更为丰富的文字和多媒体信息。</p><p>注意:同一时刻只能有一个信息窗口在地图上打开。</p><h2 id="添加信息窗口"><a href="#添加信息窗口" class="headerlink" title="添加信息窗口"></a>添加信息窗口</h2><p>信息窗口在地图上方的浮动显示HTML内容。</p><p>信息窗口可直接在地图上的任意位置打开,也可以在标注对象上打开(此时信息窗口的坐标与标注的坐标一致)。</p><p>您可以使用InfoWindow来创建一个信息窗实例,</p><p>注意同一时刻地图上只能有一个信息窗口处于打开状态。</p><figure class="highlight plain"><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">var opts = { </span><br><span class="line"> width : 250, // 信息窗口宽度 </span><br><span class="line"> height: 100, // 信息窗口高度 </span><br><span class="line"> title : "Hello" // 信息窗口标题 </span><br><span class="line">} </span><br><span class="line">var infoWindow = new BMap.InfoWindow("World", opts); // 创建信息窗口对象 </span><br><span class="line">map.openInfoWindow(infoWindow, map.getCenter()); // 打开信息窗口</span><br></pre></td></tr></table></figure><h2 id="提供的自定义信息窗口工具"><a href="#提供的自定义信息窗口工具" class="headerlink" title="提供的自定义信息窗口工具"></a>提供的自定义信息窗口工具</h2><p>infoBox:自定义信息窗口工具。类似于infoWindow,比infoWindow更有灵活性,比如可以定制border,关闭按钮样式等。</p><h1 id="叠加图层"><a href="#叠加图层" class="headerlink" title="叠加图层"></a>叠加图层</h1><p>地图可以包含一个或多个图层,每个图层在每个级别都是由若干张图块组成的,它们覆盖了地球的整个表面。例如您所看到包括街道、兴趣点、学校、公园等内容的地图展现就是一个图层,另外交通流量的展现也是通过图层来实现的。</p><h2 id="提供的图层"><a href="#提供的图层" class="headerlink" title="提供的图层"></a>提供的图层</h2><p>TrafficLayer:交通流量图层。</p><h2 id="添加和移除图层"><a href="#添加和移除图层" class="headerlink" title="添加和移除图层"></a>添加和移除图层</h2><p>通过map.addTileLayer方法可向地图添加图层,例如下面代码将显示北京市的交通流量。</p><figure class="highlight plain"><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">var map = new BMap.Map("l-map"); // 创建地图实例 </span><br><span class="line">var point = new BMap.Point(116.404, 39.915); // 创建点坐标 </span><br><span class="line">map.centerAndZoom(point, 15); // 初始化地图,设置中心点坐标和地图级别 </span><br><span class="line">var traffic = new BMap.TrafficLayer(); // 创建交通流量图层实例 </span><br><span class="line">map.addTileLayer(traffic); // 将图层添加到地图上</span><br></pre></td></tr></table></figure><p>若要从地图上移除图层,需要调用map.removeTileLayer方法。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">map.removeTileLayer(traffic); // 将图层移除</span><br></pre></td></tr></table></figure><h1 id="事件处理"><a href="#事件处理" class="headerlink" title="事件处理"></a>事件处理</h1><p>浏览器中的JavaScript是“事件驱动的”,这表示JavaScript通过生成事件来响应交互,并期望程序能够“监听”感兴趣的活动。例如,在浏览器中,用户的鼠标和键盘交互可以创建在DOM内传播的事件。对某些事件感兴趣的程序会为这些事件注册JavaScript事件监听器,并在接收这些事件时执行代码。</p><p>百度地图API拥有一个自己的事件模型,程序员可监听地图API对象的自定义事件,使用方法和DOM事件类似。但请注意,地图API事件是独立的,与标准DOM事件不同。</p><h2 id="事件监听"><a href="#事件监听" class="headerlink" title="事件监听"></a>事件监听</h2><p>百度地图API中的大部分对象都含有addEventListener方法,您可以通过该方法来监听对象事件。例如,BMap.Map包含click、dblclick等事件。在特定环境下这些事件会被触发,同时监听函数会得到相应的事件参数e,比如当用户点击地图时,e参数会包含鼠标所对应的地理位置point。</p><h3 id="弹窗事件"><a href="#弹窗事件" class="headerlink" title="弹窗事件"></a>弹窗事件</h3><p>addEventListener方法有两个参数:监听的事件名称和事件触发时调用的函数。<br>如下示例中,每当用户点击地图时,会弹出一个警告框:</p><figure class="highlight plain"><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">var map = new BMap.Map("container"); </span><br><span class="line">map.centerAndZoom(new BMap.Point(116.404, 39.915), 11); </span><br><span class="line">map.addEventListener("click", function(){ </span><br><span class="line"> alert("您点击了地图。"); </span><br><span class="line">}</span><br><span class="line">);</span><br></pre></td></tr></table></figure><h3 id="捕获状态"><a href="#捕获状态" class="headerlink" title="捕获状态"></a>捕获状态</h3><p>通过监听事件还可以捕获事件触发后的状态。<br>如下示例,显示用户拖动地图后地图中心的经纬度信息:</p><figure class="highlight plain"><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">var map = new BMap.Map("container"); </span><br><span class="line">map.centerAndZoom(new BMap.Point(116.404, 39.915), 11); </span><br><span class="line">map.addEventListener("dragend", function(){ </span><br><span class="line"> var center = map.getCenter(); </span><br><span class="line"> alert("地图中心点变更为:" + center.lng + ", " + center.lat); </span><br><span class="line">}</span><br><span class="line">);</span><br></pre></td></tr></table></figure><h3 id="事件参数和this"><a href="#事件参数和this" class="headerlink" title="事件参数和this"></a>事件参数和this</h3><p>在标准的DOM事件模型中(DOM Level 2 Events),监听函数会得到一个事件对象e,在e中可以获取有关该事件的信息。同时在监听函数中this会指向触发该事件的DOM元素。</p><p>百度地图API的事件模型与此类似,在事件监听函数中传递事件对象e,每个e参数至少包含事件类型(type)和触发该事件的对象(target)。</p><p>API还保证函数内的this指向触发(同时也是绑定)事件的API对象。</p><h4 id="事件参数e获取有关信息"><a href="#事件参数e获取有关信息" class="headerlink" title="事件参数e获取有关信息"></a>事件参数e获取有关信息</h4><p>例如,通过参数e得到点击的经纬度坐标:</p><figure class="highlight plain"><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">var map = new BMap.Map("container"); </span><br><span class="line">map.centerAndZoom(new BMap.Point(116.404, 39.915), 11); </span><br><span class="line">map.addEventListener("click", function(e){ </span><br><span class="line"> alert(e.point.lng + ", " + e.point.lat); </span><br><span class="line">});</span><br></pre></td></tr></table></figure><h4 id="this指向DOM元素"><a href="#this指向DOM元素" class="headerlink" title="this指向DOM元素"></a>this指向DOM元素</h4><p>监听函数中this会指向触发该事件的DOM元素。<br>如下示例,通过this得到地图缩放后的级别:</p><figure class="highlight plain"><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">var map = new BMap.Map("container"); </span><br><span class="line">map.centerAndZoom(new BMap.Point(116.404, 39.915), 11); </span><br><span class="line">map.addEventListener("zoomend", function(){ </span><br><span class="line"> alert("地图缩放至:" + this.getZoom() + "级"); </span><br><span class="line">});</span><br></pre></td></tr></table></figure><h3 id="移除监听事件"><a href="#移除监听事件" class="headerlink" title="移除监听事件"></a>移除监听事件</h3><p>当您不再希望监听事件时,可以将事件监听进行移除。每个API对象提供了removeEventListener用来移除事件监听函数。</p><p>如下示例中,用户第一次点击地图会触发事件监听函数,在函数内部对事件监听进行了移除,因此后续的点击操作则不会触发监听函数。</p><figure class="highlight plain"><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">var map = new BMap.Map("container"); </span><br><span class="line">map.centerAndZoom(new BMap.Point(116.404, 39.915), 11); </span><br><span class="line">function showInfo(e){ </span><br><span class="line"> alert(e.point.lng + ", " + e.point.lat); </span><br><span class="line"> map.removeEventListener("click", showInfo); </span><br><span class="line">} </span><br><span class="line">map.addEventListener("click", showInfo);</span><br></pre></td></tr></table></figure><h1 id="地图数据获取"><a href="#地图数据获取" class="headerlink" title="地图数据获取"></a>地图数据获取</h1><h2 id="检索POI"><a href="#检索POI" class="headerlink" title="检索POI"></a>检索POI</h2><p>检索服务提供某一特定地区的兴趣点位置查询服务(POI:Point of Interest,感兴趣点)。允许设置检索城市、检索圆形区域内POI、检索矩形区域内POI、检索结果详情。</p><h2 id="提供的检索服务"><a href="#提供的检索服务" class="headerlink" title="提供的检索服务"></a>提供的检索服务</h2><p>LocalSearch:本地搜索,提供某一特定地区的位置搜索服务,比如在北京市搜索“公园”。目前支持城市检索、圆形检索、矩形检索。</p><p>说明:BMap.LocalSearch提供本地搜索服务,在使用本地搜索时需要为其设置一个检索区域,检索区域可以是BMap.Map对象、BMap.Point对象或者是省市名称(比如:”北京市”)的字符串。BMap.LocalSearch构造函数的第二个参数是可选的,您可以在其中指定结果的呈现。BMap.RenderOptions类提供了若干控制呈现的属性,其中map指定了结果所展现的地图实例,panel指定了结果列表的容器元素。</p><h2 id="检索POI方法"><a href="#检索POI方法" class="headerlink" title="检索POI方法"></a>检索POI方法</h2><p>检索POI服务提供三种检索方法:城市检索、圆形区域检索、矩形区域检索。</p><h3 id="城市检索"><a href="#城市检索" class="headerlink" title="城市检索"></a>城市检索</h3><p>search方法提供根据关键字检索特定POI信息服务。 如下示例,为根据关键字“天安门”检索POI:</p><figure class="highlight plain"><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">var map = new BMap.Map("container"); </span><br><span class="line">map.centerAndZoom(new BMap.Point(116.404, 39.915), 11); </span><br><span class="line">var local = new BMap.LocalSearch(map, { </span><br><span class="line"> renderOptions:{map: map} </span><br><span class="line">}); </span><br><span class="line">local.search("天安门");</span><br></pre></td></tr></table></figure><h3 id="圆形区域检索"><a href="#圆形区域检索" class="headerlink" title="圆形区域检索"></a>圆形区域检索</h3><p>searchNearby方法提供圆形区域检索服务。您可以在某个地点附近进行搜索,也可以在某一个特定结果点周围进行搜索。 下面示例展示如何在前门附近搜索小吃:</p><figure class="highlight plain"><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">var map = new BMap.Map("container"); </span><br><span class="line">map.centerAndZoom(new BMap.Point(116.404, 39.915), 11); </span><br><span class="line">var local = new BMap.LocalSearch(map, </span><br><span class="line"> { renderOptions:{map: map, autoViewport: true}}); </span><br><span class="line">local.searchNearby("小吃", "前门");</span><br></pre></td></tr></table></figure><h3 id="矩形区域检索"><a href="#矩形区域检索" class="headerlink" title="矩形区域检索"></a>矩形区域检索</h3><p>searchInBounds方法提供矩形区域检索服务。矩形范围搜索将根据您提供的视野范围提供搜索结果。<br>注意:当搜索范围过大时可能会出现无结果的情况。</p><p>如下示例,展示在当前地图视野范围内搜索银行:</p><figure class="highlight plain"><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">var map = new BMap.Map("container"); </span><br><span class="line">map.centerAndZoom(new BMap.Point(116.404, 39.915), 14); </span><br><span class="line">var local = new BMap.LocalSearch(map, </span><br><span class="line"> { renderOptions:{map: map}}); </span><br><span class="line">local.searchInBounds("银行", map.getBounds());</span><br></pre></td></tr></table></figure><h3 id="配置搜索"><a href="#配置搜索" class="headerlink" title="配置搜索"></a>配置搜索</h3><p>BMap.LocalSearch提供了若干配置方法,通过它们可以自定义搜索服务的行为以满足您的需求。</p><p>如下示例中,我们调整每页显示8个结果,并且根据结果点位置自动调整地图视野,不显示第一条结果的信息窗口:</p><figure class="highlight plain"><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">var map = new BMap.Map("container"); </span><br><span class="line">map.centerAndZoom(new BMap.Point(116.404, 39.915), 14); </span><br><span class="line">var local = new BMap.LocalSearch("北京市", </span><br><span class="line"> {renderOptions: {map: map,autoViewport: true},pageCapacity: 8}); </span><br><span class="line">local.search("中关村");</span><br></pre></td></tr></table></figure><h3 id="结果面板"><a href="#结果面板" class="headerlink" title="结果面板"></a>结果面板</h3><p>通过设置BMap.LocalSearchOptions.renderOptions.panel属性,可以为本地搜索对象提供一个结果列表容器,搜索结果会自动添加到容器元素中。</p><p>如下示例:</p><figure class="highlight plain"><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">var map = new BMap.Map("container"); </span><br><span class="line">map.centerAndZoom(new BMap.Point(116.404, 39.915), 11); </span><br><span class="line">var local = new BMap.LocalSearch(map, </span><br><span class="line"> {renderOptions: {map: map,panel: "results"}); </span><br><span class="line">local.search("中关村");</span><br></pre></td></tr></table></figure><h3 id="数据接口"><a href="#数据接口" class="headerlink" title="数据接口"></a>数据接口</h3><p>除了搜索结果会自动添加到地图和列表外,您还可以通过数据接口获得详细的数据信息,结合地图API您可以自行向地图添加标注和信息窗口。</p><p>BMap.LocalSearch和BMap.LocalSearchOptions类提供了若干设置回调函数的接口,通过它们可得到搜索结果的数据信息。 例如,通过onSearchComplete回调函数参数可以获得BMap.LocalResult对象实例,它包含了每一次搜索结果的数据信息。 当回调函数被执行时,您可以使用BMap.LocalSearch.getStatus()方法来确认搜索是否成功或者得到错误的详细信息。</p><p>在下面这个示例中,通过onSearchComplete回调函数得到第一页每条结果的标题和地址信息,并输出到页面上:</p><figure class="highlight plain"><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">var map = new BMap.Map("container"); </span><br><span class="line">map.centerAndZoom(new BMap.Point(116.404, 39.915), 11); </span><br><span class="line">var options = { </span><br><span class="line"> onSearchComplete: function(results){ </span><br><span class="line"> if (local.getStatus() == BMAP_STATUS_SUCCESS){ </span><br><span class="line"> // 判断状态是否正确 </span><br><span class="line"> var s = []; </span><br><span class="line"> for (var i = 0; i < results.getCurrentNumPois(); i ++){ </span><br><span class="line"> s.push(results.getPoi(i).title + ", " + results.getPoi(i).address); </span><br><span class="line"> } </span><br><span class="line"> document.getElementById("log").innerHTML = s.join("<br>"); </span><br><span class="line"> } </span><br><span class="line"> } </span><br><span class="line"> }; </span><br><span class="line">var local = new BMap.LocalSearch(map, options); </span><br><span class="line">local.search("公园");</span><br></pre></td></tr></table></figure><h2 id="地址解析"><a href="#地址解析" class="headerlink" title="地址解析"></a>地址解析</h2><p>地址解析服务提供从地址转换到经纬度的服务,反之,逆地址解析则提供从经纬度坐标转换到地址的转换功能。</p><h3 id="提供的转换类"><a href="#提供的转换类" class="headerlink" title="提供的转换类"></a>提供的转换类</h3><p>Geocoder:逆/地址解析,用于坐标与地址间的相互转换。</p><h3 id="地址解析服务"><a href="#地址解析服务" class="headerlink" title="地址解析服务"></a>地址解析服务</h3><p>根据地址描述获得坐标信息。</p><p>百度地图API提供Geocoder类进行地址解析,您可以通过Geocoder.getPoint()方法来将一段地址描述转换为一个坐标。</p><p>如下示例,我们将地址“北京市海淀区上地10街10号”转换获取该位置的地理经纬度坐标,并在这个位置上添加一个标注。 注意:在调用Geocoder.getPoint()方法时您需要提供地址解析所在的城市(本例为“北京市”)。</p><figure class="highlight plain"><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">var map = new BMap.Map("l-map"); </span><br><span class="line">map.centerAndZoom(new BMap.Point(116.404, 39.915), 11); </span><br><span class="line">// 创建地址解析器实例 </span><br><span class="line">var myGeo = new BMap.Geocoder(); </span><br><span class="line">// 将地址解析结果显示在地图上,并调整地图视野 </span><br><span class="line">myGeo.getPoint("北京市海淀区上地10街10号", function(point){ </span><br><span class="line"> if (point) { </span><br><span class="line"> map.centerAndZoom(point, 16); </span><br><span class="line"> map.addOverlay(new BMap.Marker(point)); </span><br><span class="line"> } </span><br><span class="line"> }, </span><br><span class="line">"北京市");</span><br></pre></td></tr></table></figure><h3 id="逆地址解析服务"><a href="#逆地址解析服务" class="headerlink" title="逆地址解析服务"></a>逆地址解析服务</h3><p>根据坐标点获得该地点的地址描述,是地址解析的逆向转换。</p><p>您可以通过Geocoder.getLocation()方法获得地址描述。当解析工作完成后,您提供的回调函数将会被触发。如果解析成功,则回调函数的参数为GeocoderResult对象,否则为null。</p><h4 id="指定经纬度获取地址"><a href="#指定经纬度获取地址" class="headerlink" title="指定经纬度获取地址"></a>指定经纬度获取地址</h4><figure class="highlight plain"><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">var map = new BMap.Map("l-map"); </span><br><span class="line">map.centerAndZoom(new BMap.Point(116.404, 39.915), 11); </span><br><span class="line">// 创建地理编码实例 </span><br><span class="line">var myGeo = new BMap.Geocoder(); </span><br><span class="line">// 根据坐标得到地址描述 </span><br><span class="line">myGeo.getLocation(new BMap.Point(116.364, 39.993), function(result){ </span><br><span class="line"> if (result){ </span><br><span class="line"> alert(result.address); </span><br><span class="line"> } </span><br><span class="line">});</span><br></pre></td></tr></table></figure><h4 id="鼠标点击地图获取地址"><a href="#鼠标点击地图获取地址" class="headerlink" title="鼠标点击地图获取地址"></a>鼠标点击地图获取地址</h4><figure class="highlight plain"><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">var map = new BMap.Map("allmap");</span><br><span class="line">var point = new BMap.Point(116.331398,39.897445);</span><br><span class="line">map.centerAndZoom(point,12);</span><br><span class="line">var geoc = new BMap.Geocoder(); </span><br><span class="line">map.addEventListener("click", function(e){ </span><br><span class="line"> var pt = e.point;</span><br><span class="line"> geoc.getLocation(pt, function(rs){</span><br><span class="line"> var addComp = rs.addressComponents;</span><br><span class="line"> alert(addComp.province + ", " + addComp.city + ", " + addComp.district + ", " + addComp.street + ", " + addComp.streetNumber);</span><br><span class="line"> }); </span><br><span class="line">});</span><br></pre></td></tr></table></figure><h2 id="出行路线规划"><a href="#出行路线规划" class="headerlink" title="出行路线规划"></a>出行路线规划</h2><p>提供的出行方式包括公交、驾车、步行。开发者可以使用我们提供的默认展示效果,也可通过结果面板或数据接口获取返回结果,自己编写实现界面。图片支持自定义。</p><h3 id="提供的路线规划方式"><a href="#提供的路线规划方式" class="headerlink" title="提供的路线规划方式"></a>提供的路线规划方式</h3><table><thead><tr><th>路线规划方式</th><th>类名</th><th>简介</th></tr></thead><tbody><tr><td>公交</td><td>TransitRoute</td><td>提供公交路线规划搜索服务</td></tr><tr><td>驾车</td><td>DrivingRoute</td><td>提供驾车路线规划服务</td></tr><tr><td>步行</td><td>WalkingRoute</td><td>提供步行路线规划服务</td></tr></tbody></table><h3 id="驾车路线规划"><a href="#驾车路线规划" class="headerlink" title="驾车路线规划"></a>驾车路线规划</h3><p>BMap.DrivingRoute提供驾车导航服务。与公交导航不同的是,驾车导航的搜索范围可以设置为省。</p><h4 id="使用服务示例"><a href="#使用服务示例" class="headerlink" title="使用服务示例"></a>使用服务示例</h4><figure class="highlight plain"><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">var map = new BMap.Map("container"); </span><br><span class="line">map.centerAndZoom(new BMap.Point(116.404, 39.915), 14); </span><br><span class="line">var driving = new BMap.DrivingRoute(map, { </span><br><span class="line"> renderOptions: { </span><br><span class="line"> map: map, </span><br><span class="line"> autoViewport: true </span><br><span class="line"> } </span><br><span class="line">}); </span><br><span class="line">driving.search("中关村", "天安门");</span><br></pre></td></tr></table></figure><h4 id="结果面板-1"><a href="#结果面板-1" class="headerlink" title="结果面板"></a>结果面板</h4><p>下面示例中,我们提供了结果面板参数,方案描述会自动展示到页面上。</p><figure class="highlight plain"><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">var map = new BMap.Map("container"); </span><br><span class="line">map.centerAndZoom(new BMap.Point(116.404, 39.915), 14); </span><br><span class="line">var driving = new BMap.DrivingRoute(map, { </span><br><span class="line"> renderOptions: { </span><br><span class="line"> map : map, </span><br><span class="line"> panel : "results", </span><br><span class="line"> autoViewport: true </span><br><span class="line"> } </span><br><span class="line">}); </span><br><span class="line">driving.search("中关村", "天安门");</span><br></pre></td></tr></table></figure><h4 id="数据接口-1"><a href="#数据接口-1" class="headerlink" title="数据接口"></a>数据接口</h4><p>驾车导航服务也提供了丰富的数据接口,通过onSearchComplete回调函数可以得到BMap.DrivingRouteResult对象,它包含了驾车导航结果数据信息。<br>结果会包含若干驾车方案(目前仅提供一条方案),每条方案中包含了若干驾车线路(如果导航方案只包含一个目的地,那么驾车线路的个数就为1,如果方案包含若干个目的地,则驾车线路的个数会大于1。目前API尚不支持多个目的地的驾车导航)。<br>每条驾车线路又会包含一系列的关键步骤(BMap.Step),关键步骤描述了具体驾车行驶方案,可通过BMap.Step.getDescription()方法获得。</p><figure class="highlight plain"><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">var map = new BMap.Map("container"); </span><br><span class="line">map.centerAndZoom(new BMap.Point(116.404, 39.915), 14); </span><br><span class="line">var options = { </span><br><span class="line"> onSearchComplete: function(results){ </span><br><span class="line"> if (driving.getStatus() == BMAP_STATUS_SUCCESS){ </span><br><span class="line"> // 获取第一条方案 </span><br><span class="line"> var plan = results.getPlan(0); </span><br><span class="line"> // 获取方案的驾车线路 </span><br><span class="line"> var route = plan.getRoute(0); </span><br><span class="line"> // 获取每个关键步骤,并输出到页面 </span><br><span class="line"> var s = []; </span><br><span class="line"> for (var i = 0; i < route.getNumSteps(); i ++){ </span><br><span class="line"> var step = route.getStep(i); </span><br><span class="line"> s.push((i + 1) + ". " + step.getDescription()); </span><br><span class="line"> } </span><br><span class="line"> document.getElementById("log").innerHTML = s.join("<br>"); </span><br><span class="line"> } </span><br><span class="line"> } </span><br><span class="line">}; </span><br><span class="line">var driving = new BMap.DrivingRoute(map, options); </span><br><span class="line">driving.search("中关村","天安门");</span><br></pre></td></tr></table></figure><h3 id="步行路线规划"><a href="#步行路线规划" class="headerlink" title="步行路线规划"></a>步行路线规划</h3><p>BMap.WalkingRoute提供步行线路规划服务。基本用法和驾车线路规划类似。</p><figure class="highlight plain"><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">var map = new BMap.Map("container"); </span><br><span class="line"> map.centerAndZoom(new BMap.Point(116.404, 39.915), 14); </span><br><span class="line"> var walk = new BMap.WalkingRoute(map, { </span><br><span class="line"> renderOptions: {map: map} </span><br><span class="line"> }); </span><br><span class="line">walk.search("王府井", "西单");</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
百度地图JSai是我们在日常开发中最常用的地图JSapi之一, 详细使用总结如下
</summary>
</entry>
<entry>
<title>MySQL的基本使用</title>
<link href="http://blog.changerhe.cn/2017/12/23/MySQL%E7%9A%84%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/"/>
<id>http://blog.changerhe.cn/2017/12/23/MySQL的基本使用/</id>
<published>2017-12-23T11:36:43.000Z</published>
<updated>2018-08-12T11:09:10.451Z</updated>
<content type="html"><![CDATA[<h2 id="登陆"><a href="#登陆" class="headerlink" title="登陆"></a>登陆</h2><p><code>mysql -u root -p</code></p><h2 id="显示所有数据库信息"><a href="#显示所有数据库信息" class="headerlink" title="显示所有数据库信息"></a>显示所有数据库信息</h2><p><code>show databases</code></p><h2 id="创建数据库的同时记得同步设置其编码格式-否则默认为utf8"><a href="#创建数据库的同时记得同步设置其编码格式-否则默认为utf8" class="headerlink" title="创建数据库的同时记得同步设置其编码格式, 否则默认为utf8"></a>创建数据库的同时记得同步设置其编码格式, 否则默认为utf8</h2><p><code>create database <数据库名> character set utf8;</code></p><h2 id="查看数据库的编码方式"><a href="#查看数据库的编码方式" class="headerlink" title="查看数据库的编码方式"></a>查看数据库的编码方式</h2><p><code>show variables like "%char%"</code></p><h2 id="切换数据库"><a href="#切换数据库" class="headerlink" title="切换数据库"></a>切换数据库</h2><p><code>use 数据库名</code></p><h2 id="创建数据表"><a href="#创建数据表" class="headerlink" title="创建数据表"></a>创建数据表</h2><figure class="highlight plain"><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">create table [if not exists] table_name (</span><br><span class="line"> column_name data_type</span><br><span class="line"> ...</span><br><span class="line">)</span><br></pre></td></tr></table></figure><h2 id="查看数据表"><a href="#查看数据表" class="headerlink" title="查看数据表"></a>查看数据表</h2><p><code>show tables</code></p><p><code>show tables from mysql</code>: 查看mysql中所有的数据表</p><h2 id="查看表的列"><a href="#查看表的列" class="headerlink" title="查看表的列"></a>查看表的列</h2><p><code>show cloumns from 表名</code></p><h2 id="查看表结构"><a href="#查看表结构" class="headerlink" title="查看表结构"></a>查看表结构</h2><p><code>desc 表名</code></p><h2 id="向数据表中写入记录"><a href="#向数据表中写入记录" class="headerlink" title="向数据表中写入记录"></a>向数据表中写入记录</h2><p><code>insert [into] 表名 [列名列表] values(值)</code></p><p>当需要为列的部分数据写入记录的时候,i 需要在表名中指定需要插入的对应列名称</p><p><code>insert tb1(username, age) values('Changer', 18);</code></p><h2 id="查看数据记录"><a href="#查看数据记录" class="headerlink" title="查看数据记录"></a>查看数据记录</h2><p><code>select 表达式 from 表名</code></p><p>在tb1表中查看所有记录: <code>select * from tb1</code></p><h2 id="设置字段的值为空值或者非空"><a href="#设置字段的值为空值或者非空" class="headerlink" title="设置字段的值为空值或者非空"></a>设置字段的值为空值或者非空</h2><p>在创建表的时候设置表的列的属性为not null或 为null, 这两个是成对出现的</p><p><code>null</code> / <code>not null</code></p><h2 id="设置字段的值自增"><a href="#设置字段的值自增" class="headerlink" title="设置字段的值自增"></a>设置字段的值自增</h2><p>设置字段的值自增时, 每个表只能设置一个, 并且需要将该值设置为主键(主键约束)</p><p><code>auto_increment</code></p><h2 id="约束"><a href="#约束" class="headerlink" title="约束"></a>约束</h2><h3 id="唯一约束"><a href="#唯一约束" class="headerlink" title="唯一约束"></a>唯一约束</h3><p>唯一约束可以保证记录的唯一性</p><p>唯一约束的字段可以为空值</p><p>每张数据表可以有多个唯一约束, 但是只能有一个主键约束</p><p><code>unique key</code></p><h3 id="默认约束"><a href="#默认约束" class="headerlink" title="默认约束"></a>默认约束</h3><p>也就是默认值</p><p>当插入记录时, 如果没有明确为字段赋值, 则自动服务默认值</p><p><code>default 默认值</code></p><p>约束保证数据的完整性和一致性</p><p>约束分为表级约束和列级约束</p><p>约束类型包括: 非空约束, 主键约束, 唯一约束, 默认约束, 外键约束</p><h3 id="外键约束"><a href="#外键约束" class="headerlink" title="外键约束"></a>外键约束</h3><p>保证数据的唯一性, 实现一对一或一对多的关系</p><p>外键约束的要求:</p><ol><li>父表和子表必须使用相同的存储引擎(InnoDB)</li><li>外键列和参照列必须具有相似的数据类型, 其中数字的长度或是否有符号位必须相同, 而字符的长度则可以不同</li><li>外键列和参照列必须创建索引, 如果外键列不存在索引的话, mysql将会自动创建索引</li></ol><p><code>foreign key (当前表的字段名) references 关联的表 (关联的表字段)</code></p><h2 id="修改数据表"><a href="#修改数据表" class="headerlink" title="修改数据表"></a>修改数据表</h2><h3 id="添加单列-为表结构中插入一个列"><a href="#添加单列-为表结构中插入一个列" class="headerlink" title="添加单列(为表结构中插入一个列)"></a>添加单列(为表结构中插入一个列)</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">alter table tbl_name add col_name col_type [first / after col_name];</span><br></pre></td></tr></table></figure><p>插入单列, 添加时指定该列的类型, 并指定其位于首行(first) 或者在某行之后(after)</p><h3 id="删除单列"><a href="#删除单列" class="headerlink" title="删除单列"></a>删除单列</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">aleter table tbl_name drop col_name;</span><br></pre></td></tr></table></figure><p>删除单列上面这一整列的内容</p><h3 id="删除和增加列的主键约束-外键约束"><a href="#删除和增加列的主键约束-外键约束" class="headerlink" title="删除和增加列的主键约束, 外键约束"></a>删除和增加列的主键约束, 外键约束</h3><p>略</p><h3 id="修改列定义"><a href="#修改列定义" class="headerlink" title="修改列定义"></a>修改列定义</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">alter table tbl_name modify col_name col_type [first / after col_name];</span><br></pre></td></tr></table></figure><p>注意, 修改列定义的时候, 由大修改为小的, 有可能会造成数据丢失</p><h3 id="修改列名称"><a href="#修改列名称" class="headerlink" title="修改列名称"></a>修改列名称</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">alter table tbl_name change old_col_name new_col_name new_col_type [first / after col_name];</span><br></pre></td></tr></table></figure><h3 id="修改数据表名"><a href="#修改数据表名" class="headerlink" title="修改数据表名"></a>修改数据表名</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">alter table tbl_name rename new_tbl_name;</span><br></pre></td></tr></table></figure><h2 id="插入记录"><a href="#插入记录" class="headerlink" title="插入记录"></a>插入记录</h2><p>对于插入内容中的自增数据, 当我们传一个<code>null</code>或者传一个<code>default</code>的时候, 其内容会产生一个自增的数据, 但是不能不传, 不传的话会产生报错</p><figure class="highlight plain"><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">create table users(</span><br><span class="line"> id smallint unsigned primary key auto_increment,</span><br><span class="line"> username varchar(20) not null,</span><br><span class="line"> password varchar(32) not null,</span><br><span class="line"> age tinyint unsigned not null,</span><br><span class="line"> sex boolean</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>对于上面的结构, 我们进行数据插入的时候, 如果需要其内容自增, 可以直接使用<code>null</code>或者传一个<code>default</code></p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">insert users values(null, 'John', '123', 15, 1);</span><br></pre></td></tr></table></figure><p>上段命令用于插入一个自增的数据, username为John, password为123, age为15, 性别为1</p><p>所以同样的, 我们是用default替代null, 也能得到相同的结果</p><p>对于tinyint字段, 我们可以使用数学表达式来进行输入, mysql将会把内容计算之后插入</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">insert users values(null, 'John', '345', 3*7-5, 0);</span><br></pre></td></tr></table></figure><p>通过在插入前进行加密, 可以直接在数据库中插入对应数据的加密值</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">insert users values(null, 'Changer', md5('123'), 18, 0);</span><br></pre></td></tr></table></figure><h3 id="set-select"><a href="#set-select" class="headerlink" title="set-select"></a>set-select</h3><p>与前一种方式的区别在于, 此方法可以使用子查询</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">insert tb_name set key_1='value_1' key_2='value2';</span><br></pre></td></tr></table></figure><p>另外, 还可以使用insert select语句来将查询结果插入到指定数据表</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">insert tb_name [col_name] select</span><br></pre></td></tr></table></figure><h3 id="单表更新记录"><a href="#单表更新记录" class="headerlink" title="单表更新记录"></a>单表更新记录</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">update [low_primarity] [ignore] table_reference set col_name1={expr1|default}[,col_name2={expr2|default}]... [where where_condition]</span><br></pre></td></tr></table></figure><p>例子:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">update users set age = age + 5;</span><br></pre></td></tr></table></figure><p>为没个数据的年龄字段全部加上5</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">update users set age = age - id, sex = 0;</span><br></pre></td></tr></table></figure><p>为没个数据的年龄等于源年龄减id, 所有sex都是0</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">update users set age = age + 10 where id % 2 = 0;</span><br></pre></td></tr></table></figure><p>为所有id能被2整除的字段的年龄加10</p><h3 id="单表删除操作"><a href="#单表删除操作" class="headerlink" title="单表删除操作"></a>单表删除操作</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">delete from table_name [where where_condition];</span><br></pre></td></tr></table></figure><p>删除数据表中的内容, 不加where时会被全部删除</p><h3 id="删除行操作"><a href="#删除行操作" class="headerlink" title="删除行操作"></a>删除行操作</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">DELETE FROM 表名称 WHERE 列名称 = 值</span><br></pre></td></tr></table></figure><p>注, 当有外键约束在其中的时候, 该行是无法删除的</p><h2 id="select语句"><a href="#select语句" class="headerlink" title="select语句"></a>select语句</h2><ul><li>select中字段名的出现顺序将会影响输出的结果顺序</li><li>select中的字段别名将会影响输出的结果名</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select users.id,users.username from users;</span><br></pre></td></tr></table></figure><p>可以在输出的select选择时加上前缀, 以免出现重复的情况</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select id as userId, username as uname from users;</span><br></pre></td></tr></table></figure><p>可以将输出的结果的列名设置一个别名来进行输出</p><h3 id="group-by-分组"><a href="#group-by-分组" class="headerlink" title="group by 分组"></a>group by 分组</h3><p>将select中的查询条件进行分组</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select sex from users group by sex;</span><br></pre></td></tr></table></figure><p>group by也允许在后面传递一个数字, 表示以select所选择的第几个字作为分组条件</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select sex from users group by 1;</span><br></pre></td></tr></table></figure><p>得到的结果与上一表达式相同</p><p>但是需要注意的是, group by后面跟的条件是不能设置为之前select中没有的内容的, 如果需要设置为之前没有的内容, 应该使用函数的方式进行书写</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select sex from users group by 1 having count(id) <= 2;</span><br></pre></td></tr></table></figure><h3 id="order-by-对结果进行排序"><a href="#order-by-对结果进行排序" class="headerlink" title="order by 对结果进行排序"></a>order by 对结果进行排序</h3><p>通过在select语句后加上order by的方式可以实现输出内容的顺序排序, 默认为由低向高排序, 可加desc来进行由高向低排序</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select * from users order by age desc;</span><br></pre></td></tr></table></figure><p>对于输出排序结果相同的情况, 我们则需要增加一个排序条件, 排序条件可直接以逗号分隔</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select * from users order by age desc, id;</span><br></pre></td></tr></table></figure><p>上段语句的意思是, 显示所有users表中内容, 其中输出结果以age从高向低排列, 当age相同时, 以id排序, 从低向高排列</p><h3 id="限制查询limit"><a href="#限制查询limit" class="headerlink" title="限制查询limit"></a>限制查询limit</h3><p>可以进行限制, 每次返回几条数据, 从第几条开始</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select * from users limit 0, 2;</span><br></pre></td></tr></table></figure><p>以上表示返回两条数据, 从第0条开始</p><p>需要注意的是, 每次返回会以表中的默认排序顺序进行排序</p><h3 id="创建新表-并将原来表的内容输入到新表"><a href="#创建新表-并将原来表的内容输入到新表" class="headerlink" title="创建新表, 并将原来表的内容输入到新表"></a>创建新表, 并将原来表的内容输入到新表</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">insert test(username) select username from users where age >= 20;</span><br></pre></td></tr></table></figure><p>上个语句的意思是, 为test中的username字段, 插入users表中age大于等于20的所有内容</p><h2 id="子查询"><a href="#子查询" class="headerlink" title="子查询"></a>子查询</h2><p>求平均值</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select avg(goods_price) from tdb_goods;</span><br></pre></td></tr></table></figure><p>求平均值, 并将值省略小数点后两位</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select round(avg(goods_price), 2) from tdb_goods;</span><br></pre></td></tr></table></figure><p>输出符合条件的, 需要的内容</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">selct goods_id,goods_name,goods_price from tdb_goods where goods_price >= 5636;</span><br></pre></td></tr></table></figure><p>上面的查询语句输出<code>goods_id</code>, <code>goods_name</code>, <code>goods_price</code>三个字段, 输出的条件是, <code>goods_price</code>的值大于等于5636</p><p>所以同样的, 因为上面的方法我们是分开两个方法来执行了, 当我们需要作为一条语句执行的时候, 可以将两条语句合并起来</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select goods_id,goods_name,goods_price from tdb_goods where goods_price >= (select round(avg(goods_price),2) from tdb_goods);</span><br></pre></td></tr></table></figure><h3 id="使用any-some-all来修饰的比较运算符"><a href="#使用any-some-all来修饰的比较运算符" class="headerlink" title="使用any, some, all来修饰的比较运算符"></a>使用any, some, all来修饰的比较运算符</h3><h3 id="联合使用select和insert语句将原表的分类导入到另一张表"><a href="#联合使用select和insert语句将原表的分类导入到另一张表" class="headerlink" title="联合使用select和insert语句将原表的分类导入到另一张表"></a>联合使用select和insert语句将原表的分类导入到另一张表</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">insert ttb_goods_cates(cate_name) selct goods_cate from tdb_goods order by goods_cate;</span><br></pre></td></tr></table></figure><p>上个语句的意思是, 将<code>tdb_goods</code>表中的<code>goods_cate</code>的分类导出到<code>ttb_goods_cates</code>表中的<code>cate_name</code>字段中去</p><h3 id="表连接"><a href="#表连接" class="headerlink" title="表连接"></a>表连接</h3><p>连接两表, 并将原表中的各种分类导出到另一张表之后, 我们暂时还没有办法去将原表的内容与导出的表的分类的对应id进行匹配, 那么可以使用多表更新的方式, 使两表产生一个连接的关系</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">update tdb_goods inner join tdb_goods_cates on goods_cate = cate_name set goods_cate = cate_id;</span><br></pre></td></tr></table></figure><p>上个语句的意思是, 将<code>tdb_goods</code>这个表, 设置<code>tdb_goods_cates</code>作为其子表, 并更新<code>goods_cate</code>的内容为<code>cate_id</code>前提是<code>good_cate = cate_name</code></p><h3 id="创建表的同时将内容插入数据表"><a href="#创建表的同时将内容插入数据表" class="headerlink" title="创建表的同时将内容插入数据表"></a>创建表的同时将内容插入数据表</h3><p>在创建表的同时, 可以将表的内容进行填充, 使用select语句</p><figure class="highlight plain"><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">create table tdb_goods_brands (</span><br><span class="line"> brand_id smallint unsigned primary key auto_increment,</span><br><span class="line"> brand_name varchar(40) not null</span><br><span class="line">)</span><br><span class="line">select brand_name from tdb_goods group by brand_name;</span><br></pre></td></tr></table></figure><p>同样的, 我们需要在处理完成之后, 根据分类对原表进行更新</p><p>此时要注意的是, 我们在两个表中都有<code>brand_name</code>这个字段, 因此我们使用时, mysql并不知道我们两个字段指得是谁的, 所以一般通用的做法是, 做一个别名</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">update tdb_goods as a inner join tdb_goods_brands as b on a.brand_name = b.brand_name set a.brand_name = brand_id;</span><br></pre></td></tr></table></figure><p>通过别名的方式, 可以是mysql对相应的字段进行操作</p><p>但是此时我们虽然改了原表中的内容, 但是现在还存在一个问题, 就是我们原表的数据中是用的<code>varchar</code>进行存储的, 自然会浪费比较多的空间, 此时我们可以使用<code>alter</code>来对表内容中的字段名称和类型进行一下更改</p><figure class="highlight plain"><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">alter table tdb_goods</span><br><span class="line">change goods_cate cate_id smallint unsigned not null,</span><br><span class="line">change brand_name brand_id smallint unsigned not null;</span><br></pre></td></tr></table></figure><h2 id="连接"><a href="#连接" class="headerlink" title="连接"></a>连接</h2><h2 id="无限极分类表设计"><a href="#无限极分类表设计" class="headerlink" title="无限极分类表设计"></a>无限极分类表设计</h2><figure class="highlight plain"><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">create table tdb_goods_types(</span><br><span class="line"> type_id smallint unsigned primary key auto_increment,</span><br><span class="line"> type_name varchar(20) not null,</span><br><span class="line"> parent_id smallint unsigned not null default 0</span><br><span class="line">);</span><br></pre></td></tr></table></figure><p>此时我们插入一些数据, <code>parent_id</code>对应了同表中的<code>type_id</code>字段</p><p>因此我们可以在这种情况下, 直接使用这个表来连接其表本身</p><figure class="highlight plain"><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">select s.type_id,s.type_name,p.type_name from tdb_goods_types as s join tdb_goods_types as p</span><br><span class="line">on s.parent_id = p.type_id;</span><br></pre></td></tr></table></figure><h2 id="字符函数"><a href="#字符函数" class="headerlink" title="字符函数"></a>字符函数</h2><h3 id="concat"><a href="#concat" class="headerlink" title="concat"></a>concat</h3><p>连接两个或多个字符串</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select concat('a', 'b', 'c'); // abc</span><br></pre></td></tr></table></figure><h3 id="concat-ws"><a href="#concat-ws" class="headerlink" title="concat_ws()"></a>concat_ws()</h3><p>使用指定字符串连接后面的字符串</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select concat_ws('-', 'a', 'b', 'c'); // a-b-c</span><br></pre></td></tr></table></figure><h3 id="format"><a href="#format" class="headerlink" title="format"></a>format</h3><p>数字格式化, 会将数字加上千分位, 并省略到小数点后某位</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select format(123456.456, 2); // 123,456.46</span><br></pre></td></tr></table></figure><h3 id="lower"><a href="#lower" class="headerlink" title="lower"></a>lower</h3><p>转换为小写</p><h3 id="upper"><a href="#upper" class="headerlink" title="upper"></a>upper</h3><p>转换为大写</p><h3 id="left"><a href="#left" class="headerlink" title="left"></a>left</h3><p>获取左侧字符</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select lower(left('MySQL'), 2); // my</span><br></pre></td></tr></table></figure><h3 id="right"><a href="#right" class="headerlink" title="right"></a>right</h3><p>获取右侧字符</p><h3 id="length"><a href="#length" class="headerlink" title="length"></a>length</h3><p>获取字符串长度</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select length('my sql'); // 6</span><br></pre></td></tr></table></figure><h3 id="ltrim"><a href="#ltrim" class="headerlink" title="ltrim"></a>ltrim</h3><p>去掉前导空格</p><h3 id="rtrim"><a href="#rtrim" class="headerlink" title="rtrim"></a>rtrim</h3><p>取消后导空格</p><h3 id="trim"><a href="#trim" class="headerlink" title="trim"></a>trim</h3><p>去掉前后空格</p><p>除删除空格外, 还可以删除掉某些特定字符串</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select trim(leading '?' from '???mysql????'); // mysql????</span><br></pre></td></tr></table></figure><p>去掉左边的问号</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select trim(trailing '?' from '???mysql????'); // ???mysql</span><br></pre></td></tr></table></figure><p>去掉右边的问号</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select trim(both '?' from '???mysql????'); // mysql</span><br></pre></td></tr></table></figure><p>去掉左右两边的问号</p><h3 id="replace"><a href="#replace" class="headerlink" title="replace"></a>replace</h3><p>为字符串中的a字符替换为b字符</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select replace('??mysq?l', '!'); // !!mysq!l</span><br></pre></td></tr></table></figure><h3 id="substring"><a href="#substring" class="headerlink" title="substring"></a>substring</h3><p>字符串截取, 需要注意的是字符串从1开始截取, 第二个参数为截取的字符串长度</p><p>如果只传一位数时, 是从该位开始, 往后</p><p>第一位数可以传负数, 如传-1表示从倒数第一位开始</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select substring('mysql', 1, 2); // my</span><br></pre></td></tr></table></figure><h3 id="查找类似值"><a href="#查找类似值" class="headerlink" title="查找类似值"></a>查找类似值</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select * from test where first_name like '%1%';</span><br></pre></td></tr></table></figure><p>需要注意的是, %代表任意个字符, 但是_代表的是任意个字符, 当我们需要查找这两种字符本身的时候, 需要使用escape方法</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select * from test where first_name like '%1%%' escape '1';</span><br></pre></td></tr></table></figure><h2 id="数值运算符"><a href="#数值运算符" class="headerlink" title="数值运算符"></a>数值运算符</h2><h3 id="ceil"><a href="#ceil" class="headerlink" title="ceil"></a>ceil</h3><p>进一取整</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select ceil(3.01); // 4</span><br></pre></td></tr></table></figure><h3 id="floor"><a href="#floor" class="headerlink" title="floor"></a>floor</h3><p>舍一取整</p><h3 id="div"><a href="#div" class="headerlink" title="div"></a>div</h3><p>整数除法</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select 3 div 4; // 0</span><br></pre></td></tr></table></figure><h3 id="mod"><a href="#mod" class="headerlink" title="mod"></a>mod</h3><p>取余数, 和%等价</p><figure class="highlight plain"><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">select 3 mod 4; // 3</span><br><span class="line">select 3 % 4; // 3</span><br></pre></td></tr></table></figure><h3 id="power"><a href="#power" class="headerlink" title="power"></a>power</h3><p>幂运算</p><h3 id="round"><a href="#round" class="headerlink" title="round"></a>round</h3><p>四舍五入</p><h3 id="truncate"><a href="#truncate" class="headerlink" title="truncate"></a>truncate</h3><p>数字截取, 不同于四舍五入, 是将该位上的内容拿掉, 传负数代表是整数位</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select truncate(1234.321, -1); // 1230</span><br></pre></td></tr></table></figure><h2 id="从外部导入mysql表"><a href="#从外部导入mysql表" class="headerlink" title="从外部导入mysql表"></a>从外部导入mysql表</h2><p>导入的方式应为, 先导入schema表, 用于创建sql语句的表头结构, 然后再导入data内容</p><ul><li><p>在MYSQL 命令下: SOURCE 下载路径/sakila-schema.sql #建立表结构</p></li><li><p>在MYSQL 命令下: SOURCE 下载路径/sakila-data.sql #插入数据</p></li></ul>]]></content>
<summary type="html">
MySQL的基本使用
</summary>
<category term="MySQL" scheme="http://blog.changerhe.cn/categories/MySQL/"/>
<category term="MySQL" scheme="http://blog.changerhe.cn/tags/MySQL/"/>
</entry>
<entry>
<title>Objective-c基础学习</title>
<link href="http://blog.changerhe.cn/2017/10/07/Objective-c%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0/"/>
<id>http://blog.changerhe.cn/2017/10/07/Objective-c基础学习/</id>
<published>2017-10-07T13:13:58.000Z</published>
<updated>2018-08-12T10:48:59.236Z</updated>
<content type="html"><![CDATA[<p>objective-c是乔帮主所开发出来的一种类似于c的面向对象编程语言, 拥有诸多c的优点且支持面相对象的编程方式, 是ios开发的一大利器</p><h2 id="环境准备"><a href="#环境准备" class="headerlink" title="环境准备"></a>环境准备</h2><p>要开发ios是有门槛的, 前提是你必须拥有一台mac电脑, 准确的说, 你的设备必须能够跑得了macos</p><p>在上面的基础上, 还必须要安装好开发所需软件xcode</p><h2 id="hello-world"><a href="#hello-world" class="headerlink" title="hello world"></a>hello world</h2><p>依照惯例, 我们在电脑上面输出一下oc的hello world程序</p><p>首先, 打开xcode, 新建项目, 存储到本机的一个位置上</p><p>然后, 打开这个项目, 点击项目的主文件(main.m)并按住command + r进行编辑, 就可以看到控制台输出了一个hello world啦</p><p>我们可以看到, 代码的整体的骨架是这样子的</p><figure class="highlight plain"><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">// 导入mac所提供的库</span><br><span class="line">#import <Foundation/Foundation.h></span><br><span class="line"></span><br><span class="line">// 程序的主函数, 所有函数都要从这里开始执行</span><br><span class="line">int main(int argc, const char * argv[]) {</span><br><span class="line">@autoreleasepool {</span><br><span class="line">// 所有的代码写在这里</span><br><span class="line">}</span><br><span class="line">return 0;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="oc的变量和表达式"><a href="#oc的变量和表达式" class="headerlink" title="oc的变量和表达式"></a>oc的变量和表达式</h2><p>声明变量的方法和js不同, 变量类型必须要声明对应的类型, 声明类型之后如果没有赋值, 则为默认值</p><p>如, 当我们声明了int类型的a, 并不对其赋值, 最后打印出a的值就是0</p><figure class="highlight plain"><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">int a;</span><br><span class="line">int b = 0;</span><br><span class="line">a = 5;</span><br><span class="line">b = 3;</span><br><span class="line">int c = (a + b) * 2</span><br><span class="line">NSLog(@"变量a + 变量b的值是: %d", c)</span><br></pre></td></tr></table></figure><h2 id="oc的基本数据类型"><a href="#oc的基本数据类型" class="headerlink" title="oc的基本数据类型"></a>oc的基本数据类型</h2><p>int 整型, 数值不超过32位, 也就是大概从-21亿到21亿<br>float 浮点型, 声明的时候建议即使为整数, 也应写上小数点后面的值<br>double 64位浮点型<br>char 8位字符串, 只能包含一个字符<br>NSString: @”Hello world” nsstring类型</p><h2 id="限定词"><a href="#限定词" class="headerlink" title="限定词"></a>限定词</h2><p>long int a 长整型a 32位(在c中原来int是16位, 只能存储数值为五位数左右的数)<br>long long int a 长长整型 64位整形<br>short 等于或小于16位整数<br>unsigned 无符号整形<br>signed 有符号整形<br>指针类型<br>自定义类型<br>万能类型</p><h2 id="逻辑运算符"><a href="#逻辑运算符" class="headerlink" title="逻辑运算符"></a>逻辑运算符</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">if () {} else {}</span><br></pre></td></tr></table></figure><p>if中的条件可以为布尔值, 可以为数字</p><p>goto语句, 当条件成立的时候, 跳转到某个地方</p><figure class="highlight plain"><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">int i = 0;</span><br><span class="line">a: {</span><br><span class="line"> i++;</span><br><span class="line"> NSLog(@"i的值为%d", i);</span><br><span class="line">}</span><br><span class="line">if(i < 5) {</span><br><span class="line">goto a;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>上例可导出四次五次打印值</p><h2 id="循环"><a href="#循环" class="headerlink" title="循环"></a>循环</h2><p>当需要多次执行某段代码的时候, 可以使用循环语句</p><figure class="highlight plain"><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">int i - 0;</span><br><span class="line">while(i < 5) {</span><br><span class="line"> i++;</span><br><span class="line"> NSLog(@"hello world");</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight plain"><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">for(int i; i < 10; i++) {</span><br><span class="line"> NSLog(@"i = %d", i);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight plain"><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">do {</span><br><span class="line"> NSLog(@"我至少打印一次");</span><br><span class="line">} while(0) {}</span><br></pre></td></tr></table></figure><h2 id="switch语句"><a href="#switch语句" class="headerlink" title="switch语句"></a>switch语句</h2><figure class="highlight plain"><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">switch(i) {</span><br><span class="line"> case 1:</span><br><span class="line"> NSLog(@"i的值等于1");</span><br><span class="line"> break;</span><br><span class="line"> case 2:</span><br><span class="line"> NSlog(@"i的值等于2");</span><br><span class="line"> break;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="程序的函数"><a href="#程序的函数" class="headerlink" title="程序的函数"></a>程序的函数</h1><p>函数的书写也应该严格定义好函数的类型之后再进行处理</p><figure class="highlight plain"><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">double getSquare(double a, double b) {</span><br><span class="line"> return a * b;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// 函数的调用</span><br><span class="line">couble e = 1.3;</span><br><span class="line">double f = 3.1;</span><br><span class="line">double c = getSquare(e, f);</span><br><span class="line">NSLog(@"%f", c);</span><br></pre></td></tr></table></figure><p>除了有返回值函数外, 还有无返回值函数</p><figure class="highlight plain"><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">void print() {</span><br><span class="line"> NSLog(@"test");</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">// 这个时候因为没有返回值, 所以直接调用即可</span><br><span class="line">print();</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html">
objective-c是乔帮主所开发出来的一种类似于c的面向对象编程语言, 拥有诸多c的优点且支持面相对象的编程方式, 是ios开发的一大利器
</summary>
</entry>
<entry>
<title>Chrome61发布,这新功能怕是没谁了</title>
<link href="http://blog.changerhe.cn/2017/09/25/Chrome61%E5%8F%91%E5%B8%83,%E8%BF%99%E6%96%B0%E5%8A%9F%E8%83%BD%E6%80%95%E6%98%AF%E6%B2%A1%E8%B0%81%E4%BA%86/"/>
<id>http://blog.changerhe.cn/2017/09/25/Chrome61发布,这新功能怕是没谁了/</id>
<published>2017-09-25T15:11:42.000Z</published>
<updated>2017-11-22T05:36:10.836Z</updated>
<content type="html"><![CDATA[<p>Chrome 61 正式版已于2017年9月6日正式发布,并增加了很多开发者相关的功能。在 Mac、Windows 和 Linux 系统中,Chrome 61 开始支持 WebUSB API,以及 PaymentRequest API。</p><p>高级网络平台 API 支持大多数硬件外设,如键盘、鼠标、打印机和游戏手柄。为了使用教育、科学或工业等专用 USB 外设,用户必须使用系统级权限查找和安装可能不安全的驱动程序和软件。</p><p>当然, 最让人激动的是, chrome已经开始支持ES6的module功能, 原生开始支持模块化开发!</p><h1 id="chrome中使用模块化功能"><a href="#chrome中使用模块化功能" class="headerlink" title="chrome中使用模块化功能"></a>chrome中使用模块化功能</h1><p>Chrome 61 加入了对 JavaScript Module <code><script type="module"></code>的原生支持。Chrome 现在可以并行地获取颗粒化的依赖模块,利用浏览器缓存的优势,在多个页面之间共享模块,并且可以保证脚本按照正确地顺序执行。</p><p>下面是我直接在html文件中写入, 的代码</p><figure class="highlight plain"><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"><script type="module"></span><br><span class="line">import utils from "./test.js"</span><br><span class="line">utils()</span><br><span class="line"></script></span><br></pre></td></tr></table></figure><p>再看一下我所引入的依赖</p><figure class="highlight plain"><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">// 相同目录下的test.js</span><br><span class="line">function utils() {</span><br><span class="line"> console.log(1)</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">export default utils</span><br></pre></td></tr></table></figure><p>最后, 我们使用编辑器自带的服务器开启运行, 我使用的是VSCode, 当然, 像webstorm, Hbuilder之类的都自带了服务器</p><p>需要注意的是, 不使用服务器而是直接使用双击打开文件的方式是没有办法体验这种功能的</p><p>最后我们可以看到在chrome61+控制台上打印出了1</p><h1 id="web-share-api"><a href="#web-share-api" class="headerlink" title="web share api"></a>web share api</h1><p>为了让用户把他们喜欢的内容分享到网络上,不得把所有的社交按钮在自己的网站上添加一遍。这让页面变得很臃肿,很可能这些分享按钮和网站的视觉不匹配,并且还要添加来自第三方的代码。</p><p>现在,Android 版的 Chrome 新增了 Web Share API,该 API 可以直接调用原生的分享功能,用户可以很方便的将自己喜欢的文本和链接分享到其他原生 App 上了!</p><p>在之后的版本中,这个 API 还能分享到已安装的 web app 中。直接调用 navigator.share 方法,传递相关的参数,就可以发起分享。其他事情系统会帮你搞定。</p><figure class="highlight plain"><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">navigator.share({</span><br><span class="line"> title: document.title, text: 'Hello',</span><br><span class="line"> url: window.location.href</span><br><span class="line">}).then(() => {</span><br><span class="line"> console.log('Successful share');</span><br><span class="line">});</span><br></pre></td></tr></table></figure><h1 id="WebUSB"><a href="#WebUSB" class="headerlink" title="WebUSB"></a>WebUSB</h1><p>很多电脑的周边硬件在 Web 平台上都有对应的 API,比如键盘、鼠标、打印机和手柄等等。但是,想要在浏览器中使用某些特殊的用于教育、科研、工业等等 USB 设备很困难,通常需要特殊的驱动才行。</p><p>现在 Chrome 提供了 WebUSB API,在用户授权后,Web 应用可以直接可 USB 设备通信。</p><p>要了解更多, 可登陆google开发者平台了解详情…</p>]]></content>
<summary type="html">
Chrome 61 正式版已于2017年9月6日正式发布,并增加了很多开发者相关的功能。在 Mac、Windows 和 Linux 系统中,Chrome 61 开始支持 WebUSB API,以及 PaymentRequest API。
</summary>
<category term="Chrome" scheme="http://blog.changerhe.cn/categories/Chrome/"/>
<category term="Chrome" scheme="http://blog.changerhe.cn/tags/Chrome/"/>
</entry>
<entry>
<title>微信小程序懒加载的实现</title>
<link href="http://blog.changerhe.cn/2017/09/21/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E6%87%92%E5%8A%A0%E8%BD%BD%E7%9A%84%E5%AE%9E%E7%8E%B0/"/>
<id>http://blog.changerhe.cn/2017/09/21/微信小程序懒加载的实现/</id>
<published>2017-09-21T14:12:23.000Z</published>
<updated>2017-11-22T05:36:57.777Z</updated>
<content type="html"><![CDATA[<p>近期做了一个微信小程序的项目, 其中涉及到微信小程序的懒加载功能, 第一次做这个功能的感觉真的是让人欲(tou)罢(teng)不(bu)能(yi)啊, 所以在这里做一个小小的总结来分享一下.</p><p>不同于原始的dom操作项目, 现在的现代框架已经将dom操作高度集成到了api中, 采用数据驱动的方式, 来实现对dom的各种处理.</p><p>现在我们回忆一下当初那个青涩的原始时代, 当有懒加载的需求的时候, 我们可以开心地创建一个ajax请求, 将请求参数发送到后台, 后台反馈给我们参数后, 然后我们再开心地操作dom将数据处理后插到页面上.</p><p>“哎呀, 屁股好疼” —页面上的某个dom节点如是说</p><p>但是在数据驱动, 高度组件化处理ajax的返回参数的时候, 我们该怎么处理这个需求呢?</p><h1 id="微信小程序的scroll-view组件"><a href="#微信小程序的scroll-view组件" class="headerlink" title="微信小程序的scroll-view组件"></a>微信小程序的scroll-view组件</h1><p>说到懒加载, 那么就必须得提到微信的scroll-view组件, 这玩意儿干啥的呢?</p><p>主要的作用还是作为一个载体, 用于设置载体内的内容滚动, 当然, 如果需要在y轴滚动的话, 页面都是有这个功能的, 但是如果直接使用y轴滚动的功能的话, 就无法成功触发相应的事件了.</p><h1 id="wxml的写入方式"><a href="#wxml的写入方式" class="headerlink" title="wxml的写入方式"></a>wxml的写入方式</h1><p>我们将wxml中需要滚动的view外需要再套一层scroll-view方便让器其滚动触发事件</p><p>有一点需要特别特别注意的是, 微信原生提供了bindscrolltolower和bindscrolltoupper这两个api来专门处理对应的滚动触底(最右边或最下边)及滚动触顶(最左边或最上边)事件.</p><p>但是!!!</p><p>这两个事件的触发, 前提是必须要在对应的scroll-view上设置高度才可以的, 不然事件无法触发生效.</p><p>比如说, 针对不同的设备, 我设置了对应的触发高度</p><figure class="highlight plain"><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">@media (min-width: 375px) {</span><br><span class="line"> .all-movie{</span><br><span class="line"> height: 1300rpx;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">@media (max-width: 374px) {</span><br><span class="line"> .all-movie{</span><br><span class="line"> height: 1000rpx;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="ajax的请求分析"><a href="#ajax的请求分析" class="headerlink" title="ajax的请求分析"></a>ajax的请求分析</h1><p>在这里要特别说明一下, 因为微信不存在dom操作, 所以我们进行懒加载操作的时候, 其实是将整个页面的所有元素都重新加载了一遍的, 因为插不进去啊(#→⌒→).</p><p>那么这个时候ajax的请求就很成问题了, 我们每次加载, 需要传递不同的参数进去</p><p>那么我的思路就是, 通过在data上挂载变量, 每次请求将变量增加, 然后通过这个变量的值的增加, 每次发起的ajax请求就不一样了, 获取到的值会逐次增加</p><p>微信小程序的ajax创建方式这里就不再赘述了, 官网说的很清楚, 使用wx.request对象很容易搞定</p><p>下面是我写在ajax请求success里面的代码</p><figure class="highlight plain"><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">var data = res.data</span><br><span class="line">// 将本身setdata的对象直接拿出来, 然后再放进去</span><br><span class="line">var dataCon = {}</span><br><span class="line">// 每产生一次ajax请求, 就要使总和加10, 也就是再请求十条数据</span><br><span class="line">that.data.totalCount += 10</span><br><span class="line">dataCon.dataObj = data</span><br><span class="line">that.setData(dataCon)</span><br></pre></td></tr></table></figure><p>注意上面我是设置了一个data的数据名为totalCount, 初始值我设置其为0, 那么每次产生一次ajax 请求, 则其自加10, 通过totalCount, 在拼接上对应的请求url, 就可以成功取到相应的ajax返回值了.</p><p>到这里可能会有同学要问了, 你这里每次都要重新渲染一下页面, 难道不会增大微信小程序的压力吗? 每次请求的数据都会增加, 页面压力会很大啊</p><p>当然, 既然使用数据驱动的方式来进行开发, 对于这样的场景, 产生较大的数据压力是必然的, 但是微信小程序和浏览器一样, 本身是存在缓存的, 之前请求过的数据, 后面服务器会直接返回403, 就不会产生较大的数据流, 最后产生流量的也就是后面那一小部分的文件数据而已.</p><h1 id="对ajax请求的优化"><a href="#对ajax请求的优化" class="headerlink" title="对ajax请求的优化"></a>对ajax请求的优化</h1><p>以上方法可行肯定是可行的, 但是我们每次做ajax请求, 每次的请求数据都会增多, 那么会不会有一种更加的请求方案呢?</p><p>当然, 我们可以考虑和之前操作dom那样, 每次只请求自己需要的那一部分数据, 之前重复的数据是没有必要再到服务器请求一次的</p><p>我们的url可以这样构建</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">var nextUrl = this.data.requestUrl + "?start=" + this.data.totalCount + "&count=10"</span><br></pre></td></tr></table></figure><p>totalCount表示已经请求的数量, 而count表示每次请求的数量</p><p>很好, 一下减少了不少的ajax请求压力</p><h1 id="优化后的bug处理"><a href="#优化后的bug处理" class="headerlink" title="优化后的bug处理"></a>优化后的bug处理</h1><p>ajax请求的压力确实减少了, 但是现在还有一个问题啊, 你每次都反馈给我十条数据, 我用你给的数据渲染, 岂不是把页面懒加载变成了页面刷新了, 每次请求的数据是不一样了, 但是之前的数据已经不存在了呀</p><p>所以, 我们需要使用一个data上面的变量来存储我们之前请求到的值</p><p>我们将之前的成功回调改写一下</p><figure class="highlight plain"><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><br><span class="line">var data = res.data</span><br><span class="line">// 将本身setdata的对象直接拿出来, 然后再放进去</span><br><span class="line">var dataCon = {}</span><br><span class="line">// 每产生一次ajax请求, 就要使总和加10, 也就是再请求十条数据</span><br><span class="line">that.data.totalCount += 10</span><br><span class="line">var total = {}</span><br><span class="line">// 如果不是第一次请求数据的话,则将两次的数据相加</span><br><span class="line">if (!that.data.isEmpty) {</span><br><span class="line"> total = that.data.dataObj.concat(data)</span><br><span class="line">} else {</span><br><span class="line"> total = data</span><br><span class="line"> // 如果isEmpty为true则将其改为false</span><br><span class="line"> that.data.isEmpty = false </span><br><span class="line">}</span><br><span class="line">dataCon.dataObj = total</span><br><span class="line">that.setData(dataCon)</span><br></pre></td></tr></table></figure><p>这里我们设置了一个全局变量isEmpty, 默认为true, 表示默认为空, 当第一次请求的时候, 将数值存入total中,并将isEmpty改写为false, 之后的每一次请求都是在total中加数据, 我们渲染的话就都是用全局的dataObj这个变量来进行渲染, 即可解决之前的问题.</p><p>更新:<br> 后面有看到因为scroll-view在页面中是无法触发下拉刷新事件的,但后面微信方给出了解决办法: 不用scroll-view , 玛德坑爹</p><pre><code>现在可以直接使用onReachBottom事件,也就是触底事件来处理和进行懒加载, 相比于之前的方法简单了不少, 页面也更加流畅了期待小程序能带了更多更好的东西吧</code></pre>]]></content>
<summary type="html">
近期做了一个微信小程序的项目, 其中涉及到微信小程序的懒加载功能, 第一次做这个功能的感觉真的是让人欲(tou)罢(teng)不(bu)能(yi)啊, 所以在这里做一个小小的总结来分享一下.
</summary>
<category term="微信小程序" scheme="http://blog.changerhe.cn/categories/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F/"/>
<category term="微信小程序" scheme="http://blog.changerhe.cn/tags/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F/"/>
<category term="WXapplet" scheme="http://blog.changerhe.cn/tags/WXapplet/"/>
</entry>
<entry>
<title>网站的https证书配置小结</title>
<link href="http://blog.changerhe.cn/2017/09/05/%E7%BD%91%E7%AB%99%E7%9A%84https%E8%AF%81%E4%B9%A6%E9%85%8D%E7%BD%AE%E6%96%B9%E6%B3%95/"/>
<id>http://blog.changerhe.cn/2017/09/05/网站的https证书配置方法/</id>
<published>2017-09-05T05:12:13.000Z</published>
<updated>2017-11-22T04:45:57.235Z</updated>
<content type="html"><![CDATA[<p>HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。 它是一个URI scheme(抽象标识符体系),句法类同http:体系。用于安全的HTTP数据传输。https:URL表明它使用了HTTP,但HTTPS存在不同于HTTP的默认端口及一个加密/身份验证层(在HTTP与TCP之间)。这个系统的最初研发由网景公司(Netscape)进行,并内置于其浏览器Netscape Navigator中,提供了身份验证与加密通讯方法。现在它被广泛用于万维网上安全敏感的通讯,例如交易支付方面。</p><pre><code>----引自百度百科</code></pre><p>那么, https对于提升网站的安全性方面是卓有成效的, 但是这对于我们来说有啥作用呢?</p><p>自2014年以来, 百度就开始宣布, 优先支持对https站点的支持与收录了, 也就是说, 我们使用https的网站会被百度的蜘蛛引擎优先收录, 从而实现百度的搜索排行了.</p><p>还有更重要的一点是, 开发微信小程序和微信公众号的时候, 腾讯的马爸爸不允许我们使用http作为协议传输数据啊, 而且还只能使用默认端口传输数据啊.</p><p>所以, 这样说来, 整一个https证书还是挺有必要的</p><h1 id="话不多说开始干"><a href="#话不多说开始干" class="headerlink" title="话不多说开始干"></a>话不多说开始干</h1><p>首先我们需要到对应的https证书上那边获取到https的证书, 像我这么穷的人自然是买不起大几千的企业版https证书的了, 那么得想办法啊</p><h2 id="踩坑第一步"><a href="#踩坑第一步" class="headerlink" title="踩坑第一步"></a>踩坑第一步</h2><p>雀氏纸尿裤?</p><p>咳咳……</p><p>首先我百度了一下https的证书, 大家都在极力推荐又拍云啊, 然后我去看了看, 我擦还真有</p><p>但是整个流程走下来, 我最想吐槽的就是又拍云的页面混乱的链接了, 控制台不知道在整些什么玩意, 重要的东西完全没有分类好, 申请的话需要各种认证</p><p>先是直接手机验证之后申请, 告诉我申请失败, 也不告知原因, 几次下来我就窝火了, 遂写了个工单上去, 处理工单的工程师告诉我是没有实名认证</p><p>好, 去实名认证呗, 来来回回花了7-8天时间, 总算是申请下来了</p><p>但是!</p><p>我发现淘宝的马爸爸的阿里云也可以申请证书啊</p><p>链接在<img src="https://common-buy.aliyun.com/?spm=5176.2020520163.cas.55.cf9c783W4XZMe&commodityCode=cas#/buy" alt="这里"></p><p>因为是我直接复制的url, 路径可能会失效, 可以依照:</p><p>阿里云控制台 > CA证书服务 > 右上角购买证书</p><p>这这个流程进行证书的申购</p><p>关键是, 在又拍云每次申请要一天时间, 驳回之后又是要一天, 但是阿里云上面申请只需要一分钟左右就下来了, 部署的时候还有贴心的程序猿小哥哥录的视频告诉你配置和部署的姿势</p><h1 id="申请好了-准备部署"><a href="#申请好了-准备部署" class="headerlink" title="申请好了, 准备部署"></a>申请好了, 准备部署</h1><p>部署的话我是直接使用的nginx进行部署的, 部署也很简单, 到nginx官网下载自己对应版本的包, 解压到自己的服务器任意文件夹</p><p>还是在CA证书服务中, 将证书下载下来, 复制到nginx的conf文件夹中, 在文件夹中新建一个文件cert, 然后将两个证书复制进去</p><p>回到nginx.exe文件目录下, 双击重启一下nginx服务, 一切ok</p><p>然后, 我们就可以直接使用https访问我们的网站了, 美滋滋啊美滋滋</p>]]></content>
<summary type="html">
HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。
</summary>
<category term="HTTPS" scheme="http://blog.changerhe.cn/categories/HTTPS/"/>
<category term="HTTPS" scheme="http://blog.changerhe.cn/tags/HTTPS/"/>
</entry>
<entry>
<title>利用dpl实现对移动设备的像素实现精准控制</title>
<link href="http://blog.changerhe.cn/2017/08/05/%E5%88%A9%E7%94%A8dpl%E5%AE%9E%E7%8E%B0%E5%AF%B9%E7%A7%BB%E5%8A%A8%E8%AE%BE%E5%A4%87%E7%9A%84%E5%83%8F%E7%B4%A0%E5%AE%9E%E7%8E%B0%E7%B2%BE%E5%87%86%E6%8E%A7%E5%88%B6/"/>
<id>http://blog.changerhe.cn/2017/08/05/利用dpl实现对移动设备的像素实现精准控制/</id>
<published>2017-08-05T14:14:14.000Z</published>
<updated>2017-11-22T05:36:30.999Z</updated>
<content type="html"><![CDATA[<p>dpl, 全称是device pixel ratio ,表示设备的像素比</p><p>设备在移动端因为物理像素和理论像素的不同而产生了显示的差异, 随着科技的发展, 设备的物理像素与理论像素之比由之前的一比一变成了多比一, 其中比较典型的就是, iphone6的设备像素比是2:1, iphone6 plus是3:1</p><p>因为其显示的差异, 也造成了我们在电脑上做的页面, 在移动端出现了显示异常的情况</p><p>而在js的window对象中有一个属性专门用于表示设备我的像素比例, 名叫devicePixelRatio, 也就是说, 我们可以使用window.devicePixelRatio来显示出当前设备的物理像素和实际像素的比例.</p><p>也同样是因为这个问题, 催生了移动设备一像素的问题, 因为我们在电脑上设置1px, 导致在手机端显示为2px甚至更多, 在需要精细化控制设计图的情况下会使页面非常不美观</p><p>解决这个问题,主要思想是:使用伪元素设置1px的边框,然后使用媒体查询,根据dpr的大小,对边框进行缩放(scaleY)。详细代码如下所示: </p><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line"><template></span><br><span class="line"> <div id="app"></span><br><span class="line"> <div class="tab border-1px"> <!-- !!!!!!! --></span><br><span class="line"> <div class="tab-items"></span><br><span class="line"> <router-link to="/goods">商品</router-link></span><br><span class="line"> </div></span><br><span class="line"> <div class="tab-items"></span><br><span class="line"> <router-link to="/ratings">评价</router-link></span><br><span class="line"> </div></span><br><span class="line"> <div class="tab-items"></span><br><span class="line"> <router-link to="/seller">商店</router-link></span><br><span class="line"> </div></span><br><span class="line"> </div></span><br><span class="line"> <div class="content"></span><br><span class="line"> <router-view></router-view></span><br><span class="line"> </div></span><br><span class="line"> </div></span><br><span class="line"></template></span><br><span class="line"></span><br><span class="line"><script></span><br><span class="line"></script></span><br><span class="line"></span><br><span class="line"><style lang="stylus" rel="stylesheet/stylus"></span><br><span class="line">@import "./common/stylus/mixin.styl"</span><br><span class="line">@import "./common/stylus/base.styl"</span><br><span class="line">#app</span><br><span class="line"> .tab</span><br><span class="line"> display: flex</span><br><span class="line"> width: 100%</span><br><span class="line"> height: 40px</span><br><span class="line"> line-height: 40px</span><br><span class="line"> border-1px(blue) /*!!!!!!*/</span><br><span class="line"> .tab-items</span><br><span class="line"> flex: 1</span><br><span class="line"> text-align: center</span><br><span class="line"> font-size: 14px</span><br><span class="line"> & > a</span><br><span class="line"> display: block</span><br><span class="line"> width: 100%</span><br><span class="line"> color: rgb(77, 85, 93)</span><br><span class="line"> &.router-link-active</span><br><span class="line"> color: rgb(240, 20, 20)</span><br><span class="line"> .seller</span><br><span class="line"> border-bottom: 1px solid blue /*用于对比,在移动端实际显示2px*/</span><br><span class="line"></style></span><br></pre></td></tr></table></figure><p>看过滴滴打车的黄奕老师的vue开发饿了么教程的童鞋可以知道这就是初期构建的商家详情的spa单页骨架雏形哈哈</p><p>可以看到我们使用到了stylus中的mixin对移动端设备一像素问题的解决办法</p><figure class="highlight plain"><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">border-1px($color)</span><br><span class="line"> position: relative</span><br><span class="line"> &::after</span><br><span class="line"> position: absolute</span><br><span class="line"> left: 0</span><br><span class="line"> bottom: 0</span><br><span class="line"> width: 100%</span><br><span class="line"> content: ' '</span><br><span class="line"> border-top: 1px solid $color</span><br><span class="line"></span><br><span class="line">//图片的mixin,根据图片的不同dpr进行适配下显示高清问题</span><br><span class="line">bg-image($url) </span><br><span class="line"> background-image: url($url + "@2x.png")</span><br><span class="line"> @media (-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio: 3)</span><br><span class="line"> background-image: url($url + "@3x.png")</span><br></pre></td></tr></table></figure><p>针对边框一像素问题, 我们使用的是伪类结合子绝父相, 然后将伪类的边框使用css3的transition: scale来进行缩放从而达到效果的</p><p>这里的bg-image($url) 是负责处理图片在不同dpr下显示的问题,原来跟1像素边框问题差不多,不过这里不需要重做,只是根据不同的media query来调用不同的图片显示,而这些图片是需要放在相对应的文件夹的。</p><p>再来看一下base中的内容</p><figure class="highlight plain"><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"><!--根据媒体查询@media设置不同的缩放比例(transform 的 scale)来修复1像素边框的问题--></span><br><span class="line">@media (-webkit-min-device-pixel-ratio: 1.5),(min-device-pixel-ratio: 1.5)</span><br><span class="line"> .border-1px</span><br><span class="line"> &::after</span><br><span class="line"> -webkit-transform: scaleY(0.7)</span><br><span class="line"> transform: scaleY(0.7)</span><br><span class="line"></span><br><span class="line">@media (-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio: 2)</span><br><span class="line"> .border-1px</span><br><span class="line"> &::after</span><br><span class="line"> -webkit-transform: scaleY(0.5)</span><br><span class="line"> transform: scaleY(0.5)</span><br></pre></td></tr></table></figure><p>这里的修复1像素边框问题会拆分为2个部分,一个部分是这里的base.styl里面处理缩放,另外一部分是在mixin.styl里面处理重做border。<br>这里是一个base模块文件,只保留了基本的共用的css,需要结合其他的css文件(stylus)来合并理解<br>dpr一般是1或者2,1.5只是为了更精细的去适配1和2之间的手机型号</p>]]></content>
<summary type="html">
一般在移动端,由于dpr(设备像素比)不为1,在PC端显示1像素的边框,在移动端其实显示为2px。解决这个问题,主要思想是:使用伪元素设置1px的边框,然后使用媒体查询,根据dpr的大小,对边框进行缩放(scaleY)。详细代码如下所示: App.vue:
</summary>
<category term="移动端" scheme="http://blog.changerhe.cn/categories/%E7%A7%BB%E5%8A%A8%E7%AB%AF/"/>
<category term="移动端" scheme="http://blog.changerhe.cn/tags/%E7%A7%BB%E5%8A%A8%E7%AB%AF/"/>
</entry>
<entry>
<title>Angularjs的数据绑定和脏检查</title>
<link href="http://blog.changerhe.cn/2017/07/20/Angularjs%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%91%E5%AE%9A%E5%92%8C%E8%84%8F%E6%A3%80%E6%9F%A5/"/>
<id>http://blog.changerhe.cn/2017/07/20/Angularjs的数据绑定和脏检查/</id>
<published>2017-07-20T04:53:41.000Z</published>
<updated>2017-11-22T05:36:01.486Z</updated>
<content type="html"><![CDATA[<p>接触Angular也有一段时间了,时常问自己一些问题, 如果是我实现它,会在哪些方面选择跟它相同的道路, 哪些方面不同。为此,记录了一些思考,给自己回顾,也供他人参考。</p><p>本篇博客将分下面几个方面进行讲解</p><p>-数据双向绑定<br>-视图模型的继承关系<br>-模块和依赖注入的设计</p><h1 id="数据的双向绑定"><a href="#数据的双向绑定" class="headerlink" title="数据的双向绑定"></a>数据的双向绑定</h1><p>Angular实现了双向绑定机制。所谓的双向绑定,无非是从界面的操作能实时反映到数据,数据的变更能实时展现到界面。</p><p>一个最简单的示例就是这样:</p><figure class="highlight plain"><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"><div ng-controller="CounterCtrl"></span><br><span class="line"> <span ng-bind="counter"></span></span><br><span class="line"> <button ng-click="counter=counter+1">increase</button></span><br><span class="line"></div></span><br></pre></td></tr></table></figure><figure class="highlight plain"><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">function CounterCtrl($scope) {</span><br><span class="line"> $scope.counter = 1;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>这个例子很简单,毫无特别之处,每当点击一次按钮,界面上的数字就增加一。</p><h1 id="绑定数据是怎样生效的"><a href="#绑定数据是怎样生效的" class="headerlink" title="绑定数据是怎样生效的"></a>绑定数据是怎样生效的</h1><p>初学AngularJS的人可能会踩到这样的坑,假设有一个指令:</p><figure class="highlight plain"><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">var app = angular.module("test", []);</span><br><span class="line"></span><br><span class="line">app.directive("myclick", function() {</span><br><span class="line"> return function (scope, element, attr) {</span><br><span class="line"> element.on("click", function() {</span><br><span class="line"> scope.counter++;</span><br><span class="line"> });</span><br><span class="line"> };</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">app.controller("CounterCtrl", function($scope) {</span><br><span class="line"> $scope.counter = 0;</span><br><span class="line">});</span><br></pre></td></tr></table></figure><figure class="highlight plain"><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"><body ng-app="test"></span><br><span class="line"> <div ng-controller="CounterCtrl"></span><br><span class="line"> <button myclick>increase</button></span><br><span class="line"> <span ng-bind="counter"></span></span><br><span class="line"> </div></span><br><span class="line"></body></span><br></pre></td></tr></table></figure><p>这个时候,点击按钮,界面上的数字并不会增加。很多人会感到迷惑,因为他查看调试器,发现数据确实已经增加了,Angular不是双向绑定吗,为什么数据变化了,界面没有跟着刷新?</p><p>试试在scope.counter++;这句之后加一句scope.digest();再看看是不是好了?</p><p>为什么要这么做呢,什么情况下要这么做呢?我们发现第一个例子中并没有digest,而且,如果你写了digest,它还会抛出异常,说正在做其他的digest,这是怎么回事?</p><p>我们先想想,假如没有AngularJS,我们想要自己实现这么个功能,应该怎样?</p><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line"><!DOCTYPE html></span><br><span class="line"><html></span><br><span class="line"> <head></span><br><span class="line"> <meta charset="utf-8" /></span><br><span class="line"> <title>two-way binding</title></span><br><span class="line"> </head></span><br><span class="line"> <body onload="init()"></span><br><span class="line"> <button ng-click="inc"></span><br><span class="line"> increase 1</span><br><span class="line"> </button></span><br><span class="line"> <button ng-click="inc2"></span><br><span class="line"> increase 2</span><br><span class="line"> </button></span><br><span class="line"> <span style="color:red" ng-bind="counter"></span></span><br><span class="line"> <span style="color:blue" ng-bind="counter"></span></span><br><span class="line"> <span style="color:green" ng-bind="counter"></span></span><br><span class="line"></span><br><span class="line"> <script type="text/javascript"></span><br><span class="line"> /* 数据模型区开始 */</span><br><span class="line"> var counter = 0;</span><br><span class="line"></span><br><span class="line"> function inc() {</span><br><span class="line"> counter++;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> function inc2() {</span><br><span class="line"> counter+=2;</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"> function init() {</span><br><span class="line"> bind();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> function bind() {</span><br><span class="line"> var list = document.querySelectorAll("[ng-click]");</span><br><span class="line"> for (var i=0; i<list.length; i++) {</span><br><span class="line"> list[i].onclick = (function(index) {</span><br><span class="line"> return function() {</span><br><span class="line"> window[list[index].getAttribute("ng-click")]();</span><br><span class="line"> apply();</span><br><span class="line"> };</span><br><span class="line"> })(i);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> function apply() {</span><br><span class="line"> var list = document.querySelectorAll("[ng-bind='counter']");</span><br><span class="line"> for (var i=0; i<list.length; i++) {</span><br><span class="line"> list[i].innerHTML = counter;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> /* 绑定关系区结束 */</span><br><span class="line"> </script></span><br><span class="line"> </body></span><br><span class="line"></html></span><br></pre></td></tr></table></figure><p>可以看到,在这么一个简单的例子中,我们做了一些双向绑定的事情。从两个按钮的点击到数据的变更,这个很好理解,但我们没有直接使用DOM的onclick方法,而是搞了一个ng-click,然后在bind里面把这个ng-click对应的函数拿出来,绑定到onclick的事件处理函数中。为什么要这样呢?因为数据虽然变更了,但是还没有往界面上填充,我们需要在此做一些附加操作。</p><p>从另外一个方面看,当数据变更的时候,需要把这个变更应用到界面上,也就是那三个span里。但由于Angular使用的是脏检测,意味着当改变数据之后,你自己要做一些事情来触发脏检测,然后再应用到这个数据对应的DOM元素上。问题就在于,怎样触发脏检测?什么时候触发?</p><p>我们知道,一些基于setter的框架,它可以在给数据设值的时候,对DOM元素上的绑定变量作重新赋值。脏检测的机制没有这个阶段,它没有任何途径在数据变更之后立即得到通知,所以只能在每个事件入口中手动调用apply(),把数据的变更应用到界面上。在真正的Angular实现中,这里先进行脏检测,确定数据有变化了,然后才对界面设值。</p><p>所以,我们在ng-click里面封装真正的click,最重要的作用是为了在之后追加一次apply(),把数据的变更应用到界面上去。</p><p>那么,为什么在ng-click里面调用$digest的话,会报错呢?因为Angular的设计,同一时间只允许一个$digest运行,而ng-click这种内置指令已经触发了$digest,当前的还没有走完,所以就出错了。</p><h1 id="digest和-apply"><a href="#digest和-apply" class="headerlink" title="$digest和$apply"></a>$digest和$apply</h1><p>在Angular中,有$apply和$digest两个函数,我们刚才是通过$digest来让这个数据应用到界面上。但这个时候,也可以不用$digest,而是使用$apply,效果是一样的,那么,它们的差异是什么呢?</p><p>最直接的差异是,$apply可以带参数,它可以接受一个函数,然后在应用数据之后,调用这个函数。所以,一般在集成非Angular框架的代码时,可以把代码写在这个里面调用。</p><figure class="highlight plain"><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">var app = angular.module("test", []);</span><br><span class="line"></span><br><span class="line">app.directive("myclick", function() {</span><br><span class="line"> return function (scope, element, attr) {</span><br><span class="line"> element.on("click", function() {</span><br><span class="line"> scope.counter++;</span><br><span class="line"> scope.$apply(function() {</span><br><span class="line"> scope.counter++;</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">app.controller("CounterCtrl", function($scope) {</span><br><span class="line"> $scope.counter = 0;</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p>除此之外,还有别的区别吗?</p><p>在简单的数据模型中,这两者没有本质差别,但是当有层次结构的时候,就不一样了。考虑到有两层作用域,我们可以在父作用域上调用这两个函数,也可以在子作用域上调用,这个时候就能看到差别了。</p><p>对于$digest来说,在父作用域和子作用域上调用是有差别的,但是,对于$apply来说,这两者一样。我们来构造一个特殊的示例:</p><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">var app = angular.module("test", []);</span><br><span class="line"></span><br><span class="line">app.directive("increasea", function() {</span><br><span class="line"> return function (scope, element, attr) {</span><br><span class="line"> element.on("click", function() {</span><br><span class="line"> scope.a++;</span><br><span class="line"> scope.$digest();</span><br><span class="line"> });</span><br><span class="line"> };</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">app.directive("increaseb", function() {</span><br><span class="line"> return function (scope, element, attr) {</span><br><span class="line"> element.on("click", function() {</span><br><span class="line"> scope.b++;</span><br><span class="line"> scope.$digest(); //这个换成$apply即可</span><br><span class="line"> });</span><br><span class="line"> };</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">app.controller("OuterCtrl", ["$scope", function($scope) {</span><br><span class="line"> $scope.a = 1;</span><br><span class="line"></span><br><span class="line"> $scope.$watch("a", function(newVal) {</span><br><span class="line"> console.log("a:" + newVal);</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> $scope.$on("test", function(evt) {</span><br><span class="line"> $scope.a++;</span><br><span class="line"> });</span><br><span class="line">}]);</span><br><span class="line"></span><br><span class="line">app.controller("InnerCtrl", ["$scope", function($scope) {</span><br><span class="line"> $scope.b = 2;</span><br><span class="line"></span><br><span class="line"> $scope.$watch("b", function(newVal) {</span><br><span class="line"> console.log("b:" + newVal);</span><br><span class="line"> $scope.$emit("test", newVal);</span><br><span class="line"> });</span><br><span class="line">}]);</span><br></pre></td></tr></table></figure><figure class="highlight plain"><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"><div ng-app="test"></span><br><span class="line"> <div ng-controller="OuterCtrl"></span><br><span class="line"> <div ng-controller="InnerCtrl"></span><br><span class="line"> <button increaseb>increase b</button></span><br><span class="line"> <span ng-bind="b"></span></span><br><span class="line"> </div></span><br><span class="line"> <button increasea>increase a</button></span><br><span class="line"> <span ng-bind="a"></span></span><br><span class="line"> </div></span><br><span class="line"></div></span><br></pre></td></tr></table></figure><p>这时候,我们就能看出差别了,在increase b按钮上点击,这时候,a跟b的值其实都已经变化了,但是界面上的a没有更新,直到点击一次increase a,这时候刚才对a的累加才会一次更新上来。怎么解决这个问题呢?只需在increaseb这个指令的实现中,把$digest换成$apply即可。</p><p>当调用$digest的时候,只触发当前作用域和它的子作用域上的监控,但是当调用$apply的时候,会触发作用域树上的所有监控。</p><p>因此,从性能上讲,如果能确定自己作的这个数据变更所造成的影响范围,应当尽量调用$digest,只有当无法精确知道数据变更造成的影响范围时,才去用$apply,很暴力地遍历整个作用域树,调用其中所有的监控。</p><p>从另外一个角度,我们也可以看到,为什么调用外部框架的时候,是推荐放在$apply中,因为只有这个地方才是对所有数据变更都应用的地方,如果用$digest,有可能临时丢失数据变更。</p><h1 id="脏检测的利弊"><a href="#脏检测的利弊" class="headerlink" title="脏检测的利弊"></a>脏检测的利弊</h1><p>很多人对Angular的脏检测机制感到不屑,推崇基于setter,getter的观测机制,在我看来,这只是同一个事情的不同实现方式,并没有谁完全胜过谁,两者是各有优劣的。</p><p>大家都知道,在循环中批量添加DOM元素的时候,会推荐使用DocumentFragment,为什么呢,因为如果每次都对DOM产生变更,它都要修改DOM树的结构,性能影响大,如果我们能先在文档碎片中把DOM结构创建好,然后整体添加到主文档中,这个DOM树的变更就会一次完成,性能会提高很多。</p><p>同理,在Angular框架里,考虑到这样的场景:</p><figure class="highlight plain"><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">function TestCtrl($scope) {</span><br><span class="line"> $scope.numOfCheckedItems = 0;</span><br><span class="line"></span><br><span class="line"> var list = [];</span><br><span class="line"></span><br><span class="line"> for (var i=0; i<10000; i++) {</span><br><span class="line"> list.push({</span><br><span class="line"> index: i,</span><br><span class="line"> checked: false</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> $scope.list = list;</span><br><span class="line"></span><br><span class="line"> $scope.toggleChecked = function(flag) {</span><br><span class="line"> for (var i=0; i<list.length; i++) {</span><br><span class="line"> list[i].checked = flag;</span><br><span class="line"> $scope.numOfCheckedItems++;</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>如果界面上某个文本绑定这个numOfCheckedItems,会怎样?在脏检测的机制下,这个过程毫无压力,一次做完所有数据变更,然后整体应用到界面上。这时候,基于setter的机制就惨了,除非它也是像Angular这样把批量操作延时到一次更新,否则性能会更低。</p><p>所以说,两种不同的监控方式,各有其优缺点,最好的办法是了解各自使用方式的差异,考虑出它们性能的差异所在,在不同的业务场景中,避开最容易造成性能瓶颈的用法。</p>]]></content>
<summary type="html">
接触Angular也有一段时间了,时常问自己一些问题, 如果是我实现它,会在哪些方面选择跟它相同的道路, 哪些方面不同。为此,记录了一些思考,给自己回顾,也供他人参考。
</summary>
<category term="Angularjs" scheme="http://blog.changerhe.cn/categories/Angularjs/"/>
<category term="Angularjs" scheme="http://blog.changerhe.cn/tags/Angularjs/"/>
<category term="数据绑定" scheme="http://blog.changerhe.cn/tags/%E6%95%B0%E6%8D%AE%E7%BB%91%E5%AE%9A/"/>
</entry>
<entry>
<title>基于MongoDB 2dSphere索引查找最近的点</title>
<link href="http://blog.changerhe.cn/2017/07/05/%E5%9F%BA%E4%BA%8EMongoDB-2dSphere%E7%B4%A2%E5%BC%95%E6%9F%A5%E6%89%BE%E6%9C%80%E8%BF%91%E7%9A%84%E7%82%B9/"/>
<id>http://blog.changerhe.cn/2017/07/05/基于MongoDB-2dSphere索引查找最近的点/</id>
<published>2017-07-05T15:27:22.000Z</published>
<updated>2017-11-22T05:35:48.912Z</updated>
<content type="html"><![CDATA[<p>在移动端普及的今天,LBS应用需求也越来越大。比如查找附近的人,最近的餐厅等。面对这些需求,MongoDB提供了功能完备的解决方案。下面通过一个案例来解释一下MongoDB的2dSphere</p><p><img src="http://img.blog.csdn.net/20160923111644414" alt=""></p><p>在这个图片中,有A B C D E F G,假如我是搜索点A。我想查找离自己最近的点。下面是具体的操作步骤: </p><h1 id="建立集合和索引。sp为建立索引的字段名,我们建立的索引类型是2dsphere"><a href="#建立集合和索引。sp为建立索引的字段名,我们建立的索引类型是2dsphere" class="headerlink" title="建立集合和索引。sp为建立索引的字段名,我们建立的索引类型是2dsphere"></a>建立集合和索引。sp为建立索引的字段名,我们建立的索引类型是2dsphere</h1><figure class="highlight plain"><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"># 创建2dsphere索引</span><br><span class="line"> db.sphere.ensureIndex({"sp":"2dsphere"})</span><br></pre></td></tr></table></figure><h1 id="向集合中插入测试数据,我们插入的是实际的经纬度。"><a href="#向集合中插入测试数据,我们插入的是实际的经纬度。" class="headerlink" title="向集合中插入测试数据,我们插入的是实际的经纬度。"></a>向集合中插入测试数据,我们插入的是实际的经纬度。</h1><p>这里需要注意的是,如果我们如果用的是2dsphere索引,那么插入的应该是GeoJson数据。GeoJson的格式是 </p><p><code>{ type: ‘GeoJSON type’ , coordinates: ‘coordinates’ }</code></p><p>其中type指的是类型,可以是Point(本例中用的),LineString,Polygon等,coordinates是一个坐标数组。英语好的同学可以去官网看看<a href="https://docs.mongodb.com/manual/reference/geojson/" target="_blank" rel="noopener">https://docs.mongodb.com/manual/reference/geojson/</a></p><figure class="highlight plain"><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"># 插入Point数据</span><br><span class="line">db.sphere.insert({name:"A",sp:{type:"Point",coordinates:[105.754484701156,41.689607057699]}})</span><br><span class="line">db.sphere.insert({name:"B",sp:{type:"Point",coordinates:[105.304045248031,41.783456183240]}})</span><br><span class="line">db.sphere.insert({name:"C",sp:{type:"Point",coordinates:[105.084318685531,41.389027478812]}})</span><br><span class="line">db.sphere.insert({name:"D",sp:{type:"Point",coordinates:[105.831388998031,41.285916385493]}})</span><br><span class="line">db.sphere.insert({name:"E",sp:{type:"Point",coordinates:[106.128706502914,42.086868474465]}})</span><br><span class="line">db.sphere.insert({name:"F",sp:{type:"Point",coordinates:[105.431074666976,42.009365053841]}})</span><br><span class="line">db.sphere.insert({name:"G",sp:{type:"Point",coordinates:[104.705977010726,41.921549795110]}})</span><br></pre></td></tr></table></figure><h1 id="进行查询。介绍一下其中的参数"><a href="#进行查询。介绍一下其中的参数" class="headerlink" title="进行查询。介绍一下其中的参数"></a>进行查询。介绍一下其中的参数</h1><blockquote><p>(1)geoNear:我们要查询的集合名称 </p></blockquote><blockquote><p>(2)near:就是基于那个点进行搜索,这里是我们的搜索点A </p></blockquote><blockquote><p>(3)spherical:是个布尔值,如果为true,表示将计算实际的物理距离比如两点之间有多少km,若为false,则会基于点的单位进行计算 </p></blockquote><blockquote><p>(4)minDistance:搜索的最小距离,这里的单位是米 </p></blockquote><blockquote><p>(5)maxDistance:搜索的最大距离</p></blockquote><figure class="highlight plain"><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">db.runCommand({</span><br><span class="line"> geoNear:"sphere",</span><br><span class="line"> near:{type:"Point",coordinates:[105.794621276855,41.869574065014]},</span><br><span class="line"> spherical:true,</span><br><span class="line"> minDistance:25000,</span><br><span class="line"> maxDistance:40000,</span><br><span class="line"> })</span><br></pre></td></tr></table></figure><h1 id="结果分析"><a href="#结果分析" class="headerlink" title="结果分析"></a>结果分析</h1><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">{</span><br><span class="line"> "waitedMS" : NumberLong(0),</span><br><span class="line"> "results" : [ </span><br><span class="line"> {</span><br><span class="line"> "dis" : 33887.5416611258,</span><br><span class="line"> "obj" : {</span><br><span class="line"> "_id" : ObjectId("57e3857e6a4a326367ae0d05"),</span><br><span class="line"> "name" : "F",</span><br><span class="line"> "sp" : {</span><br><span class="line"> "type" : "Point",</span><br><span class="line"> "coordinates" : [ </span><br><span class="line"> 105.431074666976, </span><br><span class="line"> 42.009365053841</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"> "dis" : 36734.9748784127,</span><br><span class="line"> "obj" : {</span><br><span class="line"> "_id" : ObjectId("57e3857e6a4a326367ae0d04"),</span><br><span class="line"> "name" : "E",</span><br><span class="line"> "sp" : {</span><br><span class="line"> "type" : "Point",</span><br><span class="line"> "coordinates" : [ </span><br><span class="line"> 106.128706502914, </span><br><span class="line"> 42.086868474465</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"> "stats" : {</span><br><span class="line"> "nscanned" : 24,</span><br><span class="line"> "objectsLoaded" : 20,</span><br><span class="line"> "avgDistance" : 35311.2582697693,</span><br><span class="line"> "maxDistance" : 36734.9748784127,</span><br><span class="line"> "time" : 87</span><br><span class="line"> },</span><br><span class="line"> "ok" : 1.0</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在results中,我们搜索到了点F和E。每个文档都加上了一个dis字段,他表示这个点离你搜索点的距离。</p><p>比如说,在结果中name为F的点的dis为33887.5416611258。表示F点距离搜索点的距离是33887米。这个结果对于LBS应用是非常有用的。 </p>]]></content>
<summary type="html">
在移动端普及的今天,LBS应用需求也越来越大。比如查找附近的人,最近的餐厅等。面对这些需求,MongoDB提供了功能完备的解决方案。下面通过一个案例来解释一下MongoDB的2dSphere
</summary>
<category term="MongoDB学习笔记" scheme="http://blog.changerhe.cn/categories/MongoDB%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
<category term="MongoDB" scheme="http://blog.changerhe.cn/tags/MongoDB/"/>
<category term="2dSphere" scheme="http://blog.changerhe.cn/tags/2dSphere/"/>
</entry>
<entry>
<title>使用Nodejs实现简单的自动化构建</title>
<link href="http://blog.changerhe.cn/2017/06/27/%E4%BD%BF%E7%94%A8Nodejs%E5%AE%9E%E7%8E%B0%E7%AE%80%E5%8D%95%E7%9A%84%E8%87%AA%E5%8A%A8%E5%8C%96%E6%9E%84%E5%BB%BA/"/>
<id>http://blog.changerhe.cn/2017/06/27/使用Nodejs实现简单的自动化构建/</id>
<published>2017-06-27T15:56:30.000Z</published>
<updated>2017-11-22T05:35:28.351Z</updated>
<content type="html"><![CDATA[<p>自动化构建是现代前端基本都需要的东西,说起这个,大家自然会想到 Glup/Grount这些自动化的构建工具.</p><p>当然,本文只是从最最基础的角度,使用Node的fs模块进行了简单的文档的写入操作.</p><p>首先,我们先定义一个JSON,用于存放我们想要预先定义的文件夹的内容,比如说,我想要我的文件夹名称为<code>ProjectModule</code> ,里面的文件夹有 <code>css</code> / <code>js</code> / <code>img</code> 还有一个 <code>index.html</code>,同时定义好index文件中的内容</p><p>那么我的JSON结构可以这样写</p><figure class="highlight plain"><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">var projectData = {</span><br><span class="line"> 'name' : 'ProjectModule',</span><br><span class="line"> 'fileData': [</span><br><span class="line"> {</span><br><span class="line"> 'name': 'css',</span><br><span class="line"> 'type': 'dir'</span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> 'name': 'js',</span><br><span class="line"> 'type': 'dir'</span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> 'name': 'img',</span><br><span class="line"> 'type': 'dir'</span><br><span class="line"> },</span><br><span class="line"> {</span><br><span class="line"> 'name': 'index.html',</span><br><span class="line"> 'type': 'file',</span><br><span class="line"> 'content': '<html>\n\t<head>\n\t<title>MyProject</title>\n\t</head>\n\t<body>\n\t</body>\n</html>'</span><br><span class="line"> }</span><br><span class="line"> ]</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>接下来,就是引入fs模块</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">var fs = require('fs')</span><br></pre></td></tr></table></figure><p>因为这里是要实时创建的,我们可以直接使用同步的操作,就省去了异步需要使用回调函数的麻烦</p><p>当然,开始之前,要先确定一下,JSON是否有正常的给出文件夹的名称</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">if(projectData.name) {</span><br><span class="line"></span><br><span class="line"> fs.mkdirSync(projectData.name)</span><br><span class="line"></span><br><span class="line"> var fileData = projectData.fileData</span><br><span class="line"></span><br><span class="line"> fileData.forEach(function(f) {</span><br><span class="line"></span><br><span class="line"> f.content = f.content? f.content : ''</span><br><span class="line"></span><br><span class="line"> f.path = projectData.name + '/' + f.name</span><br><span class="line"></span><br><span class="line"> switch (f.type) {</span><br><span class="line"> </span><br><span class="line"> case 'dir':</span><br><span class="line"> fs.mkdirSync(f.path)</span><br><span class="line"> break;</span><br><span class="line"> case 'file':</span><br><span class="line"> fs.writeFileSync(f.path, f.content)</span><br><span class="line"> break;</span><br><span class="line"> default:</span><br><span class="line"> break;</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>如果使用的是webstorm, 那么直接使用ctrl+f9, 让你的node程序跑起来吧~</p>]]></content>
<summary type="html">
自动化构建是现代前端基本都需要的东西,说起这个,大家自然会想到 Glup/Grount这些自动化的构建工具.
当然,本文只是从最最基础的角度,使用Node的fs模块进行了简单的文档的写入操作.
</summary>
<category term="Nodejs学习笔记" scheme="http://blog.changerhe.cn/categories/Nodejs%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
<category term="Nodejs学习笔记" scheme="http://blog.changerhe.cn/tags/Nodejs%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
</entry>
<entry>
<title>ES6中的遍历器接口Iterator</title>
<link href="http://blog.changerhe.cn/2017/06/25/ES6%E4%B8%AD%E7%9A%84%E9%81%8D%E5%8E%86%E5%99%A8%E6%8E%A5%E5%8F%A3Iterator/"/>
<id>http://blog.changerhe.cn/2017/06/25/ES6中的遍历器接口Iterator/</id>
<published>2017-06-25T15:34:18.000Z</published>
<updated>2017-11-22T05:35:19.586Z</updated>
<content type="html"><![CDATA[<p>初读阮一峰老师的这本书,简直如发现了新世界一般.原来ES6的语法是如此的清奇.</p><p>随着ES6, ES7, 到今年七月份的ES8. 我们会发现,javascript这门最初被定义在客户端的’玩具语言’已经变得越发的强壮和标准,这也是我们作为前端ers 所希望看到的,毕竟,这涉及到以后的饭碗呢哈哈.</p><p>阮一峰老师的文笔还是不错的,但是随着后面的阅读,会发现有一些后面的知识,被直接不明就里的拿到前面来用了,这就导致我这个新手小白就有点懵逼了.</p><p>比如说: 箭头函数,当然,这个比较好理解,有固定的语法</p><p>但是,阮老师一直有提到的iterator接口,到底是个啥? 估计初学ES6的新手小白自然会有着和我一样的困惑.</p><p>那么,下面就综合我的搜索和总结,对iterator接口的相关知识,做一个分享,也算是对自己所学的一个总结</p><h1 id="iterator接口是什么"><a href="#iterator接口是什么" class="headerlink" title="iterator接口是什么"></a>iterator接口是什么</h1><p>不知大家碰到此问题的时候是不是和我一样马上选择了百度(毕竟英语不够好,不能随随便便Google一下啊),泪奔~</p><p>百度上面会告诉你, Java的iterator很好用巴拉巴拉</p><p>那么,在javascript中,iterator接口到底是个神马东西呢?</p><p>iterator, 其实就是一个迭代器,或者说,是一个迭代器</p><p>在es6中,能表示“集合”概念的数据类型大致有四种:Array,Object,Map,Set</p><p>既然是集合,那遍历便是一种基本需求。而Iterator就是为了提供一种统一的接口机制。任何的数据结构,只要部署了Iterator接口,便可以使用类似的方式完成遍历操作。</p><p>当然,Iterator还有2个作用,它使数据结构的成员按某种次序排列,其次,es6有一种新的遍历方式,前面也说过,for…of,而Iterator的主要作用,就是支持此操作。</p><h2 id="Iteartor的遍历过程是这样的"><a href="#Iteartor的遍历过程是这样的" class="headerlink" title="Iteartor的遍历过程是这样的"></a>Iteartor的遍历过程是这样的</h2><blockquote><p>创建一个指向数据结构起始位置的指针。(起始位置不是第一个成员的位置,起始位置使一个单独的标志位。)</p></blockquote><blockquote><p>当调用next()方法,指针就向后移动一个位置,并返回当前位置上的成员,直到指针指向数据结构的结束位置为止。</p></blockquote><p>第二步中,js语言返回的的成员信息是两个,value和done,value不用介绍,done是一个表示遍历是否结束的布尔值。</p><h1 id="部署接口"><a href="#部署接口" class="headerlink" title="部署接口"></a>部署接口</h1><p>上面我们说到的部署接口,那js怎么部署接口呢。其实我们之前已经说到过,在Symbol一节中,介绍了很多es6内置的Symbol值,这些就是接口。</p><p>es6中有三类结构生来就具有Iterator接口:数组、类数组对象、Map和Set结构。</p><p>当然,如果你和我一样,现在看到第八章的话,暂时是没有学到Map和Set结构的,这个看下就好</p><figure class="highlight plain"><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">var arr = [1,2,3,4];</span><br><span class="line">let iterator = arr[Symbol.iterator]();</span><br><span class="line"></span><br><span class="line">console.log(iterator.next()); //{ value: 1, done: false }</span><br><span class="line">console.log(iterator.next()); //{ value: 2, done: false }</span><br><span class="line">console.log(iterator.next()); //{ value: 3, done: false }</span><br><span class="line">console.log(iterator.next()); //{ value: 4, done: false }</span><br><span class="line">console.log(iterator.next()); //{ value: undefined, done: true }</span><br></pre></td></tr></table></figure><p>数组,Map等结构中的成员都是有顺序的,即都是线性的结构,而对象,各成员并没有一个确定的顺序,所以遍历时先遍历谁后遍历谁并不确定。所以,给一个对象部署iterator接口,其实就是对该对象做一种线性转换。</p><p>如果有需要,可以手动给对象部署iterator接口</p><figure class="highlight plain"><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">let obj = {</span><br><span class="line"> data: [ 'hello', 'world' ],</span><br><span class="line"> [Symbol.iterator]() {</span><br><span class="line"> const self = this;</span><br><span class="line"> let index = 0;</span><br><span class="line"> return {</span><br><span class="line"> next() {</span><br><span class="line"> if (index < self.data.length) {</span><br><span class="line"> return {</span><br><span class="line"> value: self.data[index++],</span><br><span class="line"> done: false</span><br><span class="line"> };</span><br><span class="line"> } else {</span><br><span class="line"> return { value: undefined, done: true };</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>可以看到,Symbol.iterator会返回一个对象,这就是一个遍历器对象,而作为遍历器对象,其必须具备的特征就是必须具备next()方法。</p><p>至于可以使用Array.from转换成数组的类数组对象,部署iterator有一种很简单的方法,即直接使用数组的[Symbol.iterator]接口。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">fakeArray.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];</span><br></pre></td></tr></table></figure><p>用Generator函数来实现Symbol.iterator接口,事半功倍。</p><p>这也是看到第八章我要出来百度的原因,因为影响到了我正常的往下阅读了</p><figure class="highlight plain"><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">var yieldIterator = {};</span><br><span class="line">yieldIterator[Symbol.iterator] = function* () {</span><br><span class="line"> yield 1;</span><br><span class="line"> yield 2;</span><br><span class="line"> yield 3;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">[...yieldIterator] // [1, 2, 3]</span><br></pre></td></tr></table></figure><p>注意,yield* 后面跟的是一个可遍历的结构,它会调用该结构的遍历器接口。</p><p> 其次,其它调用到遍历器的操作还有解构赋值、扩展操作符、其它任何接受数组作为参数的场合,如:</p><blockquote><p>for…of<br>Array.from()<br>Map(), Set(), WeakMap(), WeakSet()(比如)<br>Promise.all()<br>Promise.race()</p></blockquote><p>一旦当你给你的结构部署了iterator接口,那么恭喜你,你可以使用for…of来遍历你的结构了!</p><p>遍历器对象除了必须布置next方法以外,还有2个可选方法。return()和throw()。当一个解构在遍历的时候异常提前退出(比如break,continue或者出错)的时候,就会调用return方法,其次,return方法必须返回一个对象。</p><p>至于throw方法,则是用于抛出错误,Generator.prototype.throw</p><p>for of循环有很多优点,比如不像for…in一样只遍历键名(甚至包括原型链上的键),而且不像foreach不能跳出循环。并且for…of为各种数据结构提供了一个统一的遍历方法。所以,尽量使用它吧~</p>]]></content>
<summary type="html">
初读阮一峰老师的这本书,简直如发现了新世界一般.原来ES6的语法是如此的清奇.
随着ES6, ES7, 到今年七月份的ES8. 我们会发现,javascript这门最初被定义在客户端的'玩具语言'已经变得越发的强壮和标准,这也是我们作为前端ers 所希望看到的,毕竟,这涉及到以后的饭碗呢哈哈.
</summary>
<category term="ES6标准入门阅读笔记" scheme="http://blog.changerhe.cn/categories/ES6%E6%A0%87%E5%87%86%E5%85%A5%E9%97%A8%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0/"/>
<category term="ES6标准入门阅读笔记" scheme="http://blog.changerhe.cn/tags/ES6%E6%A0%87%E5%87%86%E5%85%A5%E9%97%A8%E9%98%85%E8%AF%BB%E7%AC%94%E8%AE%B0/"/>
</entry>
<entry>
<title>理解Node.js里的process.nextTick()</title>
<link href="http://blog.changerhe.cn/2017/06/18/%E7%90%86%E8%A7%A3Nodejs%E9%87%8C%E7%9A%84process-nextTick/"/>
<id>http://blog.changerhe.cn/2017/06/18/理解Nodejs里的process-nextTick/</id>
<published>2017-06-18T12:00:32.000Z</published>
<updated>2017-11-22T05:35:00.881Z</updated>
<content type="html"><![CDATA[<p>Nodejs的事件驱动,异步IO模型另异步编程变得异常风行,它借助了异步IO模型及V8高性能引擎,突破了单线程的性能瓶颈. 让Jacascript在后端达到了其应有的使用价值. </p><p>另外一方面,它也统一了前后端的javascript编程模型.</p><p>异步编程也给前端程序猿带来了诸多的痛苦和不适应. 这也是我今天着重想提<code>process.nextTick()</code>这个API的原因之一.</p><h1 id="异常处理"><a href="#异常处理" class="headerlink" title="异常处理"></a>异常处理</h1><p>在过去,我们处理异常一般使用try catch fanily这个语句块进行异常捕获和处理</p><figure class="highlight plain"><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">try {</span><br><span class="line">JSON.parse(jsonObj)</span><br><span class="line">} catch(e) {</span><br><span class="line">// do something...</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>但是这个方法对异步编程而言是并不适用的, 举个很简单的例子,也是我们在日常开发中常常使用的一个小技巧: 当我们想要某个在文档中间的语句块在整个脚本的最后执行的时候,可以使用setTimeout将这个语句块包起来,将延时时间设为0, 那么这个时候它就会等待所有同步的进程全部执行完毕之后再执行.</p><p>在try中,我们进行异步的方式处理JSON.parse的时候,那么它也会被放到文档流的最后执行而try catch先执行了,这就是导致出现这个问题的原因</p><p>那么这个时候,就需要们的主角登场了</p><p>同样的,我们再来一个例子</p><figure class="highlight plain"><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">function foo() {</span><br><span class="line">console.error('foo');</span><br><span class="line">}</span><br><span class="line">process.nextTick(foo);</span><br><span class="line">console.error('bar');</span><br></pre></td></tr></table></figure><p>运行上面的代码,你从下面终端打印的信息会看到,”bar”的输出在“foo”的前面。这就验证了上面的说法,foo()是在下一个时间点运行的。</p><p>但在内部的处理机制上,process.nextTick()和setTimeout(fn, 0)是不同的,process.nextTick()不是一个单纯的延时,他有更多的 特性。</p><p>更精确的说,process.nextTick()定义的调用会创建一个新的子堆栈。在当前的栈里,你可以执行任意多的操作。但一旦调用netxTick,函数就必须返回到父堆栈。然后事件轮询机制又重新等待处理新的事件,如果发现nextTick的调用,就会创建一个新的栈。</p><p>下面我们来看看,什么情况下使用process.nextTick():</p><h1 id="在多个事件里交叉执行CPU运算密集型的任务:"><a href="#在多个事件里交叉执行CPU运算密集型的任务:" class="headerlink" title="在多个事件里交叉执行CPU运算密集型的任务:"></a>在多个事件里交叉执行CPU运算密集型的任务:</h1><p>在下面的例子里有一个compute(),我们希望这个函数尽可能持续的执行,来进行一些运算密集的任务。</p><p>但与此同时,我们还希望系统不要被这个函数堵塞住,还需要能响应处理别的事件。这个应用模式就像一个单线程的web服务server。在这里我们就可以使用process.nextTick()来交叉执行compute()和正常的事件响应。</p><figure class="highlight plain"><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">var http = require('http');</span><br><span class="line"></span><br><span class="line">function compute() {</span><br><span class="line"> // performs complicated calculations continuously</span><br><span class="line"> // ...</span><br><span class="line"> process.nextTick(compute);</span><br><span class="line">}</span><br><span class="line"> </span><br><span class="line">http.createServer(function(req, res) {</span><br><span class="line"> res.writeHead(200, {'Content-Type': 'text/plain'});</span><br><span class="line"> res.end('Hello World');</span><br><span class="line">}).listen(5000, '127.0.0.1');</span><br><span class="line"> </span><br><span class="line">compute();</span><br></pre></td></tr></table></figure><p>在这种模式下,我们不需要递归的调用compute(),我们只需要在事件循环中使用process.nextTick()定义compute()在下一个时间点执行即可。在这个过程中,如果有新的http请求进来,事件循环机制会先处理新的请求,然后再调用compute()。反之,如果你把compute()放在一个递归调用里,那系统就会一直阻塞在compute()里,无法处理新的http请求了。你可以自己试试。</p><p>当然,我们无法通过process.nextTick()来获得多CPU下并行执行的真正好处,这只是模拟同一个应用在CPU上分段执行而已。</p><h1 id="保持回调函数异步执行的原则"><a href="#保持回调函数异步执行的原则" class="headerlink" title="保持回调函数异步执行的原则"></a>保持回调函数异步执行的原则</h1><p>当你给一个函数定义一个回调函数时,你要确保这个回调是被异步执行的。下面我们看一个例子,例子中的回调违反了这一原则:</p><figure class="highlight plain"><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">function asyncFake(data, callback) { </span><br><span class="line"> if(data === 'foo') callback(true);</span><br><span class="line"> else callback(false);</span><br><span class="line">}</span><br><span class="line"> </span><br><span class="line">asyncFake('bar', function(result) {</span><br><span class="line"> // this callback is actually called synchronously!</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p>为什么这样不好呢?我们来看Node.js 文档里一段代码:</p><figure class="highlight plain"><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">var client = net.connect(8124, function() { </span><br><span class="line"> console.log('client connected');</span><br><span class="line"> client.write('world!\r\n');</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p>在上面的代码里,如果因为某种原因,net.connect()变成同步执行的了,回调函数就会被立刻执行,因此回调函数写到客户端的变量就永远不会被初始化了。</p><p>这种情况下我们就可以使用process.nextTick()把上面asyncFake()改成异步执行的:</p><figure class="highlight plain"><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">function asyncReal(data, callback) {</span><br><span class="line"> process.nextTick(function() {</span><br><span class="line"> callback(data === 'foo'); </span><br><span class="line"> });</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h1 id="用在事件触发过程中"><a href="#用在事件触发过程中" class="headerlink" title="用在事件触发过程中"></a>用在事件触发过程中</h1><p>来看一个例子,你想写一个库实现这样的功能:从源文件里读取数据,当读取完毕后,触发一个事件同时传递读取的数据。可能你会这样写:</p><figure class="highlight plain"><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">var EventEmitter = require('events').EventEmitter;</span><br><span class="line"> </span><br><span class="line">function StreamLibrary(resourceName) { </span><br><span class="line"> this.emit('start');</span><br><span class="line"> </span><br><span class="line"> // read from the file, and for every chunk read, do: </span><br><span class="line"> this.emit('data', chunkRead); </span><br><span class="line">}</span><br><span class="line">StreamLibrary.prototype.__proto__ = EventEmitter.prototype; </span><br><span class="line">// inherit from EventEmitter</span><br></pre></td></tr></table></figure><p>下面是一段调用这个库的客户端程序,我们想在程序中监听这些事件:</p><figure class="highlight plain"><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">var stream = new StreamLibrary('fooResource');</span><br><span class="line"> </span><br><span class="line">stream.on('start', function() {</span><br><span class="line"> console.log('Reading has started');</span><br><span class="line">});</span><br><span class="line"> </span><br><span class="line">stream.on('data', function(chunk) {</span><br><span class="line"> console.log('Received: ' + chunk);</span><br><span class="line">});</span><br></pre></td></tr></table></figure><p>但是上面的代码中,将永远接收不到“start”事件,因为在这个库实例化的时候,“start”事件会被立刻触发执行,但此时事件的回调函数还没有准备好,所以在客户端根本无法接收到这个事件。同样,我们可以用process.nextTick()来改写事件触发的过程,下面是一个正确的版本:</p><figure class="highlight plain"><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">function StreamLibrary(resourceName) { </span><br><span class="line"> var self = this;</span><br><span class="line"> </span><br><span class="line"> process.nextTick(function() {</span><br><span class="line"> self.emit('start');</span><br><span class="line"> });</span><br><span class="line"> </span><br><span class="line"> // read from the file, and for every chunk read, do:</span><br><span class="line"> this.emit('data', chunkRead);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>(文章部分引用了网上内容)</p>]]></content>
<summary type="html">
Nodejs的事件驱动,异步IO模型另异步编程变得异常风行,它借助了异步IO模型及V8高性能引擎,突破了单线程的性能瓶颈. 让Jacascript在后端达到了其应有的使用价值. 另外一方面,它也统一了前后端的javascript编程模型.
</summary>
<category term="Nodejs学习笔记" scheme="http://blog.changerhe.cn/categories/Nodejs%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
<category term="Nodejs" scheme="http://blog.changerhe.cn/tags/Nodejs/"/>
<category term="process.nextTick()" scheme="http://blog.changerhe.cn/tags/process-nextTick/"/>
</entry>
</feed>