Node.js(一)——(Node.js安裝及使用,通過Node.js搭建服務器,模塊化及自定義模塊,npm/yarn/nvm,內置模塊fs的使用,buffer及stream,新聞列表案例)

目錄

1.Node.js介紹

2.安裝Node.js

3.使用Node.js實現第一個服務器

3.1初步感受Node.js

3.2Google Chrome 默認非安全端口列表,儘量避免以下端口。

3.3nodemon自動監控服務端更改

4.模塊化——Node.js使用commonjs規範

4.1創建自定義模塊(引入文件/文件夾,按需導出)

4.1.1引入文件

4.1.2引入文件夾

4.1.3引入node_modules裏的文件夾

4.1.4描述功能性文件package.json

4.1.5 自定義模塊的按需導出

4.2.2內置模塊;

5.npm包管理器

5.1 npm常用指令;

5.2註冊與發佈npm項目

5.2.1 註冊賬號:

5.2.2發佈包

5.2.3cnpm的安裝及使用

6.fs模塊(內置模塊)

6.1寫入文件writeFile()

6.2刪除文件

6.3修改文件名

6.4讀取文件

6.5複製文件

6.6自定義複製文件實現原理

6.7創建目錄

6.8修改目錄名

6.9讀取目錄中的文件及子目錄

6.10刪除目錄

6.10判斷文件或目錄是否存在

6.11獲取文件或目錄的詳細信息

6.12刪除非空文件夾

7.buffer緩衝區

7.1buffer的創建:

8.stream流

8.1data:監控得到的數據,並將其分成多份

8.2 end監控文件是否讀取完成

8.3pipe:管道,將得到的數據通過pipe進行寫入(fs.createWriteStream())

9.包管理工具yarn 

10.node.js版本管理工具NVM

10.1NVM下載

10.2安裝NVM

10.3NVM常用指令

11.通過fs模塊加載頁面

11.1- 普通方式加載頁面

11.2- 通過stream流方式加載頁面

12.node+cheerio實現爬蟲獲取數據

13.實現新聞列表頁面


本節知識要點

  • - Node.js安裝及使用
  • - 通過Node.js搭建服務器
  • - 模塊化及自定義模塊
  • - 內置模塊fs的使用
  • - buffer及stream

1.Node.js介紹

- Node.js 誕生於2009年,Node.js採用C++語言編寫而成,是 一個Javascript的運行環境。Node.js 是一個基於 Chrome V8 引擎的 JavaScript 運行環境 ,讓JavaScript的運行脫離瀏覽器端,可以使用JavaScript語言 書寫服務器端代碼。

2.安裝Node.js

​ [Node.js官網](https://nodejs.org)下載穩定版本,node偶數版本爲穩定版本,奇數版本爲非穩定版本。

  1. - mac 直接安裝 或者 brew來安裝;windows直接點下一步安裝(注意windows系統下需要配置環境變量)
  2. - 安裝完Node.js會自動安裝NPM(Node Package Manager):包管理工具;
  3. - 通過指令 node -v 來查看是否安裝完成和查看node版本號;npm -v 來查看npm版本。

3.使用Node.js實現第一個服務器

3.1初步感受Node.js

//引入http模塊
let http = require("http");
//創建一個服務器
let serve = http.createServer((req, res) => {
    console.log("hello");
    res.end("hello world");
})

//設置端口號
serve.listen(3000);
  • 使用快捷鍵ctrl + `打開VScode的終端;
  • 使用node server.js(node js文件名)執行js文件;

結果:瀏覽器端打印hello world; 服務端打印hello

3.2Google Chrome 默認非安全端口列表,儘量避免以下端口。

1, // tcpmux
7, // echo
9, // discard
11, // systat
13, // daytime
15, // netstat
17, // qotd
19, // chargen
20, // ftp data
21, // ftp access
22, // ssh
23, // telnet
25, // smtp
37, // time
42, // name
43, // nicname
53, // domain
77, // priv-rjs
79, // finger
87, // ttylink
95, // supdup
101, // hostriame
102, // iso-tsap
103, // gppitnp
104, // acr-nema
109, // pop2
110, // pop3
111, // sunrpc
113, // auth
115, // sftp
117, // uucp-path
119, // nntp
123, // NTP
135, // loc-srv /epmap
139, // netbios
143, // imap2
179, // BGP
389, // ldap
465, // smtp+ssl
512, // print / exec
513, // login
514, // shell
515, // printer
526, // tempo
530, // courier
531, // chat
532, // netnews
540, // uucp
556, // remotefs
563, // nntp+ssl
587, // stmp?
601, // ??
636, // ldap+ssl
993, // ldap+ssl
995, // pop3+ssl
2049, // nfs
3659, // apple-sasl / PasswordServer
4045, // lockd
6000, // X11
6665, // Alternate IRC [Apple addition]
6666, // Alternate IRC [Apple addition]
6667, // Standard IRC [Apple addition]
6668, // Alternate IRC [Apple addition]
6669, // Alternate IRC [Apple addition]

3.3nodemon自動監控服務端更改

使用node js文件名,方式在node.js下啓動時,如果JS文件進行了修改就必須,重啓服務;

解決:使用nodemon會自動監聽服務端JS文件的修改

在全局下安裝nodemon的命令:npm i nodemon -g

nodemon啓動:通過nodemon命令 nodemon JS文件名 啓動文件後,會自動監聽和重啓服務器。如 nodemon index.js

4.模塊化——Node.js使用commonjs規範

爲什麼會有模塊化:

- 在JavaScript發展初期就是爲了實現簡單的頁面交互邏輯,隨着前端代碼日益膨脹,JavaScript作爲嵌入式的腳本語言的定位動搖了,JavaScript卻沒有爲組織代碼提供任何明顯幫助,JavaScript極其簡單的代碼組織規範不足以駕馭如此龐大規模的代碼;

每個模塊之間有獨立的空間,從而防止模塊間的變量污染

Node.js中的模塊化 commonjs規範:

- CommonJS就是爲JS的表現來制定規範,因爲js沒有模塊的功能所以CommonJS應運而生,它希望js可以在任何地方運行,不只是瀏覽器中。

前端規範:AMD sea.js  和 CMD require.js

node.js安裝完成後,就自帶commonjs規範。

4.1創建自定義模塊(引入文件/文件夾,按需導出)

模塊化引入:可以引入文件,文件夾和node_modules文件夾下的自定義文件夾。

4.1.1引入文件

注意:當引入文件或自定義文件夾時require("./mydir")中需要加"./",當引入的是node_modules時,不能加"./",如require("node_modules")

  • - 引入一個文件 形式模塊:require("./JS文件名"),也可以省略.js即require("./home");

moduleA.js:

console.log("這是moduleA.js 文件");

home.js執行文件:輸入命令:nodemon home.js

console.log("這是home主頁JS文件");
require("./moduleA.js");

結果:執行home.js文件中的內容時也能執行引入文件moduleA.js文件中的內容

4.1.2引入文件夾

  • - 引入文件夾形式模塊 require("./文件夾名")

如下:home.js爲執行JS文件,自身執行及引入moduleA.js的同時引入了文件夾mydir ,則在文件夾mydir中會默認去找index.js文件,發現index.js引入了a.js文件,而a.js文件引入了b.js文件,所以執行home.js時,會執行index.js a.js b.js中的內容。

home.js執行文件:

console.log("這是home主頁JS文件");
require("./moduleA.js");//引入moduleA.js文件
require("./mydir");//引入文件夾mydir,就會自動查找文件夾mydir下的index.js文件

​ home.js引入mydir文件夾後,會自動查找文件夾下的index.js文件執行:

index.js文件:

console.log("這是index.js文件");
require("./a");

index.js中引入了a.js文件:

console.log("這是a.js文件");
require("./b");

a.js文件中又引入了b.js文件:

console.log("這是b.js文件");

結果:所以最後結果是,會執行mydir下所有js文件,index.js a.js  b.js文件

  • - 當然也可以配置默認啓動文件(默認index.js文件,但也可以修改),在文件夾內新建package.json來指定執行文件
{
"name":"aModule",
"version":"1.0.0",
"main":"test.js"

}

4.1.3引入node_modules裏的文件夾

node_modules主要針對第三方JS文件的管理。

引入node_modules裏的文件夾時,文件夾不需要加"./",如,require("文件夾")

package.json:描述功能性文件。可以在裏面設置node_modules中的默認執行文件,版本號,文件夾名等配置

示例:

文件目錄層級:

home.js爲執行文件:在home.js中引入node_modules中的文件夾mytest

require("mytest");

index.js:

console.log("這是index.js文件");
require("./a");

a.js:

console.log("這是a.js文件");
require("./b");

b.js:

console.log("這是b.js文件");

結果:

4.1.4描述功能性文件package.json

項目上線或者項目轉移時,不會轉移或上線node_modules文件夾,而是使用時再通過package.json去下載第三方模塊

node_modules的查找規則:向上查找。首先會在當前文件夾下查找node_modules,沒有再查找上一級文件夾下有沒有node_modules,再沒有會找到系統根目錄user文件夾下的node_modules。

引入node_modules文件夾下的自定義文件夾時,默認去執行文件夾下面的index.js。

如果想引入的文件夾默認執行文件不是index.js,而執行自定義的文件夾,需要通過package.json文件定義:

package.json文件:

{
    "name":"mytest",
    "version":"1.0.0",
    "main":"test.js"
}

test.js:

console.log("使用了package.json文件,默認引入text.js");

結果:

4.1.5 自定義模塊的按需導出

通過module.exports 導出; \_\__dirname , \_\_filename

exports是module.exports的引用 :可以使用module.exports = {}進行導出,而不能使用exports = {}進行導出,要使用exports導出,只能使用exports.a 的形式。因爲exports是module.exports的一個引用。

__dirname: 獲得當前執行文件所在目錄的完整目錄名
__filename: 獲得當前執行文件的帶有完整絕對路徑的文件名
process.cwd():獲得當前執行node命令時候的文件夾目錄名
  • 通過module.exports 導出

Ma.js:有變量a和類Person,通過module.exports = {}將變量a和Person類進行導出

console.log("這是Ma.js文件");
let a = 10;
class Person{
    constructor(){
        this.name = "zhangsan";
    }
    hobby(){
        console.log("喜歡籃球");
    }
}
module.exports = {
    a,
    Person
}

Mb.js:使用require("./Ma.js")引入文件,將引入後的結果存起來,再獲取裏面的變量a和Person類

console.log("這是Mb.js文件");
let Ma = require("./Ma");
console.log(Ma.a);
let p = new Ma.Person();
p.hobby();
  • 或者 通過 exports來導出。

exports是module.exports的一個引用,使用時不能使用exports = {}進行導出(不會改變module.exports的值,只會改變exports 的值就沒有意義),必須使用exports.a 和exports.Person

所以上例可以改寫爲以下:

Ma.js:

console.log("這是Ma.js文件");
let a = 10;
class Person{
    constructor(){
        this.name = "zhangsan";
    }
    hobby(){
        console.log("喜歡籃球");
    }
}
module.exports = {
    a,
    Person
}

exports.a = a;
exports.Person = Person;

//解構賦值
// exports.hobby = new Person().hobby;

Mb.js::注意使用解構賦值時 {hobby}結構的值必須和exports.hobby的值相同

console.log("這是Mb.js文件");
let Ma = require("./Ma");
console.log(Ma.a);
let p = new Ma.Person();
p.hobby();

//也可以通過結構賦值方式得到值
// 或者 通過解構賦值 
// let { hobby } = require("./Ma");
// hobby();
  • - 模塊加載的優先級 ,先文件再目錄;

4.2.2內置模塊;

內置模塊即不需要下載,nodejs中本身就有的模塊,內置模塊不需要安裝,外置模塊需要安裝;

nodejs內置模塊有:Buffer,C/C++Addons,Child Processes,Cluster,Console,Crypto,Debugger,DNS,Domain,Errors,Events,File System,Globals,HTTP,HTTPS,Modules,Net,OS,Path,Process,P unycode,Query Strings,Readline,REPL,Stream,String De coder,Timers,TLS/SSL,TTY,UDP/Datagram,URL, Utilities,V8,VM,ZLIB;

5.npm包管理器

安裝node.js時,npm也會一起安裝,npm的版本號和node.js的版本號是關聯的。一般如果npm版本不夠,只要升級node.js的版本即可。

NPM(Node Package Manager) 官網的地址是 [npm官網](https://www.npmjs.com)  ,可以註冊和發佈項目。

node.js是輕量級加載,用到某個模塊時再去安裝,沒有用到就先不安裝。

5.1 npm常用指令;

  • - npm init:引導創建一個package.json文件
  • - npm help(npm -h) :查看npm幫助信息
  • - npm version (npm -v) : 查看npm版本;
  • - npm search:查找
  • - npm install (npm i)  module_name :安裝 默認在當前目錄,如果沒有node_modules 會創建node_modules文件夾,並將下載的第三方模塊放在創建好的node_modules裏;
  • - npm install module_name -S 或者--save 即 npm install module_name --save 寫入dependencies運行依賴新版本中默認會加上-S(--save)
  • - npm install module_name -D 或者 --save-dev 即 npm install module_name --save-dev 寫入devDependencies開發依賴
  • - npm install module_name -g 全局安裝(命令行使用),即會按照在npm root -g下。如C:\Users\Administrator\AppData\Roaming\npm\node_modules即npm安裝的系統根目錄
  • - 指定版本安裝模塊 npm i module_name @1.0 通過 "@"符號指定;
  • - npm update(npm -up):更新
  • - npm remove 或者 npm uninstall module_name :刪除
  • - npm root 查看當前包安裝(即node-modules)的路徑 或者通過 npm root -g 來查看全局安裝路徑
  • npm config set registry https://registry.npmjs.org/ (官方地址)設置下載源地址,https://registry.npm.taobao.org/(淘寶源地址)
  • npm config list 查詢源地址 

示例:使用npm i cookie創建cookie模塊:

如在npm文件夾下執行這一命令後,會自定創建一個node_modules文件夾以及package.json和package-lock.json文件,並創建cookie模塊

"cookie": "^0.4.0"的^表示安裝時自動查找或使用0.4.0及其以上版本

使用npm init 引導創建package.json文件:

{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

5.2註冊與發佈npm項目

5.2.1 註冊賬號:

[https://www.npmjs.com/](https://www.npmjs.com/) (郵箱驗證)

- npm adduser 輸入剛剛註冊好的用戶名和密碼 ;

如果註冊地址不對需要重新改回來:使用淘寶源地址源下載速度快些。

  • npm config set registry https://registry.npmjs.org/  (官方地址)
  • https://registry.npm.taobao.org/(淘寶源地址)

查詢源地址:npm config list

5.2.2發佈包

創建項目:index.js默認入口文件;npm i 創建package.json文件,npm start啓動項目

  • 發佈publish 命令 :npm publish 項目名  。項目名不能重複
  • 下載發佈上去的項目:npm i 項目名
  • 刪除發佈的項目:npm unpublish 項目名

5.2.3cnpm的安裝及使用

cnpm是淘寶出的。使用cnpm會直接在淘寶源地址進行下載。

一般不建議使用cnpm命令 。下載地址會很怪,且會出現未知問題。

可以使用npm命令,使用淘寶源,下載地址就會是國內地址

安裝命令:會到國內淘寶源地址進行下載安裝

$ npm install -g cnpm --registry=https://registry.npm.taobao.org

6.fs模塊(內置模塊)

內置模塊只需要引入,不需要安裝。

fs模塊:針對文件和目錄的增刪改查。

- fs是文件操作模塊,所有文件操作都是有同步和異步之分,特點是同步會加上 "Sync" 如:異步讀取文件 "readFile",同步讀取文件 "readFileSync";

文件操作:

6.1寫入文件writeFile()

let fs = require("fs");

fs.writeFile(filename,data,[options],callback)寫入內容到文件.

  1. 第一個參數filename:文件名;
  2. 第二個參數data:要寫入的內容;寫入數據的類型必須是字符串或buffer二進制數據 ,對象等。如果 data 是一個 buffer,則 encoding 選項會被忽略。如果 options 是一個字符串,則可以指定字符編碼。
  3. 第三個參數options:可選,對象形式。encoding 文件編碼,mode 寫入模式,寫入方式(a追加,w覆蓋),如{flag:'w'}
  • option Object
    • encoding String |nulldefault='utf-8'
    • mode Number default=438(aka 0666 in Octal)
    • flag Stringdefault='w'

在同一個文件上多次使用 fs.writeFile() 且不等待回調是不安全的。 對於這種情況,建議使用 fs.createWriteStream()

異步寫入:

let fs = require("fs");

//異步寫入
fs.writeFile("1.txt","323",{flag:'w'},function(err){
    //如果有錯誤,就返回錯誤
    if(err){
        return console.log(err);
    }
    //寫入成功
    console.log("寫入成功");
});

同步寫入:沒有錯誤回調

fs.writeFileSync("2.txt","sdfa",{flags:'a'});

6.2刪除文件

異步刪除:

//異步刪除文件
fs.unlink("2.txt",function(err){
    //刪除失敗
    if(err){
        return console.log(err);
    }
    console.log("刪除成功");
});

同步刪除:

//同步刪除文件
fs.unlinkSync("1.txt");

6.3修改文件名

異步修改文件名:

fs.rename(oldFile,newFile,callback)

//異步修改文件
fs.rename("1.txt","11.txt",err=>{
    if(err){
        return console.log(err);
    }
    console.log("修改文件名成功");
});

同步修改文件名:

//同步修改文件名
fs.renameSync("11.txt","2.txt");

6.4讀取文件

異步讀取:

fs.readFile(path: string | number | Buffer | URL,callback)

//異步讀取文件
fs.readFile("1.txt",(err,data)=>{
    if(err){
        return console.log(err);
    }
    console.log("讀取成功"+data);
    
});

同步讀取:

readFileSync(path: string | number | Buffer | URL, options?: {
encoding?: null;
flag?: string;
})

直接讀取出來的數據時Buffer數據,需要使用toString()將其轉換爲字符串

//同步讀取文件
let data = fs.readFileSync("1.txt").toString();
console.log(data);

6.5複製文件

異步複製文件:

copyFile(src: PathLike, dest: PathLike, callback)

//異步複製文件
fs.copyFile("1.txt","3.txt",err=>{
    if(err){
        return console.log(err);
    }
    console.log("複製成功");
});

同步複製文件:

//同步複製文件
fs.copyFileSync("3.txt","4.txt");

6.6自定義複製文件實現原理

原理:先讀取到文件,再將讀取到的文件進行寫入

//複製文件實現原理
function copyFile(src,dir){
    let data = fs.readFileSync(src).toString();
    fs.writeFileSync(dir,data);
}

copyFile("1.txt","5.txt");

6.7創建目錄

異步創建目錄:

//創建目錄
fs.mkdir("11",err=>{
    if(err){
        return console.log(err);
    }
    console.log("創建成功");
    
});

同步創建目錄:

fs.mkdirSync("22");

6.8修改目錄名

異步修改目錄名:

//異步修改目錄名
fs.rename("11","44",err=>{
    if(err){
        return console.log(err);
    }
    console.log(修改目錄成功);
});

同步修改目錄名:

fs.renameSync("44","33");

6.9讀取目錄中的文件及子目錄

會將目錄中的子目錄和文件都讀取出來,放到數組中

//異步讀取目錄中的文件和子目錄
fs.readdir("33",(err,files)=>{
    if(err){
        return console.log(err);
    }
    console.log(files);//[ '1.txt', '2.txt', '22' ]
})
//同步讀取目錄中的文件和子目錄
let data = fs.readdirSync("33");
console.log(data);//[ '1.txt', '2.txt', '22' ]

6.10刪除目錄

刪除的目錄必須是空目錄,否則刪除不了

//刪除空目錄
fs.rmdir("./33/22",err=>{
    if(err){
        return console.log(err);
    }
    console.log("刪除成功");
});

6.10判斷文件或目錄是否存在

//判斷文件或目錄是否存在
fs.exists("33",exists=>{
    console.log(exists);
});
//同步判斷文件或目錄是否存在
let flag = fs.existsSync("33");
console.log(flag);

6.11獲取文件或目錄的詳細信息

//獲取文件或目錄的詳細信息
fs.stat("33",(err,stats)=>{
    if(err){
        return console.log(err);
    }
    console.log(stats);
    //通過stas.isFile()判斷是否是一個文件
    console.log(stats.isFile());
    //通過stats.isDirectory()判斷是否是一個目錄
    console.log(stats.isDirectory());  
});

結果:

6.12刪除非空文件夾

  • 先獲取路徑下所有文件夾和文件;
  • 再通過stat.isDirectory()判斷時文件夾時繼續找下面的文件,是文件就刪除;
  • 最後循環完成後刪除空文件夾
//自定義刪除非空文件夾
function removeDir(dir) {
    let data = fs.readdirSync(dir);
    data.forEach(item=>{
        //注意這裏的路徑循環出來的是原來目錄的子級,所以刪除時,需要加上原來目錄級別才能找到
        let url = dir + "/" + item;
        let stats = fs.statSync(url);
        if(stats.isDirectory()){
            //如果是文件夾繼續向下查找
            removeDir(url);
        }else{
            //如果是文件就刪除文件
            console.log("是文件");

            fs.unlinkSync(url);
        }
    });
    //循環完後刪除空目錄
    fs.rmdirSync(dir);
}
removeDir("33");

7.buffer緩衝區

  • - buffer的創建
  • - 直接創建
  • - 數組創建
  • - 字符串創建
  • - 亂碼的處理
  • - buffer轉換tostring

7.1buffer的創建:

buffer是以二進制的形式進行保存,但是是以十六進制的方式進行展示

buffer創建方式一:ES6.1之前:new Buffer()

//ES6.1之前buffer緩衝區創建
let buffer = new Buffer("大家好");
console.log(buffer);//<Buffer e5 a4 a7 e5 ae b6 e5 a5 bd>

buffer創建方式二:ES6.1: let buffer = Buffer.alloc(10);

//buffer緩衝區創建方式二:
let buffer = Buffer.alloc(10);//創建一個10字節的buffer緩衝區
console.log(buffer);//<Buffer 00 00 00 00 00 00 00 00 00 00>

buffer創建方式三:Buffer.from()

//buffer緩衝區創建方式三:
let buffer = Buffer.from("大家好");
console.log(buffer);//<Buffer e5 a4 a7 e5 ae b6 e5 a5 bd>

buffer創建方式四:數組方式創建

//buffer緩衝區創建方式四:
let buffer = Buffer.from([0xe5, 0xa4, 0xa7, 0xe5, 0xae, 0xb6, 0xe5, 0xa5, 0xbd]);
console.log(buffer.toString());//大家好

通過數組方式創建,一箇中文對應3個16進制位,如果給的位數不對就會亂碼: 

//通過數組方式創建,一箇中文對應3個16進制位,如果給的位數不對就會亂碼
let buffer1 = Buffer.from([0xe5, 0xa4, 0xa7, 0xe5]);
let buffer2 = Buffer.from([ 0xae, 0xb6, 0xe5, 0xa5, 0xbd]);
console.log(buffer1.toString());//大�
console.log(buffer2.toString());//��好

亂碼解決方法一:使用concat([buffer1,buffer2])連接多個buffer(注意參數必須是數組),並調用toString()再輸出

//解決:使用concat連接多個buffer(注意參數必須是數組),再輸出
console.log(Buffer.concat([buffer1,buffer2]).toString());

亂碼解決方法二(性能更好):引入string_decoder模塊,再通過其write()方法

// 亂碼解決方法二:
let { StringDecoder } = require("string_decoder");
let decoder = new StringDecoder();
let buf1 = decoder.write(buffer1);
let buf2 = decoder.write(buffer2);
console.log(buf1);//大
console.log(buf2);//家好

8.stream流

  • - stream流:流與數據處理方面密不可分
  • - 流的原理
  • - 流數據的獲取 fs.createReadStream()
  • - pipe:管道,將得到的數據通過pipe進行寫入(fs.createWriteStream())
  • - data:監控得到的數據,並將其分成多份
  • - end:監控文件是否讀取完畢
  • - copy的流方法實現
  • - 加載視圖的流方法實現

數據傳輸時,如果數據過大,帶寬不足,會造成內存溢出,或者叫內存爆倉。

stream流會將數據,分割成多份,然後依次進行傳遞。

文件上傳讀取等多會涉及到stream流。

8.1data:監控得到的數據,並將其分成多份

示例:

讀取home.js文件中的內容:

home.js:

// console.log("這是home主頁JS文件");
// require("./moduleA.js");//引入moduleA.js文件
// require("./mydir");//引入文件夾mydir,就會自動查找文件夾mydir下的index.js文件
// require("mytest");

stream.js讀取文件:

方式一:使用fs.readFileSync("home.js");讀取時發現是一次性進行讀取,一旦文件內容過大,就會造成內存溢出。

//讀取文件home.js的數據
const fs = require("fs");
let data = fs.readFileSync("home.js");
console.log(data);//<Buffer 0d 0a 2f 2f 20 63 6f 6e 73 6f 6c 65 2e 6c 6f 67 28 22 e8 bf 99 e6 98 af 68 6f 6d 65 e4 b8 bb e9 a1 b5 4a 53 e6 96 87 e4 bb b6 22 29 3b 0d 0a 2f 2f 20 ... >

方式二:fs.createReadStream("home.js"),通過on方法監聽這個數據,並分成多份

//使用可讀流進行讀取
let re = fs.createReadStream("home.js");
re.on("data",chunk=>{
    console.log(chunk.toString());
});

創建一個65kb的文件,再通過createReadStream()進行讀取,發現會打印兩次chunk

//創建一個65kb大小的buffer,再通過createReadStream()讀取
let buffer = Buffer.alloc(65*1024);
fs.writeFile("65kb.txt",buffer,err=>{
    if(err){
        return console.log(err);
    }
});
let res = fs.createReadStream("65kb.txt");
let num = 0;
res.on("data",chunk=>{
    num++;
    console.log(chunk);//發現會打印兩次
    console.log(num);
    
    /*
        <Buffer 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... >
        1
        <Buffer 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... >
        2
    */
});

當創建64kb的文件,通過createReadStream()進行讀取,發現只會打印一次:

//再讀取64kb文件時,發現只會打印一次
let res = fs.createReadStream("64kb.txt");
let num = 0;
let str = "";
res.on("data",chunk=>{
    num++;
    str += chunk;
    console.log(chunk);//發現會打印兩次
    console.log(num);
    /*
        <Buffer 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... >
        1
    */
});

8.2 end監控文件是否讀取完成

//再讀取64kb文件時,發現只會打印一次
let res = fs.createReadStream("home.js");
let num = 0;
let str = "";
res.on("data",chunk=>{
    num++;
    str += chunk;
    console.log(chunk);//發現會打印兩次
    console.log(num);
    /*
        <Buffer 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... >
        1
    */
});

//end監控文件是否讀取完成,並可以得到讀取完成後的數據
res.on("end",()=>{
    console.log(str);
    
});

結果:會將讀取到的所有數據進行打印

8.3pipe:管道,將得到的數據通過pipe進行寫入(fs.createWriteStream())

  • 通過fs.createWriteStream()創建寫入文件;
  • 通過res.pipe() 流方式通過管道一點一點寫入到文件中
let res = fs.createReadStream("home.js");
let num = 0;
let str = "";
res.on("data",chunk=>{
    num++;
    str += chunk;
    console.log(chunk);//發現會打印兩次
    console.log(num);
    /*
        <Buffer 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... >
        1
    */
});

//pipe管道,將讀到的數據,通過pipe()寫入到文件
let pipeTxt = fs.createWriteStream("pipe.txt");
res.pipe(pipeTxt);

9.包管理工具yarn 

npm install -g yarn

yarn會相對簡單,但是最好使用npm

10.node.js版本管理工具NVM

- 使用NVM(Node Version Manager)控制Node.js版本

10.1NVM下載

  • - nvm是mac環境下管理nodejs的工具。在windows環境下推薦使用nvmw或者nvm-windows(建議使用);Nvm-windows 下載地址 https://github.com/coreybutler/nvm-windows
  • 也可以在https://github.com/coreybutler/nvm-windows/releases 下載 nvm-setup.zip

10.2安裝NVM

mac上安裝NVM

  • - 在安裝nvm之前需要一個c++編譯器,在mac上可以安裝Xcode命令工具(已經安裝可以忽略) :`xcode-select --install`
  • - 使用 curl安裝:`curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash`
  • - 或者使用wget來安裝:`wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash`

- NVM [github的地址](<https://github.com/creationix/nvm>)可以查看最新版本

windows上直接上一步下一步;

10.3NVM常用指令

  • nvm --version查看版本`
  • nvm install stable //安裝最新穩定版nodejs``
  • nvm install 8.11.1 //安裝指定版本``
  • nvm install 8.11 //安裝 8.11.x系列最新版本``
  • nvm ls-remote //列出遠程服務器上所有可用的版本`` nvm use 8.11.1 //切換到8.11.1版本``
  • nvm use 8.11 //切換到8.11.x最新版本``
  • nvm use node //切換到最新版本``
  • nvm alias default node //設置默認版本爲最新版本``
  • nvm ls //列出所有已經安裝的版本``

11.通過fs模塊加載頁面

通過路由地址/index 和/product路由到不同的頁面

11.1- 普通方式加載頁面

  • - 路由區分
  • - 加載頁面

index.html:

<body>
    這是主頁........
</body>

product.html:

<body>
    這是產品頁........ 
</body>

style.css:

body {
    background: red;
}

index.js:創建服務器,並使用fs模塊加載不同頁面,並使用nodemon index.js啓動服務器,即可熱更新,自動監控頁面的變化

頁面由頁面內容和請求頭,響應頭組成,頭信息必不可少。

//使用fs模塊加載頁面
const fs = require("fs");
const http = require("http");
const url = require("url");
const path = require("path");
//引入靜態文件後綴json文件
const mime = require("./mime.json");

let server = http.createServer((req, res) => {
    //如果不設置HTML請求頭會亂碼(注意參數的寫法不能錯)
    // res.setHeader('Content-Type', 'text/html; charset=utf-8');
    res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
        if (req.url === "/index") {
            // res.write("這是主頁");
            //方法一:通過fs模塊讀取頁面,再進行寫入內容
            let index = fs.readFileSync("index.html");
            res.write(index);
            // 監控響應結束,不寫的話會一直 請求
            res.end();
        } else if (req.url === "/product") {
            // res.write("這是產品頁");
            //通過fs模塊讀取頁面,再進行寫入內容
            let product = fs.readFileSync("product.html");
            res.write(product);
            res.end();

        } else {
            //其他靜態文件(文件的後綴不統一),使用mime.json文件處理
            //通過path模塊獲取到文件後綴名 /.css => .css
            let extname = path.extname(req.url);
            //注意這裏必須設置響應頭,否則沒有響應頭頁面不會顯示(注意拼接形式)
            res.writeHead(200, { 'Content-Type': mime[extname]});
            //再讀取到靜態文件,並響應到頁面
            let static = fs.createReadStream("."+req.url);
            static.pipe(res);
        }

});
server.listen("8000");

mime.json:各種靜態文件(文件的後綴不統一),操作複雜,可以使用mime.json文件處理。

如,通過path模塊獲取到文件後綴名 /.css => .css , let extname = path.extname(req.url) ;然後必須設置響應頭,否則沒有響應頭頁面不會顯示(注意拼接形式)  res.writeHead(200, { 'Content-Type': mime[extname]});

{ ".323":"text/h323" ,
  ".3gp":"video/3gpp" ,
  ".aab":"application/x-authoware-bin" ,
  ".aam":"application/x-authoware-map" ,
  ".aas":"application/x-authoware-seg" ,
  ".acx":"application/internet-property-stream" ,
  ".ai":"application/postscript" ,
  ".aif":"audio/x-aiff" ,
  ".aifc":"audio/x-aiff" ,
  ".aiff":"audio/x-aiff" ,
  ".als":"audio/X-Alpha5" ,
  ".amc":"application/x-mpeg" ,
  ".ani":"application/octet-stream" ,
  ".apk":"application/vnd.android.package-archive" ,
  ".asc":"text/plain" ,
  ".asd":"application/astound" ,
  ".asf":"video/x-ms-asf" ,
  ".asn":"application/astound" ,
  ".asp":"application/x-asap" ,
  ".asr":"video/x-ms-asf" ,
  ".asx":"video/x-ms-asf" ,
  ".au":"audio/basic" ,
  ".avb":"application/octet-stream" ,
  ".avi":"video/x-msvideo" ,
  ".awb":"audio/amr-wb" ,
  ".axs":"application/olescript" ,
  ".bas":"text/plain" ,
  ".bcpio":"application/x-bcpio" ,
  ".bin ":"application/octet-stream" ,
  ".bld":"application/bld" ,
  ".bld2":"application/bld2" ,
  ".bmp":"image/bmp" ,
  ".bpk":"application/octet-stream" ,
  ".bz2":"application/x-bzip2" ,
  ".c":"text/plain" ,
  ".cal":"image/x-cals" ,
  ".cat":"application/vnd.ms-pkiseccat" ,
  ".ccn":"application/x-cnc" ,
  ".cco":"application/x-cocoa" ,
  ".cdf":"application/x-cdf" ,
  ".cer":"application/x-x509-ca-cert" ,
  ".cgi":"magnus-internal/cgi" ,
  ".chat":"application/x-chat" ,
  ".class":"application/octet-stream" ,
  ".clp":"application/x-msclip" ,
  ".cmx":"image/x-cmx" ,
  ".co":"application/x-cult3d-object" ,
  ".cod":"image/cis-cod" ,
  ".conf":"text/plain" ,
  ".cpio":"application/x-cpio" ,
  ".cpp":"text/plain" ,
  ".cpt":"application/mac-compactpro" ,
  ".crd":"application/x-mscardfile" ,
  ".crl":"application/pkix-crl" ,
  ".crt":"application/x-x509-ca-cert" ,
  ".csh":"application/x-csh" ,
  ".csm":"chemical/x-csml" ,
  ".csml":"chemical/x-csml" ,
  ".css":"text/css" ,
  ".cur":"application/octet-stream" ,
  ".dcm":"x-lml/x-evm" ,
  ".dcr":"application/x-director" ,
  ".dcx":"image/x-dcx" ,
  ".der":"application/x-x509-ca-cert" ,
  ".dhtml":"text/html" ,
  ".dir":"application/x-director" ,
  ".dll":"application/x-msdownload" ,
  ".dmg":"application/octet-stream" ,
  ".dms":"application/octet-stream" ,
  ".doc":"application/msword" ,
  ".docx":"application/vnd.openxmlformats-officedocument.wordprocessingml.document" ,
  ".dot":"application/msword" ,
  ".dvi":"application/x-dvi" ,
  ".dwf":"drawing/x-dwf" ,
  ".dwg":"application/x-autocad" ,
  ".dxf":"application/x-autocad" ,
  ".dxr":"application/x-director" ,
  ".ebk":"application/x-expandedbook" ,
  ".emb":"chemical/x-embl-dl-nucleotide" ,
  ".embl":"chemical/x-embl-dl-nucleotide" ,
  ".eps":"application/postscript" ,
  ".epub":"application/epub+zip" ,
  ".eri":"image/x-eri" ,
  ".es":"audio/echospeech" ,
  ".esl":"audio/echospeech" ,
  ".etc":"application/x-earthtime" ,
  ".etx":"text/x-setext" ,
  ".evm":"x-lml/x-evm" ,
  ".evy":"application/envoy" ,
  ".exe":"application/octet-stream" ,
  ".fh4":"image/x-freehand" ,
  ".fh5":"image/x-freehand" ,
  ".fhc":"image/x-freehand" ,
  ".fif":"application/fractals" ,
  ".flr":"x-world/x-vrml" ,
  ".flv":"flv-application/octet-stream" ,
  ".fm":"application/x-maker" ,
  ".fpx":"image/x-fpx" ,
  ".fvi":"video/isivideo" ,
  ".gau":"chemical/x-gaussian-input" ,
  ".gca":"application/x-gca-compressed" ,
  ".gdb":"x-lml/x-gdb" ,
  ".gif":"image/gif" ,
  ".gps":"application/x-gps" ,
  ".gtar":"application/x-gtar" ,
  ".gz":"application/x-gzip" ,
  ".h":"text/plain" ,
  ".hdf":"application/x-hdf" ,
  ".hdm":"text/x-hdml" ,
  ".hdml":"text/x-hdml" ,
  ".hlp":"application/winhlp" ,
  ".hqx":"application/mac-binhex40" ,
  ".hta":"application/hta" ,
  ".htc":"text/x-component" ,
  ".htm":"text/html" ,
  ".html":"text/html" ,
  ".hts":"text/html" ,
  ".htt":"text/webviewhtml" ,
  ".ice":"x-conference/x-cooltalk" ,
  ".ico":"image/x-icon" ,
  ".ief":"image/ief" ,
  ".ifm":"image/gif" ,
  ".ifs":"image/ifs" ,
  ".iii":"application/x-iphone" ,
  ".imy":"audio/melody" ,
  ".ins":"application/x-internet-signup" ,
  ".ips":"application/x-ipscript" ,
  ".ipx":"application/x-ipix" ,
  ".isp":"application/x-internet-signup" ,
  ".it":"audio/x-mod" ,
  ".itz":"audio/x-mod" ,
  ".ivr":"i-world/i-vrml" ,
  ".j2k":"image/j2k" ,
  ".jad":"text/vnd.sun.j2me.app-descriptor" ,
  ".jam":"application/x-jam" ,
  ".jar":"application/java-archive" ,
  ".java":"text/plain" ,
  ".jfif":"image/pipeg" ,
  ".jnlp":"application/x-java-jnlp-file" ,
  ".jpe":"image/jpeg" ,
  ".jpeg":"image/jpeg" ,
  ".jpg":"image/jpeg" ,
  ".jpz":"image/jpeg" ,
  ".js":"application/x-javascript" ,
  ".jwc":"application/jwc" ,
  ".kjx":"application/x-kjx" ,
  ".lak":"x-lml/x-lak" ,
  ".latex":"application/x-latex" ,
  ".lcc":"application/fastman" ,
  ".lcl":"application/x-digitalloca" ,
  ".lcr":"application/x-digitalloca" ,
  ".lgh":"application/lgh" ,
  ".lha":"application/octet-stream" ,
  ".lml":"x-lml/x-lml" ,
  ".lmlpack":"x-lml/x-lmlpack" ,
  ".log":"text/plain" ,
  ".lsf":"video/x-la-asf" ,
  ".lsx":"video/x-la-asf" ,
  ".lzh":"application/octet-stream" ,
  ".m13":"application/x-msmediaview" ,
  ".m14":"application/x-msmediaview" ,
  ".m15":"audio/x-mod" ,
  ".m3u":"audio/x-mpegurl" ,
  ".m3url":"audio/x-mpegurl" ,
  ".m4a":"audio/mp4a-latm" ,
  ".m4b":"audio/mp4a-latm" ,
  ".m4p":"audio/mp4a-latm" ,
  ".m4u":"video/vnd.mpegurl" ,
  ".m4v":"video/x-m4v" ,
  ".ma1":"audio/ma1" ,
  ".ma2":"audio/ma2" ,
  ".ma3":"audio/ma3" ,
  ".ma5":"audio/ma5" ,
  ".man":"application/x-troff-man" ,
  ".map":"magnus-internal/imagemap" ,
  ".mbd":"application/mbedlet" ,
  ".mct":"application/x-mascot" ,
  ".mdb":"application/x-msaccess" ,
  ".mdz":"audio/x-mod" ,
  ".me":"application/x-troff-me" ,
  ".mel":"text/x-vmel" ,
  ".mht":"message/rfc822" ,
  ".mhtml":"message/rfc822" ,
  ".mi":"application/x-mif" ,
  ".mid":"audio/mid" ,
  ".midi":"audio/midi" ,
  ".mif":"application/x-mif" ,
  ".mil":"image/x-cals" ,
  ".mio":"audio/x-mio" ,
  ".mmf":"application/x-skt-lbs" ,
  ".mng":"video/x-mng" ,
  ".mny":"application/x-msmoney" ,
  ".moc":"application/x-mocha" ,
  ".mocha":"application/x-mocha" ,
  ".mod":"audio/x-mod" ,
  ".mof":"application/x-yumekara" ,
  ".mol":"chemical/x-mdl-molfile" ,
  ".mop":"chemical/x-mopac-input" ,
  ".mov":"video/quicktime" ,
  ".movie":"video/x-sgi-movie" ,
  ".mp2":"video/mpeg" ,
  ".mp3":"audio/mpeg" ,
  ".mp4":"video/mp4" ,
  ".mpa":"video/mpeg" ,
  ".mpc":"application/vnd.mpohun.certificate" ,
  ".mpe":"video/mpeg" ,
  ".mpeg":"video/mpeg" ,
  ".mpg":"video/mpeg" ,
  ".mpg4":"video/mp4" ,
  ".mpga":"audio/mpeg" ,
  ".mpn":"application/vnd.mophun.application" ,
  ".mpp":"application/vnd.ms-project" ,
  ".mps":"application/x-mapserver" ,
  ".mpv2":"video/mpeg" ,
  ".mrl":"text/x-mrml" ,
  ".mrm":"application/x-mrm" ,
  ".ms":"application/x-troff-ms" ,
  ".msg":"application/vnd.ms-outlook" ,
  ".mts":"application/metastream" ,
  ".mtx":"application/metastream" ,
  ".mtz":"application/metastream" ,
  ".mvb":"application/x-msmediaview" ,
  ".mzv":"application/metastream" ,
  ".nar":"application/zip" ,
  ".nbmp":"image/nbmp" ,
  ".nc":"application/x-netcdf" ,
  ".ndb":"x-lml/x-ndb" ,
  ".ndwn":"application/ndwn" ,
  ".nif":"application/x-nif" ,
  ".nmz":"application/x-scream" ,
  ".nokia-op-logo":"image/vnd.nok-oplogo-color" ,
  ".npx":"application/x-netfpx" ,
  ".nsnd":"audio/nsnd" ,
  ".nva":"application/x-neva1" ,
  ".nws":"message/rfc822" ,
  ".oda":"application/oda" ,
  ".ogg":"audio/ogg" ,
  ".oom":"application/x-AtlasMate-Plugin" ,
  ".p10":"application/pkcs10" ,
  ".p12":"application/x-pkcs12" ,
  ".p7b":"application/x-pkcs7-certificates" ,
  ".p7c":"application/x-pkcs7-mime" ,
  ".p7m":"application/x-pkcs7-mime" ,
  ".p7r":"application/x-pkcs7-certreqresp" ,
  ".p7s":"application/x-pkcs7-signature" ,
  ".pac":"audio/x-pac" ,
  ".pae":"audio/x-epac" ,
  ".pan":"application/x-pan" ,
  ".pbm":"image/x-portable-bitmap" ,
  ".pcx":"image/x-pcx" ,
  ".pda":"image/x-pda" ,
  ".pdb":"chemical/x-pdb" ,
  ".pdf":"application/pdf" ,
  ".pfr":"application/font-tdpfr" ,
  ".pfx":"application/x-pkcs12" ,
  ".pgm":"image/x-portable-graymap" ,
  ".pict":"image/x-pict" ,
  ".pko":"application/ynd.ms-pkipko" ,
  ".pm":"application/x-perl" ,
  ".pma":"application/x-perfmon" ,
  ".pmc":"application/x-perfmon" ,
  ".pmd":"application/x-pmd" ,
  ".pml":"application/x-perfmon" ,
  ".pmr":"application/x-perfmon" ,
  ".pmw":"application/x-perfmon" ,
  ".png":"image/png" ,
  ".pnm":"image/x-portable-anymap" ,
  ".pnz":"image/png" ,
  ".pot,":"application/vnd.ms-powerpoint" ,
  ".ppm":"image/x-portable-pixmap" ,
  ".pps":"application/vnd.ms-powerpoint" ,
  ".ppt":"application/vnd.ms-powerpoint" ,
  ".pptx":"application/vnd.openxmlformats-officedocument.presentationml.presentation" ,
  ".pqf":"application/x-cprplayer" ,
  ".pqi":"application/cprplayer" ,
  ".prc":"application/x-prc" ,
  ".prf":"application/pics-rules" ,
  ".prop":"text/plain" ,
  ".proxy":"application/x-ns-proxy-autoconfig" ,
  ".ps":"application/postscript" ,
  ".ptlk":"application/listenup" ,
  ".pub":"application/x-mspublisher" ,
  ".pvx":"video/x-pv-pvx" ,
  ".qcp":"audio/vnd.qcelp" ,
  ".qt":"video/quicktime" ,
  ".qti":"image/x-quicktime" ,
  ".qtif":"image/x-quicktime" ,
  ".r3t":"text/vnd.rn-realtext3d" ,
  ".ra":"audio/x-pn-realaudio" ,
  ".ram":"audio/x-pn-realaudio" ,
  ".rar":"application/octet-stream" ,
  ".ras":"image/x-cmu-raster" ,
  ".rc":"text/plain" ,
  ".rdf":"application/rdf+xml" ,
  ".rf":"image/vnd.rn-realflash" ,
  ".rgb":"image/x-rgb" ,
  ".rlf":"application/x-richlink" ,
  ".rm":"audio/x-pn-realaudio" ,
  ".rmf":"audio/x-rmf" ,
  ".rmi":"audio/mid" ,
  ".rmm":"audio/x-pn-realaudio" ,
  ".rmvb":"audio/x-pn-realaudio" ,
  ".rnx":"application/vnd.rn-realplayer" ,
  ".roff":"application/x-troff" ,
  ".rp":"image/vnd.rn-realpix" ,
  ".rpm":"audio/x-pn-realaudio-plugin" ,
  ".rt":"text/vnd.rn-realtext" ,
  ".rte":"x-lml/x-gps" ,
  ".rtf":"application/rtf" ,
  ".rtg":"application/metastream" ,
  ".rtx":"text/richtext" ,
  ".rv":"video/vnd.rn-realvideo" ,
  ".rwc":"application/x-rogerwilco" ,
  ".s3m":"audio/x-mod" ,
  ".s3z":"audio/x-mod" ,
  ".sca":"application/x-supercard" ,
  ".scd":"application/x-msschedule" ,
  ".sct":"text/scriptlet" ,
  ".sdf":"application/e-score" ,
  ".sea":"application/x-stuffit" ,
  ".setpay":"application/set-payment-initiation" ,
  ".setreg":"application/set-registration-initiation" ,
  ".sgm":"text/x-sgml" ,
  ".sgml":"text/x-sgml" ,
  ".sh":"application/x-sh" ,
  ".shar":"application/x-shar" ,
  ".shtml":"magnus-internal/parsed-html" ,
  ".shw":"application/presentations" ,
  ".si6":"image/si6" ,
  ".si7":"image/vnd.stiwap.sis" ,
  ".si9":"image/vnd.lgtwap.sis" ,
  ".sis":"application/vnd.symbian.install" ,
  ".sit":"application/x-stuffit" ,
  ".skd":"application/x-Koan" ,
  ".skm":"application/x-Koan" ,
  ".skp":"application/x-Koan" ,
  ".skt":"application/x-Koan" ,
  ".slc":"application/x-salsa" ,
  ".smd":"audio/x-smd" ,
  ".smi":"application/smil" ,
  ".smil":"application/smil" ,
  ".smp":"application/studiom" ,
  ".smz":"audio/x-smd" ,
  ".snd":"audio/basic" ,
  ".spc":"application/x-pkcs7-certificates" ,
  ".spl":"application/futuresplash" ,
  ".spr":"application/x-sprite" ,
  ".sprite":"application/x-sprite" ,
  ".sdp":"application/sdp" ,
  ".spt":"application/x-spt" ,
  ".src":"application/x-wais-source" ,
  ".sst":"application/vnd.ms-pkicertstore" ,
  ".stk":"application/hyperstudio" ,
  ".stl":"application/vnd.ms-pkistl" ,
  ".stm":"text/html" ,
  ".svg":"image/svg+xml" ,
  ".sv4cpio":"application/x-sv4cpio" ,
  ".sv4crc":"application/x-sv4crc" ,
  ".svf":"image/vnd" ,
  ".svg":"image/svg+xml" ,
  ".svh":"image/svh" ,
  ".svr":"x-world/x-svr" ,
  ".swf":"application/x-shockwave-flash" ,
  ".swfl":"application/x-shockwave-flash" ,
  ".t":"application/x-troff" ,
  ".tad":"application/octet-stream" ,
  ".talk":"text/x-speech" ,
  ".tar":"application/x-tar" ,
  ".taz":"application/x-tar" ,
  ".tbp":"application/x-timbuktu" ,
  ".tbt":"application/x-timbuktu" ,
  ".tcl":"application/x-tcl" ,
  ".tex":"application/x-tex" ,
  ".texi":"application/x-texinfo" ,
  ".texinfo":"application/x-texinfo" ,
  ".tgz":"application/x-compressed" ,
  ".thm":"application/vnd.eri.thm" ,
  ".tif":"image/tiff" ,
  ".tiff":"image/tiff" ,
  ".tki":"application/x-tkined" ,
  ".tkined":"application/x-tkined" ,
  ".toc":"application/toc" ,
  ".toy":"image/toy" ,
  ".tr":"application/x-troff" ,
  ".trk":"x-lml/x-gps" ,
  ".trm":"application/x-msterminal" ,
  ".tsi":"audio/tsplayer" ,
  ".tsp":"application/dsptype" ,
  ".tsv":"text/tab-separated-values" ,
  ".ttf":"application/octet-stream" ,
  ".ttz":"application/t-time" ,
  ".txt":"text/plain" ,
  ".uls":"text/iuls" ,
  ".ult":"audio/x-mod" ,
  ".ustar":"application/x-ustar" ,
  ".uu":"application/x-uuencode" ,
  ".uue":"application/x-uuencode" ,
  ".vcd":"application/x-cdlink" ,
  ".vcf":"text/x-vcard" ,
  ".vdo":"video/vdo" ,
  ".vib":"audio/vib" ,
  ".viv":"video/vivo" ,
  ".vivo":"video/vivo" ,
  ".vmd":"application/vocaltec-media-desc" ,
  ".vmf":"application/vocaltec-media-file" ,
  ".vmi":"application/x-dreamcast-vms-info" ,
  ".vms":"application/x-dreamcast-vms" ,
  ".vox":"audio/voxware" ,
  ".vqe":"audio/x-twinvq-plugin" ,
  ".vqf":"audio/x-twinvq" ,
  ".vql":"audio/x-twinvq" ,
  ".vre":"x-world/x-vream" ,
  ".vrml":"x-world/x-vrml" ,
  ".vrt":"x-world/x-vrt" ,
  ".vrw":"x-world/x-vream" ,
  ".vts":"workbook/formulaone" ,
  ".wav":"audio/x-wav" ,
  ".wax":"audio/x-ms-wax" ,
  ".wbmp":"image/vnd.wap.wbmp" ,
  ".wcm":"application/vnd.ms-works" ,
  ".wdb":"application/vnd.ms-works" ,
  ".web":"application/vnd.xara" ,
  ".wi":"image/wavelet" ,
  ".wis":"application/x-InstallShield" ,
  ".wks":"application/vnd.ms-works" ,
  ".wm":"video/x-ms-wm" ,
  ".wma":"audio/x-ms-wma" ,
  ".wmd":"application/x-ms-wmd" ,
  ".wmf":"application/x-msmetafile" ,
  ".wml":"text/vnd.wap.wml" ,
  ".wmlc":"application/vnd.wap.wmlc" ,
  ".wmls":"text/vnd.wap.wmlscript" ,
  ".wmlsc":"application/vnd.wap.wmlscriptc" ,
  ".wmlscript":"text/vnd.wap.wmlscript" ,
  ".wmv":"audio/x-ms-wmv" ,
  ".wmx":"video/x-ms-wmx" ,
  ".wmz":"application/x-ms-wmz" ,
  ".wpng":"image/x-up-wpng" ,
  ".wps":"application/vnd.ms-works" ,
  ".wpt":"x-lml/x-gps" ,
  ".wri":"application/x-mswrite" ,
  ".wrl":"x-world/x-vrml" ,
  ".wrz":"x-world/x-vrml" ,
  ".ws":"text/vnd.wap.wmlscript" ,
  ".wsc":"application/vnd.wap.wmlscriptc" ,
  ".wv":"video/wavelet" ,
  ".wvx":"video/x-ms-wvx" ,
  ".wxl":"application/x-wxl" ,
  ".x-gzip":"application/x-gzip" ,
  ".xaf":"x-world/x-vrml" ,
  ".xar":"application/vnd.xara" ,
  ".xbm":"image/x-xbitmap" ,
  ".xdm":"application/x-xdma" ,
  ".xdma":"application/x-xdma" ,
  ".xdw":"application/vnd.fujixerox.docuworks" ,
  ".xht":"application/xhtml+xml" ,
  ".xhtm":"application/xhtml+xml" ,
  ".xhtml":"application/xhtml+xml" ,
  ".xla":"application/vnd.ms-excel" ,
  ".xlc":"application/vnd.ms-excel" ,
  ".xll":"application/x-excel" ,
  ".xlm":"application/vnd.ms-excel" ,
  ".xls":"application/vnd.ms-excel" ,
  ".xlsx":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ,
  ".xlt":"application/vnd.ms-excel" ,
  ".xlw":"application/vnd.ms-excel" ,
  ".xm":"audio/x-mod" ,
  ".xml":"text/plain",
  ".xml":"application/xml",
  ".xmz":"audio/x-mod" ,
  ".xof":"x-world/x-vrml" ,
  ".xpi":"application/x-xpinstall" ,
  ".xpm":"image/x-xpixmap" ,
  ".xsit":"text/xml" ,
  ".xsl":"text/xml" ,
  ".xul":"text/xul" ,
  ".xwd":"image/x-xwindowdump" ,
  ".xyz":"chemical/x-pdb" ,
  ".yz1":"application/x-yz1" ,
  ".z":"application/x-compress" ,
  ".zac":"application/x-zaurus-zac" ,
  ".zip":"application/zip" ,
  ".json":"application/json"
}

11.2- 通過stream流方式加載頁面

  • - 路由區分
  • - 加載頁面
  • - 設置頭部:mime.json
  • - 加載第三方資源

通過fs模塊流 Stream讀取文件:在文件內容很大時一點一點讀取效率高,不會內存溢出。

注意點:

  1. fs.createReadStream()方法讀取後,直接通過pipe()方法響應到頁面,不需要再寫入(fs.createWriteStream())
  2. 注意HTML頭的書寫格式:res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
  3. 靜態文件後綴,通過path.extname(req.url)進行獲取,且對應json中不同的文件後綴
//使用fs模塊加載頁面
const fs = require("fs");
const http = require("http");
const url = require("url");
const path = require("path");
//引入靜態文件後綴json文件
const mime = require("./mime.json");

let server = http.createServer((req, res) => {
    //如果不設置HTML請求頭會亂碼(注意參數的寫法不能錯)
    // res.setHeader('Content-Type', 'text/html; charset=utf-8');
    res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
        if (req.url === "/index") {
            //方法二:通過fs模塊流 Stream讀取文件:在文件內容很大時效率高,不會內存溢出
            let resIndex = fs.createReadStream("index.html");
            //pipe管道,將讀到的數據響應到頁面
            resIndex.pipe(res);

        } else if (req.url === "/product") {
            //注意createReadStream路由只需要讀取並響應,不需要寫入
            let product = fs.createReadStream("product.html");
            product.pipe(res);

        } else {
            //其他靜態文件(文件的後綴不統一),使用mime.json文件處理
            //通過path模塊獲取到文件後綴名 /.css => .css
            let extname = path.extname(req.url);
            //注意這裏必須設置響應頭,否則沒有響應頭頁面不會顯示(注意拼接形式)
            res.writeHead(200, { 'Content-Type': mime[extname]});
            //再讀取到靜態文件,並響應到頁面
            let static = fs.createReadStream("."+req.url);
            static.pipe(res);
        }

});
server.listen("8000");

12.node+cheerio實現爬蟲獲取數據

  • - http://news.ifeng.com/ 新聞地址
  • - http.get()使用
  • - cheerio來處理數據:
  • - 文件方式儲存數據1

cheerio:類似於前端jQuery的node.js的模塊,用法基本和jQuery相同,但是沒有window對象,即location,history,location等前端對象不存在。

crawlerData.js:

const http = require("http");
//通過get方法獲取爬蟲爬到的是整個頁面,需要使用cheerio模塊進行處理(類似JQuery)
const cheerio = require("cheerio");//注意需要使用 npm i cheerio -S 按照cheerio模塊到運行環境

const fs = require("fs");

let newsData = '';
//http的get 方法會並自動調用 req.end()
http.get("http://news.ifeng.com/", (res) => {
    res.on("data", chunk => {
        newsData += chunk;
    });
    res.on("end", () => {

        //數據必須在end裏面處理,否則獲取不到數據
         //使用cheerio加載整個數據
        let $ = cheerio.load(newsData);

        //用於存json數據
        let data = [];
        
        //新聞標題
        let titles = $(".news-stream-newsStream-news-item-infor h2 a");
        titles.each((index,ele)=>{
            data.push({
                "id":index+1,
                "title":ele.attribs['title']
            });
        });
        
        //發佈者
        let publisher = $(".news-stream-newsStream-news-item-infor .clearfix span");
        publisher.each((index,ele)=>{
            data[index].publisher = ele.children[0]['data'];
        });
        
        //發佈時間
        let time = $(".news-stream-newsStream-news-item-infor .clearfix time");
        time.each((index,ele)=>{
            data[index].time = ele.children[0]['data'];
        });

        //將得到的數據寫入到json文件中
        let dataJson = fs.createWriteStream("data.json");
        //注意需要使用write(),並且將數據轉成字符串格式才能進行寫出
        dataJson.write(JSON.stringify(data));
        res.pipe(dataJson);
    });
});

獲取到的json數據文件:文件已做一定修改

[
    {
        "id": 1,
        "title": "13歲少年成社會的災難",
        "publisher": "海外網",
        "time": "今天 17:08"
    },
    {
        "id": 2,
        "title": "(全文實錄)",
        "publisher": "中國網",
        "time": "今天 16:59"
    },
    {
        "id": 3,
        "title": "禁讀《哈利·波特》 稱咒語召喚邪靈",
        "publisher": "澎湃新聞",
        "time": "今天 16:56"
    },
    {
        "id": 4,
        "title": "XXXXXXXXXXX",
        "publisher": "海外網",
        "time": "今天 16:54"
    },
    {
        "id": 5,
        "title": "空缺190天后,迎來王浩",
        "publisher": "上游新聞",
        "time": "今天 16:54"
    },
    {
        "id": 6,
        "title": "中國遊客在日本突然昏迷 2名韓國消防員及時相救",
        "publisher": "海外網",
        "time": "今天 16:53"
    },
    {
        "id": 7,
        "title": "零售雪上加霜 奢侈品牌普拉達將關閉在港最大門店",
        "publisher": "觀察者網",
        "time": "今天 16:46"
    },
    {
        "id": 8,
        "title": "拖了18年?",
        "publisher": "海外網",
        "time": "今天 16:41"
    },
    {
        "id": 9,
        "title": "誤讀",
        "publisher": "環球網",
        "time": "今天 16:37"
    },
    {
        "id": 10,
        "title": "被男議員罵“不生孩子沒盡國家責任” 韓國55歲女學者懵了",
        "publisher": "海外網",
        "time": "今天 16:29"
    },
    {
        "id": 11,
        "title": "陳剛被提起公訴",
        "publisher": "海外網",
        "time": "今天 16:29"
    },
    {
        "id": 12,
        "title": "臺假裝尿急翻牆逃出營區 10天后在網吧被抓",
        "publisher": "海外網",
        "time": "今天 16:22"
    },
    {
        "id": 13,
        "title": "出糗:成語連說了3遍都沒對",
        "publisher": "海外網",
        "time": "今天 16:21"
    },
    {
        "id": 14,
        "title": "XXXX",
        "publisher": "澎湃新聞網",
        "time": "今天 16:09"
    },
    {
        "id": 15,
        "title": "XXXX權",
        "publisher": "新京報網",
        "time": "今天 16:00"
    },
    {
        "id": 16,
        "title": "特徵",
        "publisher": "新京報即時新聞",
        "time": "今天 15:53"
    },
    {
        "id": 17,
        "title": "XXXXXX",
        "publisher": "新京報即時新聞",
        "time": "今天 15:46"
    },
    {
        "id": 18,
        "title": "XXXXXX",
        "publisher": "中國網",
        "time": "今天 15:41"
    },
    {
        "id": 19,
        "title": "XXXX",
        "publisher": "新京報即時新聞",
        "time": "今天 15:35"
    },
    {
        "id": 20,
        "title": "XXXXXX",
        "publisher": "新京報即時新聞",
        "time": "今天 15:18"
    },
    {
        "id": 21,
        "title": "商務部:上週豬肉批發價格上漲8.9%",
        "publisher": "新京報即時新聞",
        "time": "今天 15:14"
    },
    {
        "id": 22,
        "title": "出糗:這個成語連說三遍都沒對",
        "publisher": "海外網",
        "time": "今天 14:54"
    },
    {
        "id": 23,
        "title": "兩高:高考等4類考試組織作弊屬犯罪 最高判7年",
        "publisher": "新京報即時新聞",
        "time": "今天 14:33"
    }
]

13.實現新聞列表頁面

  • - 視圖邏輯分離
  • - 讀取頁面
  • - 讀取動態數據
  • - 設置頭部引入其他資源
  • - 詳細頁顯示

index.js:

//將爬蟲得到的數據,渲染到頁面,需要進行頁面路由
const http = require("http");
const fs = require("fs");
const cheerio = require("cheerio");
const url = require("url");//處理地址
const path = require("path");//處理地址後綴名
const mime = require("./mime.json");//處理後綴名文件
const dataJson = require("./data.json");//新聞數據

let server = http.createServer((req, res) => {
    res.writeHead(200, { 'Content-Type': 'text/html;charset=utf-8' });
    if (req.url === "/" || req.url === "/index") {
        //方法一:讀取到index文件,獲取文件標籤,設置文件標籤內容
        let index = fs.readFileSync("index.html");
        let $ = cheerio.load(index);
        //讀取到json文件新聞數據
        //獲取ul 將HTML設置進去
        let ulHtml = '';
        dataJson.forEach(item => {
            ulHtml += `
                <li class="news">
                    <a href="javascript:;">
                        <img src="./img/img.png" alt="">
                    </a>
                    <div>
                        <h3>
                            <a href="javascript:;">${item.title}</a>
                        </h3>
                        <div class="info">
                            <span class="tips"><span>縱火</span><span${item.publisher}</span><span>逮捕</span></span>
                            <!-- <span class="line"></span> -->
                            <span class="time">| &nbsp;&nbsp;${item.time}</span>
                        </div>
                    </div>
                </li>
             `;
        });
        $(".news-list").html(ulHtml);
        res.end($.html());

        // //方法二:如果要使用createReadStream()流方式讀取文件,就必須使用on("data")和on("end")監控頁面讀取完後再操作DOM
        // let index = fs.createReadStream("index.html");
        // let oldIndex = '';
        // index.on("data", chunk => {
        //     oldIndex += chunk;
        // });
        // index.on('end', () => {
        //     console.log(oldIndex);
        //     let $ = cheerio.load(oldIndex);
        //     let ulHtml = '';
        //     dataJson.forEach(item => {
        //         ulHtml += `
        //         <li class="news">
        //             <a href="javascript:;">
        //                 <img src="./img/img.png" alt="">
        //             </a>
        //             <div>
        //                 <h3>
        //                     <a href="javascript:;">${item.title}</a>
        //                 </h3>
        //                 <div class="info">
        //                     <span class="tips"><span>縱火</span><span${item.publisher}</span><span>逮捕</span></span>
        //                     <!-- <span class="line"></span> -->
        //                     <span class="time">| &nbsp;&nbsp;${item.time}</span>
        //                 </div>
        //             </div>
        //         </li>
        //      `;
        //     });
        //     $(".news-list").html(ulHtml);
        //     res.end($.html());
        // });

    } else if (req.url !== "/favicon.ico") {
        let extname = path.extname(req.url);
        res.writeHead(200, { 'Content-Type': mime[extname] });
        let static = fs.createReadStream("." + req.url);
        static.pipe(res);
    }

});
server.listen(4000);

index.html:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>文章信息展示</title>
    <style>
        body {
            margin: 0;
        }

        ul {
            margin: 0;
            padding: 0;
            list-style: none;
        }

        a {
            text-decoration: none;
            color: #404040;
        }
        .wrap{
            width: 600px;
            margin: 0 auto;
        }

        .news-list {
            width: 600px;
        }

        .news {
            width: 100%;
            display: flex;
            justify-content: space-between;
            padding: 15px 0;
            border-bottom: 1px solid #999;
        }

        .info {
            display: flex;
            width: 170px;
            justify-content: space-between;
            font-size: 12px;
            color: #888;
        }

        .tips {
            display: flex;
            width: 100px;
            justify-content: space-between;
        }

        .news-list li:nth-child(5) {
            border-bottom: none;
        }
        .pagination{
            display: flex;
            width: 210px;
            text-align: center;
            background-color: rgb(252, 238, 238);
            border-radius: 25px;
            overflow: hidden;
            margin: 0 auto;
            justify-content: center;
        }
        .pagination a{
            width: 30px;
            line-height: 30px;
            color: #404040;
        }
        .pagination a:nth-child(1) {
            transform: rotate(-45deg) ;
        }
        .next {
            transform: rotate(45deg) ;
        }
        .pagination a:hover{
            color: rgb(247, 73, 73);
        }
        .news div{
            width:420px;
        }
        .pagination .active {
            color: rgb(247, 73, 73);
        }
    </style>
</head>

<body>
    <div class="wrap">
        <ul class="news-list">
            <li class="news">
                <a href="javascript:;">
                    <img src="./img/img.png" alt="">
                </a>
                <div>
                    <h3>
                        <a href="javascript:;">18人死傷!韓國一男子縱火後持兇器傷害避險鄰居</a>
                    </h3>
                    <div class="info">
                        <span class="tips"><span>縱火</span><span>韓國</span><span>逮捕</span></span>
                        <!-- <span class="line"></span> -->
                        <span class="time">| &nbsp;&nbsp;1小時前</span>
                    </div>
                </div>
            </li>
            <li class="news">
                <a href="javascript:;">
                    <img src="./img/img.png" alt="">
                </a>
                <div>
                    <h3>
                        <a href="javascript:;">18人死傷!韓國一男子縱火後持兇器傷害避險鄰居</a>
                    </h3>
                    <div class="info">
                        <span class="tips"><span>縱火</span><span>韓國</span><span>逮捕</span></span>
                        <!-- <span class="line"></span> -->
                        <span class="time">| &nbsp;&nbsp;1小時前</span>
                    </div>
                </div>
            </li>
            <li class="news">
                <a href="javascript:;">
                    <img src="./img/img.png" alt="">
                </a>
                <div>
                    <h3>
                        <a href="javascript:;">18人死傷!韓國一男子縱火後持兇器傷害避險鄰居</a>
                    </h3>
                    <div class="info">
                        <span class="tips"><span>縱火</span><span>韓國</span><span>逮捕</span></span>
                        <!-- <span class="line"></span> -->
                        <span class="time">| &nbsp;&nbsp;1小時前</span>
                    </div>
                </div>
            </li>
            <li class="news">
                <a href="javascript:;">
                    <img src="./img/img.png" alt="">
                </a>
                <div>
                    <h3>
                        <a href="javascript:;">18人死傷!韓國一男子縱火後持兇器傷害避險鄰居</a>
                    </h3>
                    <div class="info">
                        <span class="tips"><span>縱火</span><span>韓國</span><span>逮捕</span></span>
                        <!-- <span class="line"></span> -->
                        <span class="time">| &nbsp;&nbsp;1小時前</span>
                    </div>
                </div>
            </li>
            <li class="news">
                <a href="javascript:;">
                    <img src="./img/img.png" alt="">
                </a>
                <div>
                    <h3>
                        <a href="javascript:;">18人死傷!韓國一男子縱火後持兇器傷害避險鄰居</a>
                    </h3>
                    <div class="info">
                        <span class="tips"><span>縱火</span><span>韓國</span><span>逮捕</span></span>
                        <!-- <span class="line"></span> -->
                        <span class="time">| &nbsp;&nbsp;1小時前</span>
                    </div>
                </div>
            </li>
        </ul>
        <div class="pagination">
            <a href="javascript:;" class="prev">⌜</a>
            <a href="javascript:;">1</a>
            <a href="javascript:;">2</a>
            <a href="javascript:;">3</a>
            <a href="javascript:;">4</a>
            <a href="javascript:;">5</a>
            <a href="javascript:;" class="next">⌝</a>
        </div>
    </div>

</body>

</html>

detail.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .text{
            width: 640px;
            margin: 0 auto;
        }
        .article-info{
            color:#999;
            font-size: 14px;
        }
        p{
            font-size: 16px;
            line-height: 30px;
        }
    </style>
</head>
<body>
    <div class="text">
        <h1 class="title">新聞標題</h1>
        <div class="article-info"> 類型:縱火 時間:2019-6-18</div>
        <p class="content">
            新聞內容新聞內容
            新聞內容新聞內容
            新聞內容新聞內容
        </p>
    </div>
</body>
</html>

data.json:同上,爬蟲所得的數據

實現詳情頁展示和分頁功能

更改index.js爲indexPager.js:其他文件不變,直接覆蓋detail.html中的內容

//將爬蟲得到的數據,渲染到頁面,需要進行頁面路由
const http = require("http");
const fs = require("fs");
const cheerio = require("cheerio");
const url = require("url");//處理地址
const path = require("path");//處理地址後綴名
const mime = require("./mime.json");//處理後綴名文件
const dataJson = require("./data.json");//新聞數據

let server = http.createServer((req, res) => {
    //地址欄加上頁碼後,會有queryString :pathname:/index ; search: '?pageNum=2';query: 'pageNum=2'
    let pathname = url.parse(req.url).pathname;
    
    if (pathname === "/" || pathname === "/index") {
        res.writeHead(200, { 'Content-Type': 'text/html;charset=utf-8' });
        //方法一:讀取到index文件,獲取文件標籤,設置文件標籤內容
        let index = fs.readFileSync("index.html");
        let $ = cheerio.load(index);
        //分頁實現:總頁數=總數據條數/每頁多少條
        //當點擊某頁時,需要獲取到傳過來的頁碼(通過path可以獲取到queryString參數)
        //url.parse(req.url, true).query 當沒有參數時[Object: null prototype] {},有參數時:[Object: null prototype] { pageNum: '2' }
        let pageNum = url.parse(req.url, true).query.pageNum || 1;//第幾頁(默認第一頁)


        let pageSize = 5;//每頁多少條
        let pageTotal = Math.ceil(dataJson.length/pageSize);//總共多少頁
        //通過數組slice方法進行分頁(如果是數據庫,需要調數據庫)0-4 5-10 11-14 =>(pageNum-1)*pageSize , pageNum*pageSize
        let pageData = dataJson.slice((pageNum-1)*pageSize,pageNum*pageSize);

        //讀取到json文件新聞數據
        //獲取ul 將HTML設置進去
        let ulHtml = '';
        pageData.forEach(item => {
            ulHtml += `
                <li class="news">
                    <a href="javascript:;">
                        <img src="./img/img.png" alt="">
                    </a>
                    <div>
                        <h3>
                            <a href="/detail?id=${item.id}">${item.title}</a>
                        </h3>
                        <div class="info">
                            <span class="tips"><span>縱火</span><span${item.publisher}</span><span>逮捕</span></span>
                            <!-- <span class="line"></span> -->
                            <span class="time">| &nbsp;&nbsp;${item.time}</span>
                        </div>
                    </div>
                </li>
             `;
        });
        $(".news-list").html(ulHtml);

        //渲染分頁按鈕
        //cheerio沒有事件,所以上下頁切換不能綁定點擊事件,只能通過操作pageNum實現,注意需要將pageNum轉爲Number類型
        let p = parseInt(pageNum);
        let pagerHtml = `<a href="/index?pageNum=${Math.max(1,p-1)}" class="prev">⌜</a>`;
        for(let i=1;i<=pageTotal;i++){
            //點擊每頁還是跳轉到本頁面,這是頁碼變化
            pagerHtml += `<a href="/index?pageNum=${i}">${i}</a>`;
        }
        pagerHtml += `<a href="/index?pageNum=${Math.min(pageTotal,p+1)}" class="next">⌝</a>`;
        $(".pagination").html(pagerHtml);

        //點擊事件:設置數組中某個元素的樣式,.eq(pageNum)
        $(".pagination a").each((index,item)=>{
            if(pageNum == index){
                $(".pagination a").eq(pageNum).addClass('active')
            }
        });

        res.end($.html());

    }else if(pathname === "/detail"){
        //跳轉到詳情頁
        //使用id重新查找對應數據
        let id = url.parse(req.url, true).query.id;
        let detailData = dataJson.find(item=>id==item.id);
        let detail = fs.readFileSync("detail.html");
        let $ = cheerio.load(detail);
        let detailHtml = `
            <h1 class="title">${detailData.title}</h1>
            <div class="article-info"> 類型:縱火 時間:${detailData.time}</div>
            <p class="content">
                ${detailData.title}
            </p>
        `;

        $(".text").html(detailHtml);  
        //一定要使用res.end()方式時響應結束
        res.end($.html());      

    } else if (pathname !== "/favicon.ico") {
        let extname = path.extname(req.url);
        res.writeHead(200, { 'Content-Type': mime[extname] });
        let static = fs.createReadStream("." + req.url);
        static.pipe(res);
    }
});
server.listen(3000);

效果:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章