node.js從入門到實(shí)踐

node.js

node.js是前端最流行的javascript運(yùn)行環(huán)境

  • node.js 是一個(gè)基于 chrome v8 引擎的 javascript 運(yùn)行環(huán)境
  • node.js 使用了一個(gè)事件驅(qū)動(dòng)、非阻塞式 I/O 模型,使其輕量又高效
  • node.js 的管理包 npm 是全球最大的開源庫生態(tài)系統(tǒng)

node-v8引擎

javascript 引擎

  • 電腦根本不識別也不理解javascript
  • javascript 引擎起到的作用就是讓電腦識別js代碼

V8引擎

  • node.js是使用c++寫的
  • V8引擎是Node.js的核心
  • V8引擎的作用是讓JS代碼能夠讓電腦識別

Module & Require

  • 在node.js中,文件和模塊是一一對應(yīng)的(每個(gè)文件被視為一個(gè)獨(dú)立的模塊)
//app.js文件引入stuff模塊并應(yīng)用
//requrie
let stuff = require('./stuff')
console.log(stuff.counter([1,2,3,4]));
console.log(stuff.adder(1,2));
console.log(stuff.pi);
//stuff模塊
var counter = function (arr) {
    return '一共有' + arr.length + '個(gè)元素在數(shù)組中';
}


var adder = function (a,b) {
    return `您需要計(jì)算的兩個(gè)值的和為:${a+b}`
}

var pi = 3.1415926;
//module
// module.exports.counter = counter;
// module.exports.adder = adder;
// module.exports.pi = pi;

module.exports = {
    counter: counter,
    adder: adder,
    pi: pi
}

事件模塊

  • 大多數(shù)node.js核心API都是采用慣用的異步事件驅(qū)動(dòng)架構(gòu)(fs/http)
  • 所有能觸發(fā)事件的對象都是EventEmitter類的實(shí)例
  • 事件流程:引入模塊 -> 創(chuàng)建 EventEmitter 對象 -> 注冊事件 -> 觸發(fā)事件
//事件模塊
//1.引入事件模塊
var events = require('events');//引入系統(tǒng)模塊,不要給定義的路徑,直接給名字就可以了
//2.創(chuàng)建EventEmitter對象
var myEmitter = new events.EventEmitter();
//3.注冊事件
myEmitter.on('someEvent',function (msg) {
    console.log(msg);
})
//4.觸發(fā)事件
myEmitter.emit('someEvent','實(shí)現(xiàn)事件并傳遞此參數(shù)到注冊事件的回調(diào)函數(shù)中')//事件名,參數(shù)
console.log(1); //先執(zhí)行函數(shù)中內(nèi)容,再執(zhí)行打印1

如果想要函數(shù)異步執(zhí)行,先執(zhí)行打印1,再執(zhí)行函數(shù)中內(nèi)容的話可以這樣修改

//事件模塊
//1.引入事件模塊
var events = require('events');//引入系統(tǒng)模塊,不要給定義的路徑,直接給名字就可以了
//2.創(chuàng)建EventEmitter對象
var myEmitter = new events.EventEmitter();
//3.注冊事件
myEmitter.on('someEvent',function (msg) {
    // console.log(msg);

    //異步
    setImmediate(() => {
        console.log(msg);
    })
})
//4.觸發(fā)事件
myEmitter.emit('someEvent','實(shí)現(xiàn)事件并傳遞此參數(shù)到注冊事件的回調(diào)函數(shù)中')//事件名,參數(shù)
console.log(1); //先執(zhí)行函數(shù)中內(nèi)容,再執(zhí)行打印1

文件系統(tǒng)模塊

文件系統(tǒng)主要對項(xiàng)目中的文件進(jìn)行操作

  • 讀取文件(fs.readFile)
  • 寫入文件(fs.writeFile)
  • 流程:引入fs模塊 -> 調(diào)用方法 -> 異常捕獲
//文件系統(tǒng)
//1.引入文件系統(tǒng)模塊
var fs = require('fs');
//2.通過對象調(diào)用方法
//同步讀取
var readMe = fs.readFileSync('./readMe.txt','utf8');//路徑,文件格式
console.log(readMe);

//異步讀取
var readMe2 = fs.readFile('./readMe.txt','utf8',function (err,data) {//路徑,文件格式,回調(diào)函數(shù)(錯(cuò)誤信息,返回值)
    if(err) throw err;
    console.log(data);
})
console.log(1);//先打印1,再打印讀取信息

//同步寫入
fs.writeFileSync('./writeMe.txt', readMe);//文件路徑,寫入內(nèi)容

//異步寫入
fs.readFile('./readMe.txt','utf8',function (err,data) {
    if(err) throw err;
    fs.writeFile('./writeMe2.txt',data);
})
  • 創(chuàng)建文件夾(fs.mkdir)
  • 刪除文件夾(fs.rmdir)
  • 刪除文件(fs.unlink)
  • 流程:引入fs模塊 -> 調(diào)用方法 -> 異常捕獲
//文件系統(tǒng)
//1.引入文件系統(tǒng)模塊
var fs = require('fs');
//2.通過對象調(diào)用方法
// 刪除文件
fs.unlink('./writeMe.txt',function (err) {
    if(err) throw err;
    console.log('文件刪除成功!');
// });

//創(chuàng)建文件夾 同步
fs.mkdirSync('stuff');

//刪除文件夾 同步
fs.rmdirSync('stuff');

//異步創(chuàng)建文件夾
fs.mkdir('stuff',function (err) {
    if(err) throw err;
    fs.readFile('readMe.txt','utf8',function (err2,data) {
        if(err2) throw err2;
        fs.writeFile('./stuff/writeMe.txt',data,function(){});
    })
})

//異步刪除文件夾
// 1.刪除文件夾中內(nèi)容
// 2.再刪除文件夾
fs.unlink('./stuff/writeMe.txt',function () {
    fs.rmdir('stuff', function (err) {
        if (err) throw err;
        console.log('文件夾刪除成功!');
    })
})

注意事項(xiàng)

  • fs.writeFile(file, data[, options], callback)在v10.0之后回調(diào)函數(shù)為必選參數(shù),否則會(huì)報(bào)錯(cuò)。
  • fs.writeFileSync(file, data[, options])沒有回調(diào)函數(shù)

http創(chuàng)建服務(wù)器

客戶端與服務(wù)端關(guān)系

client為客戶端,好比用戶看到的瀏覽器,server為服務(wù)器。當(dāng)用戶想要訪問一個(gè)頁面時(shí),內(nèi)部流程為:瀏覽器中是輸入域名 地址www.baidu.com,該域名會(huì)綁定到某個(gè)服務(wù)器上,因?yàn)橛蛎旧硎菦]有數(shù)據(jù)展示的,綁定服務(wù)器后才會(huì)請求服務(wù)器,服務(wù)器才會(huì)返回對應(yīng)的數(shù)據(jù)展示。所以客戶端的作用就是用戶輸入一個(gè)域名地址,回車后發(fā)送網(wǎng)絡(luò)請求到綁定的服務(wù)器,服務(wù)器再返回?cái)?shù)據(jù)給客戶端。

客戶端與服務(wù)器對接的方式:

客戶端想服務(wù)器方式請求時(shí)需要對應(yīng)的ip地址或域名或服務(wù)器地址,當(dāng)瀏覽器中輸入地址回車后,通過http或https協(xié)議發(fā)送請求,請求過程中可以通過socket進(jìn)行請求,請求到server后,如果網(wǎng)絡(luò)、狀態(tài)碼等都是正常的話,就可以和server進(jìn)行對接了。對接后server發(fā)現(xiàn)你的請求,需要返回對應(yīng)的數(shù)據(jù),服務(wù)端使用tcp協(xié)議返回客戶端數(shù)據(jù)。

  • 通過Http模塊創(chuàng)建本地服務(wù)器
//通過http模塊,創(chuàng)建本地服務(wù)器
var http = require('http');

//創(chuàng)建服務(wù)器方法
var server = http.createServer(function (req,res) {
    console.log('客戶端向服務(wù)器發(fā)送請求:' + req.url);
    res.writeHead(200,{"Content-type":"text/plain"});
    res.end('Server is working!');
})

//服務(wù)對象監(jiān)聽服務(wù)器地址和端口號
server.listen(8888,"127.0.0.1");
console.log('server is running...')

Buffer & Stream

  • buffer 可以在TCP流和文件系統(tǒng)操作等場景中處理二進(jìn)制數(shù)據(jù)流。


    緩存區(qū)

buffer,即緩存區(qū)。服務(wù)器向客戶端返回?cái)?shù)據(jù)時(shí)采用的是tcp協(xié)議,在返回過程中有TCP的流,在JS中沒有二進(jìn)制流的說法,但在node.js中,為了能擁有一個(gè)緩存區(qū),使用buffer。

Buffer 類在全局作用域中,因此無需使用 require('buffer').Buffer。

在引入 TypedArray 之前,JavaScript 語言沒有用于讀取或操作二進(jìn)制數(shù)據(jù)流的機(jī)制。 Buffer 類是作為 Node.js API 的一部分引入的,用于在 TCP 流、文件系統(tǒng)操作、以及其他上下文中與八位字節(jié)流進(jìn)行交互。


  • 在node.js中是處理流數(shù)據(jù)的抽象接口


  • 管道事件 改變流的走向
    左面輸出 | 右面輸入


    管道事件
let fs = require('fs');
//讀取數(shù)據(jù)流
let myReadStram = fs.createReadStream(__dirname + '/readMe.txt','utf8');
// console.log(myReadStram);


//寫入文件流
let myWriteStram = fs.createWriteStream(__dirname + '/writeMe.txt');
//再?zèng)]有填充內(nèi)容到流中時(shí),文件夾中不會(huì)新建對應(yīng)的文件


let times = 0;
myReadStram.on('data',(chunk) => {
    times++;
    console.log('===================正在接收'+ times +'一部分?jǐn)?shù)據(jù)========================')
    // console.log(chunk);
    //寫入數(shù)據(jù)
    myWriteStram.write(chunk);
});
//data為服務(wù)器返回?cái)?shù)據(jù)必須觸發(fā)的方法,且為約定俗成的,不可改變;
//返回的數(shù)據(jù)將以回調(diào)函數(shù)返回,數(shù)據(jù)為小塊小塊的返回
//讀取數(shù)據(jù)時(shí),也會(huì)經(jīng)過緩存區(qū),放到緩存區(qū)后再以流的形式展現(xiàn)給我們
let fs = require('fs');
//讀取數(shù)據(jù)流
let myReadStram = fs.createReadStream(__dirname + '/readMe.txt','utf8');
// console.log(myReadStram);


//寫入文件流
let myWriteStram = fs.createWriteStream(__dirname + '/writeMe2.txt');
//再?zèng)]有填充內(nèi)容到流中時(shí),文件夾中不會(huì)新建對應(yīng)的文件

//pipe通過管道流入到可寫流的來源流。
myReadStram.pipe(myWriteStram);//拿到的數(shù)據(jù)調(diào)用了,參數(shù)為輸入數(shù)據(jù)目的地
//通過pipe寫入瀏覽器
let http = require('http');
let fs = require('fs');


//搭建服務(wù)器
let server = http.createServer((req,res) => {
    console.log(req);
    res.writeHead(200,{"Content-type":"text/plain"});
    let myReadStram = fs.createReadStream(__dirname + '/readMe.txt','utf8');
    myReadStram.pipe(res);
})

server.listen(9999,'127.0.0.1');
console.log('服務(wù)啟動(dòng)!');

讀取HTML和JSON

let http = require('http');
let fs = require('fs');


//搭建服務(wù)器
let server = http.createServer((req,res) => {
    //console.log('客戶端向服務(wù)器發(fā)送請求:' + req.url);
    //客戶端向服務(wù)器發(fā)送請求:/               請求127.0.0.1:9999接口
    //客戶端向服務(wù)器發(fā)送請求:/favicon.ico         請求標(biāo)簽欄的logo

    if(req.url !== '/favicon.ico'){
        console.log('客戶端向服務(wù)器發(fā)送請求:' + req.url);
        //打印一遍
        //客戶端向服務(wù)器發(fā)送請求:/               請求127.0.0.1:9999接口

        // res.writeHead(200,{"Content-type":"text/plain"});//數(shù)據(jù)類型:純文本
        res.writeHead(200,{"Content-type":"text/html"});//數(shù)據(jù)類型:html
        // res.writeHead(200,{"Content-type":"application/json"});//數(shù)據(jù)類型:json


        // let myReadStram = fs.createReadStream(__dirname + '/readMe.txt','utf8');
        let myReadStram = fs.createReadStream(__dirname + '/index.html','utf8');
        // let myReadStram = fs.createReadStream(__dirname + '/perrson.json','utf8');

        myReadStram.pipe(res);
    }
})

server.listen(9999,'127.0.0.1');
console.log('服務(wù)啟動(dòng)!');

route 路由

路由既是“路在何方”

let http = require('http');
let fs = require('fs');


//搭建服務(wù)器
let server = http.createServer((req,res) => {
    if(req.url !== '/favicon.ico'){
        //判斷用戶所訪問的頁面地址
        if(req.url == '/home' || req.url == '/'){
            res.writeHead(200,{"Content-type":"text/html"});//數(shù)據(jù)類型:html
            fs.createReadStream(__dirname + '/index.html').pipe(res);
        }else if(req.url == '/contact'){
            res.writeHead(200,{"Content-type":"text/html"});//數(shù)據(jù)類型:html
            fs.createReadStream(__dirname + '/contact.html').pipe(res);
        }else if(req.url == '/api/docs'){
            // res.writeHead(200,{"Content-type":"text/html"});//數(shù)據(jù)類型:html
            // fs.createReadStream(__dirname + '/api/docs.html').pipe(res);

            var data = [
                {
                    name:'andy',
                    age:30
                },
                {
                    name:'qiongqiong',
                    age:16
                },
            ]
            res.writeHead(200,{"Content-type":"application/json"});//數(shù)據(jù)類型:json
            res.end(JSON.stringify(data));
        }
    }
})

server.listen(9999,'127.0.0.1');
console.log('服務(wù)啟動(dòng)!');

NPM_Package

  • npm : 是隨同NodeJs一起安裝的管理工具,能解決NodeJs 代碼部署上的很多問題

常用的使用場景:

  • 允許用戶從NPM服務(wù)器下載別人編寫的第三方包到本地使用
  • 允許用戶從NPM服務(wù)下載并安裝別人編寫的命令行程序到本地使用
  • 允許用戶將自己編寫的包或命令行程序上傳到NPM服務(wù)器供別人使用

安裝模塊:$ npm install 模塊名

  • package : 用于定義項(xiàng)目中所需的各種模塊,以及項(xiàng)目的配置信息(比如名稱,版本,許可證等元數(shù)據(jù))
    安裝package :在項(xiàng)目文件夾中npm init運(yùn)行,再根據(jù)自己的需求進(jìn)行配置即可。

只有當(dāng)項(xiàng)目文件夾中有package.json文件時(shí)才 可以使用npm install來安裝模塊依賴,安裝的依賴會(huì)保存在node_modules文件夾中

卸載模塊:npm uninstall 模塊名

{
  "name": "nodedemo",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "jquery": "^3.4.0"http://npm install XXX --save  保存記錄
  },
  "devDependencies": {
    "express": "^4.16.4" //npm install XXX --save-dev  保存記錄
  }
}

Experss 框架介紹及安裝

基于Node.js平臺,快速、開發(fā)、極簡的web開發(fā)框架。

  • 安裝 npm install express --save

nodemon工具

在開發(fā)環(huán)境下,往往需要一個(gè)工具來自動(dòng)重啟項(xiàng)目工程,我們可以借助nodemon來替代node進(jìn)行啟動(dòng)

  • 安裝npm install -g nodemon --save-dev
  • 運(yùn)行 使用命令nodemon 文件名
    運(yùn)行成功

Experss 框架

Experss 能做什么

  • 已經(jīng)封裝好服務(wù)器
  • 已經(jīng)封裝好路由
  • 已經(jīng)封裝好中間件
  • 已經(jīng)封裝好網(wǎng)絡(luò)請求...

使用方法:

  1. npm 安裝 Express 框架
  2. 引入 Express 模塊
  3. 實(shí)例化 Express 對象
  4. 通過對象進(jìn)行調(diào)用各種方法
//引入express模塊
var express = require('express');

//實(shí)例化express的對象
var app = express();

//通過對象調(diào)用對應(yīng)的方法

//根據(jù)用戶請求的地址,返回對應(yīng)的數(shù)據(jù)信息
app.get('/',function (req,res) {
    console.log(req.url)
    res.send('這是首頁!')
})

app.get('/contact',function (req,res) {
    console.log(req.url)
    res.send('這是聯(lián)系我們!')
})

//路由參數(shù)
//路由參數(shù)之后只能有一個(gè)斜杠
//例:http://127.0.0.1:8888/profile/list1201   ,返回的就是list1201;而http://127.0.0.1:8888/profile/list1201/ss 就顯示‘Cannot GET /profile/list1201/ss’
app.get('/profile/:id',function (req,res) {
    res.send('您所訪問的路徑參數(shù)為'+ req.params.id);
})

//監(jiān)聽服務(wù)器端口號
app.listen(8888);

EJS模板引擎

ESJ模板引擎的特點(diǎn)

  1. 快速編譯和渲染
  2. 簡單的模板標(biāo)簽
  3. 支持瀏覽器端和服務(wù)器端
  4. 支持express視圖系統(tǒng)

安裝
npm install ejs --save-dev

//引入 express 模塊
var express = require('express');
//實(shí)例化 Express 對象
var app = express();
app.set('view engine','ejs');  //配置視圖引擎使用ejs
//通過對象調(diào)用方法
//路由參數(shù)
 app.get('/profile/:id',function (req,res) {
   //   res.send('你所訪問的路徑為:'+ req.params.id);//返回路由參數(shù)
   res.sendFile(__dirname + '/views/profile.ejs');//不配置視圖引擎時(shí),訪問頁面,會(huì)將對應(yīng)的文件下載下來
   res.render('profile',{name:'LALALA'});//渲染ejs頁面   參一:渲染對應(yīng)的文件  參二:傳遞的數(shù)據(jù) 在對應(yīng)的文件中使用 ‘<h1>歡迎來到 <%=name %> 網(wǎng)頁!</h1>來接收’
  })
//監(jiān)聽服務(wù)器端口號
app.listen(8888);
//引入 express 模塊
var express = require('express');
//實(shí)例化 Express 對象
var app = express();
app.set('view engine','ejs');  //配置視圖引擎使用ejs
//通過對象調(diào)用方法

//根據(jù)用戶請求地址,返回對應(yīng)的數(shù)據(jù)信息
app.get('/',function (req,res) { //當(dāng)訪問根路徑時(shí),返回‘這是首頁!’
    console.log(req.url);//打印路徑
    res.sendFile(__dirname + '/index.html');//返回對應(yīng)的html文件
 })

 app.get('/contact',function(req,res){
    res.sendFile(__dirname + '/contact.html');
 })

 //路由參數(shù)
 app.get('/profile/:id',function (req,res) {
   // let data = {age:23,name:'andy'};
   // let data = [{age:23,name:'andy'},{age:26,name:'kitty'},{age:24,name:'jack'}];
   let data = [{age:23,name:['張三','李四']},{age:26,name:['王五','趙六']},{age:24,name:['傻大個(gè)','胖子']}];
   res.render('profile',{websiteName:req.params.id,data:data})
  })

//監(jiān)聽服務(wù)器端口號
app.listen(8888);

以上代碼data分別對應(yīng)的渲染為

//let data = {age:23,name:'andy'};
<p><strong>年齡:</strong><%= data.age %></p>
<p><strong>姓名:</strong><%= data.name %></p>
// let data = [{age:23,name:'andy'},{age:26,name:'kitty'},{age:24,name:'jack'}];
<ul>
        <% data.forEach((item) => {%>
            <li>年齡: <%= item.age%></li>
            <li>姓名: <%= item.name%></li>
        <% })%>
    </ul>
//<%%>標(biāo)簽必須每行都需要閉合,如遇到代碼換行時(shí),必須將每行都用<% %>包裹
//let data = [{age:23,name:['張三','李四']},{age:26,name:['王五','趙六']},{age:24,name:['傻大個(gè)','胖子']}];
<ul>
<% data.forEach((item) => {%>
  <li>年齡: <%= item.age%></li>
  <li>姓名: <% item.name.forEach((item2) => { %>
        <span><%= item2%></span>
  <%}) %></li>
<% })%>
</ul>

公共模板

  • 使用EJS文件替換HTML文件
  • 創(chuàng)建導(dǎo)航(公共模板)
  • 解決外部樣式不可用問題

將html頁面全部使用ejs文件進(jìn)行開發(fā),文件結(jié)構(gòu)可以參考以下


文件結(jié)構(gòu)
  • 一般頁面視圖放在views文件夾中
  • 封裝的公共模塊放在public文件夾中
  • 靜態(tài)資源放在assers文件夾中

將封裝好的公共模塊引入到對應(yīng)的頁面即可正常渲染

<!--引入公共導(dǎo)航模板-->
<% include ../public/nav.ejs%>

在頁面中引入外部樣式時(shí),需要先在app.js中進(jìn)行配置,方可引用

//app.js
//讓服務(wù)器識別外部樣式表
app.use('/assets',express.static('assets'));
//參一:路徑  參二:該路徑文件做什么事
//此時(shí)的參二表示:在項(xiàng)目中,讓css靜態(tài)文件轉(zhuǎn)化為模塊化,讓服務(wù)器進(jìn)行識別。否則加載樣式表會(huì)報(bào)錯(cuò)
//各文件中正常引用
<link rel="stylesheet" href="../assets/style.css">

實(shí)戰(zhàn)操作 ToDoApp

啟動(dòng)新項(xiàng)目
初始化webpack
安裝express框架
安裝esj body-parser 模塊

  1. 新建項(xiàng)目文件夾TodoApp,并在該文件夾中安裝 package npm init
  2. 安裝express 框架 npm install express --save-dev
  3. 安裝 ejs 和 body-parser 模塊 npm install ejs body-parser --save-dev
  4. 在項(xiàng)目文件夾中創(chuàng)建主文件的入口app.js
  5. 新建controller文件夾并添加todoController.js文件來處理項(xiàng)目中對應(yīng)的邏輯
  6. 新建public文件夾來寫入對應(yīng)的樣式
//app.js
let express = require('express');//引入express

let todoController = require('./controller/todoController')//自定義模塊todoController
let app = express();//實(shí)例化express對象
app.set('view engine','ejs');//配置視圖渲染規(guī)則按照ejs渲染

// app.use('/public',express.static('public'))
//等同于
app.use(express.static('./public'))//配置靜態(tài)資源模塊化,讓瀏覽器識別

todoController(app)

app.listen(3000)//監(jiān)聽端口號
//todoController.js
module.exports = function (app) {
    //獲取數(shù)據(jù)
    app.get('/todo', (req,res) => {
        res.send(req.url);
     })

     //傳遞數(shù)據(jù)
     app.post('/todo',(req,res) => {
        //coding...
     })

     //刪除數(shù)據(jù)
     app.delete('/todo',(req,res) => {
         //coding
     })
 }

引入jquery
設(shè)置視圖
設(shè)置請求頁面返回視圖
設(shè)置視圖樣式

  1. 在項(xiàng)目文件夾中新建views文件夾并添加todo.ejs文件并完成靜態(tài)頁面布局
  2. 將todoController.js文件修改,設(shè)置請求頁面返回視圖
//獲取數(shù)據(jù)
  app.get('/todo', (req,res) => {
        res.render('todo');
     })

在控制器中處理本地?cái)?shù)據(jù)
在視圖上將數(shù)據(jù)展示出來
最終的代碼以及樣式展示

//todoController.js

let bodyParser = require('body-parser');
//對數(shù)據(jù)進(jìn)行解析
let urlencodeParser =  bodyParser.urlencoded({extended:false});

let data = [
    {item:'歡迎大家來到煢煢課堂練習(xí)!'},
    {item:'希望大家能喜歡我的練習(xí)!'},
    {item:'一個(gè)個(gè)手敲代碼好累哦!'},
]

//todoController
module.exports = function (app) {
    //獲取數(shù)據(jù)
    app.get('/todo', (req,res) => {
        res.render('todo',{todos:data});
     })

     //傳遞數(shù)據(jù)
     app.post('/todo',urlencodeParser,(req,res) => {
        //coding...
        console.log(req.body);
        data.push(req.body);
     })

     //刪除數(shù)據(jù)
     app.delete('/todo/:item',(req,res) => {
         //coding
         console.log(req.params.item);
         data = data.filter(function (todo) {
            return req.params.item != todo.item;
          })

          res.json(data);
     })
 }
//todo.ejs
<!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>todoApp</title>
    <link rel="stylesheet" href="assets/reset.min.css">
    <link rel="stylesheet" href="assets/style.css">
    <!--引入jquery-->
    <script src="https://cdn.bootcss.com/jquery/3.4.0/jquery.min.js"></script>
</head>
<body>
    <header>
        <form>
            <input type="text" placeholder="Enter an activity..." name="item" id="item">
            <button type="submit" id="add">
                <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve"><g><path class="fill" d="M16,8c0,0.5-0.5,1-1,1H9v6c0,0.5-0.5,1-1,1s-1-0.5-1-1V9H1C0.5,9,0,8.5,0,8s0.5-1,1-1h6V1c0-0.5,0.5-1,1-1s1,0.5,1,1v6h6C15.5,7,16,7.5,16,8z"/></g></svg>
            </button>
        </form>
    </header>

    <div class="container">
        <!--未完成列表-->
        <ul class="todo" id="todo">
            <!--動(dòng)態(tài)添加數(shù)據(jù)-->
            <% todos.forEach((val,ind) => {%>
                <li>
                    <%= val.item%>
                    <div class="buttons">
                        <button class="remove">
                            <svg t="1556521793477" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2483" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path class="fill" d="M412 744c-19.8 0-36-16.2-36-36V500c0-19.8 16.2-36 36-36s36 16.2 36 36v208c0 19.8-16.2 36-36 36zM612 744c-19.8 0-36-16.2-36-36V500c0-19.8 16.2-36 36-36s36 16.2 36 36v208c0 19.8-16.2 36-36 36z" p-id="2484"></path><path class="fill" d="M923.8 248H736v-82c0-56.2-45.8-102-102-102H390c-56.2 0-102 45.8-102 102v82H100.2C80.3 248 64 264.2 64 284s16.3 36 36.2 36H192v518c0 16.4 3.2 32.4 9.6 47.5 6.1 14.5 14.9 27.6 26.1 38.8 11.2 11.2 24.2 20 38.8 26.1 15.1 6.4 31.1 9.6 47.5 9.6h396c16.4 0 32.4-3.2 47.5-9.6 14.5-6.1 27.6-14.9 38.8-26.1 11.2-11.2 20-24.2 26.1-38.8 6.4-15.1 9.6-31.1 9.6-47.5V320h91.8c19.9 0 36.2-16.2 36.2-36s-16.3-36-36.2-36zM360 166c0-16.6 13.4-30 30-30h244c16.6 0 30 13.4 30 30v82H360v-82z m400 672c0 27.6-22.4 50-50 50H314c-27.6 0-50-22.4-50-50V320h496v518z" p-id="2485"></path></svg>
                        </button>
                        <button class="complete">
                            <svg t="1556526475868" viewBox="0 0 1879 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4164" xmlns:xlink="http://www.w3.org/1999/xlink" width="366.9921875" height="200"><defs><style type="text/css"></style></defs><path class="fill" d="M801.590751 981.530636c-19.384971 0-38.030058-7.250867-52.087861-20.420809L348.337572 587.024277c-30.039306-27.96763-31.075145-74.43237-2.36763-103.731791s76.504046-30.187283 106.543353-2.219654L795.079769 800.554913 1416.434682 65.257803c26.487861-31.223121 73.988439-35.810405 106.099422-10.062427 32.110983 25.747977 36.698266 71.916763 10.358382 103.287861L859.893642 954.894798c-13.317919 15.833526-32.850867 25.452023-53.715607 26.635838h-4.587284z" class="fill" p-id="4165"></path></svg>
                        </button>
                    </div>
                </li>
            <% })%>

        </ul>
        <!--已完成列表-->
        <ul class="todo" id="completed">
            <!--動(dòng)態(tài)獲取數(shù)據(jù)-->
            <li>
                鄧倫最帥!
                <div class="buttons">
                    <button class="remove">
                        <svg t="1556521793477" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2483" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path class="fill" d="M412 744c-19.8 0-36-16.2-36-36V500c0-19.8 16.2-36 36-36s36 16.2 36 36v208c0 19.8-16.2 36-36 36zM612 744c-19.8 0-36-16.2-36-36V500c0-19.8 16.2-36 36-36s36 16.2 36 36v208c0 19.8-16.2 36-36 36z" p-id="2484"></path><path class="fill" d="M923.8 248H736v-82c0-56.2-45.8-102-102-102H390c-56.2 0-102 45.8-102 102v82H100.2C80.3 248 64 264.2 64 284s16.3 36 36.2 36H192v518c0 16.4 3.2 32.4 9.6 47.5 6.1 14.5 14.9 27.6 26.1 38.8 11.2 11.2 24.2 20 38.8 26.1 15.1 6.4 31.1 9.6 47.5 9.6h396c16.4 0 32.4-3.2 47.5-9.6 14.5-6.1 27.6-14.9 38.8-26.1 11.2-11.2 20-24.2 26.1-38.8 6.4-15.1 9.6-31.1 9.6-47.5V320h91.8c19.9 0 36.2-16.2 36.2-36s-16.3-36-36.2-36zM360 166c0-16.6 13.4-30 30-30h244c16.6 0 30 13.4 30 30v82H360v-82z m400 672c0 27.6-22.4 50-50 50H314c-27.6 0-50-22.4-50-50V320h496v518z" p-id="2485"></path></svg>
                    </button>
                    <button class="complete">
                        <svg t="1556526475868" viewBox="0 0 1879 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4164" xmlns:xlink="http://www.w3.org/1999/xlink" width="366.9921875" height="200"><defs><style type="text/css"></style></defs><path class="fill" d="M801.590751 981.530636c-19.384971 0-38.030058-7.250867-52.087861-20.420809L348.337572 587.024277c-30.039306-27.96763-31.075145-74.43237-2.36763-103.731791s76.504046-30.187283 106.543353-2.219654L795.079769 800.554913 1416.434682 65.257803c26.487861-31.223121 73.988439-35.810405 106.099422-10.062427 32.110983 25.747977 36.698266 71.916763 10.358382 103.287861L859.893642 954.894798c-13.317919 15.833526-32.850867 25.452023-53.715607 26.635838h-4.587284z" class="fill" p-id="4165"></path></svg>
                    </button>
                </div>
            </li>
        </ul>
    </div>
</body>
<script>
$(document).ready(function () {
    //添加數(shù)據(jù)
    $('header').on('submit',function () {
        let item = $('form input');
        let todo = {item:item.val()};
        if(todo.item == ""){
            alert('內(nèi)容不能為空,請重新輸入!');
            return false;
        }

        //發(fā)送數(shù)據(jù)
        $.ajax({
            type:'post',
            url:'/todo',
            data:todo,
            success:function(data){
                //coding...
            }
        })
     })

     //刪除數(shù)據(jù)
     $('.remove').on('click',function () {
         //$.trim() 函數(shù)用于去除字符串兩端的空白字符
         let item = $.trim($(this).parents('li').text());
         $.ajax({
             type:'delete',
             url:'/todo/'+ item,
             success:function(data){
                location.reload();
            }
         })
      })
 })
</script>
</html>

因?yàn)橹饕獮閚ode.js的學(xué)習(xí),此處的樣式省略,之后會(huì)拋出代碼提供參考。


最終頁面樣式展示

mongoose

安裝mongoose模塊
使用mongoDB網(wǎng)絡(luò)數(shù)據(jù)庫
創(chuàng)建數(shù)據(jù)庫及配置用戶名及密碼
鏈接mongoDB數(shù)據(jù)庫

  1. 安裝mongoose npm install mongoose --save-dev
  2. mongodb 官網(wǎng)注冊賬號并新建配置數(shù)據(jù)庫
  3. 鏈接數(shù)據(jù)庫,在 todoController.js 文件中引入并替換之前的方法

npm root -g 獲取全局安裝依賴路徑

//todoController.js
//引入mongoose 模塊
let mongoose = require('mongoose');
//鏈接數(shù)據(jù)庫
mongoose.connect('mongodb+srv:*******************',{useNewUrlParser:true})
//創(chuàng)建圖表
let todoSchema  = new mongoose.Schema({
   item:String
})

//往數(shù)據(jù)庫中存儲(chǔ)數(shù)據(jù)
let Todo = mongoose.model('Todo',todoSchema);

//測試存儲(chǔ)
// Todo({item:'大家好'})
//     .save((err,data) => {
//         if(err) throw err;
//         console.log('保存成功!')
//     })

let bodyParser = require('body-parser');
//對數(shù)據(jù)進(jìn)行解析
let urlencodeParser =  bodyParser.urlencoded({extended:false});

// let data = [
//     {item:'歡迎大家來到煢煢課堂練習(xí)!'},
//     {item:'希望大家能喜歡我的練習(xí)!'},
//     {item:'一個(gè)個(gè)手敲代碼好累哦!'},
// ]

//todoController
module.exports = function (app) {
   //獲取數(shù)據(jù)
   app.get('/todo', (req,res) => {
       // res.render('todo',{todos:data});
       Todo.find({},(err,data) => {
           if(err) throw err;
           res.render('todo',{todos:data});
       })

    })

    //傳遞數(shù)據(jù)
    app.post('/todo',urlencodeParser,(req,res) => {
       //coding...
       // console.log(req.body);
       // data.push(req.body);

       Todo(req.body)
           .save((err,data) => {
               if(err) throw err;
               res.json(data);
           })
    })

    //刪除數(shù)據(jù)
    app.delete('/todo/:item',(req,res) => {
        //coding
       //  console.log(req.params.item);
       //  data = data.filter(function (todo) {
       //     return req.params.item != todo.item;
       //   })

       //   res.json(data);

       Todo.find({item:req.params.item})
           .remove((err,data) => {
               if(err) throw err;
               res.json(data);
           })
    })
}

至此,todoApp的實(shí)戰(zhàn)已經(jīng)到達(dá)尾聲,我們已經(jīng)完成鏈接線上數(shù)據(jù)庫獲取數(shù)據(jù)、添加數(shù)據(jù),查找數(shù)據(jù)并刪除的功能。剩下的完成功能就當(dāng)做家庭小作業(yè)吧O(∩_∩)O哈哈~
源碼附上

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

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

  • 概要 64學(xué)時(shí) 3.5學(xué)分 章節(jié)安排 電子商務(wù)網(wǎng)站概況 HTML5+CSS3 JavaScript Node 電子...
    阿啊阿吖丁閱讀 9,884評論 0 3
  • 個(gè)人入門學(xué)習(xí)用筆記、不過多作為參考依據(jù)。如有錯(cuò)誤歡迎斧正 目錄 簡書好像不支持錨點(diǎn)、復(fù)制搜索(反正也是寫給我自己看...
    kirito_song閱讀 2,655評論 1 37
  • Node.js是目前非?;馃岬募夹g(shù),但是它的誕生經(jīng)歷卻很奇特。 眾所周知,在Netscape設(shè)計(jì)出JavaScri...
    Myselfyan閱讀 4,208評論 2 58
  • 33、JS中的本地存儲(chǔ) 把一些信息存儲(chǔ)在當(dāng)前瀏覽器指定域下的某一個(gè)地方(存儲(chǔ)到物理硬盤中)1、不能跨瀏覽器傳輸:在...
    萌妹撒閱讀 2,258評論 0 2
  • GitChat技術(shù)雜談 前言 本文較長,為了節(jié)省你的閱讀時(shí)間,在文前列寫作思路如下: 什么是 webpack,它要...
    蕭玄辭閱讀 12,918評論 7 110

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