node-js備忘(二)

一. 模塊系統(tǒng)

1.模塊作用域:

即使你加載我 你也不能訪問我,
除非我想讓你訪問(exports暴露)

2. exports

exports是一個對象,通過這個對象暴露屬性

exports.add=add
或者
moudle.exports={ add:add }

引用模塊的腳本可以直接這樣用:  
var 模塊別名 require('模塊名') 模塊別名.方法

如果想直接暴露一個方法直接用 不用 模塊名.方法 的話

moudle.exports=add

因為,每一個文件模塊都有一個moudle對象,他有一個成員叫exports, 又聲明了一個exports對象讓他等于moudle.exports

var exports=moudle.exports

所以,我們用exports=add 無法暴露.只能用moudle.exports=add;

3.require

var 模塊別名 require('模塊名')

require兩個作用:1. 執(zhí)行模塊中的代碼 2.導(dǎo)出模塊中的暴露對象

4.require緩存規(guī)則

(1). 優(yōu)先加載緩存中的模塊 //如果已經(jīng)加載過的模塊又被加載,會直接從緩存中加載

(2). 判斷模塊標(biāo)識

①核心文件本質(zhì)也是文件,已經(jīng)被編譯成二進(jìn)制文件了,可以直接調(diào)用

②用戶模塊 require('路徑')

③第三方模塊

  • 不可能有第三方包和核心模塊同名

  • 調(diào)用時,先找當(dāng)前模塊目錄下的node_moudles文件夾

  • 再去找該文件夾下的package.json文件

  • 在文件中找main,main屬性就記錄了當(dāng)前模塊的入口

  • 如果找不到package.json或者main,則node會自動找該目錄下的index.js

  • 如果以上操作都不成立,則進(jìn)入上一級目錄的node_moudles文件夾尋找

  • 如果還沒有,再進(jìn)入上一級,直到根目錄,然后報錯

  • 注意,一個項目只有一個node_moudles,存放于根目錄

二.npm相關(guān)

1.npm官方網(wǎng)站

npm | build amazing things?www.npmjs.com

圖標(biāo)

我們可以再網(wǎng)站中搜索包

2. npm常用命令

①版本

npm -v

②升級

npm install --global npm

③常用命令

npm init //初始化npm 生成package.json文件 
npm init -y //快速初始化npm ,跳過向?qū)?
npm install 包名 //下載包 
npm i 包名 //同上 
npm install 包名 --save //下載包,并記錄在package.json文件中 
npm i 包名 -S  //同上 
npm install //一次性將記錄在package.json文件中的包全部下載下來 
npm i  //同上 
npm uninstall 包名 //卸載包 
npm un 包名 //同上 
npm uninstall  包名 --save //卸載包,同時撤銷在package.json文件中的記錄 
npm un 包名 -S  //同上 
npm --help //幫助

3、npm被墻問題

淘寶 NPM 鏡像?npm.taobao.org

npm install --global cnpm

然后把之前的指令中的npm改為cnpm即可

4、描述文件

建議每一個項目要有一個 package.json文件(包描述文件)

我們想弄清楚項目的依賴包情況,可以訪問這個package.json文件

這個文件可以用以下命令自動創(chuàng)建:

npm init

這是一個詢問式的命令,會詢問你一些項目基本信息,按需填寫就可以

此時已經(jīng)生成了package.json

然后

npm install 包名 --save

//備注:npm 5.x以后不寫save也可以自動保存了

此時json文件會記錄下我們安裝的包

如果node_moudles被刪除了,我們可以直接執(zhí)行以下命令一口氣裝好

npm install //此命令會重新下載package.json中的dependencies中的包

三、express模塊初步使用

原生的http表現(xiàn)不足,需要使用框架加快效率,也讓代碼高度統(tǒng)一

Express - 基于 Node.js 平臺的 web 應(yīng)用開發(fā)框架?www.expressjs.com.cn

1、安裝方式

npm install express --save

2、hello world

var express =  require('express')  var app =  express();//實例化一個服務(wù)程序  //當(dāng)服務(wù)器收到請求"/"時的邏輯 
app.get('/',  (req, res)  =>  { res.send('hhello express!你好!')  }) 
app.listen(3000,()=>{  //讓服務(wù)器程序在3000端口監(jiān)聽 
  console.log('app is listening at Port 3000');  })

我們發(fā)現(xiàn)了express的幾個好處:

①響應(yīng)不用end了 ②url不用自己解析了 ③中文不用自己轉(zhuǎn)碼了

3、基本路由

get:

app.get('/',  (req, res)  =>  { res.send('hello express!你好!')  })

post

app.post('/',(req,res)=>{ res.send(req);  })

注:

  • 比如一個ajax請求要求發(fā)json, express提供一個方法 res.json(對象) 它會自動將對象轉(zhuǎn)為JSON對應(yīng)的字符串發(fā)送給瀏覽器

  • 如果將來安裝了art-template,可以用 res.render('頁面',模板規(guī)則對象)來發(fā)送頁面

4、靜態(tài)服務(wù) //指定公開目錄

app.use('/public/',express.static('./public/'))

這樣就公開了public中的所有資源,可以訪問了

image

此外,我們可以省略第一個參數(shù),這時url也省略對應(yīng)的層

app.use(express.static('./public/'))
image

其實,我們可以給文件路徑起url別名,例如:app.use('/a/',express.static('./public/')),

上面這種做法其實是起別名的一種特殊情況

5、解析get請求中的數(shù)據(jù)

req.query //會直接返回一個對象

例如:我們的get請求如下:

http://127.0.0.1:3000/commit?name=zhangsan&age=30&sex=male

app.get('/commit',(req,res)=>{ console.log(req.query);  })
image

6、在express中配置使用art-template模板引擎

(1).安裝art-template

cnpm i  art-template -S cnpm i express-art-template -S

(2).使用

①、指定后綴名的文件用art-template渲染:

app.engine('html',  require('express-art-template'))

當(dāng)渲染以.html結(jié)尾的文件時,使用art-template模板引擎

express-art-template是用來把a(bǔ)rt-template整合在Express中的

雖然不需要加載art-template但它是express-art-template的依賴,所以必須安裝

②、使用respone.render(views目錄下文件,渲染參數(shù))來進(jìn)行渲染

express有一個約定,希望開發(fā)人員把頁面文件都放在views目錄及其子目錄下,

同時,express為responce提供了對應(yīng)的render方法,此方法默認(rèn)不可用,當(dāng)配置了模板引擎時,可用!第一個參數(shù)不能寫路徑(但可以寫views的子目錄),默認(rèn)會去views路徑下查找模板

var express = require('express')
var app = express();//實例化一個服務(wù)程序

app.engine('html', require('express-art-template'))
//當(dāng)渲染以.html結(jié)尾的文件時,使用art-template模板引擎
//express-art-template是用來把a(bǔ)rt-template整合在Express中的
//雖然不需要加載art-template但它是express-art-template的依賴
//所以必須安裝

app.get('/', (req, res) => {
    res.render('index.html', {
        name: 'lili',
        age: 18,
        sex: 'girl'
    })
    //express為responce提供了對應(yīng)的render方法,此方法默認(rèn)不可用
    //當(dāng)配置了模板引擎時,可用. 
    //express有一個約定,希望開發(fā)人員把頁面文件都放在views目錄及其子目錄下
    //第一個參數(shù)不能寫路徑(但可以寫views的子目錄),默認(rèn)會去views路徑下查找模板
})
app.get('/admin', (req, res) => {
    res.render('admin/adminIndex.html', {//render里可以寫views的子目錄
        admin: '莉莉'
    })
})

app.listen(3000, () => { //讓服務(wù)器程序在3000端口監(jiān)聽
    console.log('app is listening at Port 3000');
})
image
image

③、如果想修改目錄(一般不需要)則:

app.set('views','新的路徑')

7. 重定向

res.redirect('/')

8、解析POST請求中的數(shù)據(jù)

需要借用一個插件 body-parser

(1)安裝

cnpm install body-parser --save

(2)引包

var bodyParser =  require('body-parser');

(3)配置

配置 body-parser后,會在req對象上增加一個屬性叫body

app.use(bodyParser.json());  // for parsing application/json 
app.use(bodyParser.urlencoded({ extended:  true  }));  

(4) 此時,res.body就可以用了

var express = require('express')
var app = express();//實例化一個服務(wù)程序
var bodyParser = require('body-parser');

app.engine('html', require('express-art-template'))
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true }));

var user;//創(chuàng)建一個對象接收用戶信息

app.get('/', (req, res) => {
    res.render('index.html', user)
})
app.get('/admin', (req, res) => {
    res.render("admin/adminIndex.html")
})
app.post('/post', (req, res) => {  //post到/post頁面
    console.log(req.body)  //req.body可用了
    user = req.body  //把它賦給user
    res.redirect("/") //重定向到首頁
})
app.listen(3000, () => {
    console.log('app is listening at Port 3000');
})

9.設(shè)置狀態(tài)碼

res.status(500).send("讀取文件錯誤:")  //設(shè)置了狀態(tài)碼,還返回了錯誤信息

10.操作文件中的數(shù)據(jù)

express中沒有專門的文件讀寫API,所以還是使用fs.readFile()

此外注意讀取時

app.get('/', (req, res) => {
    fs.readFile('./views/db.json', 'utf8', (err, data) => {
                                    //第二個參數(shù)加'utf8'會讀出utf8字符串
        if (err) { res.status(500).send("讀取文件錯誤:" + err); };
        res.render("index.html", {
            food: ["apple", 'orange', 'banana'],
            students: JSON.parse(data).students
                      //文件讀出的是字符串,所以應(yīng)該轉(zhuǎn)換成對象,再調(diào)用屬性
        })
    })
})

11.路由模塊的提取

(1).引用與暴露

實際工作中我們應(yīng)該將工程模塊化,不應(yīng)將所有邏輯卸載一個app.js中,這就涉及了文件的引用與參數(shù)的暴露問題

我們常用的方法是:

在app.js中 require 一個模塊 ,在模塊中又要引用app對象,所以我們在模塊中封裝一個函數(shù)并暴露,這個函數(shù)有一個形參app

app.js引入后調(diào)用時,把自己的app對象傳遞給這個函數(shù)

舉例如下:

在app.js中

var express = require('express')
var router=require('./router')

var app = express()
var port = 3000
app.engine('html', require('express-art-template'))

app.use('/public/', express.static('./public/'))
app.use('/node_modules/', express.static('./node_modules/'))


router(app)//調(diào)用router函數(shù),同時把a(bǔ)pp對象傳給他
app.listen(port, () => console.log(`app listening on port` + port))

在router.js中

var fs = require('fs')
module.exports = (app) => {  //封裝一個函數(shù)并暴露,需要形參app
    app.get('/', (req, res) => {
        fs.readFile('./views/db.json', 'utf8', (err, data) => {
            if (err) { res.status(500).send("讀取文件錯誤:" + err); };
            res.render("index.html", {
                food: ["apple", 'orange', 'banana'],
                students: JSON.parse(data).students
            })
        })
    })
}

但是,express提供了更好的方法:

(2) express路由模塊

①.引用express,實例化其中的Router路由容器對象

var express =require('express')  //1.創(chuàng)建一個路由容器  var router=express.Router()

②.把請求都掛載在router這個對象中

③.把router這個對象導(dǎo)出

④app.js引入這個模塊,同時獲得router這個對象

⑤app對象使用use方法使用router這個對象

例子:

router.js

var fs = require('fs')
var express = require('express')
//1.創(chuàng)建一個路由容器
var router = express.Router()
//2.把請求都掛在router中
router.get('/', (req, res) => {
    fs.readFile('./views/db.json', 'utf8', (err, data) => {
        if (err) { res.status(500).send("讀取文件錯誤:" + err); };
        res.render("index.html", {
            food: ["apple", 'orange', 'banana'],
            students: JSON.parse(data).students
        })
    })
})
//3.把router導(dǎo)出
module.exports = router

app.js中

var express = require('express')
var router=require('./router')  //4.app引用router

var app = express()
var port = 3000
app.engine('html', require('express-art-template'))

app.use('/public/', express.static('./public/'))
app.use('/node_modules/', express.static('./node_modules/'))
app.use(router)  //5. app使用router
app.listen(port, () => console.log(`app listening on port` + port))

13.封裝異步回調(diào)函數(shù)

如果獲取一個函數(shù)中異步操作的結(jié)果,則必須通過回調(diào)函數(shù)來獲取

先看一個錯誤的代碼: 由于return不會等待fs.readFile的執(zhí)行結(jié)果,所以obj=undefined

exports.findAll=function findAll() {
    var obj
    fs.readFile(dbPath, 'utf8', (err, data) => {
        obj=JSON.parse(data).students
    })
    return obj
}  //錯!!!!!由于異步,這種函數(shù)是無法正確返回返回值的!!!!!!

要得到返回值,則應(yīng)采用回調(diào)的方式

exports.findAll = (callback) => {  
    //如果有人想調(diào)用findAll,則必須傳入一個回調(diào)函數(shù)
    fs.readFile(dbPath, 'utf8', (err, data) => {
        //這個回調(diào)函數(shù)要有err,data兩個形參
        if(err){//如果readFile失敗了 這個err是readFile的
            callback(err)//則callback會傳遞err給回調(diào)函數(shù)
        }else{
            callback(null,JSON.parse(data).students)
            //否則callback會傳遞data給回調(diào)函數(shù) 這個data是readFile的
        }
    })
}

如果有人想調(diào)用findAll

router.get('/students', (req, res) => {
    students.findAll((err, students) => { //調(diào)用findAll,必須傳入一個回調(diào)函數(shù)
        if(err) return res.status.send("讀取文件錯誤"+err) 
         //如果callback傳出的err不是null,則報錯
        res.render("index.html",{
            food:['apple','orange'],
            students:students  //接收到callback傳遞的students(data)
        })
    })

這種方式與其說是把數(shù)據(jù)傳出來處理,不如說是使用者把邏輯傳入了封裝好的函數(shù)中處理邏輯

關(guān)鍵是轉(zhuǎn)變?yōu)?上層定義下層調(diào)用的思路 具體應(yīng)用詳見綜合練習(xí).

14.JSON處理

(1)將字符串轉(zhuǎn)換為JSON對象

students =  JSON.parse(data)

(2)將JSON對象轉(zhuǎn)換為字符串

str=  JSON.stringify(students )  //我們還可以順便調(diào)整字符串內(nèi)容 str =  JSON.stringify({ students: students })

15.如何自己編寫服務(wù)器渲染及數(shù)據(jù)處理的后端app

  • 處理模板
  • 配置開放靜態(tài)資源
  • 配置模板引擎
  • 簡單路由表設(shè)計
  • 路由設(shè)計
  • 提取路由模塊
  • 由于我們需要操作文件或數(shù)據(jù)庫,所以要封裝一個.js專門處理他們
  • 實現(xiàn)具體功能

16.小技巧

(1)如何快速找到一個不錯的HTML頁面?

建議去bootstrap看看

起步 · Bootstrap v3 中文文檔?v3.bootcss.com

Examples?v4.bootcss.com
圖標(biāo)

全局 CSS 樣式 · Bootstrap v3 中文文檔?v3.bootcss.com

17. express如何處理404頁面??

需要使用中間件

app.use(function(req,res){})

18.綜合練習(xí)

此練習(xí)為一個迷你學(xué)生信息管理系統(tǒng)

image

https://github.com/zfdok/node_stu_mgr?github.com

運(yùn)行時先執(zhí)行 npm install 重裝一下依賴庫

再用 nodemon app 啟動服務(wù)

輸入 127.0.0.1/3000訪問首頁

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容