部落格架構更新與狀態

當前使用主題為 hexo-theme-landscape,早期使用 pacman,自己修改成 moman 一個黑色系主題,但是隨著文章數量的增加,pacman 樣板的生成速度越來越慢,更新 hexo 後,發現 landscape 的速度異常地快,於是將整個樣板配色轉移到 landscape。

想打包我嗎?直接至 morris821028/morris821028.github.io 下載即可。還是即時的版本呢,可惜地是無法再用 hexo 繼續產生文章,也就是要新增一篇文章是困難的。這裡有純草稿 morris821028/HexoBlog 提供,偶爾會更新,這偶爾想必是挺久的日子。往後要在其他主題下部屬也不是問題!

反應速度

由於 hexo 本身就是 靜態網頁 的框架,所以不會有資料庫調用問題,反應速度理所當然會快很多。為了增加網頁的反應速度,要把不少重複的框捨去,siderbar 訊息最小化!

原理就當作編寫 markdown,利用 hexo 編譯成 html 後上傳。跟一般寫 cpp 程式很像呢!

  • Tags 搬移到額外的分頁,由於每一個頁面下都會出現在 sidebar,無用訊息量太多導致載入速度拉慢,不要忽視使用者經驗 (UX)!

額外分頁的建立

/blog/source/tags/index.md
1
2
3
title: Tags
layout: tags
---

hexo 配置是採用每一個 markdown 上的參數 layout。接著只需要在主題下寫一個 /themes/landscape/layout/tags.ejs,到時候會直接經過 layout.ejs 呼叫 tags.ejs

接著就可以在 http://localhost:4000/tags/ 下看到自己想要頁面,一般而言不會有這一頁,會呈現 NOT FOUND 404 狀態。

主題設定檔

既然有用 font awesome ,覺得在默認主題下 Home 顯得不太夠力且明瞭,直接點擊 logo 也是能返回主頁。於是把設定檔案改成以下內容,搭配圖示和文字描述,希望這種方式會更脫離死板的配置。

/themes/landscape/_config.yml
1
2
3
4
5
6
7
menu:
- {name: Home, path: /, class: icon-home, layout: 1}
- {name: About, path: /about, class: icon-user, layout: 2}
- {name: Archives, path: /archives, class: icon-archive, layout: 2}
- {name: Tags, path: /tags, class: icon-tags, layout: 2}
- {name: Pictures, path: /picture, class: icon-camera, layout: 2}
- {name: Works, path: /works, class: icon-trophy, layout: 2}

接著在 header.ejs 下修改一下內容,畢竟參數上有點調整。

/themes/landscape/layout/_partial/header.ejs
1
2
3
4
5
6
7
8
9
10
<a id="main-nav-toggle" class="nav-icon"></a>
<% for (var i in theme.menu){ %>
<% if (theme.menu[i].layout && theme.menu[i].layout == 1) { %>
<a class="main-nav-link" href="<%- url_for(theme.menu[i].path) %>"><i class=<%= theme.menu[i].class %> title='<%= theme.menu[i].name %>'></i></a>
<% } else if (theme.menu[i].layout && theme.menu[i].layout == 2) { %>
<a class="main-nav-link" href="<%- url_for(theme.menu[i].path) %>"><i class=<%= theme.menu[i].class %> title='<%= theme.menu[i].name %>'></i> <%= theme.menu[i].name %></a>
<% } else { %>
<a class="main-nav-link" href="<%- url_for(theme.menu[i].path) %>"><%= theme.menu[i].name %></a>
<% } %>
<% } %>

Ukagaka

由於 史蒂芙 任務結束,現在由 派拉斯 接管,她們的個人照片都可以在 Pictures 中見到哦!

關於 Ukagaka 的製作,目前把音樂坑解決,將可以在功能列表中看到音樂撥放功能!實作採用 HTML5 + js 的方式,並且把圖片部分全部用 font awesome 解決,功能還不夠齊全,希望已經能符合最低需求。

其實很早就用 HTML5 + js 弄過音樂撥放,但遲遲沒有嫁入到 Ukagaka 中。

音樂部份的免空是個問題,目前用容量較小的音樂檔案放置 hexo 中一起部屬。

至於 AIML 的 AI 智能對話部分,之前停留在 JAVA 那邊,暫且還不會去完成她,其一原因是必須轉成比較好跑在 server 上面的版本,並且能應付多人單一的狀態保留。如果不寫 web socket,必然要透過 ip 進行辨識,至少能記住當前使用者的名稱 (如果有教導 Ukagaka 的話)。

根據之前用 nodejs 寫 web socket 完成 chat room 的感想,有一部分是相當難理解的 js,同時存在瀏覽器要解析的 js 中,模組部分很好奇實際運作原理,詳細還沒有理解。

Read More +

Nodejs upload server 簡易上傳下載

Github upload-server

上傳的設定,要特別注意公開讀取的問題,採用 express 架構下,如果設定再 public 資料夾下,則任何人上傳都可以被任何人讀取。

中間有遇到一個問題 到底能不能限制使用者上傳速度

上網查了很多資料,不管是從前端還是後端,前端限制基本上沒有任何用處,後端則在這個架構中沒有找到相關的 API 限制,從作業系統中下手,則必須要找到 nodejs 執行緒中的網路限制。

奮鬥好幾天,仍然沒有這個解決方案。

Read More +

Simple Works Gallery

起源

鄰近要大學推研究所的時刻,自己做過什麼作品來說,對於推甄時相當重要,一直都沒有好好整理過自己做過什麼,有多少能拿出檯面的項目,現在發現除了 ACM 解題和曾經幫別人寫的作業以外,沒有幾項可以吸引到人的。一樣做一個 hexo tag plugin,將作品展示櫃用一個 generator.js 的方式,將展示櫃內容呈現出來,傳入的方式為 json。同樣地,你可以在這個部落格上方的 Works 看到相關作品介紹。

下載

Download on Github

使用

仍然以 github 上的 project 為優先版本。以下的內容也許不是最新版本。

html

當前採用 json 的原因是因為可以藉由較簡單的方式,以及往後可能使用 ajax 的方式運作。這樣彈性也許會比較大。

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
<script type="text/works-gallery">
{
"works" : [
{
"title": "Chat Room Application",
"cover": "http://i.imgur.com/oUO30I6.jpg",
"description": "計算機網路-一個簡單的網路聊天室<br/> Socket programming practice (Java)",
"download": ["https://github.com/morris821028/hw-ChatRoom"],
"demo": [],
"video": ["https://www.youtube.com/watch?v=7ExCn1ipKeg"]
},
{
"title": "Magic Circle",
"cover": "http://i.imgur.com/Fv8ebBY.jpg",
"description": "jquery-magic-circle, write funny for friends",
"download": ["https://github.com/morris821028/jquery-magic-circle"],
"demo": ["http://morris821028.github.io/jquery-magic-circle"],
"video": ["https://www.youtube.com/watch?v=TWqmGeuIJLo"]
},
{
"title": "Hex Image Gallery",
"cover": "http://i.imgur.com/VMf2G1v.png",
"description": "create beautiful hexagon shapes with CSS3, jquery, write funny for friends",
"download": ["https://github.com/morris821028/jquery-hex-gallery"],
"demo": ["http://morris821028.github.io/jquery-hex-gallery/"],
"video": []
}
]
}
</script>

css

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
.wg-container
{
background: none repeat scroll 0% 0% #2d2d2d;
border-color: #ddd;
border-style: solid;
border-width: 1px 0;
color: #ccc;
line-height: 25.6px;
margin: 0 -20px;
overflow: auto;
padding: 15px 20px;
position: relative;
text-align: center;
width: 100%;
z-index: 0;
}
.wg-container hr
{
background: #333;
background-image: -moz-linear-gradient(to right, #333, #ccc, #333);
background-image: -ms-linear-gradient(to right, #333, #ccc, #333);
background-image: -o-linear-gradient(to right, #333, #ccc, #333);
background-image: -webkit-linear-gradient(to right, #333, #ccc, #333);
border: 0;
height: 5px;
}
.wg-item
{
list-style: none;
}
.wg-item .inner
{
height: 160px;
}
.wg-item li
{
display: block;
float: left;
margin: 16px;
width: 45%;
}
.wg-item li .header
{
border: 4px solid #b4b4b4;
box-shadow: 1px 1px 1px 1px #ccc;
cursor: pointer;
float: left;
height: 256px;
margin: 5px;
moz-box-shadow: 1px 1px 1px 1px #ccc;
overflow: hidden;
position: relative;
webkit-box-shadow: 1px 1px 1px 1px #ccc;
width: 100%;
}
.wg-item li .header:hover a
{
moz-transform: scale(1.2);
ms-transform: scale(1.2);
o-transform: scale(1.2);
transform: scale(1.2);
webkit-transform: scale(1.2);
}
.wg-item li .header a
{
left: 0;
moz-transition: all 300ms ease-out;
ms-transition: all 300ms ease-out;
o-transition: all 300ms ease-out;
position: absolute;
transition: all 300ms ease-out;
webkit-transition: all 300ms ease-out;
}
.wg-item li .image
{
background-size: cover;
display: block;
height: 95%;
moz-background-size: cover;
padding: .5em;
webkit-background-size: cover;
width: 100%;
}
.wg-item li h3
{
font-size: 24px;
font-weight: normal;
line-height: 22px;
margin-bottom: 10px;
margin-top: 10px;
text-align: center;
}
.wg-item li h3 a:hover
{
text-decoration: none;
}
.wg-item li ul.links
{
float: right;
}
.wg-item li .links li
{
display: block;
margin-left: 5px;
margin-right: 0 !important;
width: initial;
}
.wg-item li .links li a
{
background: #65a9d7;
border-radius: 5px;
box-shadow: 0 1px 0 #000;
color: #fff;
font-family: Georgia,Serif;
font-size: 16px;
padding: 5.5px 11px;
text-decoration: none;
text-shadow: 0 1px 0 rgba(0,0,0,0.4);
vertical-align: middle;
webkit-border-radius: 5px;
webkit-box-shadow: 0 1px 0 #000;
}
.wg-item .description
{
font-size: 16px;
margin: .2em 0;
text-align: left;
}

hexo plugin

我已經把產生方式寫在 hexo-tag-oj 裡頭,下載使用 hexo-tag-plugin

不過相關的 js 還有 css 要自己擺放,請參考上面的描述項目。

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
{\% ojblock works \%}
{
"works" : [
{
"title": "Chat Room Application",
"cover": "http://i.imgur.com/oUO30I6.jpg",
"description": "計算機網路-一個簡單的網路聊天室<br/> Socket programming practice (Java)",
"download": ["https://github.com/morris821028/hw-ChatRoom"],
"demo": [],
"video": ["https://www.youtube.com/watch?v=7ExCn1ipKeg"]
},
{
"title": "Fuzzy System",
"cover": "http://i.imgur.com/C44Hbrg.png",
"description": "計算型智慧-廣義型演算法最佳化<br/>Car simulation implements PSO, GA, and fuzzy system (Java)",
"download": ["https://github.com/morris821028/hw-FuzzySystem"],
"demo": [],
"video": ["https://www.youtube.com/watch?v=kt2mu679elU"]
},
{
"title": "UML Editor",
"cover": "http://i.imgur.com/JCCweao.png",
"description": "物件導向程式設計-UML 編輯器架構設計<br/>OO design practice & make UML Editor (Java)",
"download": ["https://github.com/morris821028/hw-UML-Editor"],
"demo": [],
"video": ["https://www.youtube.com/watch?v=DKDFy6uFk8Y"]
},
{
"title": "MapleStory 遊戲仿作",
"cover": "http://i.imgur.com/i62nNgG.png",
"description": "由於硬碟損壞代碼沒有救回來,只剩下舊版,收錄於 chat room 製作中的一環,由於課程時間不夠,沒有做完。 (Java)",
"download": ["https://github.com/morris821028/hw-ChatRoom"],
"demo": [],
"video": ["https://www.youtube.com/watch?v=TWqmGeuIJLo"]
},
{
"title": "Magic Circle",
"cover": "http://i.imgur.com/Fv8ebBY.jpg",
"description": "jquery-magic-circle, write funny for friends",
"download": ["https://github.com/morris821028/jquery-magic-circle"],
"demo": ["http://morris821028.github.io/jquery-magic-circle"],
"video": ["https://www.youtube.com/watch?v=TWqmGeuIJLo"]
},
{
"title": "Hex Image Gallery",
"cover": "http://i.imgur.com/VMf2G1v.png",
"description": "create beautiful hexagon shapes with CSS3, jquery, write funny for friends",
"download": ["https://github.com/morris821028/jquery-hex-gallery"],
"demo": ["http://morris821028.github.io/jquery-hex-gallery/"],
"video": []
}
]
}
{\% endojblock \%}
Read More +

Jquery Hex Image Gallery

起源

六角形的圖片廊道,一開始給定的是提案是做出一個圖片展示櫃,可是想到要放在這個 hexo 部落格,要做到類似的相簿功能其實是很麻煩的,還有必須要關聯 generator 的產生方式,才能製作出相對的 static website,那只好將項目弄成單獨一頁,而這一頁要怎麼製作其實很難捉摸。失敗的設計總是這樣子開始的。

由於圖片量太大的話,變成一開始載入速度會太慢,因此找來了 lazyload.js,但是跟展示窗口銜接上仍有一些問題,無法適時地反映操作,所以需要 call back 操作,否則圖片會載入失敗。再者是原本六角 CSS 問題,找來網路上提供的 CSS,發現更換大型圖片的時候,會造成圖片顯示不正常,因此在這一塊費時了相當長的時間來符合預期的操作。

此項目已經放在我的 Github 上面,同時你也可以在這個 blog 上方的 Picture 中看到 demo,萬萬沒想到居然有人願意 Star 標記,真的是相當令人動容啊,從來沒想過有人對於這樣的蠢製作感興趣。

下載

Download on Github

Demo

使用

仍然以 github 上的 project 為優先版本。以下的內容也許不是最新版本。

html

為了方便產生器運行,產生方式採用 json 的生成方式。相關的動畫製作引入

  • jquery.lazyload.js 圖片動態載入
  • jquery.als.link-1.6.js 幻燈片的展示窗口 (經過修改,來完成跳轉操作)

當前採用 json 的原因是因為可以藉由較簡單的方式,以及往後可能使用 ajax 的方式運作。這樣彈性也許會比較大。

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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" type="text/javascript"></script>
<script src="js/jquery.hex.gallery.js" type="text/javascript"></script>
<script src="js/jquery.lazyload.js" type="text/javascript"></script>
<script src="js/jquery.als.link-1.6.js" type="text/javascript"></script>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
...
<script type="text/hex-gallery">
{
"album" : [
{
"cover": {"title": "<h4>THEME</h4><hr /><p>Stephanie Dola</p>", "class": "hex-1"},
"photo": [
{"imgur": "http://i.imgur.com/yIoACHc.gif"},
{"imgur": "http://i.imgur.com/uINck6K.gif"},
{"imgur": "http://i.imgur.com/zOZJEex.gif"}
]
},
{
"cover": {"title": "<h4>THEME</h4><hr /><p>萌~萌~哒~</p>", "class": "hex-2"},
"photo": [
{"imgur": "http://i.imgur.com/YSmWA3g.gif"},
]
},
{
"cover": {"title": "<h4>THEME</h4><hr /><p>其他</p>", "class": "hex-3"},
"photo": [
{"imgur": "http://i.imgur.com/vpKzynV.gif"},
{"imgur": "http://i.imgur.com/rctEEyS.gif"}
]
}
]
}
</script>
...
</body>
</html>

css

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
.hex-container
{
display: block;
height: 320px;
position: relative;
width: 800px;
}
.hex
{
animation: animatedBackground 10s linear infinite;
background-color: #ccc;
background-position: 50% 50%;
background-repeat: no-repeat;
background-size: cover;
float: left;
font-family: Georgia,"Microsoft YaHei","Times New Roman",serif;
font-weight: bold;
height: 86px;
margin: 25px 5px;
moz-animation: animatedBackground 10s linear infinite;
moz-background-size: cover;
ms-animation: animatedBackground 10s linear infinite;
position: relative;
text-align: center;
webkit-animation: animatedBackground 10s linear infinite;
webkit-background-size: cover;
width: 150px;
zoom: 1;
}
.hex.hex-gap
{
margin-left: 86px;
}
.hex a
{
display: block;
height: 100%;
left: 0;
position: absolute;
text-indent: -9999em;
top: 0;
width: 100%;
}
.hex .corner-1
{
moz-transform: rotate(60deg);
ms-transform: rotate(60deg);
o-transform: rotate(60deg);
transform: rotate(60deg);
webkit-transform: rotate(60deg);
}
.hex .corner-1:before
{
moz-transform: rotate(-60deg) translate(-87px,0);
moz-transform-origin: 0 0;
ms-transform: rotate(-60deg) translate(-87px,0);
ms-transform-origin: 0 0;
o-transform: rotate(-60deg) translate(-87px,0);
o-transform-origin: 0 0;
transform: rotate(-60deg) translate(-87px,0);
transform-origin: 0 0;
webkit-transform: rotate(-60deg) translate(-87px,0);
webkit-transform-origin: 0 0;
}
.hex .corner-2
{
moz-transform: rotate(-60deg);
ms-transform: rotate(-60deg);
o-transform: rotate(-60deg);
transform: rotate(-60deg);
webkit-transform: rotate(-60deg);
}
.hex .corner-2:before
{
bottom: 0;
moz-transform: rotate(60deg) translate(-44px,-12px);
ms-transform: rotate(60deg) translate(-44px,-12px);
o-transform: rotate(60deg) translate(-44px,-12px);
transform: rotate(60deg) translate(-44px,-12px);
webkit-transform: rotate(60deg) translate(-44px,-12px);
}
.hex .corner-3
{
moz-transform: rotate(0);
ms-transform: rotate(0);
o-transform: rotate(0);
transform: rotate(0);
webkit-transform: rotate(0);
}
.hex .corner-3:before
{
moz-transform: rotate(0) translate(-12px,-44px);
ms-transform: rotate(0) translate(-12px,-44px);
o-transform: rotate(0) translate(-12px,-44px);
transform: rotate(0) translate(-12px,-44px);
webkit-transform: rotate(0) translate(-12px,-44px);
}
.hex .inner
{
color: #eee;
position: absolute;
right: 0;
top: 0;
display: inline;
float: left;
width: 98.3333%;
margin: 0px 0.833333%;
}
.hex .inner a
{
color: #fff;
text-indent: 0;
}
.hex h4
{
margin: 0;
}
.hex hr
{
border: 0;
border-top: 1px solid #eee;
margin: 15px auto;
width: 60%;
}
.hex p
{
font-size: 22px;
margin: 0 auto;
width: 80%;
}
.hex.hex-1
{
background: #74cddb;
}
.hex.hex-2
{
background: #f00;
}
.hex.hex-3
{
background: #80b971;
}
.hex.hex-back
{
background: #80b971;
}
.hex.hex-back a
{
padding: 0 4px;
}
.hex .corner-1,.hex .corner-2,.hex .corner-3
{
backface-visibility: hidden;
background: inherit;
height: 100%;
left: 0;
moz-backface-visibility: hidden;
ms-backface-visibility: hidden;
o-backface-visibility: hidden;
overflow: hidden;
position: absolute;
top: 0;
webkit-backface-visibility: hidden;
width: 100%;
}
.hex .corner-1:before,.hex .corner-2:before,.hex .corner-3:before
{
backface-visibility: hidden;
background: inherit;
background-repeat: no-repeat;
content: '';
height: 173px;
left: 0;
moz-backface-visibility: hidden;
ms-backface-visibility: hidden;
o-backface-visibility: hidden;
position: absolute;
top: 0;
webkit-backface-visibility: hidden;
width: 173px;
}
.hex-caption
{
background-color: rgba(0,0,0,0.5);
color: #fff;
left: 0;
moz-transition: all 300ms ease-out;
ms-transition: all 300ms ease-out;
o-transition: all 300ms ease-out;
position: absolute;
transition: all 300ms ease-out;
webkit-transition: all 300ms ease-out;
}
.hex:hover .hex-simple-caption
{
moz-transform: translateY(-100%);
ms-transform: translateY(-100%);
o-transform: translateY(-100%);
transform: translateY(-100%);
visibility: visible;
webkit-transform: translateY(-100%);
}
.hex-simple-caption
{
bottom: -60px;
display: block;
height: 30px;
line-height: 25pt;
text-align: center;
visibility: hidden;
width: 100%;
}
.hex-background
{
left: -80px;
position: absolute;
top: -136px;
width: 900px;
z-index: -1;
}
.hex-background .hex
{
background-color: #708090;
}
.als-viewport
{
height: 390px;
margin: 0 auto;
overflow: hidden;
position: relative;
}
.als-wrapper
{
list-style: none;
position: relative;
}
.als-item
{
cursor: pointer;
display: block;
float: left;
position: relative;
text-align: center;
}
.als-prev,.als-next
{
clear: both;
cursor: pointer;
position: absolute;
}
.als-container
{
background: none repeat scroll 0% 0% #2d2d2d;
border-color: #ddd;
border-style: solid;
border-width: 1px 0;
color: #ccc;
line-height: 25.6px;
margin: 0 -20px;
overflow: auto;
padding: 15px 20px;
position: relative;
text-align: center;
width: 100%;
z-index: 0;
}
.als-container .als-item
{
display: block;
margin: 0 5px;
margin: 0 auto;
min-height: 120px;
min-width: 100px;
padding: 4px 0;
text-align: center;
vertical-align: middle;
}
.als-container .als-prev
{
font-size: 30px;
left: 30px;
}
.als-container .als-next
{
font-size: 30px;
right: 30px;
}
.als-container .als-prev,.als-container .als-next
{
top: 175px;
}
.icon-arrow-left
{
display:inline-block;
width:32px;
height:32px;
line-height:32px;
border-top:3px solid #aaa;
border-right:3px solid #aaa;
-ms-transform:rotate(225deg);
-moz-transform:rotate(225deg);
-webkit-transform:rotate(225deg);
transform:rotate(225deg);
}
.icon-arrow-right
{
display:inline-block;
width:32px;
height:32px;
line-height:32px;
border-top:3px solid #aaa;
border-right:3px solid #aaa;
-ms-transform:rotate(45deg);
-moz-transform:rotate(45deg);
-webkit-transform:rotate(45deg);
transform:rotate(45deg);
}

架構

hex page

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="hex-container">
<div class="hex-background">
<div class="hex hex-gap" style="background-image: url();">
<div class="corner-1"></div>
<div class="corner-2"></div>
<div class="corner-3"></div>
<div class="inner"></div>
</div>
<div class="hex" style="background-image: url();">
<div class="corner-1"></div>
<div class="corner-2"></div>
<div class="corner-3"></div>
<div class="inner"></div>
</div>
...
</div>
</div>

原本網路提供 hex 只有 corner-1corner-2,這樣的做法無法產生 cover 的圖示,因此這裡增加 corner-3,但仍然會看到一條一條格線在斜邊上,不過已經相當足夠。

1
2
3
4
5
6
7
8
9
10
11
12
13
<div class="als-container" id="als-container_0" data-id="als-container_0">
<div class="als-viewport" data-id="als-viewport_0" style="width: 800px; height: 328px;">
<ul class="als-wrapper" data-id="als-wrapper_0" style="width: 4800px; height: 328px;">
<li class="als-item" data-linkid="-6" id="als-item_0_0" style="left: 0px;">
insert hex page
</li>
<li class="als-item" data-linkid="-1" id="als-item_0_0" style="left: 0px;">
insert hex page
</li>
...
</ul>
</div>
</div>

根據原本的 jquery.als-1.6.js 並沒有提供跳轉的操作,也就是說不能直接 shift 到指定位置,只能倚靠往左和往右的觸發,因此特別自己增加了 data-linkid 為操作手段。

hexo blog plugin

我已經把產生方式寫在 hexo-tag-oj 裡頭,下載使用 hexo-tag-plugin

不過相關的 js 還有 css 要自己擺放,請參考上面的描述項目。

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
{\% ojblock hex \%}
{
"album" : [
{
"cover": {"title": "<h4>THEME</h4><hr /><p>Stephanie Dola</p>", "class": "hex-1"},
"photo": [
{"imgur": "http://i.imgur.com/yIoACHc.gif"},
{"imgur": "http://i.imgur.com/4pzxseN.jpg"}
]
},
{
"cover": {"title": "<h4>THEME</h4><hr /><p>萌~萌~哒~</p>", "class": "hex-2"},
"photo": [
{"imgur": "http://i.imgur.com/YSmWA3g.gif"},
{"imgur": "http://i.imgur.com/5IHR8bQ.gif"}
]
},
{
"cover": {"title": "<h4>THEME</h4><hr /><p>其他</p>", "class": "hex-3"},
"photo": [
{"imgur": "http://i.imgur.com/vpKzynV.gif"},
{"imgur": "http://i.imgur.com/rctEEyS.gif"}
]
}
]
}
{\% endojblock \%}

#

Read More +

製作 hexo-tag-oj

Demo UVa OJ,標製作只有自己會用的 TAG,詳細請查閱 Github。

  • 目前 javascript 存放在 Google Drive
  • 每一篇限用一個 tag,無法解決多重匯入問題。如果硬是要匯入也行,只是會重複好幾次。
  • 請確保每個頁面的 <head> 有引入 jquery 1.7.0 以上的版本。

順手測一下

GitHub jQuery Repo Widget

TEST

事實上只是將上述的 jQuery 修改而已。

Read More +

Hexo Math Plugin

展示

A hexo plugin that uses MathJax to render math equations.
Simple inline $a = b + c$.

1
Simple inline $a = b + c$.

This equation $\cos 2\theta = \cos^2 \theta - \sin^2 \theta = 2 \cos^2 \theta - 1$ is inline.

1
This equation <hexoescape>1</hexoescape> is inline.
$$\begin{aligned} \dot{x} & = \sigma(y-x) \\ \dot{y} & = \rho x - y - xz \\ \dot{z} & = -\beta z + xy \end{aligned}$$

$$\begin{aligned} \dot{x} & = \sigma(y-x) \\ \dot{y} & = \rho x - y - xz \\ \dot{z} & = -\beta z + xy \end{aligned}$$

更多

http://catx.me/2014/03/09/hexo-mathjax-plugin/

Read More +

HTML5 Music Player (本地拖曳撥放)

代碼起源

tommy351 提供的。基於 HTML5 和 JQuery 運行的撥放器,HTML5 支持 .mp3, .wav, .ogg 這三個種音樂格式的撥放。

HTML5 <audio> 支持音樂撥放,撥放種類有限,而且 HTML5 不知道穩定了沒。

  • 本次挑戰的項目
    • 增加 拖曳檔案 的撥放
    • 拖曳檔案 和 拖曳資料夾 的摸索
    • HTML5 圍觀

修改

demo
如上圖,最後一個檔案 mo - 45. not yet.mp3 是拖曳上傳的內容。

歷程

  • 增加本地拖曳撥放,操作方式為將本地 mp3 檔案上傳

檔案能知道的資訊有限

  • name 取得檔案名稱,如果需要做副檔名檢查,可利用它。
  • size 取得檔案大小 (bytes)。
  • type 取得檔案的 MIME 型別 (若無法對應會傳回空白)。

因為安全性,所以得不到路徑資訊,也就是不能隨便去掃描別人的本地資料。因此要完成資料夾下的所有檔案獲取會有困難。

其實瀏覽器本上就會支持檔案拖曳,並且在新分頁上顯示資訊,如果要避免瀏覽器自己開啟檔案,則使用 evt.stopPropagation() 將 drag 相關事件關閉,也就是說在當前頁面的 drag 事件都不會被瀏覽器知曉。

後記

  • 對於 .mp3 檔案要自動獲得專輯封面可能嗎?
    請參考 這裡
1
2
3
4
5
6
7
8
Field Length Offsets
Tag 3 0-2
Songname 30 3-32
Artist 30 33-62
Album 30 63-92
Year 4 93-96
Comment 30 97-126
Genre 1 127
要自己擠去 parsing 這些資訊還是算了吧。WRYYYYY
  • 對於資料夾整包拖曳操作?HTML5 drag upload folder
    在寫這篇的時候,網路上有 demo,但是只有在 chrome 21 下才有支持,看起來是從瀏覽器 ( 本地軟件 ) 來協助遍歷資料夾下的內容。不然是沒有權限去運行的。

  • 讀取的異步操作 ?
    是的,最近在編寫時常會遇到異步操作,也就是必須全用 callback 來完成,因為讀檔的資訊完成的 callback function 中並沒有 file.name 之類的資訊,如果適用 for(var i in files) 運行,會發生變數找不到的情況,因此用 $.each()reader.onload() 來完成這個操作。

    • onloadstart、onprogress、onload、onabort、onerror 和 onloadend 這幾個可以協助監控上傳資訊,也就是能知曉現在上傳進度 … 等。
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
var dropbox = document.getElementById("dropbox")
// init event handlers
dropbox.addEventListener("dragenter", dragEnter, false);
dropbox.addEventListener("dragexit", dragExit, false);
dropbox.addEventListener("dragover", dragOver, false);
dropbox.addEventListener("drop", drop, false);
// init the widgets
$("#progressbar").progressbar();
function dragEnter(evt) {
evt.stopPropagation();
evt.preventDefault();
}
function dragExit(evt) {
evt.stopPropagation();
evt.preventDefault();
}
function dragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
}
function drop(evt) {
evt.stopPropagation();
evt.preventDefault();
var files = evt.dataTransfer.files;
var count = files.length;
// Only call the handler if 1 or more files was dropped.
if (count > 0)
handleFiles(files);
}
function handleFiles(files) {
var mp3Files = $.map(files, function(f, i) {
return f.type.indexOf("audio/mp3") == 0 ? f : null;
});
$.each(mp3Files, function(i, file) {
document.getElementById("droplabel").innerHTML = "Processing " + file.name;
var reader = new FileReader();
reader.onload = function(evt) {
$('#playlist').append('<li>' + 'mo' + ' - ' + file.name + '</li>');
playlist.push({
title: file.name,
mp3: evt.target.result
});
$('#playlist li').each(function(i) {
var _i = i;
$(this).on('click', function() {
switchTrack(_i);
});
});
}
// init the reader event handlers
reader.onprogress = handleReaderProgress;
reader.onloadend = handleReaderLoadEnd;
reader.readAsDataURL(file);
});
}
function handleReaderProgress(evt) {
if (evt.lengthComputable) {
var loaded = (evt.loaded / evt.total);
$("#progressbar").progressbar({
value: loaded * 100
});
}
}
function handleReaderLoadEnd(evt) {
$("#progressbar").progressbar({
value: 100
});
}

最後

html

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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<title>Cover Art</title>
<link rel="stylesheet" href="css/stylesheets/style.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
</head>
<body>
<div id="playblock">
<div id="player">
<div class="cover"></div>
<div class="ctrl">
<div class="tag">
<strong>Title</strong>
<span class="artist">Artist</span>
<span class="album">Album</span>
</div>
<div class="control">
<div class="left">
<div class="rewind icon"></div>
<div class="playback icon"></div>
<div class="fastforward icon"></div>
</div>
<div class="volume right">
<div class="mute icon left"></div>
<div class="slider left">
<div class="pace"></div>
</div>
</div>
</div>
<div class="progress">
<div class="slider">
<div class="loaded"></div>
<div class="pace"></div>
</div>
<div class="timer left">0:00</div>
<div class="right">
<div class="repeat icon"></div>
<div class="shuffle icon"></div>
</div>
</div>
</div>
</div>
<div id="dropbox">
<div id="dropctrl">
<span id="droplabel">Drop mp3 file here...</span>
<div id="progressbar"></div>
</div>
<ul id="playlist"></ul>
</div>
</div>
<footer>
Copyright &copy; 2012 <a href="http://zespia.tw">SkyArrow</a>
</footer>
<script src="js/script.js"></script>
</body>
</html>

js

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
(function($) {
// Settings
var repeat = localStorage.repeat || 0,
shuffle = localStorage.shuffle || 'false',
continous = true,
autoplay = false,
playlist = [{
title: 'ふわふわ時間',
artist: '桜高軽音部(平沢唯、秋山澪、田井中律、琴吹紬)',
album: 'TVアニメ「けいおん!」劇中歌 - ふわふわ時間',
cover: 'http://dl.dropbox.com/u/5480889/coverart/cover/ふわふわ時間.jpg',
mp3: 'http://dl.dropbox.com/u/5480889/coverart/music/ふわふわ時間.mp3',
ogg: 'http://dl.dropbox.com/u/5480889/coverart/music/ふわふわ時間.ogg'
}, {
title: 'リップシンク',
artist: 'nano.RIPE',
album: '細胞キオク',
cover: 'http://dl.dropbox.com/u/5480889/coverart/cover/リップシンク.jpg',
mp3: 'http://dl.dropbox.com/u/5480889/coverart/music/リップシンク.mp3',
ogg: 'http://dl.dropbox.com/u/5480889/coverart/music/リップシンク.ogg'
}];
for (var i = 0; i < playlist.length; i++) {
var item = playlist[i];
$('#playlist').append('<li>' + item.artist + ' - ' + item.title + '</li>');
}
// Load playlist
var time = new Date(),
currentTrack = shuffle === 'true' ? time.getTime() % playlist.length : 0,
trigger = false,
audio, timeout, isPlaying, playCounts;
var play = function() {
audio.play();
$('.playback').addClass('playing');
timeout = setInterval(updateProgress, 500);
isPlaying = true;
}
var pause = function() {
audio.pause();
$('.playback').removeClass('playing');
clearInterval(updateProgress);
isPlaying = false;
}
// Update progress
var setProgress = function(value) {
var currentSec = parseInt(value % 60) < 10 ? '0' + parseInt(value % 60) : parseInt(value % 60),
ratio = value / audio.duration * 100;
$('.timer').html(parseInt(value / 60) + ':' + currentSec);
$('.progress .pace').css('width', ratio + '%');
$('.progress .slider a').css('left', ratio + '%');
}
var updateProgress = function() {
setProgress(audio.currentTime);
}
// Progress slider
$('.progress .slider').slider({
step: 0.1,
slide: function(event, ui) {
$(this).addClass('enable');
setProgress(audio.duration * ui.value / 100);
clearInterval(timeout);
},
stop: function(event, ui) {
audio.currentTime = audio.duration * ui.value / 100;
$(this).removeClass('enable');
timeout = setInterval(updateProgress, 500);
}
});
// Volume slider
var setVolume = function(value) {
audio.volume = localStorage.volume = value;
$('.volume .pace').css('width', value * 100 + '%');
$('.volume .slider a').css('left', value * 100 + '%');
}
var volume = localStorage.volume || 0.5;
$('.volume .slider').slider({
max: 1,
min: 0,
step: 0.01,
value: volume,
slide: function(event, ui) {
setVolume(ui.value);
$(this).addClass('enable');
$('.mute').removeClass('enable');
},
stop: function() {
$(this).removeClass('enable');
}
}).children('.pace').css('width', volume * 100 + '%');
$('.mute').click(function() {
if ($(this).hasClass('enable')) {
setVolume($(this).data('volume'));
$(this).removeClass('enable');
} else {
$(this).data('volume', audio.volume).addClass('enable');
setVolume(0);
}
});
// Switch track
var switchTrack = function(i) {
if (i < 0) {
track = currentTrack = playlist.length - 1;
} else if (i >= playlist.length) {
track = currentTrack = 0;
} else {
track = i;
}
$('audio').remove();
loadMusic(track);
if (isPlaying == true) play();
}
// Shuffle
var shufflePlay = function() {
var time = new Date(),
lastTrack = currentTrack;
currentTrack = time.getTime() % playlist.length;
if (lastTrack == currentTrack)++currentTrack;
switchTrack(currentTrack);
}
// Fire when track ended
var ended = function() {
pause();
audio.currentTime = 0;
playCounts++;
if (continous == true) isPlaying = true;
if (repeat == 1) {
play();
} else {
if (shuffle === 'true') {
shufflePlay();
} else {
if (repeat == 2) {
switchTrack(++currentTrack);
} else {
if (currentTrack < playlist.length) switchTrack(++currentTrack);
}
}
}
}
var beforeLoad = function() {
var endVal = this.seekable && this.seekable.length ? this.seekable.end(0) : 0;
$('.progress .loaded').css('width', (100 / (this.duration || 1) * endVal) + '%');
}
// Fire when track loaded completely
var afterLoad = function() {
if (autoplay == true) play();
}
// Load track
var loadMusic = function(i) {
var item = playlist[i],
newaudio = $('<audio>').html('<source src="' + item.mp3 + '"><source src="' + item.ogg + '">').appendTo('#player');
$('.cover').html('<img src="' + item.cover + '" alt="' + item.album + '">');
$('.tag').html('<strong>' + item.title + '</strong><span class="artist">' + item.artist + '</span><span class="album">' + item.album + '</span>');
$('#playlist li').removeClass('playing').eq(i).addClass('playing');
audio = newaudio[0];
audio.volume = $('.mute').hasClass('enable') ? 0 : volume;
audio.addEventListener('progress', beforeLoad, false);
audio.addEventListener('durationchange', beforeLoad, false);
audio.addEventListener('canplay', afterLoad, false);
audio.addEventListener('ended', ended, false);
}
loadMusic(currentTrack);
$('.playback').on('click', function() {
if ($(this).hasClass('playing')) {
pause();
} else {
play();
}
});
$('.rewind').on('click', function() {
if (shuffle === 'true') {
shufflePlay();
} else {
switchTrack(--currentTrack);
}
});
$('.fastforward').on('click', function() {
if (shuffle === 'true') {
shufflePlay();
} else {
switchTrack(++currentTrack);
}
});
$('#playlist li').each(function(i) {
var _i = i;
$(this).on('click', function() {
switchTrack(_i);
});
});
if (shuffle === 'true') $('.shuffle').addClass('enable');
if (repeat == 1) {
$('.repeat').addClass('once');
} else if (repeat == 2) {
$('.repeat').addClass('all');
}
$('.repeat').on('click', function() {
if ($(this).hasClass('once')) {
repeat = localStorage.repeat = 2;
$(this).removeClass('once').addClass('all');
} else if ($(this).hasClass('all')) {
repeat = localStorage.repeat = 0;
$(this).removeClass('all');
} else {
repeat = localStorage.repeat = 1;
$(this).addClass('once');
}
});
$('.shuffle').on('click', function() {
if ($(this).hasClass('enable')) {
shuffle = localStorage.shuffle = 'false';
$(this).removeClass('enable');
} else {
shuffle = localStorage.shuffle = 'true';
$(this).addClass('enable');
}
});
var dropbox = document.getElementById("dropbox")
// init event handlers
dropbox.addEventListener("dragenter", dragEnter, false);
dropbox.addEventListener("dragexit", dragExit, false);
dropbox.addEventListener("dragover", dragOver, false);
dropbox.addEventListener("drop", drop, false);
// init the widgets
$("#progressbar").progressbar();
function dragEnter(evt) {
evt.stopPropagation();
evt.preventDefault();
}
function dragExit(evt) {
evt.stopPropagation();
evt.preventDefault();
}
function dragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
}
function drop(evt) {
evt.stopPropagation();
evt.preventDefault();
var files = evt.dataTransfer.files;
var count = files.length;
// Only call the handler if 1 or more files was dropped.
if (count > 0)
handleFiles(files);
}
function handleFiles(files) {
var mp3Files = $.map(files, function(f, i) {
return f.type.indexOf("audio/mp3") == 0 ? f : null;
});
$.each(mp3Files, function(i, file) {
document.getElementById("droplabel").innerHTML = "Processing " + file.name;
var reader = new FileReader();
reader.onload = function(evt) {
$('#playlist').append('<li>' + 'mo' + ' - ' + file.name + '</li>');
playlist.push({
title: file.name,
mp3: evt.target.result
});
$('#playlist li').each(function(i) {
var _i = i;
$(this).on('click', function() {
switchTrack(_i);
});
});
}
// init the reader event handlers
reader.onprogress = handleReaderProgress;
reader.onloadend = handleReaderLoadEnd;
reader.readAsDataURL(file);
});
}
function handleReaderProgress(evt) {
if (evt.lengthComputable) {
var loaded = (evt.loaded / evt.total);
$("#progressbar").progressbar({
value: loaded * 100
});
}
}
function handleReaderLoadEnd(evt) {
$("#progressbar").progressbar({
value: 100
});
}
})(jQuery);
Read More +

JQuery 魔法陣製作 Magic Circle

製作起源

魔法陣字型出處

也是因為在 2014-04-17 出了一款魔法陣字型,在藉由惡友們的催促下,不,是誘導下嘗試做了 jquery 的插件來完成魔法陣的製作。當然沒有網址中做得那麼好看。

不過具體下也努力去完成了。附圖如下:

製作

前置作業

  • JQuery
  • CSS 旋轉和陰影配置

開始

  • 配置多層圓,可以參考 這裡,先將內容拆成 <span>A</span> 的形式。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    h1 span {
    font: 24px myFirstFont, Monaco, MonoSpace;
    height: 300px;
    position: absolute;
    width: 20px;
    left: 50%;
    top: 0;
    -webkit-transform-origin: 50% 50%;
    -moz-transform-origin: 50% 50%;
    -ms-transform-origin: 50% 50%;
    -o-transform-origin: 50% 50%;
    transform-origin: 50% 50%;
    }
  • 將每個 <span> 設置成絕對座標配置,乍看下是一個長條形,並且使用 transform-origin 50% 50% 設置旋轉中心,也就是長條形的正中間。rgba(177, 17, 22, 1) 為血紅色

更新

  • 接著要計算字距,來方便每一個字符偏轉角度。而且每一層圓的偏轉角度還有所不同,這裡我並沒有詳細去計算。

  • transform rotate(50 deg) 用來旋轉

  • 光暈效果呈現 box-shadow 0px 0px 10px rgba(177, 17, 22, 1) 於外部產生陰影。

    • 至於內部效果沒有做得很好看。

山田かみら 的建議下,進行的大幅度地修改,同時也發現之前的版本有過度延遲的問題,原因都發生於過多的 for each 計算。

  • 先修正過於愚蠢的 CSS,加入比較好的 class 處理,來達到可以物件化。
  • 原本文字的處理仍需要使用旋轉的方式運作,而考慮將每一個圈放到同一個正方形內,直接對正方形作旋轉即可,剩下的操作交給瀏覽器去進行計算。因此,做了架構上的分層。

關於代碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script>
$(function() {
$("#test1").magicsquare('fire', {radius: 500, radius_padding: 150,
radius_center: 200, duration: 10});
$("#test2").magicsquare('fire', {radius: 300, radius_padding: 50,
radius_center: 50, duration: 30});
$("#test1").draggable();
$("#test2").draggable();
$(".center-content").click(function() {
$("#test1").magicsquare('boom');
$("#test2").magicsquare('boom');
});
});
</script>

不知道 CSS3 穩定了沒有,在動畫處理引用 animate.css。

但是如果要完成連續型的動畫播放,單純 CSS 目前不想去研究能不能寫腳本。所以在定秒處理之後呼叫 callback() 去進行下一個動畫放置 (仍以 jquery 為主)。

剩下的交給 山田君 了。

Demo & 下載

very old version demo gif
demo link

repo jquery-magic-circle on Github

Reference

Read More +

Nodejs 初學上手

網站利器

簡介

寫網站對筆者來說是第一次,只有看過別人用 PHP framework 架站,會用到 SQL 語法,還要搭配前端的 CSS、javascript,到現在 javascript 和 CSS 都仍不熟,那這麼還寫一篇文章出來害人呢。

Nodejs 出來後,一個完全 javascript 的環境,撇開了 Apache,只剩下 Javascript 和前端頁面!

前置作業

您需要會點,倒不如說吾就這點程度。

  • HTML 基礎文本語法,能夠造出靜態網頁。
  • Javascript

環境安裝

  • 安裝 NodeJs
  • 安裝 MongoDB
  • 安裝 WebMatrix
    非必要,但是開專案後大體上就會棄,用 Sublime 編輯。其實是因為到了 express 網站,也看不懂要去哪裡下什麼指令指令去安裝架設。

目標

知道 Nodejs 在做什麼,並且用它來寫網站。

歷程

一開始被丟了相當大的問題,原因是當下根本不清楚 Nodejs 是什麼,於是小夥伴們先丟了一個 七天學會 Nodejs 的鏈結給我。

就一股腦地走馬看花,同時也看了很多篇相關於 Nodejs 的文章,但仍壓根不知其何物,只有見識到相當多的指令說明,果然還真必須實作一番才能理解。

    慧根嚴重不足,請多多見諒

以前可能用過 Apache,但也不知道其功能,只知道可以幫助將資料藉由 port 80 傳出去,而且還因為某個軟件自帶的安裝 Apache ,其中漏洞導致成為殭屍網路的一群發動攻擊。那件往事還真是難忘,在宿舍還被鎖網。

Nodejs 相當強,全部基於 javascript 可以運行讀檔寫檔還有架站,php 的功能全都包了,但是對於 SQL 資料庫的部分,由於 Nodejs 的操作插件都是在 NPM 平台上,有什麼需求都必須去那邊下載使用。大多數使用 Nodejs 搭配 mongoDB,就相當於 php 搭配 MySQL。

因此藉由上述內容,請明白 Nodejs 和 NPM 是同時灌的,就像 java application 必須有 import library 使用。

換了語言換了腦袋,真的只認為是換語言如此單純的事情嗎?

對於架站 framework 來說,應該不少有人用過 php framework,如果不明白 framework 也沒關係,現在動手去查。看完之後再去查查 MVC MVP MVVM。總之,如果在大學寫過一點程式,多少都會明白自幹框架是多麻煩的事情,但也是好修好改的開始。這裡不談 php framework,nodejs 有一個 express 的 framework,基於我的無知,看不懂官方網站如何指導安裝,那使用邪惡 Windows WebMatrix 提供的網頁開發方式,先快速開啟專案。

後來是明白 express 的安裝方式,express github 上的 README.md 說得相當清楚,這時也要培養看完 README.md 再行動的習慣。

打開 express 專案,一定會發現有數個未知附檔名的出現,大多是 .jade,不要太擔心, jade 檔案就是 html 基於縮排而成的語言,相當精簡且可以根據 express 架構導入變數值。

如果要為這個專案下的 server.js (舊版命名為 app.js) 增加新的模組套用怎麼做?

yourProject/folder/
1
$ npm link modulesName

如果原本使用下述安裝至作業系統,則在 server.js 則不會發生找不到模組的問題。

anywhere
1
$ npm install -g modulesName

接著你會發現專案下 node_modules 會有無數你在 server.js 中 require 的模組內容,同時也會發現模組下又有相依模組,可以層層查閱,這是一個很有趣的現象,不知道模組與模組下會不會有相同相依模組存在。看起來可以猜測為-有。

專案都開啟了,最關注於 CSS 和 JQuery 怎麼灌輸進去。

project/views/layout.jade
1
2
3
4
5
6
7
8
9
10
11
12
doctype 5
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
link(rel='stylesheet', href='/stylesheets/ui-darkness/jquery-ui-1.10.4.custom.css')
link(rel='stylesheet', href='/stylesheets/webstyle.css')
script(src='/javascripts/jquery-1.10.2.js')
script(src='/javascripts/jquery-ui-1.10.4.custom.js')
body
block content
<script src='/javascripts/global.js'></script>

而你的 javascript file 就在 project/public/javascript 下,而 CSS 則在 project*public/stylesheets 下,頓時心中一塊大石頭放下了,在還沒調用資料庫前,至少靜態網頁能在 express 運行中出現。

先談到這裡了,要用 express 架出完整的網站,還要走段 mongoDB 的運用,還要學會 jade 的撰寫方式。

其實學到 nodejs express 後,第一個挖到的是 Hexo blog 的製作,也就是你眼前所見的網站。這是一個基於 nodejs 下的套件,使用 markdown 編撰文章,雖然沒有文章線上編輯,幾乎靠者純文字檔的方式運行,為了架設這個頁面,費盡了一番苦心想要進行搬家工程。

如何進行搬家工程? 爬蟲 對吧?那要用什麼語言進行爬蟲,沒錯!就是剛學到的 Nodejs,可是要轉換成 markdown file 耶,之後是失敗了,因為有很多 CSS 上的問題,轉換一直不理想。

如何架出第一個有 ajax 和 database 的 express 網站,可以查閱下方鏈結。

Resource & Reference

Read More +