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 +

網站看板娘製作

簡介

仿製偽春菜,用於網站小幫手,或者象徵物般的存在,高階可以引入對話 AI。 原版偽春菜,常見的別名又稱伺か、何か、任意、さくら。是一種電腦的桌面程式。視其功能的不同,從站在那陪使用者聊聊天解解悶,或報時對時收郵件,甚至處理電腦中大大小小的事都有可能辦到 而網站移植版有許多版本,看到大部分為php 版本、以WordPress Blog插件為大宗。 移植版常有的功能縮減為顯示公告、賣萌、統計上站人數等。跟電腦版不同較少出現會隨互動顯著成長的類型,另外在技術層面上,很多牽扯到資料庫的運用,相當複雜。

在靜態頁面上,如何簡單運用外連資料庫就是本次課題,決定開始偷偷動手腳了。

對了,Jquery 的模組化單純是老尼克推坑,接著朝向 AI 系統發展,就以目前情況來看,可能沒有時間去完成或了解。但是有一個關鍵詞 AIML 網址內附程式,可能會幫助興趣者從零開始建造,如果要有中文可能要去調用翻譯機就是了。還是要說明一下,這裡偷偷用了 google 提供的服務,所以沒有完善的資料庫語法,算是邪門歪道。

製作開始

前置作業

  • 獲取自己的 Google Spreadsheet 的 key 和 formkey。
  • 建立方式
    • 製作 Google 表單,也就是問卷。
    • 放出一個選項命名為 ‘store_data_base’ (預設,否則您將要修改 json)
    • 之後您將會得到表單對應的試算表。
    • 分別找到 key 和 formkey 還有表單欄位的 html tag id.
      • key - 在相對的試算表中,查閱當前網址
        https://docs.google.com/spreadsheet/ccc?key=0ArRwmWo93u-mdG93a2dkSWxIbHEzZjRIeDdxZXdsU1E&usp=drive_web#gid=0
        
        key=後面一串便是您需要的,您可以檢查以上的值和代碼中的預設值。
      • formkey - 在您開啟問卷的網址中
        https://docs.google.com/forms/d/1xADUIiBq1ksH7lxwSch1Nz_p2gSxdJttmv5OJOxJye0/viewform
        
        會發現 d/formkey/viewform 就在其中。
      • html tag id - 對問卷頁面查閱原始碼,找到輸入欄位類似於 entry.2030600456 的格式。
  • 本站使用的 My Google Spreadsheet 如有表單建立疑慮可參考。

  • 以下代碼可能會與 GitHub 上不同,會盡可能去兩邊更新。

JQuery Code

jquery.morris.ukagaka.resource.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
(function($){ // 封裝起來, 以免和外界js 變數衝突到
$.fn.extend({
//plugin name - animatemenu // 定義 plugin 名稱
ukagaka: function(options) {
//Settings list and the default values // 設定plugin input parameters 的預設值
var defaults = {
googleKey: '0ArRwmWo93u-mdG93a2dkSWxIbHEzZjRIeDdxZXdsU1E',
googleFormkey: '1xADUIiBq1ksH7lxwSch1Nz_p2gSxdJttmv5OJOxJye0',
googleSheet: "od6",
googleSheetField: "entry.2030600456",
talkTime: 10000
};
// 把預設值和實際輸入值比對, 如果有傳入值的則以傳入值為主
// 如此便得到輸入值 options (在此匿名函式中存在之變數)
var options = $.extend(defaults, options);
// 執行此 plugin 的實際動作, 對其作用對象的陣列迭代(iterate over), 例如說對$(".class_name") 呼叫此plugin, 則 this.each 就代表所有帶有 class_name 為 class 屬性的DOM element
return this.each(function() {
var o = options;
//Assign current element to variable, in this case is UL element
var obj = $(this); // obj 代表迭代到的單一物件
var key = o.googleKey;
var sheet = o.googleSheet;
var formkey = o.googleFormkey;
var sheetfield = o.googleSheetField;
var talking = [];
var innerSettingHTML = "";
innerSettingHTML += "<div id='ukagaka_img'></div>";
innerSettingHTML += "<div class='ukagaka_box'>";
innerSettingHTML += "<div class='ukagaka_msg' id='ukagaka_msgbox'>汝 先看看周遭</div>";
innerSettingHTML += "<div class='ukagaka_msg' id='ukagaka_menubox' style='display:none'>使用選單功能&#65292;吾才不需要汝教。<br/><br/><span id='ukagaka_menu_btn_addstring'>$ 學習</span><span id='ukagaka_menu_btn_renewlist'>$ 日誌</span><span id='ukagaka_menu_btn_exit'>$ 結束</span></div>";
innerSettingHTML += "<div class='ukagaka_msg' id='ukagaka_stringinput' style='display:none'>請輸入讓偽春菜學的句子<br/><br/><input id='ukagaka_addstring' type='text'/><span id='ukagaka_addmenu_add'>$ 增加</span><span id='ukagaka_btn_menu'>$ 取消</span></div>";
innerSettingHTML += "<div class='ukagaka_msg' id='ukagaka_renewlist' style='display:none'>更新日誌<br/><br/>Morris 修正<br/><br/>找尋 AI 系統<br/>找尋 AI 對話<br/><br/><span id='ukagaka_btn_menu'>$ 取消</span></div>";
innerSettingHTML += "<input id='ukagaka_sheetfield' type='hidden' value='" + sheetfield + "'>";
innerSettingHTML += "</div>";
obj.html(innerSettingHTML);
var footerMenuHTML = "";
footerMenuHTML += "<div id='ukagaka_controlpanel'>";
footerMenuHTML += "<span id='ukagaka_btn_display'>Display</span> ";
footerMenuHTML += "<span id='ukagaka_btn_menu'>Menu</span>";
footerMenuHTML += "</div>";
obj.after(footerMenuHTML);
function reloadtalking(){
/* JSON / load string from database */
$.getJSON("https://spreadsheets.google.com/feeds/list/" + key + "/" + sheet + "/public/values?alt=json", function(JData){
for (var i = 0; i < JData.feed.entry.length; i++) {
talking[i] = JData.feed.entry[i].gsx$storedatabase.$t;
// console.log("talk stmt : " + talking[i]);
}
$('input#ukagaka_addstring').attr('placeholder', '目前春菜學會了' + JData.feed.entry.length + '個字彙');
});
};
$(window).load(function(){
var talk_timer = setInterval(talkingbox, o.talkTime);
function talkingbox() {
if($("#ukagaka_msgbox").css("display") != 'none')
$("#ukagaka_msgbox").fadeOut(500, function(){
$(this).html(talking[Math.floor(Math.random() * talking.length)]).fadeIn(500)});
}
});
reloadtalking();
obj.draggable();
$(document).on('click', "span#ukagaka_btn_display", function(event) {
$("#ukagaka_panel").fadeToggle(1000);
});
$(document).on('click', "span#ukagaka_menu_btn_exit", function(event) {
$(".ukagaka_box div").fadeOut(500);
$("#ukagaka_msgbox").delay(500).fadeIn(500);
});
$(document).on('click',"span#ukagaka_btn_menu", function(event) {
$(".ukagaka_box div").fadeOut(500);
$("#ukagaka_menubox").delay(500).fadeIn(500);
});
$(document).on('click',"span#ukagaka_menu_btn_addstring", function(event) {
$(".ukagaka_box div").fadeOut(500);
$("#ukagaka_stringinput").delay(500).fadeIn(500);
});
$(document).on('click',"span#ukagaka_menu_btn_renewlist", function(event) {
$(".ukagaka_box div").fadeOut(500);
$("#ukagaka_renewlist").delay(500).fadeIn(500);
});
$(document).on('click',"span#ukagaka_addmenu_add", function(event) {
var add = $("input#ukagaka_addstring").val();
var googleSheetField = $('input#ukagaka_sheetfield').val();
var sendData = {};
sendData[googleSheetField] = add;
if(!((add.length <= 1) || add.indexOf('script') > -1|| add.indexOf('body') > -1 ||
add.indexOf('style') > -1 || add.indexOf('link') > -1 || add.indexOf('iframe') > -1 || add.indexOf('head') > -1 ||
add.indexOf('nav')>-1||add.indexOf('object')>-1||add.indexOf('embed')>-1)){
$.ajax({
type: 'POST',
url: 'https://docs.google.com/forms/d/' + formkey + '/formResponse',
data: sendData,
dataType: "xml",
statusCode: {
0: function() {
$("input#ukagaka_addstring").attr("value","");
$(".ukagaka_box div").fadeOut(500);
$("#ukagaka_msgbox").fadeOut(500, function(){
$(this).html("偽春菜學習了 !").fadeIn(1000)});
},
200: function() {
$("input#ukagaka_addstring").attr("value","");
$(".ukagaka_box div").fadeOut(500);
$("#ukagaka_msgbox").fadeOut(500, function(){
$(this).html("偽春菜學習了 !").fadeIn(1000)});
}
}
});
} else {
alert("OOPS!偽春菜不接受這個字串喔!");
}
});
});
}
});
})(jQuery);

CSS

以下 CSS 為原作設定。

ukagaka.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
#ukagaka_controlpanel {
background:white;padding:8px;
box-shadow:#555 0px 0px 4px;
text-shadow: #555 0px 0px 1px;
margin-bottom:-3px;
border-radius:5px 5px 0 0;
position:fixed;
right:40px;
bottom:0px;
font-size:10pt;
z-index:101;
}
#ukagaka_controlpanel span, #ukagaka_panel span {
padding:5px;
cursor:pointer;
height:0px;
}
#ukagaka_panel {
position: fixed;
right: 10px;
bottom: 10px;
width: 88.2px;
height: 230.3px;
z-index:10;
}
/* ukagaka msgbox */
.ukagaka_box{
position: absolute;
bottom: 117px;
right: 97px;
font-size: 10pt;
}
.ukagaka_msg{
width:195px;
background: white;
padding:10px;
word-wrap: break-word;
word-break: normal;
color:black;
box-shadow:rgba(15,15,15,0.8) 0px 0px 8px;
}
.ukagaka_msg::after {
width:10px;
height:10px;
-moz-transform:rotate(45deg);
-webkit-transform:rotate(45deg);
-o-transform:rotate(45deg);
-ms-transform:rotate(45deg);
transform:rotate(45deg);
background:white;
content: '';
float: right;
margin-right: -14px;
margin-top:7px;
box-shadow:rgba(15,15,15,0.8) 3px -3px 8px -3px;
}
/* */
#ukagaka_img {
background: url(./img/ukagaka_img.png) no-repeat;
width: 126px;
height: 329px;
transform: scale(0.7);
-ms-transform: scale(0.7);
-webkit-transform: scale(0.7);
-o-transform: scale(0.7);
-moz-transform: scale(0.7);
position: absolute;
top: -49px;
right: -19px;
}
#ukagaka_stringinput input {
width:95%;
}

Stylus

  • 如果你在 Nodejs 下想使用,這裡提供本站使用的 ukagaka.styl。
  • 最後在 theme/xxxx/source/css/style.styl 進行匯入。
    1
    @import '_partial/ukagaka'
theme/xxxx/source/css/_partial/ukagaka.styl
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
#ukagaka_controlpanel
font-size 1.1em
padding 0 0 0.3125em 0
position fixed
right 40px
bottom 0px
background color-section
span
font-family font-custom-family
color color-blue
border-radius 10px
border-width 5px
border-style solid solid solid
&:hover
color color-theme2
transition color .5s
#ukagaka_panel
padding 0.5em 2% 1em
width 88.2px
height 230.3px
position fixed
right 40px
bottom 40px
span
padding 5px
cursor pointer
height 0px
.ukagaka_box
border-radius 10px
border-width 5px
border-style solid dashed dashed
position absolute
bottom 150px
right 120px
font-size 100%
background color-section
color gray
.ukagaka_msg
border-radius 10px
padding 0.5em 2% 1em
color color-white
width 195px
font-family font-custom-family, font-default
&::before
font-smoothing()
padding-right 0.5em
span#ukagaka_menu_btn_addstring, span#ukagaka_menu_btn_renewlist,
span#ukagaka_menu_btn_exit
border-radius 5px
border-width 1px
border-style solid solid solid
display inline
color color-blue
&:hover
color color-theme2
&::before
font-smoothing()
padding-right 0.5em
span#ukagaka_btn_menu, span#ukagaka_addmenu_add
border-radius 5px
border-width 1px
border-style solid solid solid
display inline
color color-blue
&:hover
color color-theme2
&::before
font-smoothing()
padding-right 0.5em
#ukagaka_img
background url(/img/ukagaka_img.png) no-repeat
width 150px
height 350px
transform scale(0.7)
-ms-transform scale(0.7)
-webkit-transform: scale(0.7)
-o-transform scale(0.7)
-moz-transform scale(0.7)
position absolute
top -49px
right -19px
#ukagaka_stringinput
>input
width 95%

如何使用 How to use

一般網頁

  • 記得要使用 utf-8 的網頁,否則中文將會炸掉。
  • 記的要使用 jquery-ui.js。
  • 記得要使用 jquery-x.x.x.js。
  • 最後引入咱們的 ukagaka.resource.js 和 ukagaka.css。
  • 然後與一般的 jquery 綁定相同,請參考以下代碼。
  • 如果您要客製化,請傳入 $(element).ukagaka(options);
  • options 的操作,請詳見 $(element).ukagaka({xxx:yyy, zzz:www});
main.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
<script src="https://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
<script src='jquery.morris.ukagaka.resource.js' type='text/javascript'></script>
<link type="text/css" rel="stylesheet" href="ukagaka.css">
<!-- ukagaka start -->
<script>
$(document).ready(function() {
$('#ukagaka_panel').ukagaka();
});
</script>
<div id='ukagaka_panel'>
</div>
<!-- ukagaka end -->
</body>
</html>

Hexo Blog

萬里花

  • 如果您希望每一頁都能見到
    • 在 footer.ejs 下插入 HTML TAG 代碼。
    • 在 after_footer.ejs 進行綁定
  • 反之,請自行摸索
theme/xxxx/layout/_partial/post/after_footer.ejs
1
2
3
4
5
6
7
<% if (config.ukagaka) { %>
<script src="<%- config.root %>js/jquery-ui.js"></script>
<script src="<%- config.root %>js/jquery.morris.ukagaka.resource.js"></script>
<script type="text/javascript">
$('#ukagaka_panel').ukagaka();
</script>
<% } %>
  • 插入位置看您的造化
theme/xxxx/layout/_partial/post/footer.ejs
1
2
3
4
5
<!-- ukagaka BEGIN -->
<div id='ukagaka_panel'>
</div>
<!-- ukagaka END -->

學習與撰寫過程

第一次寫 JQuery 和 Google Spreadsheet 相關,然後將 CSS 修改成 Stylus。

  • Stylus 是 CSS 的前置處理,有點類似 .cpp 產出 .exe 的關係。
  • 改寫時一堆問題,Stylus 默認縮排 2 個空白,編譯上一堆問題沒發現,導致浪費時間。
  • Google Spreadsheet 由於現在比較新版,每個表單的輸入欄位 id 也有所不同,所以可能會比較特別一點。
  • 什麼是靜態網頁的定義越來越模糊,javascript 帶你引入一堆外部資料庫,用低廉免錢重新審視。
  • 學習用 ajax 調用 Google Spreadsheet 資料。
  • Track code 能力訓練。

GitHub

Reference

Read More +

解決 Hexo Comment !

評論 Widget 設定

為什麼會有這篇文章

  • 你的主題可能沒有 recent_comment.ejs
  • Comment 可能是 多說Duoshuo 而你不喜歡

開始正文

使用 Disqus

  • 請到 Disqus 申請帳號,並且記住你的 shortname

    • 到本機下,修改本機目錄下的 _confid.yml 在 disqus_shortname 貼上自己的 shortname
    • 接著,就是確認運行成功。
      1
      2
      # Disqus
      disqus_shortname: morris1028
  • Widget 側欄的近期評論,當然還有熱門、聚合 … 等。請參考 這裡

    themes/xxxx/layout/_widget/recent_comment.ejs
    1
    2
    3
    4
    <div id="recentcomments" class="dsq-widget">
    <p class="asidetitle">Recent Comments</p>
    <script type="text/javascript" src="http://morris1028.disqus.com/recent_comments_widget.js?num_items=10&hide_avatars=1&avatar_size=32&excerpt_length=100&hide_mods=0"></script>
    </div>
  • 關於主題可能沒有 comment.ejs,請在目錄下增加代碼
    themes/xxxx/layout/_partial/comment.ejs
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <% if (page.comments){ %>
    <section id="comment">
    <h1 class="title"><%= __('comment') %></h1>
    <% if (theme.comment_provider == "facebook") {
    if (theme.facebook) { %>
    <%- partial('_partial/facebook_comment', {fbConfig: theme.facebook}) %>
    <% } %>
    <% } else if(config.disqus_shortname) { %>
    <div id="disqus_thread">
    <noscript>Please enable JavaScript to view the <a href="//disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
    </div>
    <% } %>
    </section>
    <% } %>
  • 萬一還是啟動不成功,請查閱 after_footer.ejs 是否具有以下代碼
    themes/xxxx/layout/_partial/after_footer.ejs
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <% if (config.disqus_shortname){ %>
    <script type="text/javascript">
    var disqus_shortname = '<%= config.disqus_shortname %>';
    (function(){
    var dsq = document.createElement('script');
    dsq.type = 'text/javascript';
    dsq.async = true;
    dsq.src = '//' + disqus_shortname + '.disqus.com/<% if (page.comments){ %>embed.js<% } else { %>count.js<% } %>';
    (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    }());
    </script>
    <% } %>
  • 評論 CSS 設置,請到 comment.styl 查閱
    themes/xxxx/source/css/_partial/comment.styl
    1
    2
    3
    4
    5
    6
    7
    8
    #comment
    padding 20px
    background #272822
    box-shadow 1px 2px 3px #ddd
    margin-bottom 50px
    .title
    font-weight normal
    margin-bottom 15px
    • 最後再確認一下,有載入 comment 的 CSS
      theme/xxxx/source/_partial/css/style.styl
      1
      @import '_partial/comment'

更多

  • 其實差不多了,想必也能配置成功。
  • 關於近期文章 widget
    themes/xxxx/layout/_widget/recent_comment.ejs
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <% if (site.posts.length){ %>
    <div class="categorieslist">
    <p class="asidetitle">Recents</p>
    <ul>
    <% site.posts.sort('date', -1).limit(5).each(function(post){ %>
    <li>
    <a href="<%- config.root %><%- post.path %>"><%= post.title || '(no title)' %></a>
    </li>
    <% }) %>
    </ul>
    </div>
    <% } %>
  • 最後在 themes/xxxx/_config.yml 加入您的 widget
    themes/xxxx/_config.yml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #### Widgets
    widgets:
    - recent_posts
    - category
    - archive
    - tagcloud
    - recent_comment
    - links
    - rss

最後

非常感謝您的閱讀

Read More +

第一次來到 Hexo !

加油

失敗就是失敗

看著右上方的清單,還真有 wiki 的感覺,對於長篇大論是挺有用的,現在應該說是裝飾,接下來要描述失敗的開始。

這是一個搬運的過程,但是宣告失敗

初章

為了轉移過來,將 Morris’ blog(PChome) 文章倚靠爬蟲方式轉移過來,但是沒想到這裏要的是 markdown 檔案格式,用 Nodejs 寫了巨噁無比的代碼來專屬爬 PChome 新聞台,並且使用套件將其轉換成 markdown。

最後宣告失敗。

用了不少可以將 html to markdown 的工具,或者只是單純要 html to text,但是不管哪個產出的格式都不好,心灰意冷的情況下,開始動工修改 node_modules 資料夾下的插件代碼,track 相異插件各種作噁,最後還是沒成功。

次章

目前以玩玩的心態架設這個靜態頁面。

附上 20140411 BACKUP Morris’ blog(PChome) backup

nodejslink
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
var http = require('http'),
fs = require('fs');
var toMarkdown = require('to-markdown').toMarkdown;
var htmlToText = require('html-to-text');
/*
var text = htmlToText.fromString('<h1>Hello World</h1>', {
wordwrap: 130
});*/
// console.log(toMarkdown('<b>Hello world</b>'));
var websiteName = "zerojudge";
var websitePage = 141;
var websiteDomain = 'http://mypaper.pchome.com.tw/';
var url = websiteDomain + websiteName;
var loadprocess = 0;
clawingWebSite(url, websitePage);
function clawingWebSite(url, websitePage) {
for(var i = 0; i <= websitePage; i++) {
if(i == 0)
clawingWebPage(url);
else
clawingWebPage(url + "/P" + i);
}
}
function clawingWebPage(url) {
readWebPage(url);
}
function branchWebPage(source) {
var sourceIndex = source.indexOf('class="blog"');
while(sourceIndex >= 0) {
var pageLink = source.indexOf(websiteName + '/post', sourceIndex);
if(pageLink > 0) {
var endLink = source.indexOf('"', pageLink);
var articleLink = source.substr(pageLink, endLink - pageLink);
readWebArticleLink(websiteDomain + articleLink, articleLink);
sourceIndex = pageLink + 1;
sourceIndex = source.indexOf('title brk_h', sourceIndex);
} else {
break;
}
}
}
function parsingArticlePage(source, fileName) {
var contentBody = "";
var articleTitle = "";
var mdFormat = "";
var sourceIndex = source.indexOf('name="keywords"');
sourceIndex = source.indexOf('content="', sourceIndex);
var nextIndex = source.indexOf('"', sourceIndex + 10);
articleTitle = source.substr(sourceIndex + 9, nextIndex - (sourceIndex + 9));
sourceIndex = nextIndex;
console.log('Title = ' + articleTitle);
sourceIndex = source.indexOf('<div class="innertext brk_h"');
var endIndex = source.indexOf('<div id="ArticleMapTitle"');
contentBody = source.substr(sourceIndex, endIndex - sourceIndex - 1);
contentBody += "</div>";
var sourceBody = contentBody;
if(endIndex - sourceIndex - 1 <= 0)
return;
articleTitle = articleTitle.replace(/\[/g, "【");
articleTitle = articleTitle.replace(/\]/g, "】");
var text = htmlToText.fromString(sourceBody, {
wordwrap: 130
});
contentBody = toMarkdown(contentBody);
mdFormat += "title: " + articleTitle + "\n";
mdFormat += "date: 2014-04-10 20:10:28" + "\n";
mdFormat += "tags: " + "\n";
var tagIndex = source.indexOf('<div id="article_tag">');
if(tagIndex > 0) {
tagIndex += '<div id="article_tag">'.length + 1;
var tagTail = source.indexOf('<div id="article_author" align="right">');
var tagEndIndex;
while(true) {
var tagStartIndex = source.indexOf('search_fields=tag">', tagIndex);
tagStartIndex += 'search_fields=tag">'.length;
if(tagStartIndex < 0 || tagStartIndex > tagTail)
break;
tagEndIndex = source.indexOf('</a>', tagStartIndex);
var articleTag = source.substr(tagStartIndex, tagEndIndex - tagStartIndex);
console.log(articleTag);
mdFormat += "- " + articleTag + "\n";
tagIndex = tagEndIndex;
}
}
mdFormat += "---" + "\n\n";
text = " " + text;
text = text.replace(/\n/g, "\n ");
mdFormat += text;
loadprocess++;
fs.open('sourcePage' + loadprocess + '.html', 'w', 0666, function(e, fd) {
if(e) {
console.log('错误信息:' + e);
} else {
fs.write(fd, source, 0, 'utf8', function(e) {
if(e) {
console.log('出错信息:' + e);
} else {
fs.closeSync(fd);
}
});
}
});
fs.open('textPC' + loadprocess + '.md', 'w', 0666, function(e, fd) {
if(e) {
console.log('错误信息:' + e);
} else {
fs.write(fd, mdFormat, 0, 'utf8', function(e) {
if(e) {
console.log('出错信息:' + e);
} else {
fs.closeSync(fd);
}
});
}
});
fs.open('oldPC' + loadprocess + '.md', 'w', 0666, function(e, fd) {
if(e) {
console.log('错误信息:' + e);
} else {
fs.write(fd, contentBody, 0, 'utf8', function(e) {
if(e) {
console.log('出错信息:' + e);
} else {
fs.closeSync(fd);
}
});
}
});
}
function readWebArticleLink(url) {
http.get(url, function(res) {
var source = "";
//通过 get 请求获取网页代码 source
res.on('data', function(data) {
source += data;
});
//获取到数据 source,我们可以对数据进行操作了!
res.on('end', function() {
parsingArticlePage(source);
});
}).on('error', function() {
console.log("获取数据出现错误");
});
}
function readWebPage(url) {
http.get(url, function(res) {
var source = "";
//通过 get 请求获取网页代码 source
res.on('data', function(data) {
source += data;
});
//获取到数据 source,我们可以对数据进行操作了!
res.on('end', function() {
branchWebPage(source);
/*fs.open('hello.txt', 'w', 0666, function(e, fd) {
if(e) {
console.log('错误信息:' + e);
} else {
fs.write(fd, source, 0, 'utf8', function(e) {
if(e) {
console.log('出错信息:' + e);
} else {
fs.closeSync(fd);
}
});
}
});*/
});
}).on('error', function() {
console.log("获取数据出现错误");
});
}
Read More +

從現在開始開始 Hexo !

用了 GitHub, 學到 Nodejs, 路過 Hexo, 到了這裡

安裝各種有趣 ?

Hexo 第一步

  • 請先把 Nodejs 和 npm 架設好
  1. 下載 Hexo
    1
    $ npm install hexo -g
  2. 安裝到你的目標目錄下
    1
    $ hexo init blog && cd blog
  3. 以下操作會將文章從 markdown 檔案產生關聯
    1
    $ hexo generate
  4. 開啟 Server, 使用於本地調效, 之後可連到 http://localhost:4000/ 查看
    1
    $ hexo server

Hexo 日常問題

  • 撰寫文章

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $ hexo new [layout]
    $ hexo new "New Post"
    # => The file will be created at source/_posts/new-post.md
    $ hexo new page "New Page"
    # => The file will be created at source/new-page/index.html
    $ hexo new draft "New Draft"
    # => The file will be created at source/_drafts/new-draft.md
  • 文章標籤使用

    1
    2
    3
    4
    title: Start Hexo !
    date: 2014-04-10 19:40:22
    tags: [hexo, image]
    categories: About This Blog
  • 文章代碼高亮

    1
    2
    3
    {\% codeblock \%}
    your code here. 自行去掉反斜線
    {\% endcodeblock \%}

Hexo 個人化問題

  • 修改主題, 修改完畢後, 請進行以下操作來對 deploy 運行, style.css 才會正確, 本地查閱不影響

    1
    2
    3
    $ hexo clean
    $ hexo generate
    $ hexo deploy
  • 與 github page 連接做靜態操作

    blog_folder/_config.yml
    1
    2
    3
    4
    5
    6
    # Deployment
    ## Docs: http://zespia.tw/hexo/docs/deployment.html
    deploy:
    type: github
    repository: https://github.com/morris821028/morris821028.github.io.git
    branch: master
  • RSS 設定

    blog_folder/_config.yml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # Plugins
    plugins:
    - hexo-generator-feed
    - hexo-generator-sitemap
    # RSS hexo-generator-feed
    feed:
    type: atom
    path: atom.xml
    limit: 20
  • BLOG 主題 pacman 配置 - 增加文章列表圖片 (詳見 http://yangjian.me/pacman/hello/introducing-pacman-theme/)

    blog_folder/theme/pacman/layout/_partial/post/article.ejs
    1
    2
    3
    <@ if(item.content.indexOf('<img src="') >= 0) { @>
    <p itemprop="description"><img style='float:left;margin:5px;height:80px;' src="<@- item.content.substring(item.content.indexOf('src="', item.content.indexOf('<img src="')) + 5, item.content.indexOf('"', item.content.indexOf('<img src="') + 11)) @>">
    <@= strip_html(item.content).replace(/^\s*/, '').replace(/\s*$/, '').substring(0, 140) @></p>
  • BLOG 主題 pacman 配置 - 色彩配置

    blog_folder/theme/pacman/css/_base/variable.styl
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    color-background = #1f1f1f
    color-font = #ffffff
    color-white = #ffffff
    color-blue = #2ca6cb
    color-theme = #1f1f1f
    color-font-nav =#E9CD4C
    color-section = #272822
    color-footer = #1f1f1f
    color-gray = #CCC
    color-heading = #333333
    color-code = #eee
    color-twitter = #00aced
    color-facebook = #3b5998
    color-weibo = #eb182c
    color-google = #dd4b39
    color-qrcode= #49ae0f
    color-top = #762c54
Read More +