-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
469 lines (262 loc) · 368 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>MongoDB与Mongoose</title>
<link href="/MongoDB-Mongoose.html"/>
<content type="html"><![CDATA[<h1 id="MongoDB"><a href="#MongoDB" class="headerlink" title="MongoDB"></a>MongoDB</h1><h2 id="何为MongoDB?"><a href="#何为MongoDB?" class="headerlink" title="何为MongoDB?"></a>何为MongoDB?</h2><p>MongoDB是一个介于关系型数据库和非关系型数据库之间的开源产品,它是功能最为丰富的非关系型数据库,也是最像关系型数据库的非关系型数据库。</p><p>MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。</p><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></pre></td><td class="code"><pre><span class="line">sudo curl -O https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-4.0.0.tgz</span><br></pre></td></tr></table></figure></p><p>解压:<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">sudo tar -zxvf mongodb-osx-ssl-x86_64-4.0.0.tgz</span><br></pre></td></tr></table></figure></p><p>重命名为mongodb目录:<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">sudo mv mongodb-osx-ssl-x86_64-4.0.0 mongodb</span><br></pre></td></tr></table></figure></p><h2 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h2><p><img src="http://oubl6fzsm.bkt.clouddn.com/1538979571423.jpg" alt="image"></p><h2 id="常见使用"><a href="#常见使用" class="headerlink" title="常见使用"></a>常见使用</h2><ul><li><p><strong>查询所有结果</strong></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">select * from article</span><br><span class="line"></span><br><span class="line">db.article.find()</span><br></pre></td></tr></table></figure></li><li><p><strong>指定返回哪些键</strong></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">select title, author from article</span><br><span class="line"></span><br><span class="line">db.article.find({}, {"title": 1, "author": 1})</span><br></pre></td></tr></table></figure></li><li><p><strong>where条件</strong></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">select * from article where title = "深入浅出Node"</span><br><span class="line"></span><br><span class="line">db.article.find({"title": "深入浅出Node"})</span><br></pre></td></tr></table></figure></li><li><p><strong>and条件</strong></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">select * from article where title = "深入浅出Node" and author = "朴灵"</span><br><span class="line"></span><br><span class="line">db.article.find({"title": "深入浅出Node", "author": "朴灵"})</span><br></pre></td></tr></table></figure></li><li><p><strong>or条件</strong></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">select * from article where title = "深入浅出Node" or author = "朴灵"</span><br><span class="line"></span><br><span class="line">db.article.find({"$or": [{"title": "深入浅出Node"}, {"author": "朴灵"}]})</span><br></pre></td></tr></table></figure></li><li><p><strong>比较条件</strong></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">select * from article where read >= 100</span><br><span class="line"></span><br><span class="line">db.article.find({"like": {"$gt": 100}}) //$gt(>)、$gte(>=)、$lt(<)、$lte(<=) $ne(!=)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">select * from article where read >= 100 and read <= 200</span><br><span class="line"></span><br><span class="line">db.article.find({"like": {"$gte": 100, "lte": 200}})</span><br></pre></td></tr></table></figure></li><li><p><strong>in条件</strong></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">select * from article where author in ("a", "b", "c")</span><br><span class="line"></span><br><span class="line">db.article.find({"author": {"$in": ["a", "b", "c"]}})</span><br></pre></td></tr></table></figure></li><li><p><strong>like条件</strong></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">select * from article where title like "%深入%"</span><br><span class="line"></span><br><span class="line">db.article.find({"title": /深入/i})</span><br></pre></td></tr></table></figure></li><li><p><strong>取反</strong></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">db.article.find({"author": {"$not": /mongodb/i}})</span><br></pre></td></tr></table></figure></li><li><p><strong>排序</strong></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">select * from article where type = "mongodb" order by read desc</span><br><span class="line">db.article.find({"type": "mongodb"}).sort({"like": -1})</span><br><span class="line"></span><br><span class="line">//降序</span><br><span class="line">select * from article where type = "mongodb" order by read asc</span><br><span class="line">db.article.find({"type": "mongodb"}).sort({"like": 1})</span><br></pre></td></tr></table></figure></li><li><p><strong>更新特定字段($set)</strong></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">update article set like = 10000 where _id = 123</span><br><span class="line"></span><br><span class="line">db.article.update({"_id": 123}, { "$set": {"like": 10000}})</span><br></pre></td></tr></table></figure></li><li><p><strong>递增或递减($inc)</strong></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">db.article.update({"_id": 123}, { "$inc": {"like": 10}}) // 每次count都加10</span><br></pre></td></tr></table></figure></li><li><p><strong>数组追加($push)</strong></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">db.article.update({"_id": 123}, { "$push": {"comment": '真好'}})</span><br></pre></td></tr></table></figure></li><li><p><strong>删除指定文档</strong></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">delete from article where title = "mongodb"</span><br><span class="line"></span><br><span class="line">db.article.remove({title: "mongodb"})</span><br></pre></td></tr></table></figure></li><li><p><strong>limit和skip</strong></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">select * from article limit 10, 20</span><br><span class="line"></span><br><span class="line">db.article.find().skip(10).limit(20) //结合limit()和skip()来达到分页效果</span><br></pre></td></tr></table></figure></li></ul><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></pre></td><td class="code"><pre><span class="line">//数据库</span><br><span class="line">use xxx //创建或选择数据库</span><br><span class="line"></span><br><span class="line">show dbs / collections</span><br><span class="line"></span><br><span class="line">use xxx db.dropDatabase() //删除数据库</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">//集合</span><br><span class="line">db.createCollection("mycol", { capped : true, autoIndexId : true, size : 6142800, max : 10000 } ) //创建集合</span><br><span class="line">db.mycol2.insert({"name" : "黄明照"}) //创建集合并插入</span><br><span class="line"></span><br><span class="line">db.mycol2.drop() //删除集合</span><br><span class="line"></span><br><span class="line">db.mycol2.save(...) //无_id插入文档 有_id表示更新</span><br><span class="line"> </span><br><span class="line">db.mycol2.update({'age': 18},{$set:{'age': 20}}) //更新集合</span><br><span class="line"></span><br><span class="line">db.mycol2.remove({'age': 20}) //删除文档</span><br><span class="line"></span><br><span class="line">db.mycol2.find({key1:value1, key2:value2}).pretty() //查询 并and</span><br><span class="line">db.mycol2.find({$or: [{key1: value1}, {key2:value2}]}).pretty() //or 或</span><br><span class="line">db.mycol2.find({"age": {$gt:18}, $or: [{"name": "hmz"},{"name": "黄明照"}]}).pretty() //查询 并和或一起使用</span><br><span class="line"></span><br><span class="line">//limit 和 skip 方法 做分页查询</span><br><span class="line">db.COLLECTION_NAME.find().limit(NUMBER)</span><br><span class="line">db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)</span><br><span class="line"></span><br><span class="line">// 排序</span><br><span class="line">db.col.find({},{"name":1, _id:0}).sort({"age":-1})</span><br></pre></td></tr></table></figure><h1 id="Mongoose"><a href="#Mongoose" class="headerlink" title="Mongoose"></a>Mongoose</h1><h2 id="何为Mongoose?"><a href="#何为Mongoose?" class="headerlink" title="何为Mongoose?"></a>何为Mongoose?</h2><p>简单的说,Mongoose就是对node环境中MongoDB数据库操作的封装,一个对象模型工具,将数据库中的数据转换为JavaScript对象以供我们在应用中使用。</p><h2 id="Schema、Model、Entity"><a href="#Schema、Model、Entity" class="headerlink" title="Schema、Model、Entity"></a>Schema、Model、Entity</h2><p>在使用Mongoose前,先了解一下 Mongoose 中的三个概念:Schema、Model、Entity</p><h3 id="Schema"><a href="#Schema" class="headerlink" title="Schema"></a>Schema</h3><p><code>Schema</code>是一种以文件形式存储的数据库模型骨架,不具备数据库的操作能力,其实也可以看作是表结构的定义。</p><p>如何创建一个Schema?<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></pre></td><td class="code"><pre><span class="line">const UserSchema = new Schema({</span><br><span class="line"> token: String,</span><br><span class="line"> is_banned: {type: Boolean, default: false}, //是否禁言</span><br><span class="line"> enable: { type: Boolean, default: true }, //用户是否有效</span><br><span class="line"> is_actived: {type: Boolean, default: false}, //邮件激活</span><br><span class="line"> username: String,</span><br><span class="line"> password: String,</span><br><span class="line"> email: String, //email唯一性</span><br><span class="line"> code: String,</span><br><span class="line"> email_time: {type: Date},</span><br><span class="line"> phone: {type: String},</span><br><span class="line"> description: { type: String, default: "这个人很懒,什么都没有留下..." },</span><br><span class="line"> avatar: { type: String, default: "http://p89inamdb.bkt.clouddn.com/default_avatar.png" },</span><br><span class="line"> bg_url: { type: String, default: "http://p89inamdb.bkt.clouddn.com/FkagpurBWZjB98lDrpSrCL8zeaTU"},</span><br><span class="line"> ip: String,</span><br><span class="line"> ip_location: { type: Object },</span><br><span class="line"> agent: { type: String }, // 用户ua</span><br><span class="line"> last_login_time: { type: Date },</span><br><span class="line"> openid: {</span><br><span class="line"> WeiChat: String,</span><br><span class="line"> WeiBo: String,</span><br><span class="line"> QQ: String,</span><br><span class="line"> },</span><br><span class="line"> create_time: { type: Date },</span><br><span class="line"> // retrieve_time: { type: Number }, // 用户发送激活请求的时间</span><br><span class="line"> image_article: [{ type: mongoose.Schema.Types.ObjectId, ref: 'ImageArticle', }],</span><br><span class="line"> collection_image_article: [{ type: mongoose.Schema.Types.ObjectId, ref: 'ImageArticle', }],</span><br><span class="line"> collection_reading_article: [{ type: mongoose.Schema.Types.ObjectId, ref: 'ReadingArticle', }],</span><br><span class="line"> collection_music_article: [{ type: mongoose.Schema.Types.ObjectId, ref: 'MusicArticle', }],</span><br><span class="line"> collection_film_article: [{ type: mongoose.Schema.Types.ObjectId, ref: 'FilmArticle', }],</span><br><span class="line"> collection_sound_article: [{ type: mongoose.Schema.Types.ObjectId, ref: 'SoundArticle', }],</span><br><span class="line"> following_user: [{type: mongoose.Schema.Types.ObjectId, ref: 'User'}], //关注</span><br><span class="line"> follower_user: [{type: mongoose.Schema.Types.ObjectId, ref: 'User'}] //粉丝</span><br><span class="line">});</span><br></pre></td></tr></table></figure></p><p>对了,MongoDB支持的数据类型很多,如下:</p><ul><li><p>String:字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。</p></li><li><p>Integer:整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。</p></li><li><p>Boolean:布尔值。用于存储布尔值(真/假)。</p></li><li><p>Double:双精度浮点值。用于存储浮点值。</p></li><li><p>Arrays:用于将数组或列表或多个值存储为一个键。</p></li><li><p>Timestamp:时间戳。记录文档修改或添加的具体时间。</p></li><li><p>Object:用于内嵌文档。</p></li><li><p>Null:用于创建空值。</p></li><li><p>Symbol:符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。</p></li><li><p>Date:日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。</p></li><li><p>Object ID:对象 ID。用于创建文档的 ID。</p></li><li><p>Binary Data:二进制数据。用于存储二进制数据。</p></li><li><p>Code:代码类型。用于在文档中存储 JavaScript 代码。</p></li><li><p>Regular expression:正则表达式类型。用于存储正则表达式。</p></li></ul><h3 id="Model"><a href="#Model" class="headerlink" title="Model"></a>Model</h3><p>由Schema发布生成的模型,具有抽象属性和行为的数据库操作对象。正是Model的存在,让我们操作数据库更加方便快捷。<br>依赖<code>Schema</code>生成一个<code>Model</code>:</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 User = mongoose.model("User", UserSchema);</span><br><span class="line">module.exports = User;</span><br></pre></td></tr></table></figure><h3 id="Entity"><a href="#Entity" class="headerlink" title="Entity"></a>Entity</h3><p>由Model创建的实体,它的操作也会影响数据库。<br>依赖<code>Model</code>,创造一个<code>Entity</code>:<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></pre></td><td class="code"><pre><span class="line">const UserModel = require('../../models/user/user')</span><br><span class="line">const newUser = new UserModel({</span><br><span class="line"> username: '就这样子吧',</span><br><span class="line"> password: sha1('xxx'),</span><br><span class="line"> token: createToken('就这样子吧'),</span><br><span class="line"> email: '651734877@qq.com',</span><br><span class="line"> phone: '13003919397',</span><br><span class="line"> agent: req.headers['user-agent'],</span><br><span class="line"> ip: ip,</span><br><span class="line"> ip_location: geoip.lookup(ip)</span><br><span class="line">})</span><br></pre></td></tr></table></figure></p><h2 id="document的CRUD操作"><a href="#document的CRUD操作" class="headerlink" title="document的CRUD操作"></a>document的CRUD操作</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><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">const Articles = mongoose.model('Articles', articleSchema);</span><br><span class="line"></span><br><span class="line">let article = new Articles({ title: '我不知道' });</span><br><span class="line">//使用实例创建</span><br><span class="line">article.save((err) => {</span><br><span class="line"> if (err) return handleError(err);</span><br><span class="line"> // saved!</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line">//使用Model类创建</span><br><span class="line">Articles.create({ title: '我不知道' }, (err, article) => {</span><br><span class="line"> if (err) return handleError(err);</span><br><span class="line"> // saved!</span><br><span class="line">})</span><br></pre></td></tr></table></figure><h3 id="查询"><a href="#查询" class="headerlink" title="查询"></a>查询</h3><p>Mongoose查找文档很容易,它支持MongoDB的丰富的查询语法。 可以使用每个models的find,findById,findOne等静态方法进行查找文档。<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">UserModel.findOne({ 'name': '黄' }, (err, person) => {</span><br><span class="line"> if (err) return handleError(err);</span><br><span class="line"> // get data</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line"> let user = await UserModel.findOne({email: userObj.email, is_actived: false})</span><br></pre></td></tr></table></figure></p><h3 id="删除"><a href="#删除" class="headerlink" title="删除"></a>删除</h3><p>有remove()、findOneAndRemove()、findByIdAndRemove()<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></pre></td><td class="code"><pre><span class="line">ArticlesModel.remove({'_id': id}, (err) => { </span><br><span class="line"> if (err) { </span><br><span class="line"> return res.status(400).send({ </span><br><span class="line"> message: '删除失败', </span><br><span class="line"> data: [] </span><br><span class="line"> }); </span><br><span class="line"> } else { </span><br><span class="line"> } </span><br><span class="line">})</span><br></pre></td></tr></table></figure></p><h3 id="更新"><a href="#更新" class="headerlink" title="更新"></a>更新</h3><p>有update()、updateMany()、find() + save()、updateOne()、findByIdAndUpdate()、fingOneAndUpdate()等等<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">const userObj = {</span><br><span class="line"> email: req.body.email, //email唯一性</span><br><span class="line"> username: req.body.username,</span><br><span class="line"> password: password,</span><br><span class="line"> token: createToken(req.body.email),</span><br><span class="line"> is_actived: true,</span><br><span class="line"> ip: ip,</span><br><span class="line"> ip_location: ip_location,</span><br><span class="line"> agent: agent,</span><br><span class="line"> create_time: Date.now(),</span><br><span class="line">}</span><br><span class="line">await UserModel.findOneAndUpdate({email: userObj.email, is_actived: false}, {</span><br><span class="line"> $set: userObj</span><br><span class="line">})</span><br></pre></td></tr></table></figure></p><h2 id="索引"><a href="#索引" class="headerlink" title="索引"></a>索引</h2><p>索引可以加快查询速度,我们通过一个例子来看看效果。<br>在mongo Shell中,我们创建10000条数据:<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></pre></td><td class="code"><pre><span class="line">$ mongo</span><br><span class="line"></span><br><span class="line">for (var i = 0; i < 10000; i++){</span><br><span class="line"> db.users.insert({'name':'user' + i}); </span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>看看未加索引的情况下查询:<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">db.hello.find({'name': 'user1000'}).explain('executionStats')</span><br></pre></td></tr></table></figure></p><p><img src="http://oubl6fzsm.bkt.clouddn.com/mongoose-explain.jpg" alt="image"><br>图中可以看出<code>executionTimeMillis</code>字段为7。<br>现在我们来添加索引后执行查询:<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">db.hello.ensureIndex({name: 1});</span><br><span class="line">db.hello.find({'name': 'user1000'}).explain('executionStats')</span><br></pre></td></tr></table></figure></p><p><img src="http://oubl6fzsm.bkt.clouddn.com/mongoose-explain2.jpg" alt="image"><br>图中可以看出<code>executionTimeMillis</code>字段为1。</p><p>从上面的实例可以看出,加了索引后,能快速的查询一条,这可以看到索引极大的提升了查询速度。</p><p>下面我们看看如何使用Mongoose创建:<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">const ArticlesSchema = new Schema({ </span><br><span class="line"> title: { </span><br><span class="line"> ...</span><br><span class="line"> index: true / 1 / -1 </span><br><span class="line"> } </span><br><span class="line">});</span><br></pre></td></tr></table></figure></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><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">const ArticlesSchema = new Schema({ </span><br><span class="line"> title: { </span><br><span class="line"> ... </span><br><span class="line"> index: true, </span><br><span class="line"> unique: true </span><br><span class="line"> } </span><br><span class="line">});</span><br></pre></td></tr></table></figure></p><p>复合索引:<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">ArticlesSchema.index({name: 1, create_time: -1}); //可以指定不同字段的排序 1是正序,-1是倒序</span><br></pre></td></tr></table></figure></p><p><strong>注</strong>: 对于添加的每一条索引,每次写操作(插入、更新、删除)都将耗费更多的时间。这是因为,当数据发生变化时,不仅要更新文档,还要更新集合上的所有索引。通常,在一个特定的集合上,不应该拥有两个以上的索引。如果数据量很多且查询多于更新时,可以用索引提高查询的速度。</p><h2 id="虚拟属性VirtualType"><a href="#虚拟属性VirtualType" class="headerlink" title="虚拟属性VirtualType"></a>虚拟属性VirtualType</h2><p>虚拟属性并不会存储到MongoDB中,利用它,我们可以格式化和自定义组合属性值。<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></pre></td><td class="code"><pre><span class="line">const UsersSchema = new Schema({ </span><br><span class="line"> ... </span><br><span class="line"> address: { </span><br><span class="line"> city: {type: String}, </span><br><span class="line"> street: {type: String} </span><br><span class="line"> } </span><br><span class="line">});</span><br><span class="line">const address = UsersSchema.virtual('address.full'); </span><br><span class="line"></span><br><span class="line">address.get(function () { </span><br><span class="line"> return this.address.city + ' ' + this.address.street; </span><br><span class="line">});</span><br></pre></td></tr></table></figure></p><p>通过定义set方法,我们可以给两个字段快速赋值:<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">address.set(function(v) { </span><br><span class="line"> const split = v.split(' '); </span><br><span class="line"> this.address.city = split[0]; </span><br><span class="line"> this.address.street = split[1]; </span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">const body = { </span><br><span class="line"> name: 'abcd', </span><br><span class="line"> phone: '13123123123', </span><br><span class="line"> age: 20, </span><br><span class="line"> sex: 'male' </span><br><span class="line">}; </span><br><span class="line">const user = new UsersModel(body); </span><br><span class="line">user.address.full = 'xiamen meitu'; </span><br><span class="line">user.save();</span><br></pre></td></tr></table></figure></p><h2 id="验证器Validate"><a href="#验证器Validate" class="headerlink" title="验证器Validate"></a>验证器Validate</h2><h3 id="内置验证器"><a href="#内置验证器" class="headerlink" title="内置验证器"></a>内置验证器</h3><p>Mongoose提供了几个内置验证器。</p><ul><li>所有的SchemaType都有内置的require验证器。</li><li>数值( Numbers )有最大(max)和最小(min)的验证器。</li><li>字符串(String)有enum,maxLength和minLength验证器。</li></ul><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">const UsersSchema = new Schema({ </span><br><span class="line"> ...</span><br><span class="line"> age: { </span><br><span class="line"> type: Number, </span><br><span class="line"> min: [18, "自定义错误提示"] </span><br><span class="line"> max: 30, </span><br><span class="line"> required: true </span><br><span class="line"> }, </span><br><span class="line"> sex: { </span><br><span class="line"> type: String, </span><br><span class="line"> enum: { </span><br><span class="line"> values: ['male', 'female'],</span><br><span class="line"> message: '`{PATH}` 是 `{VALUE}`, 您必须确认您的性别!' </span><br><span class="line"> }, </span><br><span class="line"> required: true </span><br><span class="line"> } </span><br><span class="line">}); </span><br><span class="line"></span><br><span class="line">mongoose.model('users', UsersSchema);</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><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">const UsersSchema = new Schema({ </span><br><span class="line"> ... </span><br><span class="line"> phone: { </span><br><span class="line"> type: String, </span><br><span class="line"> validate: { </span><br><span class="line"> validator: function (v) {</span><br><span class="line"> return /1[3|5|8]\d{9}/.test(v);</span><br><span class="line"> },</span><br><span class="line"> message: '`{PATH}` 必须是有效的11位手机号码!' </span><br><span class="line"> }, </span><br><span class="line"> required: 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><span class="line">UsersSchema.path('phone').validate(function (v) {</span><br><span class="line"> return /1[3|5|8]\d{9}/.test(v);</span><br><span class="line">}, '`{PATH}` 必须是有效的11位手机号码!');</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><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">const user = new UsersModel(req.body);</span><br><span class="line"></span><br><span class="line">user.save((err, result) => {</span><br><span class="line"> if (err) {</span><br><span class="line"> console.error(err.errors['name']['message']);</span><br><span class="line"> return res.status(400)</span><br><span class="line"> .send({</span><br><span class="line"> message: err</span><br><span class="line"> });</span><br><span class="line"> } else {</span><br><span class="line"> res.send(user);</span><br><span class="line"> }</span><br><span class="line">})</span><br></pre></td></tr></table></figure><h2 id="statics和methods"><a href="#statics和methods" class="headerlink" title="statics和methods"></a>statics和methods</h2><p>都是schema的属性,statics和methods的区别:</p><p>区别就是一个给Model添加方法(statics),<br>一个给实例添加方法(methods)。<br>statics:<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></pre></td><td class="code"><pre><span class="line">UserSchema.statics.find_by_username = function(username, cb) {</span><br><span class="line"> return this.findOne({</span><br><span class="line"> username: username</span><br><span class="line"> }, cb);</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">UserModal.find_by_username('hmz', (err, user) => {</span><br><span class="line"> console.log('find_by_username', user)</span><br><span class="line">})</span><br></pre></td></tr></table></figure></p><p>methods:<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></pre></td><td class="code"><pre><span class="line">UserSchema.methods.is_exist = function(cb) {</span><br><span class="line"> const query = {</span><br><span class="line"> username: this.username,</span><br><span class="line"> password: this.password</span><br><span class="line"> };</span><br><span class="line"> return this.model('UserModel').findOne(query, cb);</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">const user = new User({</span><br><span class="line"> username: 'hmz',</span><br><span class="line"> password: 'sadsaa';</span><br><span class="line">});</span><br><span class="line">user.is_exist(cb)</span><br></pre></td></tr></table></figure></p><h2 id="联表查询"><a href="#联表查询" class="headerlink" title="联表查询"></a>联表查询</h2><p>如果你使用过MySql,肯定用过join,用来联表查询,但Mongoose中并没有join,不过它提供了一种更方便快捷的方法:<code>Population</code>。<br>用简短的话来概括Population的使用:在一个Collection(articles)中定义一个指向另一个Collection(comment)的_id字段的字段(comment)<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></pre></td><td class="code"><pre><span class="line">//FilmComment</span><br><span class="line">const filmCommentSchema = new Schema({</span><br><span class="line"> ...</span><br><span class="line"> article_id: {type: mongoose.Schema.Types.ObjectId, ref: 'FilmArticle', required: true},</span><br><span class="line"> ...</span><br><span class="line"> reply_to_id: {type: mongoose.Schema.Types.ObjectId, ref: 'FilmComment'} //ref的值是模型(model)名称 //被回复的评论id</span><br><span class="line"> ...</span><br><span class="line">})</span><br><span class="line">const FilmComment = mongoose.model('FilmComment', filmCommentSchema);</span><br><span class="line">module.exports = FilmComment</span><br><span class="line"></span><br><span class="line">//FilmArticle</span><br><span class="line">const filmArticleSchema = new Schema({</span><br><span class="line"> ...</span><br><span class="line"> comment: [{type: mongoose.Schema.Types.ObjectId, ref: 'FilmComment'}],</span><br><span class="line"> ...</span><br><span class="line">})</span><br><span class="line">let FilmArticle = mongoose.model('FilmArticle', filmArticleSchema);</span><br><span class="line">module.exports = FilmArticle</span><br><span class="line"></span><br><span class="line">const newFilmComment = req.body.reply_to_id ? new FilmCommentModel({</span><br><span class="line"> article_id: req.body.article_id,</span><br><span class="line"> content: content,</span><br><span class="line"> create_time: Date.now(),</span><br><span class="line"> reply_to_id: req.body.reply_to_id</span><br><span class="line">}) : new FilmCommentModel({</span><br><span class="line"> article_id: req.body.article_id,</span><br><span class="line"> content: content,</span><br><span class="line"> create_time: Date.now(),</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line">await FilmCommentModel.create(newFilmComment)</span><br><span class="line">const newFilmArticle = await FilmArticleModel.findByIdAndUpdate(req.body.article_id, {</span><br><span class="line"> $push': {</span><br><span class="line"> comment: newFilmComment._id</span><br><span class="line"> },</span><br><span class="line">}, {new: true}).populate({</span><br><span class="line"> path: 'comment',</span><br><span class="line"> model: 'FilmComment',</span><br><span class="line"> populate: {</span><br><span class="line"> path: 'reply_to_id',</span><br><span class="line"> model: 'FilmComment',</span><br><span class="line"> populate: {</span><br><span class="line"> path: 'user_id',</span><br><span class="line"> select: {</span><br><span class="line"> password: 0, token: 0</span><br><span class="line"> },</span><br><span class="line"> model: 'User'</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="前后钩子"><a href="#前后钩子" class="headerlink" title="前后钩子"></a>前后钩子</h2><p>前:pre() 后:post(),在执行某些操作时可以执行的函数,在Schema上指定。<br>在以下操作中触发执行 中间件<br>schame的钩子有:<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></pre></td><td class="code"><pre><span class="line">//--------pre 前置</span><br><span class="line">schema.pre('init', function (next) {</span><br><span class="line"> console.log('init');</span><br><span class="line"> next();</span><br><span class="line">});</span><br><span class="line">schema.pre('validate', function (next) {</span><br><span class="line"> console.log('validate');</span><br><span class="line"> next();</span><br><span class="line">});</span><br><span class="line">schema.pre('save', function (next) {</span><br><span class="line"> console.log('save');</span><br><span class="line"> next();</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">schema.pre('find', function(next) {</span><br><span class="line"> console.log('find');</span><br><span class="line"> next();</span><br><span class="line">});</span><br><span class="line">//--------post 后置</span><br><span class="line">schema.post('init', function (doc,next) {</span><br><span class="line"> console.log('post-init');</span><br><span class="line"> next();</span><br><span class="line">});</span><br><span class="line">schema.post('validate', function (doc,next) {</span><br><span class="line"> console.log('post-validate');</span><br><span class="line"> next();</span><br><span class="line">});</span><br><span class="line">schema.post('save', function (doc,next) {</span><br><span class="line"> console.log('post-save');</span><br><span class="line"> next();</span><br><span class="line">});</span><br><span class="line">schema.post('find', function (doc,next) {</span><br><span class="line"> console.log('post-find');</span><br><span class="line"> next();</span><br><span class="line">});</span><br></pre></td></tr></table></figure></p><h2 id="插件"><a href="#插件" class="headerlink" title="插件"></a>插件</h2><p>我们是可以通过插件形式来拓展Schema的功能。</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><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">// plugins/plugins.js </span><br><span class="line">module.exports = { </span><br><span class="line"> lastModified(schema, options) {</span><br><span class="line"> schema.add({ lastMod: Date })</span><br><span class="line"> schema.pre('save', function (next) { //前置钩子</span><br><span class="line"> this.lastMod = new Date; </span><br><span class="line"> next() </span><br><span class="line"> }) </span><br><span class="line"> if (options && options.index) {</span><br><span class="line"> schema.path('lastMod').index(options.index)</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">// articles/filmArticles.js</span><br><span class="line"></span><br><span class="line">const plugins = require('../plugins/plugins'); </span><br><span class="line"></span><br><span class="line">filmArticlesSchema.plugin(plugins.lastModified, {index: true});</span><br></pre></td></tr></table></figure></p><h2 id="聚合函数"><a href="#聚合函数" class="headerlink" title="聚合函数"></a>聚合函数</h2><p>MongoDB中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。有点类似sql语句中的 count(*)。</p>]]></content>
<categories>
<category> 渣技术 </category>
</categories>
<tags>
<tag> Mongoose </tag>
</tags>
</entry>
<entry>
<title>聊聊毕业设计系列 --- 系统实现</title>
<link href="/%E8%81%8A%E8%81%8A%E6%AF%95%E4%B8%9A%E8%AE%BE%E8%AE%A1%E7%B3%BB%E5%88%972.html"/>
<content type="html"><![CDATA[<h1 id="效果展示"><a href="#效果展示" class="headerlink" title="效果展示"></a>效果展示</h1><p><img src="https://user-gold-cdn.xitu.io/2018/8/26/16576a709bd02f5f?w=1409&h=521&f=gif&s=30128195" alt="管理系统"></p><p><img src="https://user-gold-cdn.xitu.io/2018/8/26/16576a8711c14cbc?w=341&h=569&f=gif&s=48073144" alt="WebApp"></p><h1 id="github"><a href="#github" class="headerlink" title="github"></a>github</h1><p><a href="https://github.com/ishareme/moment-server" target="_blank" rel="noopener">moment-server github地址</a></p><p><a href="https://github.com/ishareme/moment" target="_blank" rel="noopener">moment github地址</a></p><p><a href="https://github.com/ishareme/moment-manage" target="_blank" rel="noopener">moment-manage github地址</a></p><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>在上一篇文章中,主要是对项目做了介绍,并且对系统分析和系统设计做了大概的介绍。那么接下来这篇文章会对系统的实现做介绍,主要是选择一些比较主要的模块或者说可拿出来与大家分享的模块。好了,接入正题吧~~</p><h1 id="MongoDB"><a href="#MongoDB" class="headerlink" title="MongoDB"></a>MongoDB</h1><p>服务端这边使用的是Express框架,数据库使用的是MongoDB,通过Mongoose模块来操作数据库。这边主要是想下对MongoDB做个介绍,当然看官了解的话直接往下划<del>~</del>~</p><p>在项目开始前要确保电脑是否安装mongoDB,<a href="https://www.mongodb.com/download-center?jmp=nav#atlas" target="_blank" rel="noopener">下载点我</a>,<a href="https://robomongo.org/download" target="_blank" rel="noopener">图像化工具Robo 3T 点我</a>,下载好具体怎么配置还请问度娘或Google吧,本文不做介绍了哈。注意:安装完mongoDB的时候进行项目时要把lib目录下的mongod服务器打开哈~~</p><p>MongoDB 是一个基于分布式文件存储的数据库,是一个介于关系型数据库和非关系型数据库之间的开源产品,它是功能最为丰富的非关系型数据库,也是最像关系型数据库的。但是和关系型数据库不同,MongoDB没有表和行的概念,而是一个面向<code>集合、文档</code>的数据库。其中的文档是一个键值对,采用BSON(Binary Serialized Document Format),BSON是一种类似于JSON的二进制形式的存储格式,并且BSON具有表示数据类型的扩展,因此支持的数据非常丰富。MongoDB有两个很重要的数据类型就是<code>内嵌文档和数组</code>,而且在数组内可以嵌入其他文档,这样一条记录就能表示非常复杂的关系。</p><p>Mongoose是在node.js异步环境下对MongoDB进行简便操作的对象模型工具,能从数据库提取任何信息,可以用面向对象的方法来读写数据,从而使操作MongoDB数据库非常便捷。Mongoose中有三个非常重要的概念,便是Schema(模式),Model(模型),Entity(实体)。</p><ol><li><p>Schema: 一种以文件形式存储的数据库模型骨架,不具备数据库的操作能力,创建它的过程如同关系型数据库建表的过程,如下:</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></pre></td><td class="code"><pre><span class="line">//Schema</span><br><span class="line">const mongoose = require('mongoose');</span><br><span class="line">const Schema = mongoose.Schema;</span><br><span class="line"></span><br><span class="line">const UserSchema = new Schema({</span><br><span class="line"> token: String,</span><br><span class="line"> is_banned: {type: Boolean, default: false}, //是否禁言</span><br><span class="line"> enable: { type: Boolean, default: true }, //用户是否有效</span><br><span class="line"> is_actived: {type: Boolean, default: false}, //邮件激活</span><br><span class="line"> username: String,</span><br><span class="line"> password: String,</span><br><span class="line"> email: String, //email唯一性</span><br><span class="line"> code: String,</span><br><span class="line"> email_time: {type: Date},</span><br><span class="line"> phone: {type: String},</span><br><span class="line"> description: { type: String, default: "这个人很懒,什么都没有留下..." },</span><br><span class="line"> avatar: { type: String, default: "http://p89inamdb.bkt.clouddn.com/default_avatar.png" },</span><br><span class="line"> bg_url: { type: String, default: "http://p89inamdb.bkt.clouddn.com/FkagpurBWZjB98lDrpSrCL8zeaTU"},</span><br><span class="line"> ip: String,</span><br><span class="line"> ip_location: { type: Object },</span><br><span class="line"> agent: { type: String }, // 用户ua</span><br><span class="line"> last_login_time: { type: Date },</span><br><span class="line"> .....</span><br><span class="line">});</span><br></pre></td></tr></table></figure></li><li><p>Model: 由Schema发布生成的模型,具有抽象属性和行为的数据库操作对象</p></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></pre></td><td class="code"><pre><span class="line">//生成一个具体User的model并导出</span><br><span class="line">const User = mongoose.model("User", UserSchema); //第一个参数是集合名,在数据库中会把Model名字字母全部变小写和在后面加复数s</span><br><span class="line"></span><br><span class="line">//执行到这个时候你的数据库中就有了 users 这个集合</span><br><span class="line"></span><br><span class="line">module.exports = User;</span><br></pre></td></tr></table></figure><ol><li>Entity: 由Model创建的实体,他的操作也会影响数据库,但是它操作数据库的能力比Model弱<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">const newUser = new UserModel({ //UserModel 为导出来的 User</span><br><span class="line"> email: req.body.email,</span><br><span class="line"> code: getCode(),</span><br><span class="line"> email_time: Date.now()</span><br><span class="line"> });</span><br></pre></td></tr></table></figure></li></ol><p>Mongoose中有一个东西个人感觉非常主要,那便是<code>populate</code>,通过populate他可以很方便的与另一个集合建立关系。如下,user集合可以与article集合、user集合本身进行关联,根据其内嵌文档的特性,这样子他便可以内嵌子文档,子文档中有可以内嵌子文档,这样子它返回的数据就会异常的丰富。<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></pre></td><td class="code"><pre><span class="line">const user = await UserModel.findOne({_id: req.query._id, is_actived: true}, {password: 0}).populate({</span><br><span class="line"> path: 'image_article',</span><br><span class="line"> model: 'ImageArticle',</span><br><span class="line"> populate: {</span><br><span class="line"> path: 'author',</span><br><span class="line"> model: 'User'</span><br><span class="line"> }</span><br><span class="line"> }).populate({</span><br><span class="line"> path: 'collection_film_article',</span><br><span class="line"> model: 'FilmArticle',</span><br><span class="line"> }).populate({</span><br><span class="line"> path: 'following_user',</span><br><span class="line"> model: 'User',</span><br><span class="line"> }).populate({</span><br><span class="line"> path: 'follower_user',</span><br><span class="line"> model: 'User',</span><br><span class="line"> }).exec();</span><br></pre></td></tr></table></figure></p><p>服务端主要是操作数据库,对数据库进行增删改查(CRUD)等操作。项目中的接口,Mongoose的各种方法这边就不对其做详细介绍,大家可以查看<a href="https://mongoosejs.com/docs/guide.html" target="_blank" rel="noopener">Mongoose文档</a>。</p><h1 id="用户身份认证实现"><a href="#用户身份认证实现" class="headerlink" title="用户身份认证实现"></a>用户身份认证实现</h1><h2 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h2><p>本系统的用户身份认证机制采用的是<code>JSON Web Token(JWT)</code>,它是一种轻量的认证规范,也用于接口的认证。我们知道,HTTP协议是一种无状态的协议,这便意味着每个请求都是独立的,当用户提供了用户名和密码来对我们的应用进行用户认证,那么在下一次请求的时候,用户需要再进行一次用户的认证才可以,因为根据HTTP协议,我们并不能知道是哪个用户发出的请求,本系统采用了token的鉴权机制。这个token必须要在每次请求时传递给服务端,它应该保存在请求头里,另外,服务端要支持CORS(跨来源资源共享)策略,一般我们在服务端这么做就可以了Access-Control-Allow-Origin: *。</p><p>在用户身份认证这一块有很多方法,最常见的像cookie ,session。那么他们三之间又有什么区别,这里有两篇文章介绍的挺全面。</p><ul><li><a href="http://www.52im.net/thread-1525-1-1.html" target="_blank" rel="noopener">正确理解HTTP短连接中的Cookie、Session和Token</a></li><li><a href="https://zhuanlan.zhihu.com/p/38227861" target="_blank" rel="noopener">小白必读:闲话HTTP短连接中的Session和Token</a></li></ul><p>token 与 session的区别在于,它不同于传统的session认证机制,它不需要在服务端去保留用户的认证信息或其会话的信息。系统一旦比较大,都会采用机器集群来做负载均衡,这需要多台机器,由于session是保存在服务端,那么就要 去考虑用户到底是在哪一台服务器上进行登录的,这便是一个很大的负担。</p><p>那么就有人想问了,你这个系统这么小,为什么不使用传统的session机制呢?哈~因为之前自己的项目一般都是使用session做登录,没使用过token,想尝试尝试入入坑~~哈哈哈~</p><h2 id="实现思路"><a href="#实现思路" class="headerlink" title="实现思路"></a>实现思路</h2><p>JWT主要的实现思路如下:</p><ol><li><p>在用户登录成功的时候创建token保存于数据库中,并返回给客户端。</p></li><li><p>客户端之后的每一次请求都要带上token,在请求头里加入Authorization,并加上token.</p></li><li><p>在服务端进行验证token的有效性,在有效期内返回200状态码,token过期则返回401状态码</p></li></ol><p>如下图所示: </p><p><img src="https://user-gold-cdn.xitu.io/2018/8/19/16551e5acf4fb44e?w=685&h=563&f=png&s=59915" alt="JWT请求图"></p><center>JWT请求图</center><p>在node中主要用了<code>jsonwebtoken</code>这个模块来创建JWT,jsonwebtoken的使用请查看<a href="https://segmentfault.com/a/1190000009494020" target="_blank" rel="noopener">jsonwebtoken文档</a>。项目中创建token的中间件createToken如下</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">/**</span><br><span class="line"> * createToken.js</span><br><span class="line"> */</span><br><span class="line">const jwt = require('jsonwebtoken'); // 引入jsonwebtoken模块</span><br><span class="line">const secret = '我是密钥'</span><br><span class="line"></span><br><span class="line">//登录时:核对用户名和密码成功后,应用将用户的id(user_id)作为JWT Payload的一个属性</span><br><span class="line">module.exports = function(user_id){</span><br><span class="line"> const token = jwt.sign({</span><br><span class="line"> user_id: user_id</span><br><span class="line"> }, secret, { //密钥</span><br><span class="line"> expiresIn: '24h' //过期时间设置为24h。那么decode这个token的时候得到的过期时间为:创建token的时间+设置的值</span><br><span class="line"> });</span><br><span class="line"> return token;</span><br><span class="line">};</span><br></pre></td></tr></table></figure><p>return 出来的 token 类似<code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiYWRtaW4iLCJpYXQiOjE1MzQ2ODQwNzAsImV4cCI6MTUzNDc3MDQ3MH0.Y3kaglqW9Fpe1YxF_uF7zwTV224W4W97MArU0aI0JgM</code>。我们仔细看这字符串,分为三段,分别被 “.” 隔开。现在我们分别对前两段进行base64解码如下:<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></pre></td><td class="code"><pre><span class="line">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 ===> {"alg":"HS256","typ":"JWT"} 其中 alg是加密算法名字,typ是类型</span><br><span class="line"></span><br><span class="line">eyJ1c2VyX2lkIjoiYWRtaW4iLCJpYXQiOjE1MzQ2ODQwNzAsImV4cCI6MTUzNDc3MDQ3MH0 ===> {"user_id":"admin","iat":1534684070,"exp":1534770470} 其中 name是我们储存的内容,iat创建的时间戳,exp到期时间戳。</span><br><span class="line"></span><br><span class="line">Y3kaglqW9Fpe1YxF_uF7zwTV224W4W97MArU0aI0JgM ===> 最后一段是由前面两段字符串,HS256加密后得到。所以前面的任何一个字段修改,都会导致加密后的字符串不匹配。</span><br></pre></td></tr></table></figure></p><p>当我们根据用户的id创建获取到token之后,我们需要把token返回到客户端,客户端对其在本地(localStorage)保存, 客户端之后的每一次请求都要带上token,在请求头里加入Authorization,并加上token,服务端进行验证token的有效性。那么我们如何验证token的有效性呢? 所以我们需要checkToken这个中间件来检测token的有效性。<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></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * checkToken</span><br><span class="line"> */</span><br><span class="line">const jwt = require('jsonwebtoken');</span><br><span class="line">const secret = '我是密钥'</span><br><span class="line"></span><br><span class="line">module.exports = async ( req, res, next ) => {</span><br><span class="line"> const authorization = req.get('Authorization');</span><br><span class="line"> if (!authorization) {</span><br><span class="line"> res.status(401).end(); //接口需要认证但是有没带上token,返回401未授权状态码</span><br><span class="line"> return</span><br><span class="line"> }</span><br><span class="line"> const token = authorization.split(' ')[1];</span><br><span class="line"> try {</span><br><span class="line"> let tokenContent = await jwt.verify(token, secret); //如果token过期或验证失败,将抛出错误</span><br><span class="line"> next(); //执行下一个中间件</span><br><span class="line"> } catch (err) {</span><br><span class="line"> console.log(err)</span><br><span class="line"> res.status(401).end(); //token过期或者验证失败返回401状态码</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>那么现在咱们只要在需要用户认证的接口上,在操作数据之前,加上checkToken中间件即可,如下调用:<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">//更新用户信息</span><br><span class="line">router.post('/updateUserInfo', checkToken, User.updateUserInfo) </span><br><span class="line"></span><br><span class="line">//如果checkToken检测不成功,它便返回401状态码,不会对User.updateUserInfo做任何操作, 只有检测token成功,才能处理User.updateUserInfo</span><br></pre></td></tr></table></figure></p><p>我们如何保证每次请求都能在请求头里加入Authorization,并加上token,这就要用到Axios的请求拦截,并且也用到了它的响应拦截,因为在服务端返回401状态码之后应要执行登出操作,清楚本地token的存储,具体代码如下:<br><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//request拦截器</span></span><br><span class="line">instance.interceptors.request.use(</span><br><span class="line"> config => {</span><br><span class="line"> <span class="comment">//每次发送请求之前检测本地是否存有token,都要放在请求头发送给服务器</span></span><br><span class="line"> <span class="keyword">if</span>(localStorage.getItem(<span class="string">'token'</span>)){</span><br><span class="line"> <span class="keyword">if</span> (config.url.indexOf(<span class="string">'upload-z0.qiniup.com/putb64'</span>) > <span class="number">-1</span>){</span><br><span class="line"> config.headers.Authorization = config.headers[<span class="string">'UpToken'</span>]; <span class="comment">//加上七牛云上传token</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> config.headers.Authorization = <span class="string">`token <span class="subst">${localStorage.getItem(<span class="string">'token'</span>)}</span>`</span>.replace(<span class="regexp">/(^\")|(\"$)/g</span>, <span class="string">''</span>); <span class="comment">//加上系统接口token</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'config'</span>,config)</span><br><span class="line"> <span class="keyword">return</span> config;</span><br><span class="line"> },</span><br><span class="line"> err => {</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">'err'</span>,err)</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Promise</span>.reject(err);</span><br><span class="line"> }</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="comment">//response拦截器</span></span><br><span class="line">instance.interceptors.response.use(</span><br><span class="line"> response => {</span><br><span class="line"> <span class="keyword">return</span> response;</span><br><span class="line"> },</span><br><span class="line"> error => { <span class="comment">//默认除了2XX之外的都是错误的,就会走这里</span></span><br><span class="line"> <span class="keyword">if</span>(error.response){</span><br><span class="line"> <span class="keyword">switch</span>(error.response.status){</span><br><span class="line"> <span class="keyword">case</span> <span class="number">401</span>:</span><br><span class="line"> <span class="built_in">console</span>.log(error.response)</span><br><span class="line"> store.dispatch(<span class="string">'ADMIN_LOGINOUT'</span>); <span class="comment">//可能是token过期,清除它</span></span><br><span class="line"> router.replace({ <span class="comment">//跳转到登录页面</span></span><br><span class="line"> path: <span class="string">'/login'</span>,</span><br><span class="line"> query: { <span class="attr">redirect</span>: <span class="string">'/dashboard'</span> } <span class="comment">// 将跳转的路由path作为参数,登录成功后跳转到该路由</span></span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="built_in">Promise</span>.reject(error.response);</span><br><span class="line"> }</span><br><span class="line">);</span><br></pre></td></tr></table></figure></p><p>其中的if else 是因为本系统的图片,音视频是放在七牛云,上传需要七牛云上传base64图片的时候token是放在请求头的,正常的图片上传不是放在请求头,所以这边对token做了区分,如何接入七牛云也会在下面模块介绍到。</p><h1 id="七牛云接入"><a href="#七牛云接入" class="headerlink" title="七牛云接入"></a>七牛云接入</h1><p>本系统的图片,音视频是放在七牛云,所以需要接入七牛云。七牛云分了两种情况,正常图片和音视频的上传和base64图片的上传,因为七牛云在对他们两者上传的<code>Content-Type</code>和<code>domain(域)</code>有所不同,正常图片和音视频的Content-Type是<code>headers: {'Content-Type':'multipart/form-data'}</code>domain是<code>domain='https://upload-z0.qiniup.com'</code>,而base64图片的上传则是<code>headers:{'Content-Type':'application/octet-stream'}</code>domain是<code>domain='https://upload-z0.qiniup.com/putb64/-1'</code>,所以他们请求的时候token放的地方不同,base64就像上面所说的放在请求头<code>Authorization</code>中,而正常的放在<code>form-data</code>中。在服务端通过接口请求来获取七牛云上传token,客户端获取到七牛云token,通过不同方案将token带上。</p><ol><li>base64的上传: <code>headers:{'Content-Type':'application/octet-stream'}</code> 和 <code>domain='https://upload-z0.qiniup.com/putb64/-1'</code>,token放在请求头<code>Authorization</code>中。</li><li>正常图片和音视频的上传: <code>headers: {'Content-Type':'multipart/form-data'}</code>和<code>domain='https://upload-z0.qiniup.com'</code>,token 放在 <code>form-data</code>中。</li></ol><p>服务端通过<code>qiniu</code>这个模块进行创建token,服务端代码如下:</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></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * 构建一个七牛云上传凭证类</span><br><span class="line"> * @class QN</span><br><span class="line"> */</span><br><span class="line">const qiniu = require('qiniu') //导入qiniu模块</span><br><span class="line">const config = require('../config')</span><br><span class="line">class QN {</span><br><span class="line"> /**</span><br><span class="line"> * Creates an instance of qn.</span><br><span class="line"> * @param {string} accessKey -七牛云AK</span><br><span class="line"> * @param {string} secretKey -七牛云SK</span><br><span class="line"> * @param {string} bucket -七牛云空间名称</span><br><span class="line"> * @param {string} origin -七牛云默认外链域名,(可选参数)</span><br><span class="line"> */</span><br><span class="line"> constructor (accessKey, secretKey, bucket, origin) {</span><br><span class="line"> this.ak = accessKey</span><br><span class="line"> this.sk = secretKey</span><br><span class="line"> this.bucket = bucket</span><br><span class="line"> this.origin = origin</span><br><span class="line"> }</span><br><span class="line"> /**</span><br><span class="line"> * 获取七牛云文件上传凭证</span><br><span class="line"> * @param {number} time - 七牛云凭证过期时间,以秒为单位,如果为空,默认为7200,有效时间为2小时</span><br><span class="line"> */</span><br><span class="line"> upToken (time) {</span><br><span class="line"> const mac = new qiniu.auth.digest.Mac(this.ak, this.sk)</span><br><span class="line"> const options = {</span><br><span class="line"> scope: this.bucket,</span><br><span class="line"> expires: time || 7200</span><br><span class="line"> }</span><br><span class="line"> const putPolicy = new qiniu.rs.PutPolicy(options)</span><br><span class="line"> const uploadToken = putPolicy.uploadToken(mac)</span><br><span class="line"> return uploadToken</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">exports.QN = QN;</span><br><span class="line"></span><br><span class="line">exports.upToken = () => {</span><br><span class="line"> return new QN(config.qiniu.accessKey, config.qiniu.secretKey, config.qiniu.bucket, config.qiniu.origin).upToken() //每次调用都创建一个token</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><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">//获取七牛云token接口</span><br><span class="line">const {upToken} = require('../utils/qiniu')</span><br><span class="line"></span><br><span class="line">app.get('/api/uploadToken', (req, res, next) => {</span><br><span class="line"> const token = upToken()</span><br><span class="line"> res.send({</span><br><span class="line"> status: 1,</span><br><span class="line"> message: '上传凭证获取成功',</span><br><span class="line"> upToken: token,</span><br><span class="line"> })</span><br><span class="line"> })</span><br></pre></td></tr></table></figure><p>由于正常图片和音视频的上传和base64图片的上传,因为七牛云在对他们两者上传的<code>Content-Type</code>和<code>domain(域)</code>有所不同,所以的token请求存放的位置有所不同,因此要区分,客户端调用上传代码如下:</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">//根据获取到的上传凭证uploadToken上传文件到指定域</span><br><span class="line"> //正常图片和音视频的上传</span><br><span class="line"> uploadFile(formdata, domain='https://upload-z0.qiniup.com',config={headers:{'Content-Type':'multipart/form-data'}}){</span><br><span class="line"> console.log(domain)</span><br><span class="line"> console.log(formdata)</span><br><span class="line"> return instance.post(domain, formdata, config)</span><br><span class="line"> },</span><br><span class="line"> //base64图片的上传</span><br><span class="line"> //根据获取到的上传凭证uploadToken上传base64到指定域</span><br><span class="line"> uploadBase64File(base64, token, domain = 'https://upload-z0.qiniup.com/putb64/-1', config = {</span><br><span class="line"> headers: {</span><br><span class="line"> 'Content-Type': 'application/octet-stream',</span><br><span class="line"> },</span><br><span class="line"> }){</span><br><span class="line"> const pic = base64.split(',')[1];</span><br><span class="line"> config.headers['UpToken'] = `UpToken ${token}`</span><br><span class="line"> return instance.post(domain, pic, config)</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><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></pre></td><td class="code"><pre><span class="line">function upload(Vue, data, callbackSuccess, callbackFail) {</span><br><span class="line"> //获取上传token之后处理</span><br><span class="line"> Vue.prototype.axios.getUploadToken().then(res => {</span><br><span class="line"> if (typeof data === 'string'){ //如果是base64</span><br><span class="line"> const token = res.data.upToken</span><br><span class="line"> Vue.prototype.axios.uploadBase64File(data, token).then(res => {</span><br><span class="line"> if (res.status === 200){</span><br><span class="line"> callbackSuccess && callbackSuccess({</span><br><span class="line"> data: res.data,</span><br><span class="line"> result_url: `http://p89inamdb.bkt.clouddn.com/${res.data.key}`</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> }).catch((error) => {</span><br><span class="line"> callbackFail && callbackFail({</span><br><span class="line"> error</span><br><span class="line"> })</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> else if (data instanceof FormData){ //如果是FormData</span><br><span class="line"> data.append('token', res.data.upToken)</span><br><span class="line"> data.append('key', `moment${Date.now()}${Math.floor(Math.random() * 100)}`)</span><br><span class="line"> Vue.prototype.axios.uploadFile(data).then(res => {</span><br><span class="line"> if (res.status === 200){</span><br><span class="line"> callbackSuccess && callbackSuccess({</span><br><span class="line"> data: res.data,</span><br><span class="line"> result_url: `http://p89inamdb.bkt.clouddn.com/${res.data.key}`</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> }).catch((error) => {</span><br><span class="line"> callbackFail && callbackFail({</span><br><span class="line"> error</span><br><span class="line"> })</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> else {</span><br><span class="line"> const formdata = new FormData() //如果不是formData 就创建formData</span><br><span class="line"> formdata.append('token', res.data.upToken)</span><br><span class="line"> formdata.append('file', data.file || data)</span><br><span class="line"> formdata.append('key', `moment${Date.now()}${Math.floor(Math.random() * 100)}.${data.file.type.split('/')[1]}`)</span><br><span class="line"> // 获取到凭证之后再将文件上传到七牛云空间</span><br><span class="line"> console.log('formdata',formdata)</span><br><span class="line"> Vue.prototype.axios.uploadFile(formdata).then(res => {</span><br><span class="line"> console.log('res',res)</span><br><span class="line"> if (res.status === 200){</span><br><span class="line"> callbackSuccess && callbackSuccess({</span><br><span class="line"> data: res.data,</span><br><span class="line"> result_url: `http://p89inamdb.bkt.clouddn.com/${res.data.key}` //返回的图片链接</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> }).catch((error) => {</span><br><span class="line"> console.log(error)</span><br><span class="line"> callbackFail && callbackFail({</span><br><span class="line"> error</span><br><span class="line"> })</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> })</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">export default upload</span><br></pre></td></tr></table></figure><h1 id="路由权限模块"><a href="#路由权限模块" class="headerlink" title="路由权限模块"></a>路由权限模块</h1><p>系统的后台管理面向的是合作作者和管理员,涉及到两种角色,故此要做权限管理。不同的权限对应着不同的路由,同时侧边栏的菜单也需根据不同的权限,异步生成,不同于以往的服务端直接返回路由表,由前端动态生成,接下来介绍下登录和权限验证的思路:</p><ol><li><p>登录:当用户填写完账号和密码后向服务端验证是否正确,验证通过之后,服务端会返回一个token,拿到token之后前端会根据token再去拉取一个getAdminInfo的接口来获取用户的详细信息(如用户权限,用户名等等信息)。</p></li><li><p>权限验证:通过token获取用户对应的role,动态根据用户的role算出其对应有权限的路由,通过vue-router的beforeEach进行全局前置守卫再通过router.addRoutes动态挂载这些路由。</p></li></ol><p>代码有点多,这边就直接放流程图哈~~</p><p><img src="https://user-gold-cdn.xitu.io/2018/8/19/16552aedaded68fa?w=700&h=628&f=png&s=64946" alt="权限路由流程图"></p><center>权限路由流程图</center><p>最近正好也在公司做中后台项目,公司的中后台项目的这边是由服务端生成路由表,前端进行直接渲染,毕竟公司的一整套业务比较成熟。但是我们会在想能不能由前端维护路由表,这样不用到时候项目迭代,前端每增加页面都要让服务端兄弟配一下路由和权限,当然前提可能是项目比较小的时候。</p><h1 id="账号模块"><a href="#账号模块" class="headerlink" title="账号模块"></a>账号模块</h1><p>账号模块是业务中最为基础的模块,承担着整个系统所有的账号相关的功能。系统实现了用户注册、用户登录、密码修改、找回密码功能。</p><p>系统的账号模块使用了邮件服务,针对普通用户的注册采用了邮件服务来发送验证码,以及密码的修改等操作都采用了邮件服务。在node.js中主要采用了Nodemailer,Nodemailer是一个简单易用的Node.js邮件发送组件,它的使用可以<a href="https://user-gold-cdn.xitu.io/2018/8/19/16552bfb4463e4dc" target="_blank" rel="noopener">摸我摸我摸我</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><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></pre></td><td class="code"><pre><span class="line">/*</span><br><span class="line">* email 邮件模块</span><br><span class="line">*/</span><br><span class="line"></span><br><span class="line">const nodemailer = require('nodemailer');</span><br><span class="line">const smtpTransport = require('nodemailer-smtp-transport');</span><br><span class="line">const config = require('../config')</span><br><span class="line"></span><br><span class="line">const transporter = nodemailer.createTransport(smtpTransport({</span><br><span class="line"> host: 'smtp.qq.com',</span><br><span class="line"> secure: true,</span><br><span class="line"> port: 465, // SMTP 端口</span><br><span class="line"> auth: {</span><br><span class="line"> user: config.email.account,</span><br><span class="line"> pass: config.email.password //这里密码不是qq密码,是你设置的smtp授权码</span><br><span class="line"> }</span><br><span class="line">}));</span><br><span class="line"></span><br><span class="line">let clientIsValid = false;</span><br><span class="line">const verifyClient = () => {</span><br><span class="line"> transporter.verify((error, success) => {</span><br><span class="line"> if (error) {</span><br><span class="line"> clientIsValid = false;</span><br><span class="line"> console.warn('邮件客户端初始化连接失败,将在一小时后重试');</span><br><span class="line"> setTimeout(verifyClient, 1000 * 60 * 60);</span><br><span class="line"> } else {</span><br><span class="line"> clientIsValid = true;</span><br><span class="line"> console.log('邮件客户端初始化连接成功,随时可发送邮件');</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line">};</span><br><span class="line">verifyClient();</span><br><span class="line"></span><br><span class="line">const sendMail = mailOptions => {</span><br><span class="line"> if (!clientIsValid) {</span><br><span class="line"> console.warn('由于未初始化成功,邮件客户端发送被拒绝');</span><br><span class="line"> return false;</span><br><span class="line"> }</span><br><span class="line"> mailOptions.from = '"ShineTomorrow" <admin@momentin.cn>'</span><br><span class="line"> transporter.sendMail(mailOptions, (error, info) => {</span><br><span class="line"> if (error) return console.warn('邮件发送失败', error);</span><br><span class="line"> console.log('邮件发送成功', info.messageId, info.response);</span><br><span class="line"> });</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line">exports.sendMail = sendMail;</span><br></pre></td></tr></table></figure><p>账号的注册先是填写email,填写好邮箱之后会通过Nodemailer发送一封含有有效期的验证码邮件,之后填写验证码、昵称和密码即可完成注册,并且为了安全考虑,对密码采用了安全哈希算法(Secure Hash Algorithm)进行加密。账号的登录以账号或者邮箱号加上密码进行登录,并且采用上文所说的JSON Web Token(JWT)身份认证机制,从而实现用户和用户登录状态数据的对应。</p><p><img src="https://user-gold-cdn.xitu.io/2018/8/19/16552c1407819375?w=426&h=756&f=png&s=98007" alt="邮件长这样"></p><center>我的邮件长这样👆(可自己写邮件模板)</center><h1 id="实时消息推送"><a href="#实时消息推送" class="headerlink" title="实时消息推送"></a>实时消息推送</h1><p>当用户被人关注、评论被他人回复和点赞等一些社交性的操作的时候,在数据存储完成后,服务端应需要及时向用户推送消息来提醒用户。消息推送模块采用了<code>Socket.io</code>来实现,socket.io封装了websocket,不支持websocket的情况还提供了降级AJAX轮询,功能完备,设计优雅,是开发实时双向通讯的不二手段。</p><p>通过 socket.io,用户每打开一个页面,这个页面都会和服务端建立一个连接。在服务端可以通过连接的socket的id属性来匹配到一个建立连接的页面。所以用户的ID和socket的id,是一对多的关系,即一个用户可能在登录后打开多个页面。而socket.io没有提供从服务端向某个用户单独发送消息的功能,更没有提供向某个用户打开的所有页面推送消息的功能。但是socket.io提供了room的概念,即群组。在建立websocket时,客户端可以选择加入某个room,如果这个room没有存在则自动新建一个,否则直接加入,服务端可以向某个room中的所有客户端推送消息。</p><p>根据这个特性,设计将用户的ID作为room的名字,当某个用户打开页面建立连接时,会选择加入以自己用户ID为名字的room。这样,在用户ID为名字的 room中,加入的都是用户自己打开的页面建立的连接。从而向某个用户推送消息,可以直接通过向以此用户的ID为名字的room发送消息,这样就会推送到用户打开的所有页面。</p><p>有了想法后我们就开始鲁吧~,在服务端中<code>socket.io</code>在客户端中使用<code>vue-socket.io</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></pre></td><td class="code"><pre><span class="line">/*</span><br><span class="line">* app.js中</span><br><span class="line">*/</span><br><span class="line">const server = require('http').createServer(app);</span><br><span class="line">const io = require('socket.io')(server);</span><br><span class="line">global.io = io; //全局设上io值, 因为在其他模块要用到</span><br><span class="line">io.on('connection', function (socket) {</span><br><span class="line"> // setTimeout(()=>{</span><br><span class="line"> // socket.emit('nodeEvent', { hello: 'world' });</span><br><span class="line"> // }, 5000)</span><br><span class="line"> socket.on('login_success', (data) => { //接受客户端触发的login_success事件</span><br><span class="line"> //使用user_id作为房间号</span><br><span class="line"> socket.join(data.user_id);</span><br><span class="line"> console.log('login_success',data);</span><br><span class="line"> });</span><br><span class="line">});</span><br><span class="line">io.on('disconnect', function (socket) {</span><br><span class="line"> socket.emit('user disconnected');</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">server.listen(config.port, () => {</span><br><span class="line"> console.log(`The server is running at http://localhost:${config.port}`);</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><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">/*</span><br><span class="line">* 某业务模块</span><br><span class="line">*/</span><br><span class="line">//例如某文章增加评论</span><br><span class="line">io.in(newMusicArticle.author.user_id._id).emit('receive_message', newMessage); //实时通知客户端receive_message事件</span><br><span class="line">sendMail({ //发送邮件</span><br><span class="line"> to: newMusicArticle.author.user_id.email,</span><br><span class="line"> subject: `Moment | 你有未读消息哦~`,</span><br><span class="line"> text: `啦啦啦,我是卖报的小行家~~ 🤔`,</span><br><span class="line"> html: emailTemplate.comment(sender, newMusicArticle, content, !!req.body.reply_to_id)</span><br><span class="line">})</span><br></pre></td></tr></table></figure><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><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"><script></span><br><span class="line"> export default {</span><br><span class="line"> name: 'App',</span><br><span class="line"> data () {</span><br><span class="line"> return {</span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> sockets:{</span><br><span class="line"> connect(){</span><br><span class="line"> },</span><br><span class="line"> receive_message(val){ //接受服务端触发的事件,进行客户端实时更新数据</span><br><span class="line"> if (val){</span><br><span class="line"> console.log('服务端实时通信', val)</span><br><span class="line"> this.$notify(val.content)</span><br><span class="line"> console.log('this method was fired by the socket server. eg: io.emit("customEmit", data)')</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> mixins: [mixin],</span><br><span class="line"> mounted(){</span><br><span class="line"> if (!!JSON.parse(window.localStorage.getItem('user_info'))){</span><br><span class="line"> this.$socket.emit('login_success', { //通知服务端login_success 事件, 传入id</span><br><span class="line"> user_id: JSON.parse(window.localStorage.getItem('user_info'))._id</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"></script></span><br></pre></td></tr></table></figure></p><h1 id="评论模块"><a href="#评论模块" class="headerlink" title="评论模块"></a>评论模块</h1><p>评论模块是为了移动端WebApp下的文章下为用户提供关于评论的一些操作。系统实现了对文章的评论,评论的点赞功能,热门评论置顶以及评论的回复功能。在评论方面存在着各种各样的安全性问题,比如XSS攻击(Cross Site Scripting,跨站脚本攻击)以及敏感词等问题。预防XSS攻击使用了<code>xss</code>模块, 敏感词过滤使用<code>text-censor</code>模块。</p><h1 id="一些思考"><a href="#一些思考" class="headerlink" title="一些思考"></a>一些思考</h1><ol><li>接口数据问题</li></ol><p>在开发的时候经常会遇到这个问题,接口数据问题。有时候服务端返回的数据并不是我们想要的数据,前端要对数据进行再一步的处理。</p><p>例如服务端返回的某个字段为null或者服务端返回的数据结构太深,前端需要不断去判断数据结构是否真的返回了正确的东西,而不是个null 或者undefined~</p><p><img src="https://user-gold-cdn.xitu.io/2018/8/26/165750eb5f3cf2bf?w=763&h=370&f=png&s=108610" alt=""></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><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><div class="author"></span><br><span class="line"> 文 / {{(musicArticleInfo.author && musicArticleInfo.author.user_id) ? musicArticleInfo.author.user_id.username : '我叫这个名字'}}</span><br><span class="line"></div></span><br></pre></td></tr></table></figure></p><p>这就引出了一个思考:</p><p>对数据的进一步封装处理,必然渲染性能方面会存在问题,而且我们要时刻担心数据返回的问题。如果应用到公司的业务,我们应该如何处理呢 ?</p><ol><li>页面性能优化和SEO问题</li></ol><p>首屏渲染问题一直是单页应用的痛点,那么除了常用的性能优化,我们还有什么方法优化的吗 ? 这个项目虽然面向的是移动端用户,可能不存在SEO问题,如果做成pc端的话,像文章这类的应用,SEO都是必须品。<br><br><br><br><br><br><br>对于上面提出的问题,node的出现让我们看到了解决方案,那就常说的<strong>Node中间层</strong>,当然本项目中是不存在Node中间层,而是直接作为后端语言处理数据库。</p><p>由于大部分的公司后端要么是php要么是java,一般不把node直接作为后端语言,如果有使用到node,一般是作为一个中间层的形式存在。</p><p>对于第一个问题的解决:我们可以在中间层做接口转发,在转发的过程中做数据处理。而不用担心数据返回的问题。</p><p>对于第二个问题的解决:有了Node中间层的话,那么我们可以把首屏渲染的任务交给nodejs去做,次屏的渲染依然走之前的浏览器渲染。<br><br><br><br><br><br><br>有Node中间层的话,新的架构如下:</p><p><img src="https://user-gold-cdn.xitu.io/2018/8/26/1657571ab2ef3d3d?w=872&h=375&f=png&s=15216" alt="新架构"></p><p>前后端的职能:</p><p><img src="https://user-gold-cdn.xitu.io/2018/8/26/165757633f790cfb?w=859&h=469&f=png&s=23919" alt=""></p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>已经毕业一段时间了,写文章是为了回顾。本人水平一般,见谅见谅。这个产品的实现,一个人扛,在其中充当了各种角色,要有一点点产品思维,要有一点点设计的想法,要会数据库设计,要会后端开发,挺繁琐的。最难的点个人感觉还是数据库设计,数据库要一开始就要设计的很完整,不然到后面的添添补补,就会很乱很乱,当然这个基础是产品要非常清晰,刚开始自己心中对产品可能是个模糊的定义,想想差不多是那样,于是乎就开始搞<del>导致于后面数据库设计的不是很满意。由于时间关系,现在的产品中有些小模块还没完成,但是大部分的功能结构已经完成,算是个成型的产品,当然是一个没有经过测试的产品哈哈哈哈,要是有测试的话,那就哈哈哈哈你懂得 ~</del>。</p><p>前路漫漫,吾将上下而求索~</p><p><br></p><p><strong>完</strong></p><p><strong>谢谢~~</strong></p>]]></content>
<categories>
<category> 渣技术 </category>
</categories>
<tags>
<tag> Mongoose </tag>
<tag> Express </tag>
<tag> 毕业设计 </tag>
<tag> Vue </tag>
<tag> MongoDB </tag>
<tag> Node.js </tag>
<tag> Sockit.io </tag>
</tags>
</entry>
<entry>
<title>聊聊毕业设计系列 --- 项目介绍</title>
<link href="/%E8%81%8A%E8%81%8A%E6%AF%95%E4%B8%9A%E8%AE%BE%E8%AE%A1%E7%B3%BB%E5%88%971.html"/>
<content type="html"><![CDATA[<h1 id="效果展示"><a href="#效果展示" class="headerlink" title="效果展示"></a>效果展示</h1><p><img src="https://user-gold-cdn.xitu.io/2018/8/26/16576a709bd02f5f?w=1409&h=521&f=gif&s=30128195" alt="管理系统"></p><p><img src="https://user-gold-cdn.xitu.io/2018/8/26/16576a8711c14cbc?w=341&h=569&f=gif&s=48073144" alt="WebApp"></p><h1 id="github"><a href="#github" class="headerlink" title="github"></a>github</h1><p><a href="https://github.com/ishareme/moment-server" target="_blank" rel="noopener">moment-server github地址</a></p><p><a href="https://github.com/ishareme/moment" target="_blank" rel="noopener">moment github地址</a></p><p><a href="https://github.com/ishareme/moment-manage" target="_blank" rel="noopener">moment-manage github地址</a></p><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><blockquote><p>本论文对在移动互联网的大环境下,人们对阅读的需求和存在的问题以及发展趋势进行了深入分析研究之后,主要目的是设计一套简约优雅风格的UI,即UserInterface(用户界面),采用<code>Express</code>为Node.js的web开发框架,<code>Mongoose</code>模块来管理非关系型数据库MongoDB,在前端工程中主要运用了渐进式JavaScript框架<code>Vue.js</code>,使用<code>Vue-router</code>做前端页面路由的跳转,使用<code>Axios</code>作为HTTP请求库,同时使用<code>Vuex</code>负责前端全局状态管理,使用<code>ElementUI</code>作为界面基础组件库,使用<code>Webpack</code>进行模块化打包,并结合HTML5相关技术最终实现一个包含<strong>图文类、阅读类、影视类、音乐类和电台类五大版块的文艺类阅读系统</strong>,取名为<code>Moment</code>,意为片刻,旨在为人们提供一个平台,让人们在碎片化的时间里进行有效阅读。将实现系统中的两大主要部分:<strong>面向管理员和合作作者的后台管理系统</strong> 和 <strong>面向用户的移动端WebApp</strong>。 <br> <br>                                           — 摘自本人论文</p></blockquote><p>好了好了,以上纯属装x,三流的学校三流的毕业设计,看官随意就好。引言中做了毕业设计项目的介绍,实现一个包含图文类、阅读类、影视类、音乐类和电台类五大版块的<strong>文艺类阅读系统</strong>,取名为<code>Moment</code>。主要运用到的技术栈有:</p><ul><li>Node.js — Express</li><li>MongoDB — Mongoose</li><li>Vue</li><li>Vue-router</li><li>Axios</li><li>Vuex</li><li>ElementUI</li><li>Socket.io</li><li>…</li></ul><p>在项目开始之前还很激动乘还是学生的时候在腾讯云上买了云服务器,注册了第二个域名<code>momentin.cn</code>,到后面部署上去发现接口请求太慢了,于是乎还是放弃了,其实最重要的还是bug多多哈哈哈,性能优化还没做好。不过后面会继续部署上线。</p><h1 id="系统业务分析"><a href="#系统业务分析" class="headerlink" title="系统业务分析"></a>系统业务分析</h1><p>作为一个文艺类阅读系统,最主要的目的就是为用户提供优质的阅读体验和丰富的阅读内容。从而,以此作为目标,本系统业务中对阅读文章的分类又分为图文类、阅读类、影视类、音乐类和电台类这五个版块,于目于耳对文章的形式进行多样化。又将整个文艺类阅读系统的业务划分为两大部分,分别是面向管理员和合作作者的后台管理系统和面向用户的移动端WebApp,系统的需求分析将围绕这两部分进行展开。</p><h2 id="面向用户的移动端WebApp"><a href="#面向用户的移动端WebApp" class="headerlink" title="面向用户的移动端WebApp"></a>面向用户的移动端WebApp</h2><p>面向用户的移动端WebApp最重要的业务是提供文章的阅读,这个业务是面向所有可使用系统的用户。当然考虑到用户不仅仅满足于阅读,也需要以文章作为媒介进行用户之间的社交性活动,因此系统增加了图文广场模块,类似于一个圈子,所有用户都可以发布图文及查看,再比如关注,互相评论等各种互动。社交性的操作后往往需要给用户一些提醒,不然将失去意义,而且必须保证这个提醒是实时的,所以需要对用户进行实时的消息推送。当然用户难免对文章本身进行操作,比如评论、点赞、收藏等操作。所有用户都可以对文章进行阅读,但是一旦涉及到社交性操作的话就要以用户有登录注册的前提。</p><h2 id="面向管理员和合作作者的后台管理系统"><a href="#面向管理员和合作作者的后台管理系统" class="headerlink" title="面向管理员和合作作者的后台管理系统"></a>面向管理员和合作作者的后台管理系统</h2><p>这个系统的管理,系统主要分为两种角色进行管理。系统管理员角色可以看到移动端WebApp整体数据情况,可以对用户进行管理包括合作作者和所有普通用户,以及可以对图文、阅读、影视、音乐、电台所有文章进行管理,并且可以对系统的其他模块进行管理,例如广告模块、轮播图模块、公告模块等。而作者角色的权限就相对比较少,仅包含对文章的管理。</p><p>注: 由于时间关系 WebApp整体数据情况这块,它的数据库字段是有,但是当时匆匆忙忙没时间写接口,目前以静态展示。系统管理这一块也未处理完毕。</p><h1 id="系统设计"><a href="#系统设计" class="headerlink" title="系统设计"></a>系统设计</h1><h2 id="系统架构设计"><a href="#系统架构设计" class="headerlink" title="系统架构设计"></a>系统架构设计</h2><p><img src="https://user-gold-cdn.xitu.io/2018/8/9/1651f1aeaf2894a8?w=613&h=594&f=png&s=43570" alt="系统架构"></p><p>系统架构??这么装逼的词哈哈哈哈,其实也就传统的B/S架构,前后端分离。前端通过发起ajax接口请求,web服务器对请求进行处理并操作数据库服务器,返回json格式数据到前端,前端拿到数据后,处理数据并进行渲染。</p><h2 id="功能模块设计"><a href="#功能模块设计" class="headerlink" title="功能模块设计"></a>功能模块设计</h2><p><img src="https://user-gold-cdn.xitu.io/2018/8/9/1651f235d31bd879?w=947&h=659&f=png&s=96879" alt="功能模块"></p><p>这是当初项目开始前的一个粗略功能模块设计,其中一小部分模块由于当初时间关系还未做全,不过大部分功能模块已经实现。</p><h2 id="数据库设计"><a href="#数据库设计" class="headerlink" title="数据库设计"></a>数据库设计</h2><p>系统数据库的存储主要包含了:文章数据存储,用户数据存储,管理员和合作作者数据存储,文章评论存储,用户间关系存储。其中的文章数据存储又分为图文文章数据存储、阅读文章数据存储、影视文章数据存储、音乐文章数据存储、电台文章数据存储。其中的文章评论数据存储又分为阅读评论数据存储、影视评论数据存储、音乐评论数据存储、电台评论数据存储。</p><p><img src="https://user-gold-cdn.xitu.io/2018/8/18/1654d73d702c2790?w=843&h=816&f=png&s=55313" alt="数据库设计"></p><h1 id="接下来"><a href="#接下来" class="headerlink" title="接下来"></a>接下来</h1><p>现在咱们也对项目做了个介绍,并且对系统分析和系统设计做了大概的介绍。那么接下来的文章会对系统的实现做介绍,会介绍到项目中主要的一些功能模块,或者说可拿出来与大家分享的模块,以及介绍这个项目之后自己的一点点思考。</p><p>本人水平一般,介绍的可能也是一些基础,见谅见谅~~</p>]]></content>
<categories>
<category> 渣技术 </category>
</categories>
<tags>
<tag> Mongoose </tag>
<tag> Express </tag>
<tag> 毕业设计 </tag>
<tag> Vue </tag>
<tag> MongoDB </tag>
<tag> Node.js </tag>
<tag> Sockit.io </tag>
</tags>
</entry>
<entry>
<title>HTTP缓存策略与增量更新总结</title>
<link href="/HTTP%E7%BC%93%E5%AD%98%E7%AD%96%E7%95%A5%E4%B8%8E%E5%A2%9E%E9%87%8F%E6%9B%B4%E6%96%B0.html"/>
<content type="html"><![CDATA[<p>合理的利用缓存是web性能优化的必要手段,对于咱们前端来说所接触的主要缓存策略是针对客户端浏览器,客户端的缓存可以分为两种:</p><p><strong>1.</strong> 利用本地存储, 比如localStorage、SessionStorage等</p><p><strong>2.</strong> 利用HTTP缓存策略,其中又分为强制缓存和协商缓存</p><p>现在就来总结下HTTP缓存策略。HTTP缓存需要服务器配合,比如Apache、Ngnix等服务器软件可以为资源设置不同的HTTP缓存策略。增量更新是目前普遍采用的缓存更新方案,结合HTTP强制缓存策略,能够保证用户第一时间获取最新资源,又可以减少网络资源消耗,提高web应用程序的执行速度。</p><h4 id="HTTP缓存策略"><a href="#HTTP缓存策略" class="headerlink" title="HTTP缓存策略"></a>HTTP缓存策略</h4><p>浏览器对静态资源的缓存其实本质上是HTTP协议的缓存策略,其中又可分为强制缓存策略和协商缓存策略。</p><p><strong>强制缓存策略:</strong> 根据过期时间决定使用本地缓存还是请求新资源。</p><p><strong>协商缓存策略:</strong> 每次都会发出请求,经过服务器对比后决定采用本地缓存还是新资源。</p><p>具体采用哪种策略是由HTTP协议的<strong>头部</strong>信息决定</p><h5 id="1-Expires-和-max-age"><a href="#1-Expires-和-max-age" class="headerlink" title="1. Expires 和 max-age"></a>1. Expires 和 max-age</h5><p>Expires和max-age是强制缓存策略的关键信息。</p><p><strong>Expires</strong> 通过指定一个明确的时间点作为缓存资源的过期时间,在这个时间点之前将使用本地缓存的文件应答请求,不会向服务器发起实体请求(返回状态码200)<br>Expires的有点是可以在缓存的过期时间内减少客户端的HTTP请求,不仅节省了客户端处理时间和提高了web应用的执行速度,而且也减少了服务器负载和客户端网络资源的消耗。<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">expires:Fri, 09 Mar 2018 14:14:54 GMT</span><br></pre></td></tr></table></figure></p><p>不过!!!Expires有一个致命的缺陷: 它所指的时间点是以服务器为准的时间,但是客户端进行过期判断的时候是将本地的时间与此时间点进行判断的。举个🌰: 如果服务器的时间是 2018年3月10日 14:14:54, 而客户端的时间是 2018年3月10日 22:14:54 , 那么这时通过Expires控制的缓存将会失效,客户端会发起实体请求获取对应资源。(客户端动态设置时间或服务端的时间存在时间差)这显然是不合理的。</p><p>于是乎!!!在Expires之后又来了一个玩意,<strong>Cache-control</strong>。以便更精准的控制缓存。Cache-control的采用信息如下:</p><ul><li><strong>no-cache 和 no-store</strong>:no-cache并非禁止缓存,而是需要先与服务端确认返回的响应是否发生变化,如果资源没有发生变化,就可以使用缓存副本而避免下载。no-store是真正意义上的禁止缓存,禁止缓存资源的返回响应。</li><li><strong>public 和 private</strong>: public不太常用,意思是响应可以被浏览器缓存器无限期的缓存,通常是使用max-age指定精准的缓存时间。 private表示响应可以被浏览器缓存,但是不予许任何中间缓存器对其缓存。(不太明白😢~~)</li><li><strong>max-age</strong>: 指定从请求的时刻开始计算,此响应的缓存副本有效的最长时间(秒)。再举个🌰: “max-age=3600”表示浏览器在接下来的1个小时内使用此响应的本地缓存,不会发送实体请求到服务器。</li></ul><p><strong>max-age指定的是缓存的时间跨度,而非失效的时间点,不会受到服务器时间误差的影响。</strong> 所以,与Expires相比起来,max-age可以更精准的控制缓存,并且<strong>比Expires的优先级高</strong></p><p><img src="http://oubl6fzsm.bkt.clouddn.com/http-cache.png" alt="fistPost"></p><h5 id="2-Etag-和-if-none-match"><a href="#2-Etag-和-if-none-match" class="headerlink" title="2. Etag 和 if-none-match"></a>2. Etag 和 if-none-match</h5><p>Etag 是服务器为资源分配的字符串形式唯一性标识。 浏览器在<strong>cache-control指定的no-cache或者max-age和Expires均过期之后,将Etag值通过if-none-match作为请求首部信息发送给服务器</strong>,服务器接受到请求之后,对比请求资源的Etag是否发生变化,如果未改变将返回 304 Not Modified,并且根据既定的缓存策略分配新的cache-control信息,如果资源发生改变,则会返回最新的资源以及重新分配的Etag值。</p><p><strong>如果强制浏览器使用协商缓存策略,需要将cache-control首部信息设置为no-cache,这样便不会判断max-age和expires过期的时间,从而每次请求资源都会经过服务器对比。</strong></p><p>协商缓存并非是一种比强制缓存“低级”的策略,对于一些比较特殊的应用场景或资源,协商缓存优于强制缓存。再举个🌰, 非服务端渲染的html文档,由于它是所有静态资源的引用者,所以必须保证每次请求到的资源都是最新的。同时,为了保证服务器解析和保证网站的唯一性,html文件不能包含hash指纹,在这种场景只能使用协商缓存。(使用强制缓存的话,文件的修改,由于客户端存在缓存,导致于客户端浏览的是原先的代码,不是最新修改的)</p><h4 id="覆盖更新和增量更新"><a href="#覆盖更新和增量更新" class="headerlink" title="覆盖更新和增量更新"></a>覆盖更新和增量更新</h4><p>简单总结下覆盖更新和增量更新吧,覆盖更新和增量更新都是建立在浏览器启用强制缓存策略的前提下。</p><p><strong>覆盖更新:</strong> 覆盖更新的实现方案是在引用资源的URL后面添加请求参数(比如添加请求时间搓或hash值参数),优于存在缺陷,逐渐被淘汰。</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">//通过添加hash指纹(md5算法)</span><br><span class="line"><head></span><br><span class="line"> <link rel="stylesheet" href="main.home.css?v=858d5483"></span><br><span class="line"></head></span><br></pre></td></tr></table></figure><p>覆盖更新存在的缺陷: </p><ol><li>必须保证html文件与改动的静态文件同步更新。 对于服务端渲染的项目,网站人口html和静态资源分开部署,静态资源的实现和动态资源的上线存在时间差。</li><li>不利于版本回滚</li></ol><p><strong>增量更新</strong>: 实现方案是将作为参数的hash值改为作为资源文件名的一部分并删除用于更新的url参数,解决了覆盖更新的两个缺陷。</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">//通过添加hash指纹(md5算法)</span><br><span class="line"><head></span><br><span class="line"> <link rel="stylesheet" href="main.home.858d5483.css"></span><br><span class="line"></head></span><br></pre></td></tr></table></figure><h4 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h4><p>enen~~ 对!!就这样吧,收获不少~~感恩</p>]]></content>
<categories>
<category> 渣技术 </category>
</categories>
<tags>
<tag> 缓存 </tag>
</tags>
</entry>
<entry>
<title>video标签移动端兼容性问题总结</title>
<link href="/video-compatible.html"/>
<content type="html"><![CDATA[<p>由于video标签在各个平台下存在的各种各样的兼容性问题,遇到了各种坑,目前总结了下篇,待更新~~</p><a id="more"></a><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"><video class="js-video"</span><br><span class="line"> loop</span><br><span class="line"> airplay="allow"</span><br><span class="line"> x5-playsinline /**/</span><br><span class="line"> playsinline /*IOS微信浏览器支持小播放*/ </span><br><span class="line"> webkit-playsinline /*这个属性是ios 10中设置可以让视频在小窗内播放,也就是不是全屏播放*/ </span><br><span class="line"> preload="auto" /*预加载*/</span><br><span class="line">></span><br><span class="line"></video></span><br></pre></td></tr></table></figure><h4 id="安卓微信下不能自动播放"><a href="#安卓微信下不能自动播放" class="headerlink" title="安卓微信下不能自动播放"></a>安卓微信下不能自动播放</h4><p>安卓微信下autoplay无效,不能自动播放,可以通过<strong>用户交互进行手动播放</strong>。<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></pre></td><td class="code"><pre><span class="line">//在安卓微信下</span><br><span class="line">$('body').one('touchstart', function () {</span><br><span class="line"> //ios微信下可以自动播放</span><br><span class="line"> if (is.iOS) {</span><br><span class="line"> return;</span><br><span class="line"> </span><br><span class="line"> $('.video-icon').hide()</span><br><span class="line"> $('.js-video')[0].play();</span><br><span class="line">});</span><br></pre></td></tr></table></figure></p><h4 id="safari下无法自动播放"><a href="#safari下无法自动播放" class="headerlink" title="safari下无法自动播放"></a>safari下无法自动播放</h4><p>在safari下,autoplay也无效,在iphone上做测试,发现autoplay属性在safari里无效,苹果对video标签的autoplay属性做了如下规定:</p><blockquote><p>In Safari on iOS (for all devices, including iPad), where the user may be on a cellular network and be charged per data unit, preload and autoplay are disabled.</p></blockquote><p>其实safari的并不是autoplay的问题,而是视频有声音导致于safari不能自动播放,<strong>给video的muted[是否静音]设置为true</strong>,视频便会自动播放,但是视频没有声音(降级处理)</p><p>safari下,设置muted为true<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></pre></td><td class="code"><pre><span class="line">//safari下</span><br><span class="line">if(is.safari){</span><br><span class="line"> $('.js-video')[0].play();</span><br><span class="line"> $('.js-video')[0].muted = true; </span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h4 id="video的poster的问题"><a href="#video的poster的问题" class="headerlink" title="video的poster的问题"></a>video的poster的问题</h4><ul><li>在安卓的有些机子下,给video增加了poster,但是还是没有效果,poster在android兼容的并不好,不如在视频上层加个div铺张图片</li><li>iPhoneX的video在有poster的情况下,播放视频poster不会自动去掉,要自己逻辑手动去掉poster(之前测到过)</li></ul><h4 id="黑屏问题"><a href="#黑屏问题" class="headerlink" title="黑屏问题"></a>黑屏问题</h4><p>部分环境中视频从开始播到能展现画面会有短暂的黑屏(处理视频源数据的时间),为了避免这个黑屏,可以在视频上加个浮层或设置容器背景并在播放前隐藏video,然后监听相关事件,开始播放或认为有画面的时候再切换到Video界面。</p><p>解决方案<br>微信下,通过用户交互进行播放,最好给他一个播放小icon</p><h4 id="微博下的视频问题"><a href="#微博下的视频问题" class="headerlink" title="微博下的视频问题"></a>微博下的视频问题</h4><p>对于小视频为了美观,一般都是把control属性拿掉,而在微博下视频默认是全屏播放的,点击返回视频在没有控制条control的情况下会不能再次播放,因此在weibo下要加上control</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><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">if(is.Weibo){</span><br><span class="line"> $('.js-video')[0].control = true; </span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p> </p>]]></content>
<categories>
<category> 渣技术 </category>
</categories>
<tags>
<tag> video </tag>
</tags>
</entry>
<entry>
<title></title>
<link href="/practice-summary-andy-move2.html"/>
<content type="html"><![CDATA[<hr><p>title: 实习&andyMove小结<br>date: 2018-03-06 17:01:01<br>comments: true</p><p>tags:</p><pre><code>- 美图- H5项目</code></pre><p>categories:</p><pre><code>- 渣技术</code></pre><p>–</p><p>这学期的实习也快结束了,想想还是挺感慨的。这次对andyMove的总结就当做对自己这学期实习的总结吧。</p><p>在美图也快满4个月了,总感觉自己进步的非常慢,有时候会在想是不是自己变得不上心了?变得不进取了?对!!你就是不进取了,松懈了!!不,这完全不是我!!!!当然在这四个月里或多或少还是比刚进美图的时候有所收获。从刚开始什么都不太懂的情况下开始的第一个H5,到现在相对比较清楚的开发(bug满天飞)。真的非常感谢有这个平台让我更加清楚的看清自己的不足,在这里真的非常感谢板栗兄一对一的辅导,自己的渣技术对他造成的不便深感自责。非常感谢晓东兄照顾~~</p><h2 id="反思"><a href="#反思" class="headerlink" title="反思"></a>反思</h2><ul><li><p>不管做什么事,<strong>细节</strong>真的很重要,在开发中,正如晓东说的多去注意一些细节的东西,这个项目就会更好,不要马虎的去对待它,比如动画微调的时候比较麻烦,一旦你马虎应付的话,细节处理不到位,动画不写反而会比较好!!说的就是你要细心!!多注意~~</p></li><li><p>在开发<strong>效率</strong>方面真的需要再提升提升,比如像一些比较麻烦的animation动画可以先不用处理,写animation有时候真的会挺花费时间的,导致于项目进展的比较慢,有可能会误期,所以可以先把项目做出来,把项目先跑通,逻辑处理好了再去处理animation等等。</p></li><li><p><strong>代码方面</strong>正如晓东说的目前自己写的 <strong>代码</strong>可能还是比较面条化,没有很好的去优化,重复性太强,没有模块化</p></li><li><p><strong>js css 没有模块化</strong>,要有<strong>模块化</strong>的思想,减少代码耦合,这一点非常非常重要!!!谨记!!!写到重复的代码的时候一点要想着怎么去优化!!!拿到PSD的时候<strong>不要马上就开始切</strong>,应该要想好好的想想如何去模块化,如何去布局,把逻辑理清楚,不然你会做很多无用功!!!</p></li><li><p><strong>bug修改方面</strong>提交测试版完之后测试便会开始测试逐步提交bug出来,要时常去<strong>关注jira</strong>上自己的bug,及时修复!!及时!!修复完毕一定要关闭bug给出合理的bug修复解释。bug修复时自己要先测一遍在提交给测试,可能有时候bug并未解决,导致于测试那边做无用功。[你还要不要脸害人家白忙活。。。]</p></li><li><p><strong>不要害怕麻烦</strong>在做lancome的时候需求的变动,让我觉得有些麻烦,故而就想到把需求砍掉,事后想想那时候的自己真的很垃圾,有什么问题就去解决,而不是想着如何不去解决!!</p></li><li><p><strong>依赖</strong>方面,能不麻烦别人的就不麻烦别人,坐在板栗旁边,有时候就产生了过度依赖的问题,一遇到bug自己不能解决的情况,就去问,[怪对不起板栗兄,真的超谢谢],自己并没有好好想想自己如何解决,产生过度依赖。凡事一定要自己解决,自己解决!!!!</p></li><li><p>在<strong>沟通方面</strong>,态度谦和多沟通,不要把自己的情绪影响到别人,特别是产品运营设计测试这些大佬<del>~[[受小奴一跪</del>]</p></li></ul><h2 id="BUG"><a href="#BUG" class="headerlink" title="BUG"></a>BUG</h2><p>下面是一些这次开发过程中出现的一些问题:</p><h4 id="QQ平台,结果页不能滑动"><a href="#QQ平台,结果页不能滑动" class="headerlink" title="QQ平台,结果页不能滑动"></a>QQ平台,结果页不能滑动</h4><p>由于iOS下z-index的层级影响,导致于有些平台在ios下会很难出现滑动的情况(不顺畅),以及transition和animation同时使用ios端可能会出现问题</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><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line">css:</span><br><span class="line"></span><br><span class="line">目前</span><br><span class="line">page{</span><br><span class="line"> position: absolute;</span><br><span class="line"> top: 0;</span><br><span class="line"> left: 0;</span><br><span class="line"> width: 100%;</span><br><span class="line"> height: 100%;</span><br><span class="line"> overflow: hidden;</span><br><span class="line"> //transition: transform .5s;</span><br><span class="line"> //opacity: 0;</span><br><span class="line"> overflow-x: hidden;</span><br><span class="line"> overflow-y: auto;</span><br><span class="line"> &.transition{</span><br><span class="line"> transition: all .3s;</span><br><span class="line"> }</span><br><span class="line"> &.show{</span><br><span class="line"> transform: translateX(0);</span><br><span class="line"> }</span><br><span class="line"> &.hide-after{</span><br><span class="line"> transform: translateX(100%);</span><br><span class="line"> }</span><br><span class="line"> &.hide-before{</span><br><span class="line"> transform: translateX(-100%);</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">page{</span><br><span class="line"> position: absolute;</span><br><span class="line"> top: 0;</span><br><span class="line"> left: 0;</span><br><span class="line"> width: 100%;</span><br><span class="line"> height: 100%;</span><br><span class="line"> overflow: hidden;</span><br><span class="line"> transition: transform .5s;</span><br><span class="line"> opacity: 0;</span><br><span class="line"> overflow-x: hidden;</span><br><span class="line"> overflow-y: auto;</span><br><span class="line"> &.in {</span><br><span class="line"> opacity: 1;</span><br><span class="line"> z-index: 2;</span><br><span class="line"> //animation: in 0.5s ease both;</span><br><span class="line"> //</span><br><span class="line"> //@keyframes in {</span><br><span class="line"> // 0% { opacity: 0; }</span><br><span class="line"> // 100% { opacity: 1; }</span><br><span class="line"> //}</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> &.out {</span><br><span class="line"> opacity: 0.5;</span><br><span class="line"> z-index: 1;</span><br><span class="line"> //transform: translateX(-100%);</span><br><span class="line"> //transition: all .5s;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h4 id="上传完图片要进行预加载"><a href="#上传完图片要进行预加载" class="headerlink" title="上传完图片要进行预加载"></a>上传完图片要进行预加载</h4><p>在上传完图片生成url的时候一般都需要在接下来的页面中用到,故要对其进行预加载。在做帧动画更换图片的时候要注意,也是要预加载</p><h4 id="ios秀秀端结果页转发qq和qq空间转发不了"><a href="#ios秀秀端结果页转发qq和qq空间转发不了" class="headerlink" title="ios秀秀端结果页转发qq和qq空间转发不了"></a>ios秀秀端结果页转发qq和qq空间转发不了</h4><p>这个要注意,在做拼接url的时候要对带有中文或者其他字符做encodeURIComponent处理,再到要用的地方(分享页)进行decodeURIComponent获取,上次在群里面看到share的imageURL为空或者这个图片太大的话在端内分享qq也会调不起来</p><h4 id="图片repeat重复问题"><a href="#图片repeat重复问题" class="headerlink" title="图片repeat重复问题"></a>图片repeat重复问题</h4><p>js动态加上图片的时候要记得加上background-repeat:no-repeat,不要只加background-image</p><h4 id="share页也要做分享,auth权限模块是异步执行的"><a href="#share页也要做分享,auth权限模块是异步执行的" class="headerlink" title="share页也要做分享,auth权限模块是异步执行的"></a>share页也要做分享,auth权限模块是异步执行的</h4><p>在share页的时候一般也要加上分享,auth权限模块是异步执行的~~</p><h4 id="微博下的视频问题"><a href="#微博下的视频问题" class="headerlink" title="微博下的视频问题"></a>微博下的视频问题</h4><p>微博下视频默认是全屏播放的,点击返回视频在没有控制条control的情况下会不能再次播放,因此在weibo下要加上control</p><h4 id="gif在Android下会出现显示一段时间之后不显示,但是可以保存和转发-后端算法已解决,无需降级"><a href="#gif在Android下会出现显示一段时间之后不显示,但是可以保存和转发-后端算法已解决,无需降级" class="headerlink" title="gif在Android下会出现显示一段时间之后不显示,但是可以保存和转发(后端算法已解决,无需降级)"></a>gif在Android下会出现显示一段时间之后不显示,但是可以保存和转发(后端算法已解决,无需降级)</h4><p>此次采用降级的方案,直接放图片,子元素gif的opacity为0</p><h4 id="video-在微信下会显示内置的播放器"><a href="#video-在微信下会显示内置的播放器" class="headerlink" title="video 在微信下会显示内置的播放器"></a>video 在微信下会显示内置的播放器</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"><video class="js-video"</span><br><span class="line"> loop</span><br><span class="line"> airplay="allow"</span><br><span class="line"> x5-playsinline</span><br><span class="line"> playsinline</span><br><span class="line"> webkit-playsinline</span><br><span class="line"> preload="auto"</span><br><span class="line">></span><br><span class="line"></video></span><br></pre></td></tr></table></figure><h4 id="iPhoneX在video问题"><a href="#iPhoneX在video问题" class="headerlink" title="iPhoneX在video问题"></a>iPhoneX在video问题</h4><p>iPhoneX的video在有poster的情况下,播放视频poster不会自动去掉,要自己逻辑手动去掉poster</p><h4 id="尽量不要去用touchstart"><a href="#尽量不要去用touchstart" class="headerlink" title="尽量不要去用touchstart"></a>尽量不要去用touchstart</h4><p>touchstart时间间隔太小,有可能不会生效,一般使用tap,click,touchend,而touchstart主要用于事件状态方面</p><h4 id="在开发要尽可能模块化"><a href="#在开发要尽可能模块化" class="headerlink" title="在开发要尽可能模块化"></a>在开发要尽可能模块化</h4><p>对于css也是,类似的css可以抽出模块,js更是,逻辑尽可能写成模块</p><h4 id="开发过程中多去注意一些性能优化"><a href="#开发过程中多去注意一些性能优化" class="headerlink" title="开发过程中多去注意一些性能优化"></a>开发过程中多去注意一些性能优化</h4><h4 id="代码要尽可能简洁,能优化的逻辑尽可能优化,以后要全使用ES6!!ES6!!!!"><a href="#代码要尽可能简洁,能优化的逻辑尽可能优化,以后要全使用ES6!!ES6!!!!" class="headerlink" title="代码要尽可能简洁,能优化的逻辑尽可能优化,以后要全使用ES6!!ES6!!!!"></a>代码要尽可能简洁,能优化的逻辑尽可能优化,以后要全使用ES6!!ES6!!!!</h4><h4 id="在移动端的话最好不要去用flexbox"><a href="#在移动端的话最好不要去用flexbox" class="headerlink" title="在移动端的话最好不要去用flexbox"></a>在移动端的话最好不要去用flexbox</h4><p>flexbox的兼容性性目前还是不够好,尽量去克服这个习惯</p><h4 id="视频播放延迟问题-后端算法已解决"><a href="#视频播放延迟问题-后端算法已解决" class="headerlink" title="视频播放延迟问题(后端算法已解决)"></a>视频播放延迟问题(后端算法已解决)</h4><h4 id="ios低端机下gif保存为静态-ios早些版本的问题,目前无解"><a href="#ios低端机下gif保存为静态-ios早些版本的问题,目前无解" class="headerlink" title="ios低端机下gif保存为静态(ios早些版本的问题,目前无解)"></a>ios低端机下gif保存为静态(ios早些版本的问题,目前无解)</h4><h4 id="开始开发之前就应该通知运营把文案给好"><a href="#开始开发之前就应该通知运营把文案给好" class="headerlink" title="开始开发之前就应该通知运营把文案给好"></a>开始开发之前就应该通知运营把文案给好</h4><p>不然在开发期间会去很频繁的跟换文案,挺费时的</p><h4 id="埋点统计也应该给好"><a href="#埋点统计也应该给好" class="headerlink" title="埋点统计也应该给好"></a>埋点统计也应该给好</h4><p>不要到了要上线的时候才给到哪里哪里需要埋点</p><h4 id="还有一个小请求就是希望在开前端需求会的时候,希望晓东板栗能过带上我们参加参加会议,让我们也体验体验一下会议平常是怎么进行讨论的,怎么讨论需求的,以及一些细节的东西"><a href="#还有一个小请求就是希望在开前端需求会的时候,希望晓东板栗能过带上我们参加参加会议,让我们也体验体验一下会议平常是怎么进行讨论的,怎么讨论需求的,以及一些细节的东西" class="headerlink" title="还有一个小请求就是希望在开前端需求会的时候,希望晓东板栗能过带上我们参加参加会议,让我们也体验体验一下会议平常是怎么进行讨论的,怎么讨论需求的,以及一些细节的东西"></a>还有一个小请求就是希望在开前端需求会的时候,希望晓东板栗能过带上我们参加参加会议,让我们也体验体验一下会议平常是怎么进行讨论的,怎么讨论需求的,以及一些细节的东西</h4><p>就像这次的andy-move进行云美化接口的时候可能也是自己比较笨刚开始没理解清楚板栗的要求,导致这个方面接口老是不匹配问题</p><h1 id="之后-不对!现在"><a href="#之后-不对!现在" class="headerlink" title="之后(不对!现在~~)"></a>之后(不对!现在~~)</h1><h3 id="1、调整好状态,充满激情才是我!!"><a href="#1、调整好状态,充满激情才是我!!" class="headerlink" title="1、调整好状态,充满激情才是我!!"></a>1、调整好状态,充满激情才是我!!</h3><h3 id="2、-专心于学习"><a href="#2、-专心于学习" class="headerlink" title="2、 专心于学习"></a>2、 专心于学习</h3><p>买了书买了椅子买了显示器,对!!就是要读书!!哈哈哈<br>这是在春节放假前自己给过年回来的自己定下的学习</p><h4 id="2018-如何把自我学习和工作时间分配弄好?-粗略"><a href="#2018-如何把自我学习和工作时间分配弄好?-粗略" class="headerlink" title="2018 如何把自我学习和工作时间分配弄好? (粗略)"></a>2018 如何把自我学习和工作时间分配弄好? (粗略)</h4><ul><li>周一-周五: 上班 — 6点半下班,利用好上班的时间处理好,吃完饭回去</li><li>没任务的时候如何处理? 1、主动请求加任务 2、像这个时候? 在公司看书又不好….写东 西?写插件?<br>增加表现机会,不会的先接,接完不会的再问<br>,不会的自己要先思考再问,不要一不懂就问</li><li><p>周六周日: 全看书和处理毕业设计, 晚上有时间再回学校</p></li><li><p>生活: 买个显示器、买个椅子、家里打扫干净、自己做饭</p></li></ul><h4 id="书-要看完"><a href="#书-要看完" class="headerlink" title="书 [要看完]"></a>书 [要看完]</h4><ul><li>ES6 [es6还是很薄弱]</li><li>深入浅出Webpack</li><li>Web高效编程与优化实践</li><li>体系设计与实践</li><li>Vue</li><li>Web前端高效开发</li><li>微信小程序</li></ul><h3 id="3、做好毕设、顺利毕业"><a href="#3、做好毕设、顺利毕业" class="headerlink" title="3、做好毕设、顺利毕业"></a>3、做好毕设、顺利毕业</h3><h3 id="4、好好吃饭,好好睡觉,好好生活"><a href="#4、好好吃饭,好好睡觉,好好生活" class="headerlink" title="4、好好吃饭,好好睡觉,好好生活"></a>4、好好吃饭,好好睡觉,好好生活</h3><h1 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h1><p><strong>注: 博客是放假前写的,那时候本来打算这学期请假的</strong></p><p>请假了,想想还是挺纠结的,想了好久,也是这段的实习让我看到了自己身上各个方面的不足,也借请假期间好好再充电充电,调整调整心态。2018想想应该会是一个充实的一年,想做的事情很多,希望自己能够把它过的充实,善待于它。</p><p>美图,6月份再见!希望来时是一个不一样的自己。</p><p><strong>更正如下:</strong></p><p>晓东说明天有个总结会,不知道拿这篇博客去会怎么样,写博客都是写心声,内心对自己过去否定以及对接下来充满期待的总结我想最能说明现在的我。应该可以吧,就这样吧~~</p><p>那个在新年前无数幻想着新的一年我该如何如何努力的少年希望你在新的一年勇往直前,不辜负那个幻想的少年。</p><blockquote><p>也许过去的一年,你曾被风浪拍打的颓废失意,但新的一年,愿你乘风破浪。 ——《乘风破浪》</p></blockquote><p>更新于 2018-03-01 00: 17<br>于自己的小窝</p>]]></content>
</entry>
<entry>
<title>canvas粒子背景</title>
<link href="/particle-canvas.html"/>
<content type="html"><![CDATA[<p>根据网上的思路用canvas实现之前知乎的粒子背景。 </p><blockquote><p><a href="https://github.com/ishareme/Particle/" target="_blank" rel="noopener">github 地址</a><br><a href="https://github.com/ishareme/ParticleCanvas/" target="_blank" rel="noopener">example</a></p></blockquote><a id="more"></a><h2 id="主要思路"><a href="#主要思路" class="headerlink" title="主要思路"></a>主要思路</h2><ul><li>需要一张 Canvas 画布</li><li>在画布上绘制许多个小点</li><li>小点会来回移动</li><li>小点移动到边框的时候需要回弹</li><li>每两个小点之间在一定距离之内,绘制线</li><li>当鼠标移入的时候,让内部的小点跟随鼠标的移动</li></ul><h4 id="需要一张-Canvas-画布"><a href="#需要一张-Canvas-画布" class="headerlink" title="需要一张 Canvas 画布"></a>需要一张 Canvas 画布</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">this</span>.ctx = <span class="keyword">this</span>.canvas.getContext(<span class="string">'2d'</span>);</span><br><span class="line"><span class="keyword">this</span>.canvas.width = <span class="built_in">window</span>.innerWidth || <span class="built_in">document</span>.documentElement.clientWidth || <span class="built_in">document</span>.body.clientWidth;</span><br><span class="line"><span class="keyword">this</span>.canvas.height = <span class="built_in">window</span>.innerHeight || <span class="built_in">document</span>.documentElement.clientHeight || <span class="built_in">document</span>.body.clientHeight;</span><br><span class="line"><span class="keyword">this</span>.drawBackground();</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><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">for(let i = 0; i < this.options.particleNum; i++){</span><br><span class="line"> let circleX = utils.randomNumber(this.canvas.width);</span><br><span class="line"> let circleY = utils.randomNumber(this.canvas.height);</span><br><span class="line"> let circleVX = utils.randomNumber(this.options.particleSpeed, this.options.particleSpeed * -1) / 20;</span><br><span class="line"> let circleVY = utils.randomNumber(this.options.particleSpeed, this.options.particleSpeed * -1) / 20;</span><br><span class="line"> let circleR = this.options.particleR;</span><br><span class="line"> let circleColor = utils.randomColor();</span><br><span class="line"> this.circleArr.push(new Circle(circleX, circleY, circleVX, circleVY, circleR, circleColor));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> //包括鼠标的位置</span><br><span class="line"> this.circleArrAll = [this.mousePoint].concat(this.circleArr);</span><br></pre></td></tr></table></figure><h4 id="小点会来回移动-amp-边界回弹"><a href="#小点会来回移动-amp-边界回弹" 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></pre></td><td class="code"><pre><span class="line">item.x += item.vx;</span><br><span class="line"> item.y += item.vy;</span><br><span class="line"> //圆点移动到边框的时候需要回弹</span><br><span class="line"> item.vx *= (item.x <= 0 || item.x >= (this.canvas.width - item.r)) ? -1 : 1;</span><br><span class="line"> item.vy *= (item.y <= 0 || item.y >= (this.canvas.height - item.r)) ? -1 : 1;</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><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></pre></td><td class="code"><pre><span class="line">this.circleArr.forEach((item) => {</span><br><span class="line"> this.ctx.fillStyle = item.color;</span><br><span class="line"> this.ctx.beginPath();</span><br><span class="line"></span><br><span class="line"> //圆点移动</span><br><span class="line"> this.circleMove(item);</span><br><span class="line"></span><br><span class="line"> this.ctx.arc(item.x, item.y, item.r, 0, 2 * Math.PI, true);</span><br><span class="line"> this.ctx.fill();</span><br><span class="line"></span><br><span class="line"> for (var i=0; i < this.circleArrAll.length; i++){</span><br><span class="line"> var currCircle = this.circleArrAll[i];</span><br><span class="line"> //如果是同项 或者 当 mousePoint 还未赋值就跳过</span><br><span class="line"> if (item === currCircle || currCircle.x === null || currCircle.y === null) continue;</span><br><span class="line"> //每两个圆点之间在一定距离(this.options.lineLength)之内,绘制线</span><br><span class="line"> if (utils.dis(item, currCircle) < this.options.lineLength){</span><br><span class="line"> //当鼠标移入的时候,让内部的圆点跟随鼠标的移动</span><br><span class="line"> //在 距离(utils.dis2(item, currCircle) > (this.options.lineLength * this.options.lineLength) /2)内 圆点跟随鼠标的移动</span><br><span class="line"> if (currCircle === this.mousePoint && utils.dis2(item, currCircle) > (this.options.lineLength * this.options.lineLength) /2){</span><br><span class="line"> //圆点跟随鼠标的移动</span><br><span class="line"> this.moveToMousePoint(item, currCircle);</span><br><span class="line"> }</span><br><span class="line"> //绘制线</span><br><span class="line"> this.drawLine(item, currCircle);</span><br><span class="line"> }</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><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">if (utils.dis(item, currCircle) < this.options.lineLength){</span><br><span class="line"> //当鼠标移入的时候,让内部的圆点跟随鼠标的移动</span><br><span class="line"> //在 距离(utils.dis2(item, currCircle) > (this.options.lineLength * this.options.lineLength) /2)内 圆点跟随鼠标的移动</span><br><span class="line"> if (currCircle === this.mousePoint && utils.dis2(item, currCircle) > (this.options.lineLength * this.options.lineLength) /2){</span><br><span class="line"> //圆点跟随鼠标的移动</span><br><span class="line"> this.moveToMousePoint(item, currCircle);</span><br><span class="line"> }</span><br><span class="line"> //绘制线</span><br><span class="line"> this.drawLine(item, currCircle);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line">moveToMousePoint(item, currCircle){</span><br><span class="line"> // 小圆点的向鼠标点移动</span><br><span class="line"> item.x -= (item.x - currCircle.x) * 0.03;</span><br><span class="line"> item.y -= (item.y - currCircle.y) * 0.03;</span><br><span class="line"> },</span><br></pre></td></tr></table></figure><h2 id="Basic-Usage"><a href="#Basic-Usage" class="headerlink" title="Basic Usage"></a>Basic Usage</h2><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">Particle</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> //参数一 canvas的id, class 或 canvas [必填]</span><br><span class="line"> //参数二 配置项 [可选]</span><br><span class="line"> new Particle(<span class="string">'#test'</span>,{</span><br><span class="line"> //画布背景(默认 <span class="comment">#FFF)[可选]</span></span><br><span class="line"> background: <span class="string">'#000'</span>,</span><br><span class="line"> //粒子数(默认 300)[可选]</span><br><span class="line"> particleNum: 300,</span><br><span class="line"> //粒子半径(默认 1)[可选]</span><br><span class="line"> particleR: 1,</span><br><span class="line"> //粒子移动速度(默认 10)[可选]</span><br><span class="line"> particleSpeed: 10,</span><br><span class="line"> //线长度(默认 70)[可选]</span><br><span class="line"> lineLength: 30,</span><br><span class="line"> //线宽度(默认 0.5)[可选]</span><br><span class="line"> lineWidth: 0.5,</span><br><span class="line"> //鼠标心颜色(默认 <span class="comment">#000)[可选]</span></span><br><span class="line"> mousePointColor: <span class="string">'#FFF'</span></span><br><span class="line"> })</span><br></pre></td></tr></table></figure><p> </p>]]></content>
<categories>
<category> 渣技术 </category>
</categories>
<tags>
<tag> Canvas </tag>
</tags>
</entry>
<entry>
<title>Html5 File API 与 ClipImage结合 Demo</title>
<link href="/ClipImageDemo-FileAPI.html"/>
<content type="html"><![CDATA[<p>用ClipImage和File Api 写的一个截图小🌰</p><blockquote><p><a href="http://f2er.meitu.com/hmz/ClipImageDemo/example/" target="_blank" rel="noopener">example</a></p></blockquote><blockquote><p><a href="https://github.com/ishareme/ClipImageDemo" target="_blank" rel="noopener">github</a><br><a id="more"></a></p></blockquote><h2 id="File-API"><a href="#File-API" class="headerlink" title="File API"></a>File API</h2><p>在File API 没有出来的时候,如果想在页面中一上传就直接预览所上传的图片一般要配合后端实现获取到图片的url,就又发起了请求,不能实时预览图片。File API 也可以实现多文件上传、上传图片实时预览、断点续传、文件下载等等。File API 主要有以下接口</p><h5 id="Blob"><a href="#Blob" class="headerlink" title="- Blob"></a>- Blob</h5><h5 id="File"><a href="#File" class="headerlink" title="- File"></a>- File</h5><h5 id="FileList"><a href="#FileList" class="headerlink" title="- FileList"></a>- FileList</h5><h5 id="FileReader"><a href="#FileReader" class="headerlink" title="- FileReader"></a>- FileReader</h5><h4 id="Blob-1"><a href="#Blob-1" class="headerlink" title="Blob"></a>Blob</h4><p>Blob对象是一个代表二进制数据的对象<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">let</span> blob = new Blob(blobParts[, options])</span><br></pre></td></tr></table></figure></p><p>注意Blob这个构造器的参数比较诡异,第一个参数是一组数据,所以必须是数组,即使像上面的例子一样只有一个字符串也必须用数组装起来。第二个参数是对这一Blob对象的配置属性.</p><p><strong>blob属性</strong></p><ul><li>size</li><li>type</li></ul><p><strong>blob方法</strong></p><ul><li>slice([start,[ end ,[contentType]]]) 返回一个新的 Blob对象,包含了源 Blob对象中指定范围内的数据。</li></ul><h4 id="File-1"><a href="#File-1" class="headerlink" title="File"></a>File</h4><p>File 对象包含文件的一些信息,比如name、size、type、lastModifiedDate等</p><p>File对象可以用来获取某个文件的信息,还可以用来读取这个文件的内容。通常情况下,</p><ol><li>File对象是来自用户在一个input元素上选择文件后返回的FileList对象</li><li>来自由拖放操作生成的 DataTransfer对象.</li></ol><p>File 接口没有定义任何方法,但是继承了<strong>Blob 接口的方法</strong>。</p><h4 id="FileList-1"><a href="#FileList-1" class="headerlink" title="FileList"></a>FileList</h4><p>FileList包含File对象列表,类数组结构</p><p><strong>属性</strong></p><ul><li>length 返回FileList的长度<br><strong> 方法</strong> </li><li>item(index) 取某个File,可以直接下标</li></ul><h4 id="FileReader-1"><a href="#FileReader-1" class="headerlink" title="FileReader"></a>FileReader</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><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></pre></td><td class="code"><pre><span class="line">let reader = new FileReader()</span><br><span class="line"></span><br><span class="line">//四种异步读取文件方法</span><br><span class="line">FileReader.onabort</span><br><span class="line">处理abort事件。该事件在读取操作被中断时触发。</span><br><span class="line"></span><br><span class="line">FileReader.onerror</span><br><span class="line">处理error事件。该事件在读取操作发生错误时触发。</span><br><span class="line"></span><br><span class="line">FileReader.onload</span><br><span class="line">处理load事件。该事件在读取操作完成时触发。</span><br><span class="line"></span><br><span class="line">FileReader.onloadstart</span><br><span class="line">处理loadstart事件。该事件在读取操作开始时触发。</span><br><span class="line"></span><br><span class="line">FileReader.onloadend</span><br><span class="line">处理loadend事件。该事件在读取操作结束时(要么成功,要么失败)触发。</span><br><span class="line"></span><br><span class="line">FileReader.onprogress</span><br><span class="line">处理progress事件(进度)。该事件在读取Blob时触发。</span><br><span class="line"></span><br><span class="line">// 读数据</span><br><span class="line">FileReader.abort()</span><br><span class="line">中止读取操作。在返回时,readyState属性为DONE。</span><br><span class="line"></span><br><span class="line">FileReader.readAsArrayBuffer()</span><br><span class="line">开始读取指定的 Blob中的内容, 一旦完成, result 属性中保存的将是被读取文件的 ArrayBuffer 数据对象.</span><br><span class="line"></span><br><span class="line">FileReader.readAsBinaryString() </span><br><span class="line">开始读取指定的Blob中的内容。一旦完成,result属性中将包含所读取文件的原始二进制数据。</span><br><span class="line"></span><br><span class="line">FileReader.readAsDataURL()</span><br><span class="line">开始读取指定的Blob中的内容。一旦完成,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容。</span><br><span class="line"></span><br><span class="line">FileReader.readAsText()</span><br><span class="line">开始读取指定的Blob中的内容。一旦完成,result属性中将包含一个字符串以表示所读取的文件内容。</span><br></pre></td></tr></table></figure><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//二进制流上传文件</span></span><br><span class="line"><span class="keyword">var</span> fileInput = <span class="built_in">document</span>.getElementById(<span class="string">"fileInput"</span>);</span><br><span class="line">fileInput.addEventListener(<span class="string">'change'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>{</span><br><span class="line"> <span class="keyword">var</span> file = fileInput.files[<span class="number">0</span>];</span><br><span class="line"> <span class="keyword">if</span> (file) {</span><br><span class="line"> <span class="keyword">var</span> reader = <span class="keyword">new</span> FileReader(); </span><br><span class="line"> <span class="keyword">var</span> xhr = <span class="keyword">new</span> XMLHttpRequest();</span><br><span class="line"> xhr.onprogress=<span class="function"><span class="keyword">function</span>(<span class="params">e</span>)</span>{</span><br><span class="line"> <span class="keyword">var</span> percentage = <span class="built_in">Math</span>.round((e.loaded * <span class="number">100</span>) / e.total);</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"percentage:"</span>+percentage);</span><br><span class="line"> }</span><br><span class="line"> xhr.onload=<span class="function"><span class="keyword">function</span>(<span class="params">e</span>)</span>{</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="string">"percentage:100"</span>);</span><br><span class="line"> }</span><br><span class="line"> xhr.open(<span class="string">"POST"</span>, <span class="string">"这里填写服务器地址"</span>); </span><br><span class="line"> reader.onload = <span class="function"><span class="keyword">function</span>(<span class="params">evt</span>) </span>{</span><br><span class="line"> xhr.send(evt.target.result);</span><br><span class="line"> };</span><br><span class="line"> reader.readAsBinaryString(file);</span><br><span class="line"> }</span><br><span class="line">});</span><br></pre></td></tr></table></figure><h2 id="URL对象"><a href="#URL对象" class="headerlink" title="URL对象"></a>URL对象</h2><p>我们除了可以使用base64字符串作为内容的DataURI将一个文件嵌入到另外一个文档里,还可以使用URL对象。URL对象用于生成指向File对象或Blob对象的URL。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> objectURL = <span class="built_in">window</span>.URL.createObjectURL(file/blob)</span><br><span class="line">img.src = objectURL</span><br><span class="line"></span><br><span class="line"><span class="comment">//静态方法用来释放一个之前通过调用 window.URL.createObjectURL() 创建的已经存在的 URL 对象。</span></span><br><span class="line"><span class="comment">//当你结束使用某个 URL 对象时,应该通过调用这个方法来让浏览器知道不再需要保持这个文件的引用了。</span></span><br><span class="line"><span class="built_in">window</span>.URL.revokeObjectURL(objecturl)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//such this example 使用对象URL来显示图片</span></span><br><span class="line"><span class="keyword">var</span> img = <span class="built_in">document</span>.createElement(<span class="string">"img"</span>);</span><br><span class="line">img.src = <span class="built_in">window</span>.URL.createObjectURL(blob);</span><br><span class="line">img.height = <span class="number">60</span>;</span><br><span class="line">img.onload = <span class="function"><span class="keyword">function</span>(<span class="params">e</span>) </span>{</span><br><span class="line"> <span class="built_in">window</span>.URL.revokeObjectURL(<span class="keyword">this</span>.src);</span><br><span class="line">}</span><br><span class="line"><span class="built_in">document</span>.body.appendChild(img);</span><br></pre></td></tr></table></figure><h4 id="CLipImage"><a href="#CLipImage" class="headerlink" title="CLipImage"></a>CLipImage</h4><p><a href="https://blog.huangmingzhao.cn/ClipImage.html" target="_blank" rel="noopener">点我!!!!</a></p><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>ps: 有空写下断点续传吧!!!巴拉巴拉~~<br>最近状态慢慢开始有所调整了哈,继续加油~~买了书,买了椅子,买了显示器,但是还没到!!有点小期待~期待自己接下来的生活,好好吃饭、好好睡觉、好好读书。晚安,睡觉….. </p>]]></content>
<categories>
<category> 渣技术 </category>
</categories>
<tags>
<tag> Canvas </tag>
<tag> FileAPI </tag>
</tags>
</entry>
<entry>
<title>ClipImage 基于canvas截图工具</title>
<link href="/ClipImage.html"/>
<content type="html"><![CDATA[<p>最近重新看了下canvas的api,于是乎就撸了几个小demo。clipImage基于canvas的截图小工具 <a href="https://github.com/ishareme/ClipImage/" target="_blank" rel="noopener">github 地址</a></p><a id="more"></a><h2 id="主要代码"><a href="#主要代码" class="headerlink" title="主要代码"></a>主要代码</h2><p>canvas实现裁剪的方法比较多,比如</p><h4 id="1-getImageData-和-putImageData"><a href="#1-getImageData-和-putImageData" class="headerlink" title="1. getImageData 和 putImageData"></a>1. getImageData 和 putImageData</h4><p>源图片画上一个canvas上,通过originCanvas.getImageData(sx,sy,sw,sh)获取到图片的image data,赋值于resultCanvas.putImageData(imagedata, dx, dy)<br>[注:putImageData 7 个参数时后四个表示imagedata的想x,y,width,height,<br>resultCanvas.putImageData(imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight)]<br><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//原图数据</span></span><br><span class="line"><span class="keyword">var</span> resultData = ctxOrigin.getImageData(x, y, width, height)</span><br><span class="line"></span><br><span class="line">canvasResult.width = width</span><br><span class="line">canvasResult.height = height</span><br><span class="line"></span><br><span class="line"><span class="comment">//结果的canvas绘上</span></span><br><span class="line">ctxResult.putImageData(resultData, <span class="number">0</span>, <span class="number">0</span>)</span><br></pre></td></tr></table></figure></p><h4 id="2-drawImage-CanvasImageSource-sx-sy-sWidth-sHeight-dx-dy-dWidth-dHeight"><a href="#2-drawImage-CanvasImageSource-sx-sy-sWidth-sHeight-dx-dy-dWidth-dHeight" class="headerlink" title="2. drawImage(CanvasImageSource, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)"></a>2. drawImage(CanvasImageSource, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)</h4><p>使用多个参数的drawImage()方法</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">ctxResult.drawImage(CanvasImageSource, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)</span><br><span class="line"></span><br><span class="line">sx,<span class="attr">sy</span>: 源图片的位置</span><br><span class="line">sw,<span class="attr">sh</span>: 要裁剪的相对于sx,sy的宽度和高度</span><br><span class="line">dx,<span class="attr">dy</span>: 要画在结果canvas的位置</span><br><span class="line">dw,<span class="attr">dh</span>: 要画在结果canvas的宽度和高度</span><br></pre></td></tr></table></figure><h4 id="3-使用clip-函数-相对比较繁琐"><a href="#3-使用clip-函数-相对比较繁琐" class="headerlink" title="3. 使用clip()函数 [相对比较繁琐]"></a>3. 使用clip()函数 [相对比较繁琐]</h4><h2 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h2><h1 id="ClipImage"><a href="#ClipImage" class="headerlink" title="ClipImage"></a>ClipImage</h1><blockquote><p><a href="https://github.com/ishareme/clipimage" target="_blank" rel="noopener">git</a></p></blockquote><blockquote><p><a href="http://npm.meitu-int.com/#@meitu/ClipImage" target="_blank" rel="noopener">npm</a></p></blockquote><h2 id="Example"><a href="#Example" class="headerlink" title="Example"></a>Example</h2><p><a href="http://f2er.meitu.com/hmz/imageclip/example/index.html" target="_blank" rel="noopener">example</a></p><h2 id="Getting-Started"><a href="#Getting-Started" class="headerlink" title="Getting Started"></a>Getting Started</h2> <figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm set registry http://npm.meitu-int.com</span><br></pre></td></tr></table></figure> <figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i @meitu/clipimage --save</span><br></pre></td></tr></table></figure> <figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">import ImageClip from '@meitu/clipimage';</span><br></pre></td></tr></table></figure><h4 id="new-ClipImage-image-options"><a href="#new-ClipImage-image-options" class="headerlink" title="new ClipImage(image,options):"></a>new ClipImage(image,options):</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">image: 背景图片 <span class="built_in">type</span>: url/HTMLImageElement/HTMLCanvasElement/HTMLVideoElement</span><br><span class="line">options:{</span><br><span class="line"> // 结果图宽度 高度</span><br><span class="line"> // 100 / <span class="string">'100%[相对于原图]'</span> / <span class="string">'100px'</span></span><br><span class="line"> width: 100,</span><br><span class="line"> height: 100,</span><br><span class="line"> //left top 从哪开始裁剪</span><br><span class="line"> // 100 / <span class="string">'50%'</span> / <span class="string">'100px'</span> / <span class="string">'center'</span> / <span class="string">'top'</span> / <span class="string">'left'</span></span><br><span class="line"> left: <span class="string">'center'</span>,</span><br><span class="line"> top: <span class="string">'center'</span>,</span><br><span class="line"> //导出图片类型 <span class="string">'jpeg'</span> / <span class="string">'jpg'</span> / <span class="string">'png'</span></span><br><span class="line"> <span class="built_in">type</span>: <span class="string">'jpg'</span>,</span><br><span class="line"> //导出图片的质量 数值[0-1]</span><br><span class="line"> quality: 1, </span><br><span class="line"> //成功时的回调</span><br><span class="line"> success(b64){</span><br><span class="line"> </span><br><span class="line"> },</span><br><span class="line"> //失败时的回调</span><br><span class="line"> error(err){</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"> width: 100,</span><br><span class="line"> height: 100,</span><br><span class="line"> left: 0, </span><br><span class="line"> top: 0,</span><br><span class="line"> <span class="built_in">type</span>: <span class="string">'jpeg'</span>,</span><br><span class="line"> quality: 1, </span><br><span class="line"> <span class="function"><span class="title">success</span></span>(){},</span><br><span class="line"> <span class="function"><span class="title">error</span></span>(){},</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="Basic-Usage"><a href="#Basic-Usage" class="headerlink" title="Basic Usage"></a>Basic Usage</h2><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><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">ClipImage</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">new ClipImage(<span class="variable">$originCanvas</span>,{</span><br><span class="line"> width: <span class="string">'200px'</span>,</span><br><span class="line"> height: <span class="string">'200px'</span>,</span><br><span class="line"> left: <span class="string">'100px'</span>, </span><br><span class="line"> top: <span class="string">'100px'</span>,</span><br><span class="line"> <span class="built_in">type</span>: <span class="string">'jpg'</span>,</span><br><span class="line"> quality: 1, </span><br><span class="line"> success(b64){</span><br><span class="line"> <span class="variable">$result</span>.src = b64</span><br><span class="line"> },</span><br><span class="line"> <span class="function"><span class="title">error</span></span>(){},</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line">or</span><br><span class="line"></span><br><span class="line">new ClipImage(<span class="string">'http://mtapplet.meitudata.com/596c72073971d86b5128.jpg'</span>,{</span><br><span class="line"> width: 100,</span><br><span class="line"> height: 100,</span><br><span class="line"> left: <span class="string">'center'</span>, </span><br><span class="line"> top: <span class="string">'center'</span>,</span><br><span class="line"> <span class="built_in">type</span>: <span class="string">'png'</span>,</span><br><span class="line"> quality: 0.8, </span><br><span class="line">}).<span class="keyword">then</span>(<span class="keyword">function</span> (b64) {</span><br><span class="line"> <span class="variable">$result</span>.src = b64</span><br><span class="line">})</span><br></pre></td></tr></table></figure><p> </p>]]></content>
<categories>
<category> 渣技术 </category>
</categories>
<tags>
<tag> Canvas </tag>
</tags>
</entry>
<entry>
<title>canvas API 汇总</title>
<link href="/canvas-api.html"/>
<content type="html"><![CDATA[<p>canvas 的 API 汇总</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><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></pre></td><td class="code"><pre><span class="line">rect( x, y, width, height ) 绘制矩形</span><br><span class="line"></span><br><span class="line">fillRect( x, y, width, height ) 绘制被填充的矩形</span><br><span class="line"></span><br><span class="line">strokeRect( x, y, width, height ) 绘制矩形(边框,无填充)</span><br><span class="line"></span><br><span class="line">clearRect( x, y, width, height ) 清除指定的矩形内的像素</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">fill() 填充当前绘图(路径)</span><br><span class="line"></span><br><span class="line">stroke() 绘制已定义的路径</span><br><span class="line"></span><br><span class="line">beginPath() 起始(重置)当前路径</span><br><span class="line"></span><br><span class="line">moveTo( x, y ) 将笔触移动到指定的坐标(x,y)</span><br><span class="line"></span><br><span class="line">lineTo( x, y ) 绘制一条从当前位置到指定的坐标(x,y)的直线</span><br><span class="line"></span><br><span class="line">clip() 从原始画布剪切任意形状和尺寸的区域</span><br><span class="line"></span><br><span class="line">quadraticCurveTo() 创建二次贝塞尔曲线</span><br><span class="line"></span><br><span class="line">bezierCurveTo() 创建三次贝塞尔曲线</span><br><span class="line"></span><br><span class="line">arc( x, y, radius, startAngle, endAngle, anticlockwise) 绘制圆或圆弧</span><br><span class="line"></span><br><span class="line">arcTo( x1, y1, x2, y2, radius) 根据给定点画圆弧,再以直线连接两个点</span><br><span class="line"></span><br><span class="line">isPointInPath( x, y ) 检测指定的点是否在当前路径中,在则返回<span class="literal">true</span>。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">fillStyle 设置或返回用于填充绘画的颜色、渐变或模式</span><br><span class="line"></span><br><span class="line">strokeStyle 设置或返回用于笔触的颜色、渐变或模式</span><br><span class="line"></span><br><span class="line">shadowColor 设置或返回用于阴影的颜色</span><br><span class="line"></span><br><span class="line">shadowBlur 设置或返回用于阴影的模糊级别</span><br><span class="line"></span><br><span class="line">shadowOffsetX 设置或返回阴影与形状的水平距离</span><br><span class="line"></span><br><span class="line">shadowOffsetY 设置或返回阴影与形状的垂直距离</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">lineCap 设置或返回线条的结束点样式(butt、round、square)</span><br><span class="line"></span><br><span class="line">lineJoin 设置或返回当两条线交汇时,边角的类型(bevel、round、miter)</span><br><span class="line"></span><br><span class="line">lineWidth 设置或返回当前的线条宽度</span><br><span class="line"></span><br><span class="line">miterLimit 设置或返回最大斜接长度</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">createLinearGradient( x0, y0, x1, y1 ) 创建线性渐变</span><br><span class="line"></span><br><span class="line">createPattern( image/canvas/video, repeat ) 在指定的方向内重复绘制指定的元素</span><br><span class="line"></span><br><span class="line">createRadialGradient( x0, y0, r0, x1, y1, r1 ) 创建径向渐变</span><br><span class="line"></span><br><span class="line">addColorStop( stop, color ) 规定渐变对象中的颜色和停止位置</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">font 设置或返回文本内容的当前字体属性(和css的font一样)</span><br><span class="line"></span><br><span class="line">textAlign 设置或返回文本内容的当前对齐方式</span><br><span class="line"></span><br><span class="line">textBaseline 设置或返回在绘制文本时使用的当前文本基线</span><br><span class="line"></span><br><span class="line">fillText( text, x, y ) 在画布上绘制“被填充”的文本</span><br><span class="line"></span><br><span class="line">strokeText( text, x, y ) 在画布上绘制文本(无填充)</span><br><span class="line"></span><br><span class="line">measureText( text ) 返回包含指定文本宽度的对象(属性width获取宽度)</span><br><span class="line"></span><br><span class="line">drawImage( image/canvas, x, y )、drawImage( image/canvas, x, y, width, height )、drawImage( image/canvas, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight ) 在画布上绘制图像、画布或视频</span><br><span class="line"></span><br><span class="line">createImageData( width, height )、createImageData(imageData) 绘制ImageData对象</span><br><span class="line"></span><br><span class="line">getImageData( x, y, width, height ) 返回ImageData对象,该对象为画布上指定的矩形复制像素数据。</span><br><span class="line"></span><br><span class="line">putImageData( ImageData, x, y )、putImageData( imageData, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight ) 把图像数据放回画布上。</span><br><span class="line"></span><br><span class="line">width 返回ImageData对象的宽度</span><br><span class="line"></span><br><span class="line">height 返回ImageData对象的高度</span><br><span class="line"></span><br><span class="line">data 返回一个对象,包含指定的ImageData对象的图像数据</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">globalAlpha 设置或返回绘图的当前alpha或透明度</span><br><span class="line"></span><br><span class="line">globalCompositeOperation 设置或返回新图像如何绘制到已有的图像上。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">scale( x, y ) 缩放当前绘图</span><br><span class="line"></span><br><span class="line">translate( x, y ) 重新设置画布上的(<span class="number">0</span>,<span class="number">0</span>)位置</span><br><span class="line"></span><br><span class="line">rotate( angle ) 选择当前绘图,单位为“弧度”,角度转弧度公式( degrees*<span class="built_in">Math</span>.PI/<span class="number">180</span>)</span><br><span class="line"></span><br><span class="line">transform( m11, m12, m21, m22, dx, dy ) 替换绘图的当前转换矩阵</span><br><span class="line"></span><br><span class="line">setTransform() 将当前转换重置为单元矩阵,然后运行transform()</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">save() 保存当前环境的状态</span><br><span class="line"></span><br><span class="line">restore() 恢复之前保存过的路径状态和属性</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">getContext(<span class="string">'2d'</span>) 获取<span class="number">2</span>d对象</span><br><span class="line"></span><br><span class="line">toDataURL() 将canvas转换成图片,返回地址</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> 渣技术 </category>
</categories>
<tags>
<tag> canvas </tag>
</tags>
</entry>
<entry>
<title>javascript 观察者模式 (订阅者与发布者)</title>
<link href="/publish-subscribe-mode.html"/>
<content type="html"><![CDATA[<p>javascript 观察者模式 (订阅者与发布者)</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><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 class="function"><span class="keyword">function</span> <span class="title">PubSub</span>(<span class="params"></span>) </span>{</span><br><span class="line"> <span class="keyword">this</span>.handlers = {};</span><br><span class="line">}</span><br><span class="line">PubSub.prototype = {</span><br><span class="line"> <span class="comment">// 订阅事件</span></span><br><span class="line"> on: <span class="function"><span class="keyword">function</span>(<span class="params">eventType,handler</span>)</span>{</span><br><span class="line"> <span class="keyword">var</span> self = <span class="keyword">this</span>;</span><br><span class="line"> <span class="keyword">if</span>(!(eventType <span class="keyword">in</span> self.handlers)) {</span><br><span class="line"> self.handlers[eventType] = [];</span><br><span class="line"> }</span><br><span class="line"> self.handlers[eventType].push(handler);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line"> },</span><br><span class="line"> <span class="comment">// 触发事件(发布事件)</span></span><br><span class="line"> emit: <span class="function"><span class="keyword">function</span>(<span class="params">eventType</span>)</span>{</span><br><span class="line"> <span class="keyword">var</span> self = <span class="keyword">this</span>;</span><br><span class="line"> <span class="keyword">var</span> handlerArgs = <span class="built_in">Array</span>.prototype.slice.call(<span class="built_in">arguments</span>,<span class="number">1</span>);</span><br><span class="line"> <span class="keyword">for</span>(<span class="keyword">var</span> i = <span class="number">0</span>; i < self.handlers[eventType].length; i++) {</span><br><span class="line"> self.handlers[eventType][i].apply(self,handlerArgs);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> self;</span><br><span class="line"> }</span><br><span class="line">};<span class="comment">// 调用方式如下:</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> pubsub = <span class="keyword">new</span> PubSub();</span><br><span class="line"></span><br><span class="line">pubsub.on(<span class="string">'A'</span>,<span class="function"><span class="keyword">function</span>(<span class="params">data</span>)</span>{</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(<span class="number">1</span> + data); <span class="comment">// 执行第一个回调业务函数</span></span><br><span class="line"></span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">pubsub.on(<span class="string">'A'</span>,<span class="function"><span class="keyword">function</span>(<span class="params">data</span>)</span>{</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(<span class="number">2</span> + data); <span class="comment">// 执行第二个业务回调函数</span></span><br><span class="line"></span><br><span class="line">});</span><br><span class="line"></span><br><span class="line"><span class="comment">// 触发事件A</span></span><br><span class="line"></span><br><span class="line">pubsub.emit(<span class="string">'A'</span>,<span class="string">"我是参数"</span>);</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> 渣技术 </category>
</categories>
<tags>
<tag> JavaScript </tag>
</tags>
</entry>
<entry>
<title>实习&andyMove小结</title>
<link href="/practice-summary-andy-move.html"/>
<content type="html"><![CDATA[<p>这学期的实习也快结束了,想想还是挺感慨的。这次对andyMove的总结就当做对自己这学期实习的总结吧。</p><p>在美图也快满4个月了,总感觉自己进步的非常慢,有时候会在想是不是自己变得不上心了?变得不进取了?对!!你就是不进取了,松懈了!!不,这完全不是我!!!!当然在这四个月里或多或少还是比刚进美图的时候有所收获。从刚开始什么都不太懂的情况下开始的第一个H5,到现在相对比较清楚的开发(bug满天飞)。真的非常感谢有这个平台让我更加清楚的看清自己的不足,在这里真的非常感谢板栗兄一对一的辅导,自己的渣技术对他造成的不便深感自责。非常感谢晓东兄照顾~~</p><h2 id="反思"><a href="#反思" class="headerlink" title="反思"></a>反思</h2><ul><li><p>不管做什么事,<strong>细节</strong>真的很重要,在开发中,正如晓东说的多去注意一些细节的东西,这个项目就会更好,不要马虎的去对待它,比如动画微调的时候比较麻烦,一旦你马虎应付的话,细节处理不到位,动画不写反而会比较好!!说的就是你要细心!!多注意~~</p></li><li><p>在开发<strong>效率</strong>方面真的需要再提升提升,比如像一些比较麻烦的animation动画可以先不用处理,写animation有时候真的会挺花费时间的,导致于项目进展的比较慢,有可能会误期,所以可以先把项目做出来,把项目先跑通,逻辑处理好了再去处理animation等等。</p></li><li><p><strong>代码方面</strong>正如晓东说的目前自己写的 <strong>代码</strong>可能还是比较面条化,没有很好的去优化,重复性太强,没有模块化</p></li><li><p><strong>js css 没有模块化</strong>,要有<strong>模块化</strong>的思想,减少代码耦合,这一点非常非常重要!!!谨记!!!写到重复的代码的时候一点要想着怎么去优化!!!拿到PSD的时候<strong>不要马上就开始切</strong>,应该要想好好的想想如何去模块化,如何去布局,把逻辑理清楚,不然你会做很多无用功!!!</p></li><li><p><strong>bug修改方面</strong>提交测试版完之后测试便会开始测试逐步提交bug出来,要时常去<strong>关注jira</strong>上自己的bug,及时修复!!及时!!修复完毕一定要关闭bug给出合理的bug修复解释。bug修复时自己要先测一遍在提交给测试,可能有时候bug并未解决,导致于测试那边做无用功。[你还要不要脸害人家白忙活。。。]</p></li><li><p><strong>不要害怕麻烦</strong>在做lancome的时候需求的变动,让我觉得有些麻烦,故而就想到把需求砍掉,事后想想那时候的自己真的很垃圾,有什么问题就去解决,而不是想着如何不去解决!!</p></li><li><p><strong>依赖</strong>方面,能不麻烦别人的就不麻烦别人,坐在板栗旁边,有时候就产生了过度依赖的问题,一遇到bug自己不能解决的情况,就去问,[怪对不起板栗兄,真的超谢谢],自己并没有好好想想自己如何解决,产生过度依赖。凡事一定要自己解决,自己解决!!!!</p></li><li><p>在<strong>沟通方面</strong>,态度谦和多沟通,不要把自己的情绪影响到别人,特别是产品运营设计测试这些大佬<del>~[[受奴才一跪</del>]</p></li></ul><h2 id="BUG"><a href="#BUG" class="headerlink" title="BUG"></a>BUG</h2><p>下面是一些这次开发过程中出现的一些问题:</p><h4 id="QQ平台,结果页不能滑动"><a href="#QQ平台,结果页不能滑动" class="headerlink" title="QQ平台,结果页不能滑动"></a>QQ平台,结果页不能滑动</h4><p>由于iOS下z-index的层级影响,导致于有些平台在ios下会很难出现滑动的情况(不顺畅),以及transition和animation同时使用ios端可能会出现问题</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><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line">css:</span><br><span class="line"></span><br><span class="line">目前</span><br><span class="line">page{</span><br><span class="line"> position: absolute;</span><br><span class="line"> top: 0;</span><br><span class="line"> left: 0;</span><br><span class="line"> width: 100%;</span><br><span class="line"> height: 100%;</span><br><span class="line"> overflow: hidden;</span><br><span class="line"> //transition: transform .5s;</span><br><span class="line"> //opacity: 0;</span><br><span class="line"> overflow-x: hidden;</span><br><span class="line"> overflow-y: auto;</span><br><span class="line"> &.transition{</span><br><span class="line"> transition: all .3s;</span><br><span class="line"> }</span><br><span class="line"> &.show{</span><br><span class="line"> transform: translateX(0);</span><br><span class="line"> }</span><br><span class="line"> &.hide-after{</span><br><span class="line"> transform: translateX(100%);</span><br><span class="line"> }</span><br><span class="line"> &.hide-before{</span><br><span class="line"> transform: translateX(-100%);</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">page{</span><br><span class="line"> position: absolute;</span><br><span class="line"> top: 0;</span><br><span class="line"> left: 0;</span><br><span class="line"> width: 100%;</span><br><span class="line"> height: 100%;</span><br><span class="line"> overflow: hidden;</span><br><span class="line"> transition: transform .5s;</span><br><span class="line"> opacity: 0;</span><br><span class="line"> overflow-x: hidden;</span><br><span class="line"> overflow-y: auto;</span><br><span class="line"> &.in {</span><br><span class="line"> opacity: 1;</span><br><span class="line"> z-index: 2;</span><br><span class="line"> //animation: in 0.5s ease both;</span><br><span class="line"> //</span><br><span class="line"> //@keyframes in {</span><br><span class="line"> // 0% { opacity: 0; }</span><br><span class="line"> // 100% { opacity: 1; }</span><br><span class="line"> //}</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> &.out {</span><br><span class="line"> opacity: 0.5;</span><br><span class="line"> z-index: 1;</span><br><span class="line"> //transform: translateX(-100%);</span><br><span class="line"> //transition: all .5s;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><h4 id="上传完图片要进行预加载"><a href="#上传完图片要进行预加载" class="headerlink" title="上传完图片要进行预加载"></a>上传完图片要进行预加载</h4><p>在上传完图片生成url的时候一般都需要在接下来的页面中用到,故要对其进行预加载。在做帧动画更换图片的时候要注意,也是要预加载</p><h4 id="ios秀秀端结果页转发qq和qq空间转发不了"><a href="#ios秀秀端结果页转发qq和qq空间转发不了" class="headerlink" title="ios秀秀端结果页转发qq和qq空间转发不了"></a>ios秀秀端结果页转发qq和qq空间转发不了</h4><p>这个要注意,在做拼接url的时候要对带有中文或者其他字符做encodeURIComponent处理,再到要用的地方(分享页)进行decodeURIComponent获取,上次在群里面看到share的imageURL为空或者这个图片太大的话在端内分享qq也会调不起来</p><h4 id="图片repeat重复问题"><a href="#图片repeat重复问题" class="headerlink" title="图片repeat重复问题"></a>图片repeat重复问题</h4><p>js动态加上图片的时候要记得加上background-repeat:no-repeat,不要只加background-image</p><h4 id="share页也要做分享,auth权限模块是异步执行的"><a href="#share页也要做分享,auth权限模块是异步执行的" class="headerlink" title="share页也要做分享,auth权限模块是异步执行的"></a>share页也要做分享,auth权限模块是异步执行的</h4><p>在share页的时候一般也要加上分享,auth权限模块是异步执行的~~</p><h4 id="微博下的视频问题"><a href="#微博下的视频问题" class="headerlink" title="微博下的视频问题"></a>微博下的视频问题</h4><p>微博下视频默认是全屏播放的,点击返回视频在没有控制条control的情况下会不能再次播放,因此在weibo下要加上control</p><h4 id="gif在Android下会出现显示一段时间之后不显示,但是可以保存和转发-后端算法已解决,无需降级"><a href="#gif在Android下会出现显示一段时间之后不显示,但是可以保存和转发-后端算法已解决,无需降级" class="headerlink" title="gif在Android下会出现显示一段时间之后不显示,但是可以保存和转发(后端算法已解决,无需降级)"></a>gif在Android下会出现显示一段时间之后不显示,但是可以保存和转发(后端算法已解决,无需降级)</h4><p>此次采用降级的方案,直接放图片,子元素gif的opacity为0</p><h4 id="video-在微信下会显示内置的播放器"><a href="#video-在微信下会显示内置的播放器" class="headerlink" title="video 在微信下会显示内置的播放器"></a>video 在微信下会显示内置的播放器</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"><video class="js-video"</span><br><span class="line"> loop</span><br><span class="line"> airplay="allow"</span><br><span class="line"> x5-playsinline</span><br><span class="line"> playsinline</span><br><span class="line"> webkit-playsinline</span><br><span class="line"> preload="auto"</span><br><span class="line">></span><br><span class="line"></video></span><br></pre></td></tr></table></figure><h4 id="iPhoneX在video问题"><a href="#iPhoneX在video问题" class="headerlink" title="iPhoneX在video问题"></a>iPhoneX在video问题</h4><p>iPhoneX的video在有poster的情况下,播放视频poster不会自动去掉,要自己逻辑手动去掉poster</p><h4 id="尽量不要去用touchstart"><a href="#尽量不要去用touchstart" class="headerlink" title="尽量不要去用touchstart"></a>尽量不要去用touchstart</h4><p>touchstart时间间隔太小,有可能不会生效,一般使用tap,click,touchend,而touchstart主要用于事件状态方面</p><h4 id="在开发要尽可能模块化"><a href="#在开发要尽可能模块化" class="headerlink" title="在开发要尽可能模块化"></a>在开发要尽可能模块化</h4><p>对于css也是,类似的css可以抽出模块,js更是,逻辑尽可能写成模块</p><h4 id="代码要尽可能简洁,能优化的逻辑尽可能优化,以后要全使用ES6!!ES6!!!!"><a href="#代码要尽可能简洁,能优化的逻辑尽可能优化,以后要全使用ES6!!ES6!!!!" class="headerlink" title="代码要尽可能简洁,能优化的逻辑尽可能优化,以后要全使用ES6!!ES6!!!!"></a>代码要尽可能简洁,能优化的逻辑尽可能优化,以后要全使用ES6!!ES6!!!!</h4><h4 id="在移动端的话最好不要去用flexbox"><a href="#在移动端的话最好不要去用flexbox" class="headerlink" title="在移动端的话最好不要去用flexbox"></a>在移动端的话最好不要去用flexbox</h4><p>flexbox的兼容性性目前还是不够好,尽量去克服这个习惯</p><h4 id="视频播放延迟问题-后端算法已解决"><a href="#视频播放延迟问题-后端算法已解决" class="headerlink" title="视频播放延迟问题(后端算法已解决)"></a>视频播放延迟问题(后端算法已解决)</h4><h4 id="ios低端机下gif保存为静态-ios早些版本的问题,目前无解"><a href="#ios低端机下gif保存为静态-ios早些版本的问题,目前无解" class="headerlink" title="ios低端机下gif保存为静态(ios早些版本的问题,目前无解)"></a>ios低端机下gif保存为静态(ios早些版本的问题,目前无解)</h4><h1 id="之后-不对!现在"><a href="#之后-不对!现在" class="headerlink" title="之后(不对!现在~~)"></a>之后(不对!现在~~)</h1><h3 id="1、调整好状态,充满激情才是我!!"><a href="#1、调整好状态,充满激情才是我!!" class="headerlink" title="1、调整好状态,充满激情才是我!!"></a>1、调整好状态,充满激情才是我!!</h3><h3 id="2、-专心于学习"><a href="#2、-专心于学习" class="headerlink" title="2、 专心于学习"></a>2、 专心于学习</h3><p>买了书买了椅子买了显示器,对!!就是要读书!!哈哈哈<br>这是在春节放假前自己给过年回来的自己定下的学习</p><h4 id="2018-如何把自我学习和工作时间分配弄好?-粗略"><a href="#2018-如何把自我学习和工作时间分配弄好?-粗略" class="headerlink" title="2018 如何把自我学习和工作时间分配弄好? (粗略)"></a>2018 如何把自我学习和工作时间分配弄好? (粗略)</h4><ul><li>周一-周五: 上班 — 6点半下班,利用好上班的时间处理好,吃完饭回去</li><li>没任务的时候如何处理? 1、主动请求加任务 2、像这个时候? 在公司看书又不好….写东 西?写插件?<br>增加表现机会,不会的先接,接完不会的再问<br>,不会的自己要先思考再问,不要一不懂就问</li><li><p>周六周日: 全看书和处理毕业设计, 晚上有时间再回学校</p></li><li><p>生活: 买个显示器、买个椅子、家里打扫干净、自己做饭</p></li></ul><h4 id="书-要看完"><a href="#书-要看完" class="headerlink" title="书 [要看完]"></a>书 [要看完]</h4><ul><li>ES6 [es6还是很薄弱]</li><li>深入浅出Webpack</li><li>Web高效编程与优化实践</li><li>体系设计与实践</li><li>Vue</li><li>Web前端高效开发</li><li>微信小程序</li></ul><h3 id="3、做好毕设、顺利毕业"><a href="#3、做好毕设、顺利毕业" class="headerlink" title="3、做好毕设、顺利毕业"></a>3、做好毕设、顺利毕业</h3><h3 id="4、好好吃饭,好好睡觉,好好生活"><a href="#4、好好吃饭,好好睡觉,好好生活" class="headerlink" title="4、好好吃饭,好好睡觉,好好生活"></a>4、好好吃饭,好好睡觉,好好生活</h3><h1 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h1><p><strong>注: 博客是放假前写的,那时候本来打算这学期请假的</strong></p><p>请假了,想想还是挺纠结的,想了好久,也是这段的实习让我看到了自己身上各个方面的不足,也借请假期间好好再充电充电,调整调整心态。2018想想应该会是一个充实的一年,想做的事情很多,希望自己能够把它过的充实,善待于它。</p><p>美图,6月份再见!希望来时是一个不一样的自己。</p><p><strong>更正如下:</strong></p><p>晓东说明天有个总结会,不知道拿这篇博客去会怎么样,写博客都是写心声,内心对自己过去否定以及对接下来充满期待的总结我想最能说明现在的我。应该可以吧,就这样吧~~</p><p>那个在新年前无数幻想着新的一年我该如何如何努力的少年希望你在新的一年勇往直前,不辜负那个幻想的少年。</p><blockquote><p>也许过去的一年,你曾被风浪拍打的颓废失意,但新的一年,愿你乘风破浪。 ——《乘风破浪》</p></blockquote><p>更新于 2018-03-01 00: 17<br>于自己的小窝</p>]]></content>
<categories>
<category> 渣技术 </category>
</categories>
<tags>
<tag> 美图 </tag>
<tag> H5项目 </tag>
</tags>
</entry>
<entry>
<title>美图H5项目总结--lancome</title>
<link href="/meitu-item-lancome-hk.html"/>
<content type="html"><![CDATA[<p>对lancome的小项目做个小结</p><a id="more"></a><p>这是项目的时间花点有点长。或多或少还是有学到一点东西。</p><h2 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h2><h3 id="1-写到有重复的代码逻辑就要想着如何去优化代码"><a href="#1-写到有重复的代码逻辑就要想着如何去优化代码" class="headerlink" title="1. 写到有重复的代码逻辑就要想着如何去优化代码"></a>1. 写到有重复的代码逻辑就要想着如何去优化代码</h3><h3 id="2-为了适配各种端,可以采用上下固定,中部居中布局"><a href="#2-为了适配各种端,可以采用上下固定,中部居中布局" class="headerlink" title="2. 为了适配各种端,可以采用上下固定,中部居中布局"></a>2. 为了适配各种端,可以采用上下固定,中部居中布局</h3><h3 id="3-在ios的safari中,有些系统不支持flexbox,以下面方式兼容"><a href="#3-在ios的safari中,有些系统不支持flexbox,以下面方式兼容" class="headerlink" title="3. 在ios的safari中,有些系统不支持flexbox,以下面方式兼容"></a>3. 在ios的safari中,有些系统不支持flexbox,以下面方式兼容</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">父容器</span><br><span class="line">display: flex;</span><br><span class="line">justify-content: center;</span><br><span class="line">align-items: center;</span><br><span class="line"></span><br><span class="line">子 (水平垂直居中)</span><br><span class="line">position: absolute;</span><br><span class="line">left: 0;</span><br><span class="line">top: 0;</span><br><span class="line">right: 0;</span><br><span class="line">bottom: 0;</span><br><span class="line">margin: auto;</span><br></pre></td></tr></table></figure><h3 id="4-mapp中upload可以使用下面这种方式"><a href="#4-mapp中upload可以使用下面这种方式" class="headerlink" title="4. mapp中upload可以使用下面这种方式"></a>4. mapp中upload可以使用下面这种方式</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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">$('.js-upload-home').on('change', function () {</span><br><span class="line"> app.loading.show();</span><br><span class="line"> app.emit('uploadSuccess', this.files[0]);</span><br><span class="line"> //上传同一张的情况</span><br><span class="line"> $(this).val('');</span><br><span class="line"> gtag('event', 'completeUpload');</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> app.on('uploadSuccess', function(file) {</span><br><span class="line"> app.upload(file).then(data => {</span><br><span class="line"> self.onSuccess(data);</span><br><span class="line"> }).catch(app.catchErr.upload);</span><br><span class="line"> });</span><br></pre></td></tr></table></figure><h3 id="5-对于形如一致的模块,最好单独写个模块"><a href="#5-对于形如一致的模块,最好单独写个模块" class="headerlink" title="5. 对于形如一致的模块,最好单独写个模块"></a>5. 对于形如一致的模块,最好单独写个模块</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="built_in">let</span> firstModal = <span class="literal">true</span>;</span><br><span class="line"> this.modal = (options) =>{</span><br><span class="line"> options = $.extend(<span class="literal">true</span>,{</span><br><span class="line"> <span class="built_in">type</span>: ``,</span><br><span class="line"> delay: 100,</span><br><span class="line"> head: ``,</span><br><span class="line"> body: ``,</span><br><span class="line"> txtCancel: `取 消`,</span><br><span class="line"> txtConfirm: `确 认`,</span><br><span class="line"> onCancle: () =>{</span><br><span class="line"> $(<span class="string">'.js-modal'</span>).removeClass(<span class="string">'show'</span>);</span><br><span class="line"> },</span><br><span class="line"> onConfirm: ()=>{</span><br><span class="line"></span><br><span class="line"> },</span><br><span class="line"> },options);</span><br><span class="line"> setTimeout( ()=>{</span><br><span class="line"> $(<span class="string">'.js-modal'</span>).addClass(<span class="string">'show'</span>);</span><br><span class="line"> $(<span class="string">'.js-modal .js-image-share'</span>) && $(<span class="string">'.js-modal .js-image-share'</span>).attr(<span class="string">'src'</span>, this.image.share || <span class="string">''</span>);</span><br><span class="line"> },options.delay);</span><br><span class="line"> <span class="keyword">if</span> (options.type === <span class="string">'fb'</span>){</span><br><span class="line"> $(<span class="string">'.js-modal .js-head'</span>).addClass(<span class="string">'fb'</span>);</span><br><span class="line"> }</span><br><span class="line"> $(<span class="string">'.js-modal .js-head'</span>).text(options.head);</span><br><span class="line"> $(<span class="string">'.js-modal .js-body'</span>).html(options.body);</span><br><span class="line"> $(<span class="string">'.js-modal .js-cancel'</span>).text(options.txtCancel);</span><br><span class="line"> $(<span class="string">'.js-modal .js-confirm'</span>).text(options.txtConfirm);</span><br><span class="line"> <span class="keyword">if</span> (firstModal){</span><br><span class="line"> $(<span class="string">'.js-modal'</span>).off().on(<span class="string">'tap'</span>, (event) => {</span><br><span class="line"> <span class="built_in">let</span> target = event.target.dataset.target;</span><br><span class="line"> switch (target) {</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'cancel'</span>:</span><br><span class="line"> options.onCancle();</span><br><span class="line"> <span class="built_in">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="string">'confirm'</span>:</span><br><span class="line"> options.onConfirm();</span><br><span class="line"> <span class="built_in">break</span>;</span><br><span class="line"> default:</span><br><span class="line"> <span class="built_in">break</span>;</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><h3 id="6-可以自己单独扩展模块"><a href="#6-可以自己单独扩展模块" class="headerlink" title="6. 可以自己单独扩展模块"></a>6. 可以自己单独扩展模块</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="built_in">export</span> default {</span><br><span class="line"> name: <span class="string">'_share_'</span>,</span><br><span class="line"> main: Share,</span><br><span class="line"> <span class="function"><span class="title">init</span></span>() {</span><br><span class="line"> this.<span class="variable">$share</span> = new this._share_(this.options.shareData, this);</span><br><span class="line"> this.<span class="variable">$webShare</span> = new WebShare();</span><br><span class="line"> this.setShare = data => {</span><br><span class="line"> this.<span class="variable">$share</span>.setShare(data);</span><br><span class="line"> this.<span class="variable">$webShare</span>.setShare(data);</span><br><span class="line"> };</span><br><span class="line"> },</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="function"><span class="title">WebShare</span></span>() {</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">WebShare.prototype.setShare = <span class="keyword">function</span> (data) {</span><br><span class="line"></span><br><span class="line"> this.data = $.extend(<span class="literal">true</span>, {</span><br><span class="line"> title: <span class="string">''</span>,</span><br><span class="line"> imageUrl: <span class="string">''</span>,</span><br><span class="line"> description: <span class="string">''</span>,</span><br><span class="line"> link: <span class="string">''</span>,</span><br><span class="line"> copydata: <span class="string">''</span>,</span><br><span class="line"> }, data);</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h3 id="6-facebook带图片分享问题"><a href="#6-facebook带图片分享问题" class="headerlink" title="6. facebook带图片分享问题"></a>6. facebook带图片分享问题</h3><p>使用后端返回链接<a href="http://makeup.sea.channet.com/expre/lancome/handle2" target="_blank" rel="noopener">http://makeup.sea.channet.com/expre/lancome/handle2</a><br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">//http://makeup.sea.channet.com/expre/lancome/handle2</span><br><span class="line"></span><br><span class="line"><!DOCTYPE html></span><br><span class="line"><html lang=<span class="string">"zh-cn"</span>></span><br><span class="line"><head></span><br><span class="line"> <meta charset=<span class="string">"UTF-8"</span>></span><br><span class="line"> <title>Lancôme邀您即時製作唇色美照</title></span><br><span class="line"> <meta content=<span class="string">"width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0"</span> name=<span class="string">"viewport"</span>></span><br><span class="line"> <meta http-equiv=<span class="string">"X-UA-Compatible"</span> content=<span class="string">"IE=edge,chrome=1"</span>></span><br><span class="line"> <meta name=<span class="string">"format-detection"</span> content=<span class="string">"telephone=no"</span>></span><br><span class="line"> <meta property=<span class="string">"fb:app_id"</span> content=<span class="string">"344854949231285"</span>></span><br><span class="line"> <meta property=<span class="string">"og:image"</span> content=<span class="string">""</span>></span><br><span class="line"> <meta property=<span class="string">"og:title"</span> content=<span class="string">"一按擁有 您的瑰麗唇色美照"</span>></span><br><span class="line"> <meta property=<span class="string">"og:type"</span> content=<span class="string">"website"</span>></span><br><span class="line"> <meta property=<span class="string">"og:url"</span> content=<span class="string">"http://makeup.sea.channet.com/expre/lancome/handle2?imageurl="</span>></span><br><span class="line"> </head></span><br><span class="line"> <body></span><br><span class="line"> <script></span><br><span class="line"> (<span class="function"><span class="title">function</span></span> () {</span><br><span class="line"> location.href = <span class="string">"http://makeup.sea.channet.com/lancome/hk"</span>;</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><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">WebShare.prototype.facebook = <span class="keyword">function</span> (callback) {</span><br><span class="line"> // FB.ui({</span><br><span class="line"> // method: <span class="string">'share'</span>,</span><br><span class="line"> // mobile_iframe: <span class="literal">true</span>,</span><br><span class="line"> // href: getHomePage(),</span><br><span class="line"> // name: this.data.title,</span><br><span class="line"> // display: <span class="string">'popup'</span>,</span><br><span class="line"> // description: ``,</span><br><span class="line"> // picture: this.data.pic,</span><br><span class="line"> // frictionlessRequests: <span class="string">'false'</span>,</span><br><span class="line"> // hashtag: this.data.hashtag,</span><br><span class="line"> // }, <span class="keyword">function</span> (response) {</span><br><span class="line"> // console.log(response);</span><br><span class="line"> // });</span><br><span class="line"> const data = {</span><br><span class="line"> appID: <span class="string">'201122177111171'</span>,</span><br><span class="line"> href: getURL(this.data.pic),</span><br><span class="line"> hashtag: this.data.hashtag,</span><br><span class="line"> };</span><br><span class="line"> window.open([</span><br><span class="line"> <span class="string">'https://www.facebook.com/v2.10/dialog/share?'</span>,</span><br><span class="line"> <span class="string">'href='</span> + encodeURIComponent(data.href),</span><br><span class="line"> <span class="string">'&app_id='</span> + data.appID,</span><br><span class="line"> <span class="string">'&hashtag='</span> + encodeURIComponent(data.hashtag),</span><br><span class="line"> ].join(<span class="string">''</span>), <span class="string">'newwindow'</span>, <span class="string">'toolbar=no, menubar=no, scrollbars=yes, resizable=no, location=no, status=no'</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">function</span> getURL(imageURL) {</span><br><span class="line"> <span class="built_in">return</span> <span class="string">'http://makeup.sea.channet.com/expre/lancome/handle2?imageurl='</span> + encodeURIComponent(imageURL);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> callback && callback(this.data);</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h3 id="7-weibo分享问题"><a href="#7-weibo分享问题" class="headerlink" title="7. weibo分享问题"></a>7. weibo分享问题</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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">WebShare.prototype.weibo = <span class="function"><span class="title">function</span></span> () {</span><br><span class="line"> const shareData = {</span><br><span class="line"> title: this.data.title,</span><br><span class="line"> pic: this.data.pic,</span><br><span class="line"> url: this.data.url,</span><br><span class="line"> // appkey: <span class="string">'1895078391'</span>,</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> // encode url</span><br><span class="line"> shareData.title = encodeURIComponent(shareData.title);</span><br><span class="line"> shareData.url = encodeURIComponent(shareData.url);</span><br><span class="line"> // shareData.pic = encodeURIComponent(shareData.pic);</span><br><span class="line"></span><br><span class="line"> // location.href = `http://v.t.sina.com.cn/share/share.php?<span class="variable">${querify(shareData)}</span>`;</span><br><span class="line"> window.open(`http://v.t.sina.com.cn/share/share.php?<span class="variable">${querify(shareData)}</span>`);</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h3 id="8-复制面板"><a href="#8-复制面板" class="headerlink" title="8. 复制面板"></a>8. 复制面板</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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">import CB from <span class="string">'clipboard'</span>;</span><br><span class="line"></span><br><span class="line">WebShare.prototype.copy = <span class="keyword">function</span> (data) {</span><br><span class="line"> new CB(<span class="string">'body'</span>,{</span><br><span class="line"> text: () => {</span><br><span class="line"> <span class="built_in">return</span> data;</span><br><span class="line"> },</span><br><span class="line"> });</span><br><span class="line">};</span><br></pre></td></tr></table></figure><h3 id="9-事件绑定最好绑定一次,写在Once中"><a href="#9-事件绑定最好绑定一次,写在Once中" class="headerlink" title="9. 事件绑定最好绑定一次,写在Once中"></a>9. 事件绑定最好绑定一次,写在Once中</h3><h3 id="10-在ios的safari中,transition和animation同时使用可能会出问题"><a href="#10-在ios的safari中,transition和animation同时使用可能会出问题" class="headerlink" title="10. 在ios的safari中,transition和animation同时使用可能会出问题"></a>10. 在ios的safari中,transition和animation同时使用可能会出问题</h3><h3 id="11-唤起app的情况,ios用window-location-href的方式唤起比较合适,Android用iframe唤起比较合适。"><a href="#11-唤起app的情况,ios用window-location-href的方式唤起比较合适,Android用iframe唤起比较合适。" class="headerlink" title="11. 唤起app的情况,ios用window.location.href的方式唤起比较合适,Android用iframe唤起比较合适。"></a>11. 唤起app的情况,ios用window.location.href的方式唤起比较合适,Android用iframe唤起比较合适。</h3><h3 id="12-使用’mcanvas’放大缩小问题"><a href="#12-使用’mcanvas’放大缩小问题" class="headerlink" title="12. 使用’mcanvas’放大缩小问题;"></a>12. 使用’mcanvas’放大缩小问题;</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">竖</span><br><span class="line">mc.add(image, {</span><br><span class="line"> width: <span class="string">'100%'</span>,</span><br><span class="line"> pos: {</span><br><span class="line"> // x: (-disX + (app.canvasLeft * rateH)),</span><br><span class="line"> x: (app.canvasLeft * rateW),</span><br><span class="line"> y: (app.canvasTop * rateW),</span><br><span class="line"> scale: app.canvasScale,</span><br><span class="line"> rotate: 0,</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">mc.add(image, {</span><br><span class="line"> width: image.width * (750 / image.height),</span><br><span class="line"> pos: {</span><br><span class="line"> x: (app.canvasLeft * rateH),</span><br><span class="line"> y: (app.canvasTop * rateH),</span><br><span class="line"> // x: 0,</span><br><span class="line"> // y: 0,</span><br><span class="line"> scale: app.canvasScale,</span><br><span class="line"> rotate: 0,</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>]]></content>
<categories>
<category> 渣技术 </category>
</categories>
<tags>
<tag> 美图 </tag>
<tag> H5项目 </tag>
</tags>
</entry>
<entry>
<title>美图H5项目总结--bplus_halloween</title>
<link href="/meitu-item-two.html"/>
<content type="html"><![CDATA[<p>昨天对项目m8s_strut做了个小结(详见=><a href="https://blog.huangmingzhao.cn/meitu-item-one.html" target="_blank" rel="noopener">m8s_strut</a>),今天就继续对项目二bplus_halloween做个总结吧,嘿嘿…技术很渣,看官勿喷。。</p><a id="more"></a><p>这个项目是海外版的,接到项目他们说B+,B+,听不懂B+是什么东西,哈哈,后来才知道原来B+是美图海外版的一个App–BeautyPlus。这个项目是多语言版本,突然就不知道多语言怎么处理,问了伟程师傅说直接在url后面加参数,在代码中直接获取,哈哈,原来是这样处理多语言哈~~</p><h2 id="开发中"><a href="#开发中" class="headerlink" title="开发中"></a>开发中</h2><h3 id="1-各个字体大小不一致问题"><a href="#1-各个字体大小不一致问题" class="headerlink" title="1. 各个字体大小不一致问题"></a>1. 各个字体大小不一致问题</h3><p>各个字体大小不一致忘记考虑了,而是直接统一设置字体大小,导致各文案显示有点奇怪。这个问题应该开发的时候就应该注意到,以至于在测试的时候花了不少时间去调一些字体细节问题。谨以此为记,希望下次能够有所优化。</p><p><strong>解决:</strong> 不同的文案字体应该要不同处理</p><h3 id="2-文案间歇性滚动"><a href="#2-文案间歇性滚动" class="headerlink" title="2. 文案间歇性滚动"></a>2. 文案间歇性滚动</h3><p>文案的间歇性滚动之前想用CSS3来处理,后来发现处理不了间歇性,就改用了js来处理。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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 timer=setInterval(<span class="function"><span class="title">function</span></span> () {</span><br><span class="line"> <span class="keyword">if</span> (scrollVal < <span class="variable">$wrapDis</span>){</span><br><span class="line"> scrollUp()</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> clearInterval(timer)</span><br><span class="line"> }</span><br><span class="line"> },50);</span><br><span class="line"> </span><br><span class="line"><span class="keyword">function</span> <span class="function"><span class="title">scrollUp</span></span>(){</span><br><span class="line"> <span class="keyword">if</span>(scrollVal % <span class="variable">$pHeight</span> === 0){</span><br><span class="line"> clearInterval(timer)</span><br><span class="line"> setTimeout(startScroll,2000);</span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> scrollVal++</span><br><span class="line"> // scrollEle.style.transform=`translateY(-<span class="variable">${scrollVal}</span>px)`</span><br><span class="line"> scrollEle.style.marginTop=`-<span class="variable">${scrollVal}</span>px`</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">setTimeout(startScroll,4000)</span><br></pre></td></tr></table></figure><p>在苹果5中之前用的transform来处理滚动处理不了,改为marginTop就可以,所以就索性用marginTop来,虽然它会一直的回流和重绘性能不好,CSS3动画可以开启硬件加速。</p><h3 id="3-需求变动,文案滚动完,可以先上查看"><a href="#3-需求变动,文案滚动完,可以先上查看" class="headerlink" title="3. 需求变动,文案滚动完,可以先上查看"></a>3. 需求变动,文案滚动完,可以先上查看</h3><p><strong>解决:</strong> </p><p>在内容的父元素上设置<br><figure class="highlight bash"><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">max-height: 50px; /*no*/</span><br><span class="line">overflow-y:scroll;</span><br></pre></td></tr></table></figure></p><p>在内容元素上不设置高度,自动撑开</p><p>为了使内容可以滚动,在滚动结束的时候瞬间给内容元素移除掉style属性,给父元素加上scrollTop,scrollTop为他滚动的多少即marginTop的值,这样便可滚动,最终代码如下</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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></pre></td><td class="code"><pre><span class="line">var timer=setInterval(<span class="function"><span class="title">function</span></span> () {</span><br><span class="line"> <span class="keyword">if</span> (scrollVal < <span class="variable">$wrapDis</span>){</span><br><span class="line"> scrollUp()</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> </span><br><span class="line"> //结束时内容元素移除掉style属性</span><br><span class="line"> $(<span class="string">'.js-home-word-wrap'</span>).removeAttr(<span class="string">'style'</span>)</span><br><span class="line"> //父元素加上scrollTop</span><br><span class="line"> $(<span class="string">'.js-home-word'</span>)[0].scrollTop = <span class="variable">$wrapDis</span></span><br><span class="line"> clearInterval(timer)</span><br><span class="line"> }</span><br><span class="line"> },50);</span><br><span class="line"> </span><br><span class="line"><span class="keyword">function</span> <span class="function"><span class="title">scrollUp</span></span>(){</span><br><span class="line"> <span class="keyword">if</span>(scrollVal % <span class="variable">$pHeight</span> === 0){</span><br><span class="line"> clearInterval(timer)</span><br><span class="line"> setTimeout(startScroll,2000);</span><br><span class="line"> }<span class="keyword">else</span>{</span><br><span class="line"> scrollVal++</span><br><span class="line"> // scrollEle.style.transform=`translateY(-<span class="variable">${scrollVal}</span>px)`</span><br><span class="line"> scrollEle.style.marginTop=`-<span class="variable">${scrollVal}</span>px`</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">setTimeout(startScroll,4000)</span><br></pre></td></tr></table></figure><h2 id="测试中的问题"><a href="#测试中的问题" class="headerlink" title="测试中的问题"></a>测试中的问题</h2><h3 id="1-ios中客户端facebook机制会吊起facebook客户端主页,分享完毕后屏幕变空白"><a href="#1-ios中客户端facebook机制会吊起facebook客户端主页,分享完毕后屏幕变空白" class="headerlink" title="1. ios中客户端facebook机制会吊起facebook客户端主页,分享完毕后屏幕变空白"></a>1. ios中客户端facebook机制会吊起facebook客户端主页,分享完毕后屏幕变空白</h3><p>facebook分享<a href="https://developers.facebook.com/docs/sharing/reference/share-dialog" target="_blank" rel="noopener">facebook分享链接</a></p><p><strong>解决:</strong></p><p>在末尾添加初始化脚本<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><script></span><br><span class="line"> //初始化FB,appid要去申请</span><br><span class="line"> window.fbAsyncInit = <span class="function"><span class="title">function</span></span>() {</span><br><span class="line"> FB.init({</span><br><span class="line">// appId : <span class="string">'2052125608344073'</span>,</span><br><span class="line"> appId: <span class="string">'928616713878249'</span>,</span><br><span class="line"> autoLogAppEvents : <span class="literal">true</span>,</span><br><span class="line"> xfbml : <span class="literal">true</span>,</span><br><span class="line"> version : <span class="string">'v2.10'</span></span><br><span class="line"> });</span><br><span class="line"> FB.AppEvents.logPageView();</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> //载入facebook网页JavaScript版分享机制sdk</span><br><span class="line"> (<span class="keyword">function</span>(d, s, id){</span><br><span class="line"> var js, fjs = d.getElementsByTagName(s)[0];</span><br><span class="line"> <span class="keyword">if</span> (d.getElementById(id)) {<span class="built_in">return</span>;}</span><br><span class="line"> js = d.createElement(s); js.id = id;</span><br><span class="line"> js.src = <span class="string">"//connect.facebook.net/en_US/sdk.js"</span>;</span><br><span class="line"> fjs.parentNode.insertBefore(js, fjs);</span><br><span class="line"> }(document, <span class="string">'script'</span>, <span class="string">'facebook-jssdk'</span>));</span><br><span class="line"></script></span><br></pre></td></tr></table></figure></p><p>需要的地方调用FB.UI<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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">FB.ui({</span><br><span class="line"> //默认调用的是网页page形式,使他形式为dialog形式</span><br><span class="line"> method: <span class="string">'share'</span>,</span><br><span class="line"> mobile_iframe: <span class="literal">true</span>,</span><br><span class="line"> href: `<span class="variable">${u}</span>`,</span><br><span class="line"> name: textVal.titleText[lang],</span><br><span class="line"> display: <span class="string">'popup'</span>,</span><br><span class="line"> description: textVal.titleText[lang],</span><br><span class="line"> picture: <span class="string">''</span>,</span><br><span class="line"> frictionlessRequests: <span class="string">'false'</span></span><br><span class="line"> }, <span class="keyword">function</span> (response) {</span><br><span class="line"> <span class="built_in">let</span> reloadURL=u = getHomePage() + <span class="string">'?lang='</span> +lang + <span class="string">'#num='</span> + pageNum + <span class="string">'&page=result'</span></span><br><span class="line"> location.href=`<span class="variable">${reloadURL}</span>`</span><br><span class="line"> });</span><br></pre></td></tr></table></figure></p><p>今晚问了同事说ios中facebook分享后是白屏的问题,定位到了问题所在,但还是不能解决,记得之前他跟师傅谈论的时候好像可以解决,改天问问看。(之后再做补充…)</p><h2 id="结尾"><a href="#结尾" class="headerlink" title="结尾"></a>结尾</h2><p>这个项目相对没什么逻辑,不过我还是花了挺长时间,啊啊啊啊,感觉很不应该啦~。这个项目感觉大部分时间都在文案的修改上面,挺坑的说实话,文案没有一次性给好,陆续给就算了还各种变动,嘿嘿,算是小吐槽吧,不过这个项目让我跟设计跟产品有了交流的机会,也慢慢的明白开发中应该要注意些,像沟通呀,不要一开始拿到psd就开始切,刚开始就要多沟通,不然会做很多无用功。代码写的还不是很规范,希望接下来可以有所改进啦。明天要去参加新员工训练营,不知道怎么样,今天就这样吧~嘿,睡觉咯······· </p><p> 于 厦门前埔 自己的小屋 </p><p>本文首发于个人博客 >> <a href="http://www.huangmingzhao.cn/">黄明照–一个在路上慢慢行走的前端人</a></p>]]></content>
<categories>
<category> 渣技术 </category>
</categories>
<tags>
<tag> 美图 </tag>
<tag> H5项目 </tag>
</tags>
</entry>
<entry>
<title>美图H5项目总结--m8s_strut</title>
<link href="/meitu-item-one.html"/>
<content type="html"><![CDATA[<p>来美图实习也一个月了~从校招之后可能有点放松过头,导致与最近感觉把学习给放一边了,前几天对校招做了个总结(详见=><a href="https://blog.huangmingzhao.cn/autumn-recruit-Interview.html" target="_blank" rel="noopener">秋招面试总结</a>),所以最近要好好的收拾下心态,继续勤勤恳恳在前端路探索,接下来会对每个项目做一个总结,嘿嘿…技术很渣,看官勿喷。。</p><a id="more"></a><p>在美图的第一个小项目(<a href="http://h5.meitu.com/m8s_strut/" target="_blank" rel="noopener">请移动端模式观看哦~</a>),一上线还是出现了挺多bug。嘿嘿。。虽然有点那个什么,大家凑合着玩哈,写项目总结是想把工作中遇到的问题和解决方法整理一下,记录记录。</p><h2 id="开发中的问题"><a href="#开发中的问题" class="headerlink" title="开发中的问题"></a>开发中的问题</h2><p>H5框架用的是公司自己的mapp框架,刚进公司的时候就看mapp的文档,有点vue的味道~~</p><h3 id="1-canvas"><a href="#1-canvas" class="headerlink" title="1. canvas"></a>1. canvas</h3><p>之前并没有多大的接触到canvas,伟程师傅给我做的时候,我说不太会,好尴尬~,因为项目中的一个需求就是要在一张图片中合成字体,所以用到canvas,感觉公司h5项目都会用到canvas。上传图片到服务器之类直接调用公司的Upload组件</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line">var canvas = document.getElementById(<span class="string">'js-canvas'</span>)</span><br><span class="line"></span><br><span class="line">//getContext() 方法返回一个用于在画布上绘图的环境上下文。</span><br><span class="line">var ctx = canvas.getContext(<span class="string">'2d'</span>);</span><br><span class="line"></span><br><span class="line">//创建一个image对象</span><br><span class="line">var poster = new Image();</span><br><span class="line"></span><br><span class="line">//设置跨域</span><br><span class="line">//并不是说 canvas 使用的 image 不能跨域,而是说 canvas 使用了没有权限的跨域图片,在使用 canvas.toDataURL()等数据导出函数的时候会报错!</span><br><span class="line">poster.crossOrigin = <span class="string">"anonymous"</span>;</span><br><span class="line"></span><br><span class="line">//预加载图片</span><br><span class="line">poster.onload = () => { </span><br><span class="line"> //drawImage() 方法在画布上绘制图像 context.drawImage(img,x,y,width,height); xy为图片在画布的位置,wh是图片的宽高</span><br><span class="line"> ctx.drawImage(poster,0,0,750,1000); </span><br><span class="line"> ctx.font = <span class="string">"normal 24px webfont"</span>; </span><br><span class="line"> ctx.fillStyle = <span class="string">"#3d2a2a"</span>; </span><br><span class="line"> </span><br><span class="line"> //fillText() 方法在画布上绘制填色的文本。 context.fillText(text,x,y,maxWidth);</span><br><span class="line"> ctx.fillText(array[0], 300, 556) </span><br><span class="line"> ctx.fillText(array[1], 300,586) </span><br><span class="line"> </span><br><span class="line"> //toDataURL() 方法返回一个包含图片展示的 data URI 返回base64 第二个参数是0-1的图片质量</span><br><span class="line"> var base64 = canvas.toDataURL(<span class="string">"image/jpeg"</span>,0.8); </span><br><span class="line"> </span><br><span class="line"> //使用公司的upload组件,上传到七牛云</span><br><span class="line"> var upload = new Up({width : 600,}); </span><br><span class="line"> //传入base64图片</span><br><span class="line"> upload.up(base64, {</span><br><span class="line"> //成功时的回调</span><br><span class="line"> success(data) { </span><br><span class="line"> //data.img是返回线上的图片链接</span><br><span class="line"> app.preload(data.img).<span class="keyword">done</span>(() => { </span><br><span class="line"> console.log(data.img); </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"> error(data) { </span><br><span class="line"> console.log(<span class="string">'合成上传失败!'</span>); </span><br><span class="line"> </span><br><span class="line"> }, </span><br><span class="line"> })</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">poster.src = <span class="string">'dist/images/poster.jpg'</span>;</span><br></pre></td></tr></table></figure><h2 id="测试中的问题"><a href="#测试中的问题" class="headerlink" title="测试中的问题"></a>测试中的问题</h2><h3 id="1-在T8中,一键生成跳不过去,别的手机又是正常的"><a href="#1-在T8中,一键生成跳不过去,别的手机又是正常的" class="headerlink" title="1. 在T8中,一键生成跳不过去,别的手机又是正常的"></a>1. 在T8中,一键生成跳不过去,别的手机又是正常的</h3><p>这里洪卿大哥安利了一个在移动端调试小工具 <a href="http://h5.meitu.com/js/console.min.js" target="_blank" rel="noopener">http://h5.meitu.com/js/console.min.js</a></p><p><strong>解决:</strong> 一步步排查,原来是 </p><figure class="highlight bash"><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">var base64 = canvas.toDataURL(<span class="string">"image/jpg"</span>,0.8); //这边出错了,第一个参数的类型写错了并没有jpg类型,应该为jpeg,所以正确代码如下:</span><br><span class="line"></span><br><span class="line">var base64 = canvas.toDataURL(<span class="string">"image/jpeg"</span>,0.8);</span><br></pre></td></tr></table></figure><h3 id="2-用户保存图片时把背景保存下来"><a href="#2-用户保存图片时把背景保存下来" class="headerlink" title="2. 用户保存图片时把背景保存下来"></a>2. 用户保存图片时把背景保存下来</h3><p><strong>解决:</strong> 由于第一个项目的图片较少,自己之前也没注意到这个问题,就是在移动端中长按会保存img标签的图片,而我为了省事正好把有用到的图片全给用了img标签,测试尽然没测出来,上线用户一体验就出现bug,啊啊啊啊~ </p><p>所以正确的做法是,希望让用户保存的图片用img标签例如结果页,而像每页的背景图片什么的最好说在css中设置background-image</p><h3 id="3-使用backgroud-size-cover的问题"><a href="#3-使用backgroud-size-cover的问题" class="headerlink" title="3. 使用backgroud-size:cover的问题"></a>3. 使用backgroud-size:cover的问题</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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">background-size:100% auto; ---按容器比例撑满,图片变形;因为是移动端所以height为auto自动调整就好,只填第一个参数第二参数默认为auto</span><br><span class="line"></span><br><span class="line">background-size:cover; ---把背景图像扩展至足够大,以使背景图像完全覆盖背景区域。背景图像的某些部分也许无法显示在背景定位区域中。</span><br><span class="line"></span><br><span class="line">background-size:contain; ---把图像图像扩展至最大尺寸,以使其宽度和高度完全适应内容区域。</span><br></pre></td></tr></table></figure><h3 id="4-在ios系统中,输入框输入完成后,跳转页面之后,输入面板还在"><a href="#4-在ios系统中,输入框输入完成后,跳转页面之后,输入面板还在" class="headerlink" title="4. 在ios系统中,输入框输入完成后,跳转页面之后,输入面板还在"></a>4. 在ios系统中,输入框输入完成后,跳转页面之后,输入面板还在</h3><p><strong>解决:</strong> $(‘.js-text’).blur() 手动去焦点</p><h2 id="结尾"><a href="#结尾" class="headerlink" title="结尾"></a>结尾</h2><p> 第一次参加公司的开发,感觉做点有点不足,程序上是一方面,感觉沟通也存在不足,不会先做好沟通再写代码,而是一拿到psd就开始切,写代码,以至于有时候会做一些无用功,这是我站在面前完成两个项目的情况下思考这个问题(第一个项目比较简单可能没什么发现,第二个项目就非常明显),所以还是要先好好沟通完之后,再下手。才发现一个项目下来沟通真的至关重要,跟运营跟测试等等,这可能也是做开发有趣的一面。公司人才好多哦~,在里面自己真的是渣渣,努力吧,嘿嘿…相信勤能补拙。有空想看看公司一些组件的源码,感觉我这个层次的会看不懂,扎心·······再说说公司的氛围吧,同事都挺好玩的,互相调侃,哈哈,喜欢这样的氛围,一个月下来还是感觉还没有适应似的,跟大家也还不太熟悉,希望在接下来的日子可以用心对待,对人对事!加油,实习生!!!(顺便说下我喜欢的冬天快到了,哈哈哈哈哈哈…………….) </p><blockquote><p>不知道说什么 加油 ٩(๑❛ᴗ❛๑)۶</p></blockquote><p> 于 厦门前埔 自己的小屋 </p><p>本文首发于个人博客 >> <a href="http://www.huangmingzhao.cn/">黄明照–一个在路上慢慢行走的前端人</a></p>]]></content>
<categories>
<category> 渣技术 </category>
</categories>
<tags>
<tag> 美图 </tag>
<tag> H5项目 </tag>
</tags>
</entry>
<entry>
<title>秋招面试总结</title>
<link href="/autumn-recruit-Interview.html"/>
<content type="html"><![CDATA[<p>感觉秋招也结束了,在美图也一个月了。从拿到美图offer的时候就想说对秋招做个总结,苦于自己太懒了。可能也是因为准备秋招的那段时间对我来说有点煎熬,导致于到目前为止自己还在一个放松的状态,放松的有点过头了,没有集中注意力在技术方面。今天伟程师傅说项目做完要好好总结,才发现自己也要该好好醒醒了。好了,言归正题,对秋招也好好做个总结。</p><a id="more"></a><p>秋招,在别人眼中对于我来说可能是种幸运,但幸运当中不免有太多为此付出的艰辛,期间的苦可能也就自己知道。个人秋招面试倒不是很多家,总共面试四家。</p><h2 id="网宿"><a href="#网宿" class="headerlink" title="网宿"></a>网宿</h2><p>网宿是内推后通知面试,网宿的面试是我人生的第一场面试,自己感觉对前端方面准备的挺充分过去面试,然后呢,网宿的面试时长是十分钟!!十分钟!!!!我超级不能理解哦,人生第一场面试尽然是十分钟,面完整个人都懵了,不是技术面不都一两个小时吗?由于时间隔得比较久,所以接下来的面试题可能会说个大概~~</p><h3 id="面试题目"><a href="#面试题目" class="headerlink" title="面试题目"></a>面试题目</h3><p><strong>1. 自我介绍</strong></p><p><strong>2. JavaScript的同步和异步</strong></p><p><strong>3. 问到操作系统的信号什么的没听清楚(事后想想可能是pv操作和信号量)</strong></p><p><strong>4. ajax如何实现同步</strong></p><p><strong>5. 算法,除了选择冒泡插入说出一两个别的</strong></p><p><strong>6. 闭包</strong></p><p><strong>7. vue和Angular的区别</strong></p><p><strong>8. mvc和mvvm</strong></p><p><strong>9. 有什么要问的</strong></p><p><strong>10. 等通知</strong></p><p>网宿尽然没有现场笔试,总体面试下来就十分钟,我也不知道是什么原因,期间问到的操作系统早就还给老师了,准备面试的时候我就专门准备前端方向,哭死,,还有就是个人感觉快速排序讲的挺好的,他感觉还不是很满意,幸好后来我有补充了归并排序,他感觉还行。其他有关于js的个人感觉回答的还行,之后就说hr今天不在,回去等通知。事后问内推的人,说面试官有对他说对我印象还不错。网宿可能就是hr都跑去校招宣讲会现场了,一周之内一直没有消息~由于第一次面试就十分钟,对我个人的打击还是蛮大的,压力那时确实挺大。。(后来进美图了,有跟内推的人说进美图了,所以到目前也没有收到网宿的消息)</p><h2 id="美图"><a href="#美图" class="headerlink" title="美图"></a>美图</h2><p>美图是我校招的重点,由于自己想留在福建,自己求学又在厦门,所以美图算是求职最中意的企业。网宿之后其实自己也有去面试两家相对小点的企业,刷面筋,为美图的面试做准备。美图也是内推的,所以个人没有在线上笔试过,但是美团自己有在线上笔试过,美团厦门感觉速度很慢啊,上周才邀请面试,那时候在美图实习都快一个月了,想想还是有点可惜。</p><h3 id="现场笔试题"><a href="#现场笔试题" class="headerlink" title="现场笔试题"></a>现场笔试题</h3><p><strong>1. 不定宽高水平居中</strong></p><p><strong>2. typeof 结合 == 写出结果(几小道)</strong></p><p><strong>3. 彩色图片利用js或css实现黑白</strong></p><p><strong>4. 怎样适配移动端</strong></p><p><strong>5. 图片预加载(代码补充)</strong></p><p><strong>6. 一题settimeout和function结合,写出输出什么</strong></p><p><strong>7. 写代码,事件委托</strong></p><p><strong>8. 写自己的技术栈</strong></p><h4 id="一面"><a href="#一面" class="headerlink" title="一面"></a>一面</h4><p>笔试做完给hr后,就来了现在大家人称细老师的面试官,哈哈哈…一面先是一道道解析笔试题,期间各种问法,啊啊啊,佩服细老师呀,问很多平常都不太注意的地方,又是基础的知识点,哎,渣渣就是这样子。一道道解析完题目后就根据简历问项目~~聊了很多,下面就列一些出来~自己当场回答不上来的下面有列出答案</p><p><strong>1. margin和padding百分比的时候是相对于谁来计算的</strong></p><p><strong>答:</strong> margin和padding百分比的时候相对于父元素的宽度计算的</p><p>①、相对于父元素宽度计算的有:width、left、right、margin、padding</p><p>②、相对于父元素高度计算的有:height、top、bottom</p><p><strong>2. rem和em相对于谁计算的</strong></p><p><strong>3. 条件判断转化问题</strong></p><p><strong>4. 正则实现类似ejs的<%= %></strong></p><p><strong>答:</strong> str.replace(/<%= \s<em>([^%>]+)\s</em> %>/g , str)</p><p><strong>5. 图片预加载的时候onload和img.src这两个位置怎么放合适</strong></p><p><strong>答:</strong> 在以前的时候图片预加载的时候onload要放在img.src前面,现在主流浏览器好像没这个硬性,但为了更好的写法,最好这样做</p><p><strong>6. 同源策略中一些注意点</strong></p><p><strong>7. express的核心是什么</strong></p><p><strong>答:</strong> 路由、中间件、模板引擎 (现在我也不知道是不是正确答案)</p><p><strong>8. webpack的核心是什么</strong></p><p><strong>答:</strong> 入口、出口、加载器、插件<br>(现在我也不知道是不是正确答案)</p><p><strong>9. Express和koa的区别在哪里,讲出点</strong></p><p><strong>10. 同步异步单线程</strong></p><p><strong>11. 实现类似promise的异步</strong></p><p><strong>12. 标签语义化的理解</strong></p><p><strong>13. 一个网页从url输入到展现的过程(经典题)</strong></p><p><strong>14. 状态码,各状态码对应的信息</strong></p><p><strong>15. 性能优化</strong></p><p><strong>16. ajax请求的几个状态</strong></p><p><strong>17. sessionStorage,localStorage和cookie的区别</strong></p><p><strong>18. 事件流的几个阶段</strong></p><p><strong>19. 数据结构和算法,自己知道多少讲多少</strong></p><p><strong>20. 数组去重</strong></p><p><strong>21. 操作数组的常见方法</strong></p><p><strong>22. 非es6中,哪种数据结构像集合</strong></p><p><strong>答:</strong> 对象,理由自己想</p><p>差不对就这些了,到时候有想到再做补充。一面有些写问题对我来说确实有点难,技术面面完后hr进来说面试官现在有点纠结,叫我回去等消息,我以为我跪了,坐在回去的公交上,那个心情惆怅的呀…不过幸好在晚上六点多的时候hr叫我周一再去二面(当时周五),不免又多了点希望,可能是我笔试做的比较好点吧,后面问题回答的相对比较好,所以细老师又给我机会,改天找细老师聊聊为什么还是给我机会了呢~~</p><h3 id="二面"><a href="#二面" class="headerlink" title="二面"></a>二面</h3><p>美图二面差不多问的比较简单点,更多的问项目的问题和如何去学习前端的~</p><p><strong>1. 跨域</strong></p><p><strong>2. vue生命周期</strong></p><p><strong>3. vue数据双向绑定原理</strong></p><p><strong>4. gulp插件</strong></p><p><strong>5. 性能优化(没错又问一遍)</strong></p><p><strong>……</strong></p><h3 id="hr面"><a href="#hr面" class="headerlink" title="hr面"></a>hr面</h3><p>到了hr面大家应该也明白了些什么…,哈哈~~~但是我那时还是不知道意味着什么,都是未知数,反正hr姐姐挺漂亮的,就聊聊心声咯~就列一个问题吧</p><p><strong>长这么大讲出三个对你影响最深的三个人</strong></p><p>其他的就各种聊咯~~后面说面试结果会尽快通知,第二天耐不住了,就私聊hr什么可以确定结果,然后她回说下午会发一个正式offer,哈哈哈,那时候开心到飞起~offer来了赶快发个朋友圈压压惊···</p><h2 id="其他公司"><a href="#其他公司" class="headerlink" title="其他公司"></a>其他公司</h2><p>其他公司就不列了吧,面试无非js是重点,js中的几座大山的原理一定要很熟悉,知道所以然。</p><ol><li>原型、原型链</li><li>作用域、作用域链</li><li>异步、单线程 ····</li></ol><h2 id="结尾"><a href="#结尾" class="headerlink" title="结尾"></a>结尾</h2><p>每次写文章都喜欢夜深写,现在凌晨1点。自己的校招说真的宣讲会什么都没去,自己提前就做好准备了,各个公司的宣讲会还没开始我就开始准备面试了。现在想想自己当初自己一个人租在一个小租出屋里,学习知识、找工作期间自己一个人的开心与难过都在那里度过,一个在这个城市感觉与世隔绝的地方,可能现在没什么机会会再去那个地方,但是有机会的话还是想回去看看,自己当初付出奋斗的地方。个人比较愚笨,但是自己感觉自己的一个最大的优点就是会比同龄人吃苦,勤能补拙吧。相信付出总有收获。就这样吧,又是人生的一个新起点,职业生涯中肯定会有各种酸甜苦辣,希望自己能够坚持,加油~~</p><blockquote><p>有志者、事竟成,破釜沉舟,百二秦关终属楚,</p></blockquote><blockquote><p>苦心人、天不负,卧薪尝胆,三千越甲可吞吴! </p></blockquote><p>于 厦门前埔 自己的小屋(搬了新家哦~) </p><p>本文首发于个人博客 >> <a href="http://www.huangmingzhao.cn/">黄明照–一个在路上慢慢行走的前端人</a></p>]]></content>
<categories>
<category> 渣技术 </category>
</categories>
<tags>
<tag> 秋招 </tag>
<tag> 面试 </tag>
</tags>
</entry>
<entry>
<title>pm2的使用</title>
<link href="/the-use-of-pm2.html"/>
<content type="html"><![CDATA[<p>大家是不是会遇到过node app,js 然后Ctrl+C 就挂了? 下面利用pm2永久保持进程。</p><a id="more"></a><h2 id="安装pm2"><a href="#安装pm2" class="headerlink" title="安装pm2"></a>安装pm2</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ npm install pm2 -g</span><br></pre></td></tr></table></figure><h3 id="这里需要补充一句,启动、删除、停止都可以用文件名或者进程id,推荐用进程id"><a href="#这里需要补充一句,启动、删除、停止都可以用文件名或者进程id,推荐用进程id" class="headerlink" title="这里需要补充一句,启动、删除、停止都可以用文件名或者进程id,推荐用进程id"></a>这里需要补充一句,启动、删除、停止都可以用文件名或者进程id,推荐用进程id</h3><h4 id="启动进程"><a href="#启动进程" class="headerlink" title="启动进程"></a>启动进程</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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">// 启动app.js, 启动之后会有一个进程ID, 下面id是1</span><br><span class="line">$ pm2 start app.js</span><br><span class="line">┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────┬───────────┬──────────┐</span><br><span class="line">│ App name │ id │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ watching │</span><br><span class="line">├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────┼───────────┼──────────┤</span><br><span class="line">│ app │ 1 │ fork │ 40047 │ online │ 0 │ 8s │ 0% │ 50.6 MB │ disabled │</span><br><span class="line">└──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────┴───────────┴──────────┘</span><br><span class="line"></span><br><span class="line">// 启动所有进程, 这个意思是你停止了进程之后可以启动所有。</span><br><span class="line">pm2 start all</span><br><span class="line"></span><br><span class="line">// 重新启动进程, 如果你修改了代码可以用这个命令,或者后面是你的想要重启的进程id</span><br><span class="line">pm2 restart all</span><br></pre></td></tr></table></figure><h4 id="停止进程"><a href="#停止进程" class="headerlink" title="停止进程"></a>停止进程</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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">// 只停止app.js</span><br><span class="line">pm2 stop app.js</span><br><span class="line"></span><br><span class="line">// 或者停止进程id, 当你启动的时候会有一个进程id</span><br><span class="line">pm2 stop 1</span><br><span class="line"></span><br><span class="line">// 停止所有进程</span><br><span class="line">pm2 stop all</span><br></pre></td></tr></table></figure><h4 id="删除进程"><a href="#删除进程" class="headerlink" title="删除进程"></a>删除进程</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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">// 当你启动进程或者停止进程,其实会在pm2 list里面,如果想要删除的话...</span><br><span class="line">pm2 delete 0</span><br><span class="line"></span><br><span class="line">// 删除所有</span><br><span class="line">pm2 delete all</span><br></pre></td></tr></table></figure><h4 id="显示进程列表"><a href="#显示进程列表" class="headerlink" title="显示进程列表"></a>显示进程列表</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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">pm2 list</span><br><span class="line"></span><br><span class="line">┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────┬───────────┬──────────┐</span><br><span class="line">│ App name │ id │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ watching │</span><br><span class="line">├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────┼───────────┼──────────┤</span><br><span class="line">│ app │ 0 │ fork │ 40188 │ online │ 0 │ 3s │ 0% │ 50.5 MB │ disabled │</span><br><span class="line">└──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────┴───────────┴──────────┘</span><br></pre></td></tr></table></figure><h4 id="监视每个进程的一些状况"><a href="#监视每个进程的一些状况" class="headerlink" title="监视每个进程的一些状况"></a>监视每个进程的一些状况</h4><figure class="highlight bash"><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">// 这个非常有用,用来查看node进程的一些运行时间,重启了几次</span><br><span class="line">// 可以看运行的文件路径,内存使用情况,是否出现内存泄露</span><br><span class="line">pm2 monit</span><br></pre></td></tr></table></figure><h4 id="查看日志情况"><a href="#查看日志情况" class="headerlink" title="查看日志情况"></a>查看日志情况</h4><figure class="highlight bash"><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">// 用于查看程序打印的日志, console.log();</span><br><span class="line">pm2 logs</span><br></pre></td></tr></table></figure><h4 id="0秒停机重载"><a href="#0秒停机重载" class="headerlink" title="0秒停机重载"></a>0秒停机重载</h4><figure class="highlight bash"><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">pm2 reload all</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> 渣技术 </category>
</categories>
<tags>
<tag> Node </tag>
<tag> pm2 </tag>
</tags>
</entry>
<entry>
<title>巩固JavaScript系列--01数据类型和函数</title>
<link href="/JavaScript01.html"/>
<content type="html"><![CDATA[<p>最近感觉校招也快到了,感觉自己的知识体系还是挺乱的,所以拿起了红宝书再仔细读读,对知识点再巩固巩固,想每次学习完对整体的一个知识点总结总结,写下了自己的JavaScript系列学习。</p><a id="more"></a><p>在开始写数据类型之前,想对<script>标签记下几点内容。</p><h2 id="script标签"><a href="#script标签" class="headerlink" title="script标签"></a>script标签</h2><p><script>有以下6个属性</p><ol><li><p>async:可选。表示应该立即下载脚本,但不妨碍页面中的其他操作,比如可以下载其他资源或等待加载其他脚本。只对外部脚本文件有效。</p></li><li><p>charset:可选。表示通过src属性指定的代码的字符集。由于大多数浏览器会忽略它的值,所有很少用</p></li><li><p>defer:可选。表示脚本可以延迟到文档完全被解析和显示之后再执行。只对外部文件有效。</p></li><li><p>language:已放弃。</p></li><li><p>src:可选。表示包含要执行的外部文件。</p></li><li><p>type:可选。表示编码使用的脚本语言的内容类型</p></li></ol><p>这里重点记下两个比较特殊的属性<strong>async和defer</strong>:</p><p>defer:设置defer的脚本会在整个页面都解析完毕之后再执行。</p><p>async:指定async属性的目的是不让页面等待其脚本下载和执行,从而异步加载页面的其他内容。</p><h2 id="数据类型"><a href="#数据类型" class="headerlink" title="数据类型"></a>数据类型</h2><p>ECMAScript中有5种简单的数据类型(也称为基本数据类型):<strong>Undefined、Null、Boolean、Number和String</strong>。</p><p>还有一种复杂数据类型:<strong>Object</strong>。Object本质是由一组无序的名值(键值)组成。</p><h3 id="1-Undefined类型"><a href="#1-Undefined类型" class="headerlink" title="1. Undefined类型"></a>1. Undefined类型</h3><p>Undefined类型的值就只有一个undefined。<br><figure class="highlight bash"><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 name;</span><br><span class="line">alert(name == undefined) //<span class="literal">true</span></span><br></pre></td></tr></table></figure></p><p>从上面可以看出,name只定义,未初始化。它的默认值为undefined。与下面代码一致。<br><figure class="highlight bash"><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 name=undefined;</span><br><span class="line">alert(name == undefined) //<span class="literal">true</span></span><br></pre></td></tr></table></figure></p><p>其实我们再没必要为它赋值undefined,因为它默认的值就是undefined。</p><h3 id="2-Null类型"><a href="#2-Null类型" class="headerlink" title="2. Null类型"></a>2. Null类型</h3><p>Null类型的值也只有一个,即null。从逻辑角度来看,null值表示一个空对象指针,这也是使用typeof操作符检测null值时会返回object类型的原因。<br><figure class="highlight bash"><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 people=null</span><br><span class="line">alert(typeof people) //object</span><br></pre></td></tr></table></figure></p><p><strong>如果定义的变量准备在将来用于保存对象,那么最好将该变量初始化为null而不是其他值(像默认的undefined)</strong></p><p><strong>undefined值是派生自null值的</strong>,因此下面代码返回的是true<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">alert(alert( null == undefined)) //<span class="literal">true</span></span><br></pre></td></tr></table></figure></p><p>但如果是全等操作的话,返回的是false<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">alert(alert( null === undefined)) //<span class="literal">false</span></span><br></pre></td></tr></table></figure></p><p><strong>无论什么时候都没有必要把一个变量的值显式的设置为undefined</strong>,可是同样的规则对应null却是不适用。换句话说,<strong>只要意在保存对象的变量还没有真正的保存对象,就应该为其设置null值</strong>。这样做的目的不仅体现null做为空对象指针的惯例,而且也有助于进一步区分null和undefined。这也是null和undefined的只要区别。</p><h3 id="3-Boolean类型"><a href="#3-Boolean类型" class="headerlink" title="3. Boolean类型"></a>3. Boolean类型</h3><p>Boolean类型有两个值即true和false。Boolean类型的知识点主要是下面这个:</p><p>可以对任何数据类型调用Boolean()函数,而且总会返回一个Boolean值。</p><p><strong>除了 0、-0、’’、NaN、null、undefined、false对其使用Boolean函数返回的是假(false),其余返回的是真(true)</strong></p><p>在流控制语句中(如if语句),它会自动执行相应的Boolean转换。请看下面代码:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><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 name=<span class="string">'hmz'</span>;</span><br><span class="line"><span class="keyword">if</span> (name){</span><br><span class="line"> alert(<span class="string">'my name is hmz'</span>) //my name is hmz</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>因为name被自动执行相应的Boolean转换,返回的是true</p><h3 id="4-Number类型"><a href="#4-Number类型" class="headerlink" title="4. Number类型"></a>4. Number类型</h3><ol><li><p>浮点数值: 浮点数值需要的内存空间是保存<strong>整数值的两倍</strong>,因此ECMAScript会不失时机地将浮点数值转换为整数值。浮点数值计算会<strong>产生舍入误差</strong>,比如0.1+0.2不会等于0.3,而是等于0.3000000…0004,所以千万不要使用以下代码,你会发现代码并不会去实现alert:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><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 a=0.1,b=0.2;</span><br><span class="line"><span class="keyword">if</span>(a+b == 0.3){ //不要做这样的测试</span><br><span class="line"> alert(<span class="string">'go this'</span>)</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li><li><p>数值范围: isFinite()函数在参数位于最大值(Number.MAX_VALUE)和最小值(Number.MIN_VALUE)之间会返回true。</p></li><li><p>NaN: NaN(Not a Number)是一个特殊的数值。NaN有两个特点①任何涉及NaN的操作都会返回NaN;②NaN跟任何值都不相等,包括他自己本身。</p></li></ol><p>根据NaN的两个特点ECMAScript定义了isNaN()函数。isNaN()函数传入的参数会被想转换为数值再判断,<strong>参数不会转换为数值的函数会返回true,否则函数会返回false</strong>。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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">alert(isNaN(NaN)) //<span class="literal">true</span> 不能被转换为数值</span><br><span class="line">alert(isNaN(10)) //<span class="literal">false</span> 10是数值</span><br><span class="line">alert(isNaN(<span class="string">'blue'</span>)) //<span class="literal">true</span> 不能被转换为数值</span><br><span class="line">alert(isNaN(<span class="string">'10'</span>)) //<span class="literal">false</span> <span class="string">'10'</span>会被转换为10</span><br><span class="line">alert(isNaN(<span class="literal">true</span>)) //<span class="literal">false</span> <span class="literal">true</span>会被转换为1</span><br></pre></td></tr></table></figure></p><ol><li>数值转换<br>可以转换为数值的函数有Number()、parseInt()、parseFloat()。Number()函数可以用于任何数据类型,而parseInt()和parseFloat()专门用于把字符串转换为数值。</li></ol><p>parseInt()转化为整数,可以传入第二个参数,告诉浏览器按几进制进行解析数据,如果不传第二个参数,默认是10进制<br>parseFloat()转化为浮点数,只解析整数,故没有第二个参数。</p><h3 id="5-String类型"><a href="#5-String类型" class="headerlink" title="5. String类型"></a>5. String类型</h3><p>转换为字符的函数有:toString()和String()。</p><p>toString():①数值、布尔、对象、字符串都有toString()方法。但是<strong>null和undefined</strong>没有toString()方法。②多数情况下,toString()方法不必传参,但也可以为其传一个参数,该参数可以将num.toString(2|8|10|16)返回几进制的字符串表示</p><p>String():在不知道要转换的值是不是undefined和null的情况下,还可以使用String()函数。这个函数能将任何类型的值转换为字符串。</p><h3 id="6-Object类型"><a href="#6-Object类型" class="headerlink" title="6. Object类型"></a>6. Object类型</h3><p>ECMAScript中的对象其实就是一组数据和功能的集合。</p><p>Object的每个实例都有下列的属性和方法:</p><ol><li>constructor:保存着用于创建当前对象的函数,即构造器。</li><li>hasOwnProperty:用于检查给定的属性在当前对象实例中是否存在(而不是在实例的原型中)。如:people.hasOwnProperty(‘name’)</li><li>isPrototypeOf(object): 检测传入的对象是否是当期对象的原型</li><li>propertyIsEnumerable(propertyName): 检测传入的属性能否使用for-in进行枚举<br>5.toLocaleString():返回对象的字符串表示,该字符串与执行环境对应</li><li>toString():返回对象的字符串表示</li><li>valueOf:返回对象的字符串、数组或布尔的表示。通常与toString()的返回值相同</li></ol><p>在ECMAScript中Object是所有对象的基础,因此所有对象都具有上面这些基本的属性和方法。</p><h2 id="函数"><a href="#函数" class="headerlink" title="函数"></a>函数</h2><p>函数中个人感觉想要去注意的是函数的返回值和函数的参数。</p><ol><li>函数的返回值:函数中要么让函数始终都返回一个值,要么永远都不要返回值。如果未指定返回值的函数,那么它返回的是一个特殊的undefined值</li><li>理解参数:</li></ol><p>ECMAScript函数传递参数比较灵活,定义函数参数也比较灵活。原因在于ECMAScript的参数在内部是用一个<strong>数组来表示</strong>的。函数接收到的是这个数组,而不关心数组中包含哪些参数。实际上在函数体内可以通过arguments对象来访问这个参数数组,从而获取传递给函数的每一个参数。</p><p>arguments对象只是与数组类似(他并不是Array的实例),因为可以使用[]来访问它的每一个元素,使用length属性可以确定传递进来多少参。arguments的length由传入的参数个数决定的,不是由定义函数时的命名参数的个数决定的。对于没有传递值的命名参数将被自动赋予undefined,这就跟定义了变量但没有初始化一样。</p><h3 id="函数实现伪重载"><a href="#函数实现伪重载" class="headerlink" title="函数实现伪重载"></a>函数实现伪重载</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="function"><span class="title">doAdd</span></span>() {</span><br><span class="line"> <span class="keyword">if</span> (arguments.length == 1){</span><br><span class="line"> alert(arguments[0])</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (arguments.length == 2){</span><br><span class="line"> alert(arguments[0] + arguments[1])</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">doAdd(10) //10</span><br><span class="line">doAdd(10,20) //30</span><br></pre></td></tr></table></figure><p>上面<strong>利用arguments的length可以实现伪重载</strong>,但ECMAScript中是<strong>没有真正的重载</strong>(方法名一样,接收的参数的类型或数量不同),因为ECMAScript不存在函数签名(函数签名由参数个数与其类型组成)的特性!!!函数名相同的情况下ECMAScript中前面定义的函数会被后面定义的函数所覆盖,故而没有真正的重载,但可以使用上面的代码实现伪重载。</p><h2 id="结尾"><a href="#结尾" class="headerlink" title="结尾"></a>结尾</h2><p>时间过的很快,不知不觉快要八月中旬了,各个公司也开始陆续开放网申了,不由的会想太多东西,故而感觉最近的节奏感没跟上,上周在学Vue感觉也是不是很好,没有把真正的心思放在学Vue上面,搞七搞八的一周也过去了。现在自己就想静静,外面的世界如何如何,你的能力有限,大可不必在乎,现在呢要做的只有好好的静下心,坚持吧,一切顺其自然!再说写这个JavaScript系列,我也不知道我会写多少,当我还是会尽自己最大的努力去总结。</p><p>于 厦门高崎新村 自己的小屋 </p><p>本文首发于个人博客>> <a href="https://blog.huangmingzhao.cn" target="_blank" rel="noopener">shineTomorrow–一个路上慢慢行走的前端人</a></p><p>参考文献:《JavaScript高级程序设计》</p>]]></content>
<categories>
<category> 渣技术 </category>
</categories>
<tags>
<tag> JavaScript </tag>
</tags>
</entry>
<entry>
<title>基于Express+mongoose搭建的学生管理系统</title>
<link href="/Express-mongoose-stu-management.html"/>
<content type="html"><![CDATA[<p>上一周学了下mongoose,虽然学了点皮毛,但还是想写写总结总结,这也是我的第一篇技术博客。还是蛮开心的,happy~~来,切入正题!项目源码我会放在github上。 <a href="https://github.com/ishareme/student_manage/" target="_blank" rel="noopener">github 地址</a></p><a id="more"></a><h2 id="代码目录"><a href="#代码目录" class="headerlink" title="代码目录"></a>代码目录</h2><p><img src="http://oubl6fzsm.bkt.clouddn.com/secondpost.png" alt="secondPost"></p><p>有些东西可根据自己喜好设置,并非必须。</p><h3 id="创建并初始化目录"><a href="#创建并初始化目录" class="headerlink" title="创建并初始化目录"></a>创建并初始化目录</h3><figure class="highlight bash"><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">$ mkdir student_manage</span><br><span class="line">$ <span class="built_in">cd</span> student_manage</span><br><span class="line">$ npm init</span><br></pre></td></tr></table></figure><h2 id="第三方模块安装"><a href="#第三方模块安装" class="headerlink" title="第三方模块安装"></a>第三方模块安装</h2><h3 id="1-Express"><a href="#1-Express" class="headerlink" title="1. Express"></a>1. Express</h3><p><strong>1.1</strong> Express 基于 Node.js 平台,快速、开放、极简的 web 开发框架。<br> <a href="http://www.expressjs.com.cn/4x/api.html" target="_blank" rel="noopener">Express 4.x API 中文手册</a> 安装如下:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ npm install express --save</span><br></pre></td></tr></table></figure><p><strong>1.2</strong> body-parser用于解析客户端请求的body中的内容,内部使用JSON编码处理,url编码处理以及对于文件的上传处理。安装如下:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ npm install body-parser --save</span><br></pre></td></tr></table></figure></p><h3 id="2-mongoose"><a href="#2-mongoose" class="headerlink" title="2. mongoose"></a>2. mongoose</h3><p><strong>2.1</strong> mongoose是在node.js异步环境下对mongodb进行便捷操作的对象模型工具。<br><a href="http://www.nodeclass.com/api/mongoose.html" target="_blank" rel="noopener">mongoose文档</a> 安装如下:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ npm install mongoose --save</span><br></pre></td></tr></table></figure></p><h2 id="开始写代码咯"><a href="#开始写代码咯" class="headerlink" title="开始写代码咯~~"></a>开始写代码咯~~</h2><p>当然在项目开始前要确定电脑是否安装mongoDB </p><p><a href="https://www.mongodb.com/download-center?jmp=nav#community" target="_blank" rel="noopener">mongoDB下载地址</a> <br><a href="https://robomongo.org/download" target="_blank" rel="noopener">mongoDB图形化界面robomongo</a></p><p>下载好具体怎么配置还请问度娘或Google吧,本文不做介绍了哈。注意:安装完mongoDB的时候进行项目时要把lib目录下的mongod服务器打开哈~~</p><p>先展示下最终实现的项目效果,以防大家心里有数。</p><p><img src="http://oubl6fzsm.bkt.clouddn.com/QQ%E5%9B%BE%E7%89%8720170808002035.png" alt="首页"><br>首页</p><p><img src="http://oubl6fzsm.bkt.clouddn.com/index.png" alt="添加页"><br>添加页</p><p><img src="http://oubl6fzsm.bkt.clouddn.com/modify.png" alt="修改页"><br>修改页</p><p>前台具体代码就不列出来,比较简单,为了节约时间,就使用bootstrap进行快速生成,当然大家可以进行美化。</p><h2 id="核心代码-敲黑板"><a href="#核心代码-敲黑板" class="headerlink" title="核心代码(敲黑板~~~)"></a>核心代码(敲黑板~~~)</h2><ol><li>mydb.js 对数据库进行连接</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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></pre></td><td class="code"><pre><span class="line"> //引入mongoose模块</span><br><span class="line">var mongoose=require(<span class="string">'mongoose'</span>)</span><br><span class="line"></span><br><span class="line">//数据库连接地址 链接到myStudent数据库</span><br><span class="line">var DB_URL=<span class="string">'mongodb://localhost:27017/myStudent'</span></span><br><span class="line">//数据库连接</span><br><span class="line">mongoose.connect(DB_URL)</span><br><span class="line"></span><br><span class="line">//连接成功终端显示消息</span><br><span class="line">mongoose.connection.on(<span class="string">'connected'</span>,<span class="function"><span class="title">function</span></span> () {</span><br><span class="line"> console.log(<span class="string">'mongoose connection open to '</span>+DB_URL)</span><br><span class="line">})</span><br><span class="line">//连接失败终端显示消息</span><br><span class="line">mongoose.connection.on(<span class="string">'error'</span>,<span class="function"><span class="title">function</span></span> () {</span><br><span class="line"> console.log(<span class="string">'mongoose error '</span>)</span><br><span class="line">})</span><br><span class="line">//连接断开终端显示消息</span><br><span class="line">mongoose.connection.on(<span class="string">'disconnected'</span>,<span class="function"><span class="title">function</span></span> () {</span><br><span class="line"> console.log(<span class="string">'mongoose disconnected'</span>)</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line">//创建一个Schema 每一个schema会一一对应mongo中的collection</span><br><span class="line">var schema=mongoose.Schema</span><br><span class="line"></span><br><span class="line">//实例化一个Schema</span><br><span class="line">var studentSchema=new schema(</span><br><span class="line"> {</span><br><span class="line"> //设置studentSchema信息的数据格式</span><br><span class="line"> name:{<span class="built_in">type</span>:String},</span><br><span class="line"> sex:{<span class="built_in">type</span>:String},</span><br><span class="line"> age:{<span class="built_in">type</span>:Number},</span><br><span class="line"> phone:{<span class="built_in">type</span>:String},</span><br><span class="line"> email:{<span class="built_in">type</span>:String},</span><br><span class="line"> other:{<span class="built_in">type</span>:String},</span><br><span class="line"> },</span><br><span class="line"> //{versionKey: <span class="literal">false</span>}是干嘛用?如果不加这个设置,我们通过mongoose第一次创建某个集合时,</span><br><span class="line"> // 它会给这个集合设定一个versionKey属性值,我们不需要,所以不让它显示</span><br><span class="line"> {</span><br><span class="line"> versionKey:<span class="literal">false</span></span><br><span class="line"> }</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">//生成一个具体student的model并导出</span><br><span class="line">//第一个参数是集合名,在数据库中会自动加s</span><br><span class="line">//把Model名字字母全部变小写和在后面加复数s</span><br><span class="line">var student=mongoose.model(<span class="string">'student'</span>,studentSchema)</span><br><span class="line">//将Student的model导出</span><br><span class="line">module.exports=student</span><br></pre></td></tr></table></figure><p>里面的代码我已逐条进行注释。有几个要说明的地方:1.可能大家看到Schema的时候有一点懵,不过他理解起来挺简单的就像关系型数据库里面的表。定义可以这么讲:<strong>schema</strong>是mongoose里会用到的一种数据模式,<strong>可以理解为表结构的定义;每个schema会映射到mongodb中的一个collection</strong>,它不具备操作数据库的能力。2.生成一个student的model的时候,如果myStudent数据库里面没有student(第一个参数的值)集合的话,系统会自动创建一个students的collection,注意在student后面加了<strong>s</strong>。</p><ol><li>app.js<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br></pre></td><td class="code"><pre><span class="line">//导入express模块</span><br><span class="line">var expres=require(<span class="string">'express'</span>)</span><br><span class="line">var bodyParser=require(<span class="string">'body-parser'</span>)</span><br><span class="line">//导入之前写的mydb.js</span><br><span class="line">var student=require(<span class="string">'./mydb'</span>)</span><br><span class="line"></span><br><span class="line">//调用函数, express实例化</span><br><span class="line">var app=expres()</span><br><span class="line"></span><br><span class="line">app.use(bodyParser.urlencoded({extended:<span class="literal">false</span>}))</span><br><span class="line">app.use(bodyParser.json())</span><br><span class="line"></span><br><span class="line">//处理静态目录</span><br><span class="line">app.use(expres.static(<span class="string">'www'</span>))</span><br><span class="line"></span><br><span class="line">// 允许跨域访问///</span><br><span class="line">app.all(<span class="string">'/api/*'</span>, <span class="keyword">function</span> (req, res, next) {</span><br><span class="line"> res.header(<span class="string">'Access-Control-Allow-Origin'</span>, <span class="string">'*'</span>)</span><br><span class="line"> res.header(<span class="string">'Access-Control-Allow-Headers'</span>, <span class="string">'x-Request-with'</span>)</span><br><span class="line"> res.header(<span class="string">'Access-Control-Allow-Methods'</span>, <span class="string">'PUT,POST,GET,DELETE,OPTIONS'</span>)</span><br><span class="line"> res.header(<span class="string">'X-Powered-By'</span>, <span class="string">'4.15.2'</span>)</span><br><span class="line"> res.header(<span class="string">'Content-Type'</span>, <span class="string">'application/json;charset=utf-8'</span>)</span><br><span class="line"> next() //执行下一个中间件。</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line">//首页展示获取数据</span><br><span class="line">app.post(<span class="string">'/index'</span>,<span class="keyword">function</span> (req,res) {</span><br><span class="line"> //mongoose 数据查找</span><br><span class="line"> student.find({}).<span class="built_in">exec</span>(<span class="keyword">function</span> (error,data) {</span><br><span class="line"> <span class="keyword">if</span> (error){</span><br><span class="line"> console.log(<span class="string">'数据获取失败'</span>+error)</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> res.json({</span><br><span class="line"> status:<span class="string">'y'</span>,</span><br><span class="line"> message:<span class="string">'查询成功'</span>,</span><br><span class="line"> //传递返回的数据</span><br><span class="line"> data:data</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line">//修改页面 获取数据</span><br><span class="line">app.post(<span class="string">'/modify'</span>,<span class="keyword">function</span> (req,res) {</span><br><span class="line"> //mongoose根据条件进行查找</span><br><span class="line"> student.find({_id: req.body.id}).<span class="built_in">exec</span>(<span class="keyword">function</span> (error,data) {</span><br><span class="line"> console.log(<span class="string">'2'</span>)</span><br><span class="line"> <span class="keyword">if</span> (error){</span><br><span class="line"> console.log(<span class="string">'数据获取失败'</span>+error)</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> console.log(data)</span><br><span class="line"> res.json({</span><br><span class="line"> status:<span class="string">'y'</span>,</span><br><span class="line"> message:<span class="string">'查询成功'</span>,</span><br><span class="line"> data:data</span><br><span class="line"> })</span><br><span class="line"> console.log(4)</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.post(<span class="string">'/modifyStu'</span>,<span class="keyword">function</span> (req,res) {</span><br><span class="line"> console.log(<span class="string">'1'</span>)</span><br><span class="line"> console.log(req.body)</span><br><span class="line"> //查询的条件</span><br><span class="line"> var whereStr={_id:req.body.id}</span><br><span class="line"> //更新的内容</span><br><span class="line"> var updateStr={</span><br><span class="line"> <span class="variable">$set</span>:{</span><br><span class="line"> name:req.body.name,</span><br><span class="line"> sex:req.body.sex,</span><br><span class="line"> age: req.body.age,</span><br><span class="line"> phone:req.body.phone,</span><br><span class="line"> email:req.body.email,</span><br><span class="line"> other:req.body.other,</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"> student.update(whereStr,updateStr,<span class="keyword">function</span> (error) {</span><br><span class="line"> <span class="keyword">if</span> (error){</span><br><span class="line"> console.log(<span class="string">'数据修改失败:'</span>+error)</span><br><span class="line"> res.json({</span><br><span class="line"> status:<span class="string">'y'</span>,</span><br><span class="line"> message:<span class="string">'修改失败'</span>,</span><br><span class="line"> data:req.body</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> console.log(<span class="string">'数据修改成功'</span>)</span><br><span class="line"> res.json({</span><br><span class="line"> status:<span class="string">'y'</span>,</span><br><span class="line"> message:<span class="string">'修改成功'</span>,</span><br><span class="line"> data:req.body</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line">//删除数据库其中的项</span><br><span class="line">app.post(<span class="string">'/del'</span>,<span class="keyword">function</span> (req,res) {</span><br><span class="line"> //mongoose根据指定条件进行删除</span><br><span class="line"> student.remove({_id: req.body.id},<span class="keyword">function</span>(error){</span><br><span class="line"> <span class="keyword">if</span> (error){</span><br><span class="line"> console.log(<span class="string">'数据获取失败'</span>+error)</span><br><span class="line"> res.json({</span><br><span class="line"> status:<span class="string">'y'</span>,</span><br><span class="line"> message:<span class="string">'删除不成功'</span>,</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> res.json({</span><br><span class="line"> status:<span class="string">'y'</span>,</span><br><span class="line"> message:<span class="string">'删除成功'</span>,</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line">//导航栏search操作</span><br><span class="line">app.post(<span class="string">'/findName'</span>,<span class="keyword">function</span> (req,res) {</span><br><span class="line"> console.log(req.body.searchName)</span><br><span class="line"> student.find({name: req.body.searchName}).<span class="built_in">exec</span>(<span class="keyword">function</span> (error,data) {</span><br><span class="line"> <span class="keyword">if</span> (error){</span><br><span class="line"> console.log(<span class="string">'查询失败'</span>+error)</span><br><span class="line"> res.json({</span><br><span class="line"> status:<span class="string">'y'</span>,</span><br><span class="line"> message:<span class="string">'查询失败'</span>,</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span>{</span><br><span class="line"> res.json({</span><br><span class="line"> status:<span class="string">'y'</span>,</span><br><span class="line"> message:<span class="string">'查询成功'</span>,</span><br><span class="line"> data:data</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line">//添加数据库操作</span><br><span class="line">app.post(<span class="string">'/addStu'</span>,<span class="keyword">function</span> (req,res) {</span><br><span class="line"> console.log(req.body)</span><br><span class="line"> //实例化一个student</span><br><span class="line"> var newStu=new student({</span><br><span class="line"> name:req.body.name,</span><br><span class="line"> sex:req.body.sex,</span><br><span class="line"> age:req.body.age,</span><br><span class="line"> phone:req.body.phone,</span><br><span class="line"> email:req.body.email,</span><br><span class="line"> other:req.body.other,</span><br><span class="line"></span><br><span class="line"> })</span><br><span class="line"> //对实例化的内容进行保存</span><br><span class="line"> newStu.save(<span class="keyword">function</span> (error) {</span><br><span class="line"> <span class="keyword">if</span> (error){</span><br><span class="line"> console.log(<span class="string">'数据添加失败:'</span>+error)</span><br><span class="line"> res.json({</span><br><span class="line"> status:<span class="string">'y'</span>,</span><br><span class="line"> message:<span class="string">'添加失败'</span>,</span><br><span class="line"> data:req.body</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> console.log(<span class="string">'数据添加成功'</span>)</span><br><span class="line"> res.json({</span><br><span class="line"> status:<span class="string">'y'</span>,</span><br><span class="line"> message:<span class="string">'添加成功'</span>,</span><br><span class="line"> data:req.body</span><br><span class="line"> })</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line">})</span><br><span class="line"></span><br><span class="line">//服务器监听端口</span><br><span class="line">app.listen(3000,()=>{</span><br><span class="line"> console.log(<span class="string">'node is ok'</span>)</span><br><span class="line">})</span><br></pre></td></tr></table></figure></li></ol><p>到处服务器搭建完成,接下来就是对各个js代码进行操作,ajax获取表单数据请求服务器,ajax获取地址栏请求服务器等等。然后ajax在接收到服务器返回的数据,对此进行渲染到前台页面,此项目我用的是 <strong>artTemplate</strong> 进行模板渲染。</p><p>就举一个栗子吧~~</p><ol><li>添加页的 addAjax.js<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">$(<span class="function"><span class="title">function</span></span> () {</span><br><span class="line"></span><br><span class="line"> //添加表单验证方法 手机号的验证</span><br><span class="line"> $.validator.addMethod(<span class="string">'isPhone'</span>,<span class="keyword">function</span> (value,ele) {</span><br><span class="line"> var length=value.length</span><br><span class="line"> var reg=/^1[34578]\d{9}$/</span><br><span class="line"> <span class="keyword">if</span> (length >= 11 && reg.test(value)){</span><br><span class="line"> <span class="built_in">return</span> <span class="literal">true</span></span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> <span class="built_in">return</span> <span class="literal">false</span></span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"></span><br><span class="line"> //对表单进行验证</span><br><span class="line"> $(<span class="string">'#addForm'</span>).validate({</span><br><span class="line"> debug:<span class="literal">true</span>,</span><br><span class="line"> //验证的规则</span><br><span class="line"> rules:{</span><br><span class="line"> name:{</span><br><span class="line"> required:<span class="literal">true</span>,</span><br><span class="line"> minlength:3</span><br><span class="line"> },</span><br><span class="line"> age:{</span><br><span class="line"> required:<span class="literal">true</span></span><br><span class="line"> },</span><br><span class="line"> phone:{</span><br><span class="line"> required:<span class="literal">true</span>,</span><br><span class="line"> isPhone:<span class="literal">true</span></span><br><span class="line"> },</span><br><span class="line"> email:{</span><br><span class="line"> required:<span class="literal">true</span>,</span><br><span class="line"> email:<span class="literal">true</span></span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> //错误的提示信息</span><br><span class="line"> messages:{</span><br><span class="line"> name:{</span><br><span class="line"> required:<span class="string">'姓名不能为空'</span>,</span><br><span class="line"> minlength:<span class="string">'姓名不能少于3位'</span></span><br><span class="line"> },</span><br><span class="line"> age:{</span><br><span class="line"> required:<span class="string">'年龄不能为空'</span></span><br><span class="line"> },</span><br><span class="line"> phone:{</span><br><span class="line"> required:<span class="string">'手机号不能为空'</span>,</span><br><span class="line"> isPhone:<span class="string">'手机号格式错误'</span></span><br><span class="line"> },</span><br><span class="line"> email:{</span><br><span class="line"> required:<span class="string">'邮箱不能为空'</span>,</span><br><span class="line"> email:<span class="string">'邮箱格式错误'</span></span><br><span class="line"> }</span><br><span class="line"> },</span><br><span class="line"> //正确时执行的函数</span><br><span class="line"> submitHandler:<span class="keyword">function</span> (form) {</span><br><span class="line"> //ajax请求</span><br><span class="line"> $.ajax({</span><br><span class="line"> <span class="built_in">type</span>:<span class="string">'post'</span>,</span><br><span class="line"> url:<span class="string">'/addStu'</span>,</span><br><span class="line"> dataType:<span class="string">'json'</span>,</span><br><span class="line"> //表单数据序列化</span><br><span class="line"> data:$(form).serialize(),</span><br><span class="line"> //ajax请求成功操作</span><br><span class="line"> success:<span class="keyword">function</span> (res) {</span><br><span class="line"> $(<span class="string">'.modal-body'</span>).text(res.message)</span><br><span class="line"> //显示出模态框</span><br><span class="line"> $(<span class="string">'.modal'</span>).modal(<span class="string">'show'</span>).on(<span class="string">'hidden.bs.modal'</span>,<span class="function"><span class="title">function</span></span> () {</span><br><span class="line"> <span class="keyword">if</span> (res.message == <span class="string">'添加成功'</span>){</span><br><span class="line"> location.href=<span class="string">'index.html'</span></span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> },</span><br><span class="line"> //ajax请求失败操作</span><br><span class="line"> error:<span class="keyword">function</span> (jqXHR) {</span><br><span class="line"> console.log(jqXHR.status)</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line"> },</span><br><span class="line"></span><br><span class="line"> })</span><br><span class="line">})</span><br></pre></td></tr></table></figure></li></ol><p>表单验证我用了 <strong>jquery.validate.js</strong></p><ol><li><p>添加完毕,首页进行渲染 index.html(部分)</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><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">{{each}}</span><br><span class="line"> <tr></span><br><span class="line"> <td>{{<span class="variable">$value</span>.name}}</td></span><br><span class="line"> <td>{{<span class="variable">$value</span>.sex}}</td></span><br><span class="line"> <td>{{<span class="variable">$value</span>.age}}</td></span><br><span class="line"> <td>{{<span class="variable">$value</span>.phone}}</td></span><br><span class="line"> <td>{{<span class="variable">$value</span>.email}}</td></span><br><span class="line"> <td></span><br><span class="line"> <a href=<span class="string">"/modify.html?id={{<span class="variable">$value</span>._id}}"</span> class=<span class="string">"modify"</span> data-index=<span class="string">"{{<span class="variable">$value</span>._id}}"</span>>修改</a></span><br><span class="line"> <a href=<span class="string">""</span> class=<span class="string">"del"</span> data-index=<span class="string">"{{<span class="variable">$value</span>._id}}"</span>>删除</a></span><br><span class="line"> </td></span><br><span class="line"> </tr></span><br><span class="line"> {{/each}}</span><br></pre></td></tr></table></figure></li><li><p>首页的 indexAjax.js(部分)</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">$(<span class="function"><span class="title">function</span></span> () {</span><br><span class="line"> $.ajax({</span><br><span class="line"> <span class="built_in">type</span>:<span class="string">'post'</span>,</span><br><span class="line"> url:<span class="string">'/index'</span>,</span><br><span class="line"> success:<span class="keyword">function</span> (res) {</span><br><span class="line"> //进行模板渲染</span><br><span class="line"> var strHtml=template(<span class="string">'showStu'</span>,res.data)</span><br><span class="line"> $(<span class="string">'#tb'</span>).html(strHtml)</span><br><span class="line"> </span><br><span class="line"> ......代码有点长就不放了哈~~........</span><br></pre></td></tr></table></figure></li></ol><h2 id="结尾"><a href="#结尾" class="headerlink" title="结尾"></a>结尾</h2><p> 夜已深。不知不觉写这个文章也花了挺长时间的,哈哈哈,不过自己开心就行~~ 自己在做这个项目的时候,以为会很快搞完,但是还是遇到了问题,哎,纠结了好久,现在也没得出个答案,后来用了另一种的解决方法,感觉有点像投机取巧,但好像也不能怎么说,哈哈…个人技术水平真的很渣,写文章一方面是分享,一方面是再次重温自己的思路。请勿喷哈~~自己的第一篇技术博客,写的有点匆忙,不过还是希望可以给大家带来帮助。<br> <br> <br> <br> 于 厦门高崎新村 自己的小屋 </p><p>本文首发于个人博客 >> <a href="http://www.huangmingzhao.cn/">黄明照–一个在路上慢慢行走的前端人</a></p>]]></content>
<categories>
<category> 渣技术 </category>
</categories>
<tags>
<tag> mongoose </tag>
<tag> Express </tag>
</tags>
</entry>
<entry>
<title>我的第一篇博文</title>
<link href="/fistpost.html"/>
<content type="html"><![CDATA[<p>2017-07-28 没有特别日子,很平淡,这是我的第一篇博文,今天对我或许还有点意义。前阵日子在搭建此博客,其实有想搭建个人博客的想法好早就有了,现在才去实现,感觉确实是有点晚了。不过终于还是迈开了步子,有去做的事情,不管什么时候去做我感觉都是好的,接下来的事情就看自己的坚持与再坚持。我也不知道第一篇博文要写什么,哈哈…文笔不好只能胡写一通了~~说说搭建博客的目的吧,主要有三点吧:</p><a id="more"></a><ul><li><h3 id="Record"><a href="#Record" class="headerlink" title="Record"></a>Record</h3><p>记录自己的生活,对生活的体验和感受,自己的爱好,以及自己在前端路上行走学到的一些渣技术,对技术的总结。</p></li><li><h3 id="Share"><a href="#Share" class="headerlink" title="Share"></a>Share</h3><p>自己渣技术的分享,不过,自己的技术不怎么样,但还是会用心分享迪~~</p></li><li><h3 id="Think"><a href="#Think" class="headerlink" title="Think"></a>Think</h3><p>有记录就有总结,有总结就会有思考,有思考就会有收获,我想这就是写博客的意义。</p></li></ul><p>写在最后:</p><blockquote><p>即便最平凡的人,也得要为他那个存在的世界而战斗,从这个意义上说在这些平凡的世界里,也没有一天是平静的。 —<em>《平凡的世界》</em></p></blockquote><p><img src="http://oubl6fzsm.bkt.clouddn.com/fistpost.jpg" alt="fistPost"></p><p>放张自己当初写的字,共勉之~~</p><p>(第一篇当然要来点鸡汤咯,好喝~~ ( ̄▽ ̄)~*)<br> 于 厦门高崎新村 自己的小屋</p><p>##</p>]]></content>
<categories>
<category> 闲言语 </category>
</categories>
<tags>
<tag> 生活 </tag>
</tags>
</entry>
<entry>
<title>Hello World</title>
<link href="/hello-world.html"/>
<content type="html"><![CDATA[<p>Welcome to <a href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/" target="_blank" rel="noopener">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html" target="_blank" rel="noopener">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues" target="_blank" rel="noopener">GitHub</a>.</p><h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">"My New Post"</span></span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/writing.html" target="_blank" rel="noopener">Writing</a></p><h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/server.html" target="_blank" rel="noopener">Server</a></p><h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/generating.html" target="_blank" rel="noopener">Generating</a></p><h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/deployment.html" target="_blank" rel="noopener">Deployment</a></p>]]></content>
</entry>
<entry>
<title>gallery</title>
<link href="/gallery/index.html"/>
<content type="html"><![CDATA[]]></content>
</entry>
<entry>
<title>links</title>
<link href="/links/index.html"/>
<content type="html"><![CDATA[]]></content>
</entry>
<entry>
<title>timeline</title>
<link href="/timeline/index.html"/>
<content type="html"><![CDATA[]]></content>
</entry>
<entry>
<title>tags</title>
<link href="/tags/index.html"/>
<content type="html"><![CDATA[]]></content>
</entry>
</search>