Node.js 萬字教程

来源:https://www.cnblogs.com/codechen8848/archive/2023/11/23/17850986.html
-Advertisement-
Play Games

Node.js 是一個基於 Chrome V8 引擎的 JavaScript 運行環境,使用了一個事件驅動、非阻塞式 I/O 模型,讓 JavaScript 運行在服務端的開發平臺。 ...


0. 基礎概念

Node.js 是一個基於 Chrome V8 引擎的 JavaScript 運行環境,使用了一個事件驅動、非阻塞式 I/O 模型,讓 JavaScript 運行在服務端的開發平臺。

官方地址:https://nodejs.org/en
中文地址:https://nodejs.org/zh-cn

代碼初體驗:

console.log("hello NodeJS")

// 1.進入到對應 js 文件的目錄下
// 2.執行 node 1-hello.js 
// 3.輸出:hello NodeJS

示例代碼地址:https://github.com/chenyl8848/node.js-study

1. Buffer

1.1 概念

Buffer 是一個類似於數組的對象,用於表示固定長度的位元組序列。Buffer 本質是一段記憶體空間,專門用來處理二進位數據。

1.2 特點

  • Buffer 大小固定且無法調整
  • Buffer 性能較好,可以直接對電腦記憶體進行操作
  • 每個元素的大小為 1 位元組(byte)

1.3 使用

1.3.1 Buffer 的創建

Node.js 中創建 Buffer 的方式主要如下幾種:

Buffer.alloc

// 創建了一個長度為 10 位元組的 Buffer,相當於申請了 10 位元組的記憶體空間,每個位元組的值為 0
// 結果為 <Buffer 00 00 00 00 00 00 00 00 00 00>
let buf_1 = Buffer.alloc(10);

Buffer.allocUnsafe

// 創建了一個長度為 10 位元組的 Buffer,Buffer 中可能存在舊的數據, 可能會影響執行結果,所以叫 unsafe
let buf_2 = Buffer.allocUnsafe(10);

Buffer.from

// 通過字元串創建 Buffer
let buf_3 = Buffer.from('hello');
// 通過數組創建 Buffer
let buf_4 = Buffer.from([105, 108, 111, 118, 101, 121, 111, 117]);

1.3.2 Buffer 與字元串的轉化

可以藉助 toString 方法將 Buffer 轉為字元串

// buffer 與字元串的轉換
const buffer = Buffer.from([105, 108, 111, 118, 101, 121, 111, 117]);
// 預設使用 UTF-8 的編碼格式 
console.log(buffer.toString())

註意:toString 預設是按照 utf-8 編碼方式進行轉換的。

1.3.3 Buffer 的操作

Buffer 可以直接通過 [] 的方式對數據進行處理。

const buffer = Buffer.from('hello');
// 二進位:1101000
console.log(buffer[0].toString(2))

// 修改 buffer
buffer[0] = 95
console.log(buffer.toString())

// 溢出 如果修改的數值超過 255 ,則超過 8 位數據會被捨棄
const buffer = Buffer.from('hello')
// 會捨棄高位的數字,因為八位的二進位最高值為 255   0001 0110 1001  => 0110 1001
buffer[0] = 361
console.log(buffer)

// 中文 一個 utf-8 的字元 一般 占 3 個位元組
const buffer = Buffer.from('你好')
console.log(buffer)

註意:

  1. 如果修改的數值超過255,則超過8位數據會被捨棄
  2. 一個 utf-8 的字元一般占3個位元組

2. fs 模塊

fs 全稱為 file system,稱之為文件系統,是 Node.js 中的內置模塊,可以對電腦中的磁碟進行操作。

2.1 文件寫入

文件寫入就是將數據保存到文件中,有如下的 API

方法 說明
writeFile 非同步寫入
writeFileSync 同步寫入
appendFile/appendFileSync 追加寫入
createWriteStream 流式寫入

2.1.1 非同步寫入

語法: fs.writeFile(file, data, [options], callback)
參數說明:

  • file:文件名
  • data:待寫入的數據
  • options:選項設置 (可選)
  • callback:寫入回調

返回值: undefined
代碼示例:

// 1.導入 fs 模塊
const fs = require('fs')

// 2.寫入文件
// writeFile 非同步寫入,四個參數:1.文件路徑 2.寫入內容 3.配置信息 4.回調函數
// 文件寫入成功
fs.writeFile('./座右銘.txt', '封狼居胥,禪於姑衍,飲馬瀚海', error => {
    // errror 為 null就是寫入成功
    if (error) {
        console.log('文件寫入失敗')
        return;
    }
    console.log('文件寫入成功')
});

2.1.2 同步寫入

語法: fs.writeFileSync(file, data, [options])
參數說明:

  • file:文件名
  • data:待寫入的數據
  • options:選項設置 (可選)
    返回值: undefined
    代碼示例:
// 1.導入 fs 模塊
const fs = require('fs')

// 2.寫入文件
// 同步寫入,沒有回調函數
fs.writeFileSync('./座右銘.txt', '封狼居胥,禪於姑衍,飲馬瀚海,燕石勒然')

Node.js 中的磁碟操作是由其他線程完成的,結果的處理有兩種模式:

  • 同步處理 JavaScript 主線程會等待其他線程的執行結果,然後再繼續執行主線程的代碼,效率較低
  • 非同步處理 JavaScript 主線程不會等待其他線程的執行結果,直接執行後續的主線程代碼,效率較好

2.1.3 追加寫入

appendFile 作用是在文件尾部追加內容,appendFile 語法與 writeFile 語法完全相同
語法:

  • fs.appendFile(file, data, [options], callback)
  • fs.appendFileSync(file, data, [options])

返回值: 二者都為 undefined
代碼示例:

// 1.引入 fs 模塊
const fs = require('fs');

const content = '\r\n但使龍城飛將在,不教胡馬度陰山';

// fs.appendFile('./座右銘.txt', content, error => {
//     // errror 為 null就是寫入成功
//     if (error) {
//         console.log('文件追加寫入失敗')
//         return;
//     }
//     console.log('文件追加寫入成功');
// })

// 同步文件追加寫入
// fs.appendFileSync('./座右銘.txt', content)

// 使用 writeFile 的方式追加文件寫入
fs.writeFile('./座右銘.txt', content, {flag: 'a'}, error => {
    if (error) {
        console.log('文件追加寫入失敗')
        return;
    }
    console.log('文件追加寫入成功')
})

console.log('hello world')

2.1.4 流式寫入

語法: fs.createWriteStream(path, [options])
參數說明:

  • path:文件路徑
  • options:選項配置( 可選 )

返回值: Object
代碼示例:

// 1.導入 fs 模塊
const fs = require('fs');

// 2.創建寫入流對象
const writeStream = fs.createWriteStream('./觀書有感.txt');

// 3.寫入內容
writeStream.write('半畝方塘一鑒開\r\n')
writeStream.write('天光雲影共徘徊\r\n')
writeStream.write('問渠那得清如許\r\n')
writeStream.write('為有源頭活水來\r\n')

// 4.關閉通道 不是必須
// writeStream.close();

程式打開一個文件是需要消耗資源的,流式寫入可以減少打開關閉文件的次數。流式寫入方式適用於大文件寫入或者頻繁寫入的場景, writeFile 適合於寫入頻率較低的場景。

2.2 文件讀取

文件讀取顧名思義,就是通過程式從文件中取出其中的數據,有如下幾種 API

方法 說明
readFile 非同步讀取
readFileSync 同步讀取
createReadStream 流式讀取

2.2.1 非同步讀取

語法: fs.readFile(path, [options], callback)
參數說明:

  • path:文件路徑
  • options:選項配置
  • callback:回調函數

返回值: undefined
代碼示例:

// 1.引入 fs 模塊
const fs = require('fs')

// 2.非同步讀取
fs.readFile('./座右銘.txt', (error, data) => {
    if (error) {
        console.log('文件讀取錯誤')
        return
    }
    console.log(data.toString())
})

2.2.2 同步讀取

語法: fs.readFileSync(path, [options])
參數說明:

  • path:文件路徑
  • options:選項配置

返回值: string | Buffer
代碼示例:

// 1.引入 fs 模塊
const fs = require('fs')

// 2.同步讀取
let data = fs.readFileSync('./座右銘.txt');
console.log(data.toString())

2.2.3 流式讀取

語法: fs.createReadStream(path, [options])
參數說明:

  • path:文件路徑
  • options:選項配置(可選)

返回值:Object
代碼示例:

// 1.導入 fs 模塊
const fs = require('fs')

// 2.創建讀取流對象
const rs = fs.createReadStream('./觀書有感.txt');

// 3.綁定 data 事件
rs.on('data', chunk => {
    // chunk:塊兒、大塊兒
    console.log(chunk)
    console.log(chunk.length)
    console.log(chunk.toString())
})

// 4.結束事件(可選)
rs.on('end', () => {
    console.log('文件讀取完成')
})

2.3 文件移動與重命名

Node.js 中,可以使用 renamerenameSync 來移動或重命名文件或文件夾
語法:

  • fs.rename(oldPath, newPath, callback)
  • fs.renameSync(oldPath, newPath)

參數說明:

  • oldPath:文件當前的路徑
  • newPath:文件新的路徑
  • callback:操作後的回調

代碼示例:

// 1.導入 fs 模塊
const fs = require('fs');

// 2.文件重命名
// fs.rename('./座右銘-2.txt', './西漢名將.txt', error => {
//     if (error) {
//         console.log('文件重命名失敗')
//            return ;
//     }
//     console.log('文件重命名成功')
// })

// 3.文件移動
// 文件夾如果不存在,會報錯誤 Error: ENOENT: no such file or directory
fs.rename('./西漢名將.txt', './文件/西漢名將.txt', error => {
    if (error) {
        console.log(error, '移動文件出錯');
        return ;
    }
    console.log('操作成功')
})

2.4 文件刪除

Node.js 中,可以使用 unlinkunlinkSyncrmrmSync 來刪除文件
語法:

  • fs.unlink(path, callback)
  • fs.unlinkSync(path)

參數說明:

  • path:文件路徑
  • callback:操作後的回調

代碼示例:

// 1.引入 fs 模塊
const fs = require('fs')

// 2.調用 unlink 方法 
// unlinkSync:同步刪除
// fs.unlink('./座右銘-3.txt', error => {
//     if (error) {
//         console.log('刪除文件錯誤', error)
//         return;
//     }
//     console.log('刪除文件成功')
// })

// 3.調用 rm 方法
// rmSync:同步刪除
fs.rm('./文件/西漢名將.txt', error => {
    if (error) {
        console.log('文件刪除失敗', error)
        return;
    }
    console.log('文件刪除成功')
})

2.5 文件夾操作

Node.js 中可以通過如下 API 對文件夾進行創建、讀取、刪除等操作

方法 說明
mkdir / mkdirSync 創建文件夾
readdir / readdirSync 讀取文件夾
rmdir / rmdirSync 刪除文件夾

2.5.1 創建文件夾

Node.js 中,可以使用 mkdirmkdirSync 來創建文件夾
語法:

  • fs.mkdir(path, [options], callback)
  • fs.mkdirSync(path, [options])

參數說明:

  • path:文件夾路徑
  • options:選項配置(可選)
  • callback:操作後的回調

示例代碼:

// 1.引入 fs 模塊
const fs = require('fs')

// 2.創建文件夾
// mkdir make:製作 directory:目錄 
fs.mkdir('./html', error => {
    if (error) {
        console.log('創建目錄失敗', error)
        return;
    }
    console.log('創建目錄成功')
})

// 3.遞歸創建文件夾
fs.mkdir('./a/b/c', {
    recursive: true
}, error => {
    if (error) {
        console.log("遞歸創建文件夾失敗", error)
        return;
    }
    console.log('遞歸創建文件夾成功')
})

// 4.遞歸同步創建文件夾
fs.mkdirSync('./a/b/c', {recursive: true});

2.5.2 讀取文件夾

Node.js 中,可以使用 readdirreaddirSync 來讀取文件夾
語法:

  • fs.readdir(path, [options], callback)
  • fs.readdirSync(path, [options])

參數說明:

  • path:文件夾路徑
  • options:選項配置(可選)
  • callback:操作後的回調

示例代碼:

// 1.引入 fs 模塊
const fs = require('fs')

// 2.讀取文件夾
// readdir read:讀取 dir:directory 目錄
fs.readdir('./', (error, data) => {
    if (error) {
        console.log('讀取文件夾錯誤', error)
        return;
    }
    // [
    //     '1-文件寫入.js',
    //     '2-追加寫入.js',
    //     '3-流式寫入.js',
    //     '4-文件讀取.js',
    //     '5-流式讀取.js',
    //     '6-練習-文件複製.js',
    //     '7-文件重命名與移動.js',
    //     '8-刪除文件.js',
    //     '9-文件夾操作.js',
    //     'a',
    //     'html',
    //     '座右銘.txt',
    //     '文件',
    //     '觀書有感.txt'
    // ]
    console.log(data)
})

//同步讀取
// let data = fs.readdirSync('./');
// console.log(data);

2.5.3 刪除文件夾

Node.js 中,可以使用 rmdirrmdirSync 來刪除文件夾
語法:

  • fs.rmdir(path, [options], callback)
  • fs.rmdirSync(path, [options])
    參數說明:
  • path:文件夾路徑
  • options:選項配置(可選)
  • callback:操作後的回調

示例代碼:

// 1.引入 fs 模塊
const fs = require('fs')

// 2.刪除文件夾
// fs.rmdir('./文件', error => {
//     if (error) {
//         console.log('刪除文件夾失敗', error)
//         return;
//     }
//     console.log('刪除文件夾成功')
// })

// 3.遞歸刪除文件夾 
// 遞歸刪除文件夾失敗 [Error: ENOTEMPTY: directory not empty, rmdir 'E:\JavaEE\frontend\nodejs-study\2-fs文件系統\a'] 

// 不推薦使用
// fs.rmdir('./a', {recursive: true}, error => {
//     if (error) {
//         console.log('遞歸刪除文件夾失敗', error)
//         return ;
//     }
//     console.log('遞歸刪除文件夾成功')
// })

// 推薦使用
fs.rm('./a', {recursive: true}, error => {
    if (error) {
        console.log('遞歸刪除文件失敗', error)
        return;
    }
    console.log('遞歸刪除文件成功')
})

//同步遞歸刪除文件夾
fs.rmdirSync('./a', {recursive: true})

2.6 查看資源狀態

Node.js 中,可以使用 statstatSync 來查看資源的詳細信息
語法:

  • fs.stat(path, [options], callback)
  • fs.statSync(path, [options])

參數說明:

  • path:文件夾路徑
  • options:選項配置(可選)
  • callback:操作後的回調

示例代碼:

// 1.引入 fs 模塊
const fs = require('fs')

// 2.stat 方法 status 的縮寫:狀態
fs.stat('./觀書有感.txt', (error, data) => {
    if (error) {
        console.log('操作失敗', error)
        return;
    }
    // Stats {
    //     dev: 985301708,
    //     mode: 33206,
    //     nlink: 1,
    //     uid: 0,
    //     gid: 0,
    //     rdev: 0,
    //     blksize: 4096,
    //     ino: 281474979770305,
    //     size: 92,
    //     blocks: 0,
    //     atimeMs: 1684373309132.9426,
    //     mtimeMs: 1684289136772.1648,
    //     ctimeMs: 1684289136772.1648,
    //     birthtimeMs: 1684289136770.7136,
    //     atime: 2023 - 05 - 18 T01: 28: 29.133 Z,
    //     mtime: 2023 - 05 - 17 T02: 05: 36.772 Z,
    //     ctime: 2023 - 05 - 17 T02: 05: 36.772 Z,
    //     birthtime: 2023 - 05 - 17 T02: 05: 36.771 Z
    // }
    console.log(data)
    console.log(data.isFile())
    console.log(data.isDirectory())
})

// 3.同步獲取狀態
let data = fs.statSync('./觀書有感.txt');
console.log(data)
console.log(data.isFile())
console.log(data.isDirectory())

結果值對象結構:

  • size:文件體積
  • birthtime:創建時間
  • mtime:最後修改時間
  • isFile:檢測是否為文件
  • isDirectory:檢測是否為文件夾

2.7 相對路徑問題

fs 模塊對資源進行操作時,路徑的寫法有兩種:

  • 相對路徑
    • ./座右銘.txt:當前目錄下的座右銘.txt
    • 座右銘.txt:等效於上面的寫法
    • ../座右銘.txt:當前目錄的上一級目錄中的座右銘.txt
  • 絕對路徑
    • D:/Program Files:windows 系統下的絕對路徑
    • /usr/bin:Linux 系統下的絕對路徑

相對路徑中所謂的當前目錄,指的是命令行的工作目錄,而並非是文件的所在目錄。所以當命令行的工作目錄與文件所在目錄不一致時,會出現一些 BUG

2.8 __dirname

__dirnamerequire 類似,都是 Node.js 環境中的 '全局' 變數
__dirname 保存著當前文件所在目錄的絕對路徑,可以使用 __dirname 與文件名拼接成絕對路徑
代碼示例:

let data = fs.readFileSync(__dirname + '/data.txt');
console.log(data);

使用 fs 模塊的時候,儘量使用 __dirname 將路徑轉化為絕對路徑,這樣可以避免相對路徑產生的 Bug

2.9 練習

實現文件複製的功能
代碼示例:

/**
 * 需求:
 *  複製【座右銘.txt】
 */

// 1.引入 fs 模塊
const fs = require('fs');
// 全局對象,即 global 對象的屬性,無須聲明即可訪問。它用於描述當前 Node 進程狀態的對象,提供了一個與操作系統的簡單介面。
const process = require('process')

// 方式一:使用 readFile
// 2.讀取文件
// let data = fs.readFileSync('./座右銘.txt');

// // 3.寫入文件
// fs.writeFileSync('./座右銘-2.txt', data);

// // 查看系統耗費記憶體
// // rss: 19795968 位元組
// console.log(process.memoryUsage())

// 方式二:使用流式操作
// 2.創建流式讀取
let rs = fs.createReadStream('./座右銘.txt');

// 3.創建流式寫入
let ws = fs.createWriteStream('./座右銘-3.txt');

// // 4.綁定 data 事件
// rs.on('data', chunk => {
//     ws.write(chunk);
// })

// // 5.綁定 end 事件
// rs.on('end', () => {
//     // rss: 20885504 位元組 相比於同步的方式占用記憶體會比較小
//     console.log(process.memoryUsage())
// })

// 4.使用 pipe(管道) 可直接複製
rs.pipe(ws)

3. path 模塊

path 模塊提供了操作路徑的功能,有如下幾個較為常用的 API

方法 說明
path.resolve 拼接規範的絕對路徑常用
path.sep 獲取操作系統的路徑分隔符
path.parse 解析路徑並返回對象
path.basename 獲取路徑的基礎名稱
path.dirname 獲取路徑的目錄名
path.extname 獲得路徑的擴展名

代碼示例:

// 1.引入 path、fs 模塊
const path = require('path')
const fs = require('fs')

// 寫入文件
// fs.writeFileSync(__dirname + '/index.html', 'love')
// E:\JavaEE\frontend\nodejs-study\3-path模塊/index.html
// console.log(__dirname + '/index.html')

// 使用 path 解決
// E:\JavaEE\frontend\nodejs-study\3-path模塊\index.html
console.log(path.resolve(__dirname, './index.html'))
// E:\JavaEE\frontend\nodejs-study\3-path模塊\index.html
console.log(path.resolve(__dirname, 'index.html'))
// E:\index.html\test
console.log(path.resolve(__dirname, '/index.html', './test'))

// 分隔符
// \ windows:\ linux:/
console.log(path.sep)

// parse 方法 __dirname '全局變數'
// __filename '全局變數' 文件的絕對路徑
console.log(__filename)

let str = 'E:\\JavaEE\\frontend\\nodejs-study\\3-path模塊\\index.html';

// {
//     root: 'E:\\',
//     dir: 'E:\\JavaEE\\frontend\\nodejs-study\\3-path模塊',
//     base: 'index.html',
//     ext: '.html',
//     name: 'index'
// }
console.log(path.parse(str))

// index.html
console.log(path.basename(str))

// E:\JavaEE\frontend\nodejs-study\3-path模塊
console.log(path.dirname(str))

// .html
console.log(path.extname(str))

4. http 模塊

4.1 創建 http 服務

4.1.1 操作步驟

代碼示例:

// 1.引入 http 模塊
const http = require('http')

// 2.創建 http 服務
const server = http.createServer((request, response) => {
    
    // response.end 設置響應體 必須要返回,且只能返回一次
    // 多個 response.end 報錯 Error [ERR_STREAM_WRITE_AFTER_END]: write after end
    // response.end("hello world")
    // response.end("hello world")

    // 解決中文亂碼
    response.setHeader('content-type', 'text/html;charset=utf-8')
    response.end('你好,世界')
})

// 3.啟動服務並監聽埠
server.listen(9000, () => {
    console.log('http 服務啟動成功')
})

http.createServer 里的回調函數的執行時機:當接收到 http 請求的時候,就會執行

4.1.2 測試

瀏覽器請求對應埠
http://127.0.0.1:9000

4.1.3 註意事項

  • 命令行 ctrl + c 停止服務
  • 當服務啟動後,更新代碼必須重啟服務才能生效
  • 響應內容中文亂碼的解決辦法
    response.setHeader('content-type', 'text/html;charset=utf-8')
    
  • 埠號被占用
    • 關閉當前正在運行監聽埠的服務
    • 修改其他埠號
    • 如果埠被其他程式占用,可以使用資源監視器找到占用埠的程式,然後使用任務管理器關閉對應的程式

4.2 獲取 http 請求報文

想要獲取請求的數據,需要通過 request 對象

方法 說明
request.method 請求方法
request.httpVersion 請求版本
request.url 請求路徑
require('url').parse(request.url).pathname URL 路徑
require('url').parse(request.url, true).query URL 查詢字元串
request.headers 請求頭
request.on('data', function(chunk){})
request.on('end', function(){});
請求體

註意事項:

  • request.url 只能獲取路徑以及查詢字元串,無法獲取 URL 中的功能變數名稱以及協議的內容
  • request.headers 將請求信息轉化成一個對象,並將屬性名都轉化成了『小寫』
  • 關於路徑:如果訪問網站的時候,只填寫了 IP 地址或者是功能變數名稱信息,此時請求的路徑為『/』
  • 關於 favicon.ico:這個請求是屬於瀏覽器自動發送的請求

代碼示例:

// 1.引入 http 模塊
const http = require('http')

// 2.創建服務
const server = http.createServer((request, response) => {
    // 獲取請求的方法
    console.log(request.method)
    // 獲取請求的 url
    console.log(request.url)
    // 獲取 http 協議版本號
    console.log(request.httpVersion)
    // 獲取請求頭
    console.log(request.headers)
    // 獲取請求主機地址
    console.log(request.headers.host)

    response.end("hello world")
})

// 3.啟動服務並監聽埠‘
server.listen(9000, () => {
    console.log('服務啟動成功')
})

代碼示例:

// 1.引入 http 模塊
const http = require('http')

// 2.創建服務
const server = http.createServer((request, response) => {
    
    // 1.聲明一個變數
    let body = ''

    // 2.綁定 data 事件
    request.on('data', chunk => {
        body += chunk
    })

    // 3.綁定 end 事件
    request.on('end', () => {
        console.log(body)
        response.end("hello world")
    })

})

// 3.啟動服務並監聽埠‘
server.listen(9000, () => {
    console.log('服務啟動成功')
})

代碼示例:

// 1.引入 http 模塊
const http = require('http')

// 1.導入 url 模塊
const url = require('url')

// 2.創建服務
const server = http.createServer((request, response) => {
    // request: http://127.0.0.1:9000/search?keyword=123&username=chen

    // 2.解析 request.url
    // let res1 = url.parse(request.url)
    // Url {
    //     protocol: null,
    //     slashes: null,
    //     auth: null,
    //     host: null,
    //     port: null,
    //     hostname: null,
    //     hash: null,
    //     search: '?keyword=123&username=chen',
    //     query: 'keyword=123&username=chen',
    //     pathname: '/search',
    //     path: '/search?keyword=123&username=chen',
    //     href: '/search?keyword=123&username=chen'
    // }
    // console.log(res1)


    // let res2 = url.parse(request.url, true)
    // Url {
    //     protocol: null,
    //     slashes: null,
    //     auth: null,
    //     host: null,
    //     port: null,
    //     hostname: null,
    //     hash: null,
    //     search: '?keyword=123&username=chen',
    //     query: [Object: null prototype] {
    //         keyword: '123',
    //         username: 'chen'
    //     },
    //     pathname: '/search',
    //     path: '/search?keyword=123&username=chen',
    //     href: '/search?keyword=123&username=chen'
    // }
    // console.log(res2)

    let res = url.parse(request.url, true)
    // 請求路徑
    // /search
    console.log(res.pathname)
    // 查詢字元串
    // 123
    console.log(res.query.keyword)

    response.end('hello world')
})

// 3.啟動服務並監聽埠‘
server.listen(9000, () => {
    console.log('服務啟動成功')
})

代碼示例:

// 1.引入 http 模塊
const http = require('http')

// 2.創建服務
const server = http.createServer((request, response) => {
    // request: http://127.0.0.1:9000/search?keyword=123&username=chen

    // 第二個參數要寫完整 http://127.0.0.1  只寫 ip 會報錯
    let url = new URL(request.url, 'http://127.0.0.1')

    // URL {
    //     href: 'http://127.0.0.1/search?keyword=123&username=chen',
    //     origin: 'http://127.0.0.1',
    //     protocol: 'http:',
    //     username: '',
    //     password: '',
    //     host: '127.0.0.1',
    //     hostname: '127.0.0.1',
    //     port: '',
    //     pathname: '/search',
    //     search: '?keyword=123&username=chen',
    //     searchParams: URLSearchParams {
    //         'keyword' => '123', 'username' => 'chen'
    //     },
    //     hash: ''
    // }
    // console.log(url)

    // 請求路徑
    console.log(url.pathname)
    
    // 請求路徑參數
    console.log(url.searchParams.get('keyword'))

    response.end('hello world')
})

// 3.啟動服務並監聽埠‘
server.listen(9000, () => {
    console.log('服務啟動成功')
})

4.3 設置 http 響應報文

方法 說明
response.statusCode 設置響應狀態碼
response.statusMessage 設置響應狀態描述
response.setHeader('鍵名', '鍵值') 設置響應頭信息
response.write('xx')
response.end('xxx')
設置響應體

writeend 的兩種使用情況:

// 1.write 和 end 的結合使用 響應體相對分散
response.write('xx');
response.write('xx');
response.write('xx');

 //每一個請求,在處理的時候必須要執行 end 方法,且只能執行一次
response.end();

// 2.單獨使用 end 方法 響應體相對集中
response.end('xxx');

代碼示例:

// 1.引入 http 模塊
const http = require('http')

// 2.創建服務
const server = http.createServer((request, response) => {
    
    // 1.設置響應狀態碼
    // response.statusCode = 200
    // response.statusCode = 404

    // 2.設置響應信息 不常用
    // response.statusMessage = 'hello world'

    // 3.設置響應頭
    response.setHeader('content-type', 'text/html;charset=utf-8')
    response.setHeader('Server', 'Node.js')
    response.setHeader('myHeader', 'myHeader')
    response.setHeader('test', ['love', 'love', 'love'])

    // 4.設置響應體
    response.write('love\r\n')
    response.write('love\r\n')
    response.write('love\r\n')
    response.write('love\r\n')

    response.end('hello world')

})

// 3.啟動服務並監聽埠‘
server.listen(9000, () => {
    console.log('服務啟動成功')
})

4.4 練習

4.4.1 http 請求練習

需求:
當請求方式為 get 請求時,請求路徑為 /login 返回 login
當請求方式為 get 請求時,請求路徑為 /register 返回 register

代碼示例:

/**
 * 需求:
 *  當請求方式為 get 請求時,請求路徑為 /login 返回 login
 *  當請求方式為 get 請求時,請求路徑為 /register 返回 register
 */

// 1.引入 http 模塊
const http = require('http')

// 2.創建服務
const server = http.createServer((request, response) => {
    
    // 請求方式
    let { method } = request

    // 請求路徑
    let { pathname } = new URL(request.url, 'http://127.0.0.1')

    if (method === 'GET' && pathname === '/login') {
        response.end('login')
    } else if (method === 'GET' && pathname === '/register') {
        response.end('register')
    } else {
        response.end('hello world')
    }
})

// 3.啟動服務並監聽埠‘
server.listen(9000, () => {
    console.log('服務啟動成功')
})

4.4.1 http 響應練習

需求:
回一個4行3列的表格,且要求表格有隔行換色效果,且點擊單元格能高亮顯示

代碼示例:

/**
 * 需求:
 *  返回一個4行3列的表格,且要求表格有隔行換色效果,且點擊單元格能高亮顯示
 */


// 1.引入 http 模塊
const http = require('http')

// 2.創建服務
const server = http.createServer((request, response) => {

    response.end(`
    <!DOCTYPE html>
        <html lang="en">

        <head>
            <meta charset="UTF-8">
            <meta http-equiv="X-UA-Compatible" content="IE=edge">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Document</title>
            <style>
                td {
                    padding: 20px 40px;
                }

                table tr:nth-child(odd) {
                    background: rgb(179, 165, 201);
                }

                table tr:nth-child(even) {
                    background: #fcb;
                }

                table,
                td {
                    border-collapse: collapse;
                }
            </style>
        </head>

        <body>
            <table border="1">
                <tr>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
                <tr>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
                <tr>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
                <tr>
                    <td></td>
                    <td></td>
                    <td></td>
                </tr>
            </table>
            <script>
                //獲取所有的 td
                let tds = document.querySelectorAll('td');
                //遍歷
                tds.forEach(item => {
                    item.onclick = function () {
                        this.style.background = '#222';
                    }
                })
            </script>
        </body>

        </html>
    `)

})

// 3.啟動服務並監聽埠‘
server.listen(9000, () => {
    console.log('服務啟動成功')
})

代碼優化:

/**
 * 需求:
 *  返回一個4行3列的表格,且要求表格有隔行換色效果,且點擊單元格能高亮顯示
 */


// 1.引入 http 模塊
const http = require('http')

// 1.引入 fs 模塊
const fs = require('fs')

// 2.創建服務
const server = http.createServer((request, response) => {

    // 2.讀取文件內容
    let file = fs.readFileSync(__dirname + '/10-table.html')

    response.end(file)

})

// 3.啟動服務並監聽埠‘
server.listen(9000, () => {
    console.log('服務啟動成功')
})

4.5 靜態資源服務

靜態資源是指內容長時間不發生改變的資源,例如圖片、視頻、CSS 文件、JS 文件、HTML 文件、字體文件等。

動態資源是指內容經常更新的資源,例如百度首頁、網易首頁、京東搜索列表頁面等。

4.5.1 網頁中的 URL

網頁中的 URL 主要分為兩大類:相對路徑與絕對路徑

絕對路徑可靠性強,而且相對容易理解,在項目中運用較多

形式 特點
http://xxx.com/web 直接向目標資源發送請求,容易理解,網站的外鏈會用到此形式
//xxx.com/web 與頁面 URL 的協議拼接形成完整 URL 再發送請求,大型網站用的比較多
/web 與頁面 URL 的協議、主機名、埠拼接形成完整 URL 再發送請求,中小型網站

相對路徑在發送請求時,需要與當前頁面 URL 路徑進行計算,得到完整 URL 後,再發送請求
例如當前網頁 URLhttp://www.xxx.com/course/h5.html

形式 最終的 URL
./css/app.css http://www.xxx.com/course/css/app.css
js/app.js http://www.xxx.com/course/js/app.js
../img/logo.png http://www.xxx.com/img/logo.png
../../mp4/show.mp4 http://www.atguigu.com/mp4/show.mp4

4.5.2 設置資源類型(mime 類型)

媒體類型(通常稱為 Multipurpose Internet Mail ExtensionsMIME 類型 )是一種標準,用來表示文檔、文件或位元組流的性質和格式。

mime 類型結構: [type]/[subType]
例如: text/html text/css image/jpeg image/png application/json

http 服務可以設置響應頭 Content-Type 來表明響應體的 mime 類型,瀏覽器會根據該類型決定如何處理資源
下麵是常見文件對應的 mime 類型:

{
    html: 'text/html',
    css: 'text/css',
    js: 'text/javascript',
    png: 'image/png',
    jpg: 'image/jpeg',
    gif: 'image/gif',
    mp4: 'video/mp4',
    mp3: 'audio/mpeg',
    json: 'application/json'
}

說明:對於未知的資源類型,可以選擇 application/octet-stream 類型,瀏覽器在遇到該類型的響應時,會對響應體內容進行獨立存儲,也就是下載

代碼示例:

/**
 * 需求:
 *  根據不同的請求路徑,返回不同的文件
 */

// 1.引入模塊
const http = require('http')
const fs = require('fs')

// 2.創建服務
const server = http.createServer((request, response) => {
    
    // 獲取請求路徑
    let { pathname } = new URL(request.url, 'https://127.0.0.1:9000')
    if (pathname === '/') {
        // 獲取要響應的文件
        let data = fs.readFileSync(__dirname + '/11-table.html')
        // 設置響應
        response.end(data)
    } else if (pathname === '/index.css') {
        // 獲取要響應的文件
        let data = fs.readFileSync(__dirname + '/index.css')
        // 設置響應
        response.end(data)
    } else if (pathname === '/index.js') {
        // 獲取要響應的文件
        let data = fs.readFileSync(__dirname + '/index.js')
        // 設置響應
        response.end(data)
    } else {
        response.end(`<h1>404 Not Found</h1>`)
    }
})

// 3.啟動服務,並監聽埠‘
server.listen(9000, () => {
    console.log('服務啟動成功')
})

代碼優化:

/**
 * 需求:
 *  創建一個 HTTP 服務,埠為 9000,滿足如下需求
 *      GET  /index.html        響應  page/index.html 的文件內容
 *      GET  /css/app.css       響應  page/css/app.css 的文件內容
 *      GET  /images/logo.png   響應  page/images/logo.png 的文件內容
 */

// 1.引入模塊
const http = require('http')
const fs = require('fs')
const path = require('path')

// 2.創建服務
const server = http.createServer((request, response) => {
    
    // 獲取文件根路徑
    let root = path.resolve(__dirname + '/page')
    // 獲取文件路徑
    let { pathname } = new URL(request.url, 'https://127.0.0.1:9000')
    // 拼接文件路徑
    let filePath = root + pathname
    
    // 獲取文件
    fs.readFile(filePath, (error, data) => {
        // 設置字元集,解決打開文件中文亂碼的問題
        response.setHeader('content-type', 'text/html;charset=utf-8')

        if (error) {
            response.end('讀取文件錯誤')
        } 

        response.end(data)
        return;
    })
})

// 3.啟動服務並監聽埠
server.listen(9000, () => {
    console.log('服務啟動成功')
})

代碼優化:

/**
 * 需求:
 *  創建一個 HTTP 服務,埠為 9000,滿足如下需求
 *      GET  /index.html        響應  page/index.html 的文件內容
 *      GET  /css/app.css       響應  page/css/app.css 的文件內容
 *      GET  /images/logo.png   響應  page/images/logo.png 的文件內容
 *  根據不同的文件類型,返回不同的類型
 */

// 1.引入模塊
const http = require('http')
const fs = require('fs')
const path = require('path')

// 聲明一個變數
let mimes = {
    html: 'text/html',
    css: 'text/css',
    js: 'text/javascript',
    png: 'image/png',
    jpg: 'image/jpeg',
    gif: 'image/gif',
    mp4: 'video/mp4',
    mp3: 'audio/mpeg',
    json: 'application/json'
}

// 2.創建服務
const server = http.createServer((request, response) => {

    // 獲取文件根路徑
    let root = path.resolve(__dirname + '/page')
    // 獲取文件路徑
    let {
        pathname
    } = new URL(request.url, 'https://127.0.0.1:9000')
    // 拼接文件路徑
    let filePath = root + pathname

    // 獲取文件
    fs.readFile(filePath, (error, data) => {

        if (error) {
            // 設置字元集,解決打開文件中文亂碼的問題
            response.setHeader('content-type', 'text/html;charset=utf-8')
            switch(error.code) {
                case 'ENOENT': 
                    response.statusCode = 404
                    response.end(`<h1>404 Not Found</h1>`)
                    break;
                case 'EPERM':
                    response.statusCode = 403
                    response.end(`<h1>403 Forbidden</h1>`)
                    break;
                default: 
                    response.statusCode = 500
                    response.end(`<h1>500 Internal </h1>`)
                    break;
            }
            return;
        }

        // 獲取文件尾碼
        let ext = path.extname(filePath).slice(1)
        // 獲取對應的類型
        let type = mimes[ext]
        if (type) {
            // 匹配到了
            if (ext === 'html') {
                response.setHeader('content-type', type + ';charset=utf-8')
            } else {
                response.setHeader('content-type', type)
            }
        } else {
            // 沒有匹配到
            // 這種返回格式可以實現下載效果
            response.setHeader('content-type', 'application/octet-stream')
        }

        response.end(data)
    })
})

// 3.啟動服務並監聽埠
server.listen(9000, () => {
    console.log('服務啟動成功')
})

4.5.3 GETPOST 請求的區別

  • GETPOSThttp 協議請求的兩種方式。
  • GET 主要用來獲取數據,POST 主要用來提交數據
  • GET 帶參數請求是將參數綴到 URL 之後,在地址欄中輸入 URL 訪問網站就是 GET 請求,POST 帶參數請求是將參數放到請求體中
  • POST 請求相對 GET 安全一些,因為在瀏覽器中參數會暴露在地址欄
  • GET 請求大小有限制,一般為 2K,而 POST 請求則沒有大小限制

5. 模塊化

5.1 基礎概念

模塊化:將一個複雜的程式文件依據一定規則(規範)拆分成多個文件的過程稱之為模塊化

模塊:拆分出的每個文件就是一個模塊,模塊的內部數據是私有的,不過模塊可以暴露內部數據以便其他模塊使用

模塊化項目:編碼時是按照模塊一個一個編碼的, 整個項目就是一個模塊化的項目

模塊化好處:

  • 防止命名衝突
  • 高復用性
  • 高維護性

5.2 模塊暴露

模塊暴露的方式有兩種:

  • module.exports = value
  • exports.name = value

說明:

  • module.exports 可以暴露任意數據和方法
  • 不能使用 exports = value 的形式暴露,模塊內部 moduleexports 具有隱式關係
    exports = module.exports = {},require 返回的是目標模塊中 module.exports 的值

代碼示例:
hello.js

const type = 'hello world'

function helloWorld() {
    console.log('你好,世界....')
}

// 暴露數據、方法
module.exports = {
    type,
    helloWorld
}

// exports.type = type
// module.exports = helloWorld

// exports.type = type
// exports.helloWorld = helloWorld

index.js

// 引入自定應模塊
const hello = require('./hello')

// 調用模塊數據/方法
console.log(hello)
hello.helloWorld()
// hello()

5.3 模塊導入

在模塊中使用 require 傳入文件路徑即可引入文件
require 使用的一些註意事項:

  • 對於自己創建的模塊,導入時路徑建議寫相對路徑,且不能省略 ./../
  • jsjson 文件導入時可以不用寫尾碼,c/c++ 編寫的 node 擴展文件也可以不寫尾碼,但是一般用不到
  • 如果導入其他類型的文件,會以 js 文件進行處理
  • 如果導入的路徑是個文件夾,則會首先檢測該文件夾下 package.json 文件中 main 屬性對應的文件,如果存在則導入,反之如果文件不存在會報錯。如果 main 屬性不存在,或者 package.json 不存在,則會嘗試導入文件夾下的 index.jsindex.json,如果還是沒找到,就會報錯
  • 導入 node.js 內置模塊時,直接 require 模塊的名字即可,無需加 ./../

5.4 模塊導入流程

require 導入自定義模塊的基本流程:

  1. 將相對路徑轉為絕對路徑,定位目標文件
  2. 緩存檢測
  3. 讀取目標文件代碼
  4. 包裹為一個函數並執行(自執行函數),通過 arguments.callee.toString() 查看自執行函數
  5. 緩存模塊的值
  6. 返回 module.exports 的值

代碼示例:

/**
 * require 導入原理 偽代碼
 */

// 1.引入模塊
const path = require('path')
const fs = require('fs')

// 2.定義一個緩存數組
let caches = []

function require(file) {
    // 3.將相對路徑轉成絕對路徑
    let absolutePath = path.resolve(__dirname, file)
    
    // 4.檢測是否有緩存
    if (caches[absolutePath]) {
        return caches[absolutePath]
    }

    // 5.讀取文件的代碼
    let code = fs.readFileSync(absolutePath).toString()
    // 6.封裝一個函數
    let module = {}
    let exports = module.exports = {}

    (function (exports, require, module, __fileName, __dirname) {
        const test = {
            name: 'hello world'
        }
        module.exports = test

        console.log(arguments.callee.toString())
    })(exports, require, module, __filename, __dirname)

    // 7.緩存結果
    caches[absolutePath] = module.exports

    // 7.返回 module.exports 的值
    return module.exports
}

6. 包管理工具

6.1 基礎概念

包:英文單詞是 package,代表了一組特定功能的源碼集合
包管理工具:管理的應用軟體,可以對進行下載安裝、更新、刪除、上傳等操作。藉助包管理工具,可以快速開發項目,提升開發效率。包管理工具是一個通用的概念,很多編程語言都有包管理工具,所以 掌握好包管理工具非常重要

常用的包管理工具:

  • npm
  • cnpm
  • yarn
  • pnpm

6.2 npm

npm 全稱 Node Package Manager,翻譯為中文意思是Node 的包管理工具

npmNode.js 官方內置的包管理工具,是必須要掌握住的工具

常見使用命令:

命令 說明
npm -v 查看版本號
npm init 命令的作用是將文件夾初始化為一個包, 互動式創建 package.json 文件
npm s/search 搜索包
npm install
npm i
下載安裝包
npm i -g 全局安裝
npm i <包名@版本號> 安裝指定版本的包
npm remove
npm r
局部刪除依賴
npm remove -g 全局刪除依賴

6.2.1 初始化

創建一個空目錄,然後以此目錄作為工作目錄啟動命令行工具,執行 npm init.
npm init 命令的作用是將文件夾初始化為一個,互動式創建 package.json 文件。
package.json 文件是包的配置文件,每個包都必須要有, package.json 文件內容:

{
    "name": "1-npm", #包的名字
    "version": "1.0.0", #包的版本
    "description": "", #包的描述
    "main": "index.js", #包的入口文件
    "scripts": { #腳本配置
    "test": "echo \"Error: no test specified\" && exit 1"
    },
    "author": "", #作者
    "license": "ISC" #開源證書
}

初始化的過程中還有一些註意事項:

  • name ( 包名 ) 不能使用中文、大寫,預設值是文件夾的名稱 ,所以文件夾名稱也不能使用中文和大寫
  • version ( 版本號 )要求 x.x.x 的形式定義, x 必須是數字,預設值是 1.0.0
  • ISC 證書與 MIT 證書功能上是相同的,關於開源證書擴展閱讀 http://www.ruanyifeng.com/blog/2011/05/how_to_choose_free_software_licenses.html
  • package.json 可以手動創建與修改
  • 使用 npm init -y 或者 npm init --yes 極速創建 package.json

6.2.2 包管理

通過 npm installnpm i 命令安裝包

npm install uniq
npm i uniq

運行之後文件夾下會增加兩個資源

  • node_modules 文件夾存放下載的包,node_modules 文件夾大多數情況都不會存入版本庫(gitsvn 等)
  • package-lock.json 包的鎖文件,用來鎖定包的版本

可以使用 require 導入 npm

// 導入 uniq 包
const uniq = require('uniq')

require 導入的基本流程:

  • 在當前文件夾下 node_modules 中尋找同名的文件夾
  • 在上級目錄中下的 node_modules 中尋找同名的文件夾,直至找到磁碟根目錄

安裝的包,也稱為依賴依賴生產依賴開發依賴,二者的使用如下:

類型 命令 說明
生產依賴 npm i -S uniq
npm i --save uniq
-S 等效於 --save,-S 是預設選項
包信息保存在 package.jsondependencies 屬性
開發依賴 npm i -D less
npm i --save-dev less
-D 等效於 --save-dev
包信息保存在 package.jsondevDependencies 屬性

項目中可能會遇到版本不匹配的情況,有時就需要安裝指定版本的包,可以使用下麵的命令

npm i [email protected]

可以執行安裝選項 -g 進行全局安裝

npm i -g nodemon

全局安裝完成之後就可以在命令行的任何位置運行 nodemon 命令,該命令的作用是自動重啟 Node 應用程式

說明:

  • 全局安裝的命令不受工作目錄位置影響
  • 可以通過 npm root -g 可以查看全局安裝包的位置
  • 不是所有的包都適合全局安裝,只有全局類的工具才適合,可以通過查看包的官方文檔來確定

項目中可能需要刪除某些不需要的包,可以使用下麵的命令

## 局部刪除
npm remove uniq
npm r uniq
## 全局刪除
npm remove -g nodemon

6.2.3 啟動項目

可以通過配置 package.json 中的 scripts 屬性來啟動項目

{
    "scripts": {
        "server": "node server.js",
        "start": "node index.js",
    },
}

配置完成之後,執行命令啟動項目

npm run server
npm run start

不過 start 比較特別,使用時可以省略 run

npm start

npm run 有自動向上級目錄查找的特性,跟 require 函數一樣

6.3 cnpm

cnpm 是一個淘寶構建的 npmjs.com 的完整鏡像,也稱為淘寶鏡像,網址:https://npmmirror.com/。
cnpm 服務部署在國內阿裡雲伺服器上,可以提高包的下載速度。官方也提供了一個全局工具包 cnpm,操作命令與 npm 大體相同。

可以通過 npm 來安裝 cnpm 工具:

npm install -g cnpm --registry=https://registry.npmmirror.com

常用操作命令:

命令 說明
cnpm init / cnpm init 初始化
cnpm i uniq
cnpm i -S uniq
cnpm i -D uniq
cnpm i -g nodemon
安裝包
cnpm i 安裝項目依賴
cnpm r uniq 刪除

npm 也可以使用淘寶鏡像,配置的方式有兩種:

  • 直接配置
  • 工具配置

執行如下命令即可完成配置:

npm config set registry https://registry.npmmirror.com/

使用 nrm 配置 npm 的鏡像地址 npm registry manager

  1. 安裝 nrm
    npm i -g nrm
    
  2. 修改鏡像
     nrm use taobao
    
  3. 檢查是否配置成功(選做)
    npm config list
    
    檢查 registry 地址是否為 https://registry.npmmirror.com/, 如果是則表明成功

補充說明:

  • 建議使用第二種方式進行鏡像配置,因為後續修改起來會比較方便
  • 雖然 cnpm 可以提高速度,但是 npm 也可以通過淘寶鏡像進行加速,所以 npm 的使用率還是高於 cnpm

6.4 yarn

yarn 是由 Facebook 在 2016 年推出的新的 Javascript 包管理工具,官方網址:https://yarnpkg.com/

yarn 特點:

  • 速度超快:yarn 緩存了每個下載過的包,所以再次使用時無需重覆下載。同時利用並行下載以最大化資源利用率,因此安裝速度更快。
  • 超級安全:在執行代碼之前,yarn 會通過演算法校驗每個安裝包的完整性
  • 超級可靠:使用詳細、簡潔的鎖文件格式和明確的安裝演算法,yarn 能夠保證在不同系統上無差異的工作

可以使用 npm 安裝 yarn

npm i -g yarn

yarn 常用命令:

命令 說明
yarn init / yarn init -y 初始化
yarn add uniq 生產依賴
yarn add less --dev 開發依賴
yarn global add nodemon 全局安裝
安裝包
yarn remove uniq 刪除項目依賴包
yarn global remove nodemon 全局刪除包
刪除包
yarn/yarn install 安裝項目依賴
yarn <別名> # 不需要添加 run 運行命令別名

可以通過如下命令配置淘寶鏡像

yarn config set registry https://registry.npmmirror.com/

查看 yarn 的配置項

yarn config list

npmyarn 選擇:

  • 個人項目:如果是個人項目, 哪個工具都可以 ,可以根據自己的喜好來選擇
  • 公司項目:如果是公司要根據項目代碼來選擇,可以 通過鎖文件判斷項目的包管理工具
    • npm 的鎖文件為 package-lock.json
    • yarn 的鎖文件為 yarn.lock

切記:包管理工具不要混著用

6.5 管理髮布包

可以將自己開發的工具包發佈到 npm 服務上,方便自己和其他開發者使用,操作步驟如下:

  1. 創建文件夾,並創建文件 index.js, 在文件中聲明函數,使用 module.exports 暴露
  2. npm 初始化工具包,package.json 填寫包的信息 (包的名字是唯一的)
  3. 註冊賬號:https://www.npmjs.com/signup
  4. 激活賬號(一定要激活賬號)
  5. 修改為官方的官方鏡像(命令行中運行 nrm use npm)
  6. 命令行下 npm login 填寫相關用戶信息
  7. 命令行下 npm publish
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 一、你看得懂權威的解釋嗎? 1. CSS 規範中對 BFC 的描述 CSS 規範(英文) | 中文翻譯 浮動,絕對定位的元素,非塊盒的塊容器(例如inline-blocks,table-cells和table-captions),以及’o ...
  • 無論你的夢想有多麼高遠,記住,一切皆有可能。 我們從前面的學習知道一個 React 組件不僅僅只包含 DOM 結構的,還應該樣式和 Javascript 邏輯的。這裡我們學習下如何構建 CSS 樣式。 1. 邏輯表示 JSX 中使用大括弧語法來包裹 JS 表達式(簡單邏輯代碼)。例如: { 1 + ...
  • 最近公司項目有個掃碼打開訂單付款的功能大概是這樣的(uniapp 項目) 微信支付暫且不說網上教程也很豐富 重點講講支付寶(吐槽下支付寶小程式審核,真是太慢了,一天只能審核大概3-4次 每次審核要耗時 好幾個小時) 基本開發思路是這樣的(vue/uni-app): 1.打開頁面前獲取傳入參數(onl ...
  • 前兩期講了小程式開發的準備工作以及前期需要如何調試,今天我們就來介紹下開發一個支付寶小程式頁面需要瞭解哪些信息。 一個小程式頁面的整體功能的構成離不開頁面展示(AXML)、頁面樣式(ACSS)以及頁面邏輯(JS)這三方面,下麵本文將從這三方面具體展開。 一、AXML(組件) AXML 頁面一般用來做 ...
  • 最近在一個大屏項目遇到一個需求:用戶可以通過一個按鈕,觸發頁面部分模塊全屏。通過以下API可以實現: Element.requestFullscreen()方法用於發出非同步請求使元素進入全屏模式。 且全屏狀態變化會觸發以下事件: fullscreenchange 事件會在瀏覽器進入或退出全屏模式後立 ...
  • 1、需求 使用Vue + Element UI 實現在列表的操作欄新增一個複製按鈕,複製當前行的數據可以打開新增彈窗後亦可以跳轉到新增頁面,本文實現為跳轉到新增頁面。 2、實現 1)列表頁 index.vue <el-table> <!-- 其他列 --> <el-table-column labe ...
  • ES6中的...(展開)語法是一種可以將數組或對象展開為函數參數或數組字面量的語法。它通常用於函數調用或數組字面量的展開。 在函數調用中,...可以將一個數組展開為函數的參數列表。例如: js複製代碼 function sum(a, b, c) { return a + b + c; } const ...
  • React實現視覺差效果緩動輪播 效果如下(圖片幀率低看起來有點卡頓,看個大概就行): 分享一下思路: 1.正常引入一個輪播組件(站在巨人肩膀省時省力),去除指示點、引導箭頭等不需要的元素,有些組件支持配置,不支持就手動覆蓋CSS樣式了 2.找到組件中用於顯示展示當前圖片的類名 3.添加transf ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...