node学习笔记

179 阅读23分钟

一、Node.js介绍

1、node是什么?
    node是一个运行javascript的环境。(环境是对某个应用的支持)。
    Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine。
    node所使用的引擎即是谷歌浏览器当中v8引擎。
    安装完node之后,那么你的电脑就拥有了该环境。
    有了该环境可以通过node来运行JS。
    Node.js 可以解析JS代码,并且没有浏览器安全级别的限制,提供了很多系统级别的API,如 文件读写、进程管理、网络通信。    
    1>、安装:https://nodejs.org/zh-cn/download/
    2>、检查:
        打开cmd 然后输入node -v 检查是否安装成功
2、为什么要学node
    因为node是前端必备的一项技能。
    webpack vue react都会用到
3、学完node之后可以做什么?
    可以通过node完成一个中间层
    可以通过node实现服务代理
    可以通过node实现接口服务
    可以通过node将JS水平可以实现一个提升。

node环境和浏览器都可以运行JS代码,浏览器可以操作window,node环境可以查看进程process。

二、Node.js 基础

1、创建一个最简单的站点

//导入一个内置模块
const http = require('http')
//http下有一个方法createServer ,可以通过该方法创建服务站点
//回调函数:给createServer函数传递了一个参数(函数)
// req 是请求对象,res响应对象
http.createServer(function(req,res){
    // 指定文档的类型,以及编码格式。
    res.writeHead(200,{"content-type":"text/html;charset=utf-8"})
    res.end('<h1>响应成功</h1>')
}).listen(80,_=>{
    console.log('http://127.0.0.1:80')
})

总结:

1)、创建站点createServer

2)、运行站点服务 node server.js

3)、打开浏览器,通过服务器的IP访问该站点,可以看到站点信息。

4)、同一个端口号只允许使用一次。

5)、不管访问的具体目录是什么,都会访问到该服务。

2、手写一个404

const http = require('http')
http.createServer(function (req,res) {
    res.writeHead(404,{
        // plain格式让浏览器不识别标签
        "content-type":"text/plain;charset=utf-8"
    });
    res.end("<h2>响应404</h2>");
}).listen(80,function () {
    // 当服务启动成功以后,会运行该回调
    console.log("服务启动");
});

3、操作文件

//fs是一个内置模块,通过该模块可以对文件进行操作。
// 通过该方法读取指定的文件,第一个参数是文件的地址,第二个参数是一个回调函数(当文件读取完毕以后会执行该回调)
const fs = require('fs')
fs.readFile('index.html',function(err,results){
    // err:错误信息
    // results:读取的结果。
    // Buffer:处于缓冲阶段的一个数据格式。该格式还没有自己具体的类型。
    if(err){// 判断读取是否异常。
        console.log("读取异常")
    }else{
        //results 是Buffer格式 ,需要转换成string
        console.log(results);
        console.log(results.toString());
    }
})

4、结合创站点和操作文件

const http = require("http");
const fs = require("fs");
const server = http.createServer((req,res)=>{
    res.writeHead(200,{
        "content-type":"text/html;charset=utf-8"
    })
    //读取的可以是js、html、此时html文件中不能引入js文件,因为node没有文件夹的概念
    fs.readFile("index.html",(err,results)=>{
        if(err)
            res.end("err");
        else
            res.end(results.toString());
    })
});
server.listen(80,()=>{
    console.log("success");
})

5、加上判断req.url

const http = require("http");
const fs = require("fs");
const url = require("url");
const server = http.createServer((req,res)=>{
    console.log(req.url);
    const pathname = url.parse(req.url).pathname;
    if(pathname === "/index.html"){
        res.writeHead(200,{
            "content-type":"text/html;charset=utf-8"
        })
        fs.readFile("./index.html",(err,results)=>{
            if(err)
                res.end("err");
            else
                res.end(results.toString());
        })
    }else if(pathname === "/style.css"){
        fs.readFile("./style.css",(err,results)=>{
            if(err)
                res.end("err");
            else
                res.end(results.toString());
        })
    }else if(pathname === "/index.js"){
        fs.readFile("./index.js",(err,results)=>{
            if(err)
                res.end("err");
            else
                res.end(results.toString());
        })
    }

});
server.listen(80,()=>{
    console.log("success");
})

此处应该加上这张图,一个完整的请求过程

6、url解析

const http = require("http");
const fs = require("fs");
const url = require("url");
const myPath = "http://127.0.0.1:8081/sum?a=1&b=2#lala";
console.log(url.parse(myPath))
/*
Url {
  protocol: 'http:',
  slashes: true,
  auth: null,
  host: '127.0.0.1:8081',
  port: '8081',
  hostname: '127.0.0.1',
  hash: '#lala',
  search: '?a=1&b=2',
  query: 'a=1&b=2',
  pathname: '/sum',
  path: '/sum?a=1&b=2',
  href: 'http://127.0.0.1:8081/sum?a=1&b=2#lala' }
*/
/*
query 解析
const query = "a=1&b=2";// {a:1,b:2}
function toObj(query){
    const arr = query.split("&");
    const obj = {};
    arr.forEach(v=>{
        const arr2 = v.split("=");
        obj[arr2[0]] = arr2[1];
    })
    return obj;
}
console.log(toObj(query));

*/

console.log(url.parse(myPath).pathname);// /sum
console.log(url.parse(myPath).query);// a=1&b=2
console.log(url.parse(myPath,true).query);//  { a: '1', b: '2' }
console.log(url.parse(myPath,true).query.a);// 1
console.log(url.parse(myPath,true).query.b);// 2

7、writeFile

const fs = require('fs')
//读取
// fs.readFile("./1、http.js",(err,results)=>{
//     if(err) console.log('读取异常')
//     else console.log(results.toString())
// })

//写入
// 第一个参数是写入的地址,
// 第二个参数是写入的内容(必须是字符串),
// 第三个参数是对写入的配置(追加,覆盖),是可以省略的 {flag:"a"}
// 第四个参数是一个回调,当写入完成之后会执行
fs.writeFile('./data.txt',JSON.stringify({a:1,b:2}),err=>{
        if(err) console.log("写入失败")
        else console.log("写入成功")
})

8、一个form提交的demo

html页面

//默认以get方式提交
<form  action="http://127.0.0.1/reg" target="_blank">
    <p>姓名:<input type="text" name="userName"></p>
    <p>性别:<select name="sex">
        <option value="1">男</option>
        <option value="2">女</option>
        <option value="3">保密</option>
    </select></p>
    <p>是否已婚:
        <input type="radio" value="1" name="isJieHun">是
        <input type="radio" value="2" name="isJieHun">否
    </p>
    <p>爱好:
        <input type="checkbox" name="hobby" value="1">学习
        <input type="checkbox" name="hobby" value="2">读书
        <input type="checkbox" name="hobby" value="3">烫头
        <input type="checkbox" name="hobby" value="4">喝酒
    </p>
    <p><input type="submit" value="提交"></p>
</form>

js:

const http = require("http");
const url = require("url");
const fs = require("fs");
const sexEnum = {
    1: "男",
    2: "女",
    3: "未知"
}
const hobbyEnum = {
    1: "学习",
    2: "读书",
    3: "烫头",
    4: "喝酒",
}
function getNowTime(){
    const date = new Date();
    //padStart(长度,用什么补齐) 在数字后边后0
    //padEnd(长度,用什么补齐) 在数字前边补0
    const nowTime = date.getFullYear()+"-"+
        (date.getMonth()+1).toString().padStart(2,"0")+"-"+
        date.getDate().toString().padStart(2,"0")+ " "+
        date.getHours().toString().padStart(2,"0")+ ":"+
        date.getMinutes().toString().padStart(2,"0")+ ":"+
        date.getSeconds().toString().padStart(2,"0");
    return nowTime;
}
const server = http.createServer((req, res) => {
    // 思路:指明reg
    const pathname = url.parse(req.url).pathname.toLowerCase();
    if (pathname === "/reg") {
        res.writeHead(200, {
            "content-type": "text/html;charset=utf-8"
        })
        // 将接收的值赋值给query
        const query = url.parse(req.url, true).query;
        //将时间戳作为id存储
        let str = "ID:"+Date.now()+"\n";
        // 判断用户名是否存在,如果存在写入数据
        if (query.userName.length > 0) {
            str += "姓名:" + query.userName + "\n";
        }

        str += "性别:" + sexEnum[query.sex] + "\n";
        // 判断是否拥有isJieHun这个参数
        if (query.isJieHun) {// 拥有该参数
            str += "是否已婚:" + (query.isJieHun / 1 === 1 ? "是" : "否") + "\n";
        }
        if (query.hobby) {
            str += "爱好:";
            // 判断爱好是否为一个数组
            if (query.hobby instanceof Array)
                //join('、')用、拼接起来
                str += query.hobby.map(v => hobbyEnum[v]).join("、");
            else str += hobbyEnum[query.hobby]
            str += "\n";
        }
        str += "添加时间:"+getNowTime()+"\n***********************************\n";
        fs.writeFile("./data.txt", str, {flag: "a"}, (err) => {
           //end()里必须写字符串类型
            if (err) res.end(JSON.stringify({ok:-1,msg:"注册失败"}));
            else res.end(JSON.stringify({ok:1,msg:"注册成功"}));
        })
        console.log(query);
    } else {
        res.end("404");
    }
});
server.listen(80, () => {
    console.log("success");
})

9、一个用ajax提交的form

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form name="myForm">
    <p>姓名:<input type="text" name="userName"></p>
    <p>性别:<select name="sex">
        <option value="1">男</option>
        <option value="2">女</option>
        <option value="3">未知</option>
    </select></p>
    <p>是否已婚:
        <input type="radio" value="1" name="isJieHun">是
        <input type="radio" value="2" name="isJieHun">否
    </p>
    <p>爱好:
        <input type="checkbox" name="hobby" value="1">学习
        <input type="checkbox" name="hobby" value="2">读书
        <input type="checkbox" name="hobby" value="3">烫头
        <input type="checkbox" name="hobby" value="4">喝酒
    </p>
    <p><input type="button" name="btns" value="提交"></p>
</form>
</body>
<script>
    // const btns = document.querySelector("input[type=button]");
    const myForm = document.myForm;
    myForm.btns.onclick=()=>{
        const query = {
            userName:myForm.userName.value,
            isJieHun:myForm.isJieHun.value,
            sex:myForm.sex.value
        }
        const arr = []
        myForm.hobby.forEach(v => {
            if(v.checked) arr.push("hobby="+v.value)
        });
        const hobby = arr.join('&')
        //Object.keys(obj) 提取对象的属性名结果是数组
        //Object.keys(obj).map(v=>v+'='+obj[v]).join('&')
        //通过ajax提交表单 xml是一种数据格式
        const xhr = new XMLHttpRequest()
        xhr.open("get","http://127.0.0.1/reg?"+Object.keys(query).map(v=>v+'='+query[v]).join('&')+'&'+hobby)
        xhr.send()
        xhr.onload=()=>{
            //接收参数
            if(xhr.status === 200){
                console.log(xhr.responseText)
                const data = JSON.parse(xhr.responseText)
                if(data.ok ===1){
                    //清空myform
                    myForm.reset()
                    alert(data.msg)
                }else{
                    console.log(data.msg)
                }
            }else{
                console.log('发送失败')
            }
        }
    }
</script>
</html>

js

const http = require('http')
const url = require('url')
const fs = require('fs')
const sexEnum = {
    1: "男",
    2: "女",
    3: "未知"
}
const hobbyEnum = {
    1: "学习",
    2: "读书",
    3: "烫头",
    4: "喝酒",
}
function getNowTime(){
    const date = new Date();
    const nowTime = date.getFullYear()+"-"+
        (date.getMonth()+1).toString().padStart(2,"0")+"-"+
        date.getDate().toString().padStart(2,"0")+ " "+
        date.getHours().toString().padStart(2,"0")+ ":"+
        date.getMinutes().toString().padStart(2,"0")+ ":"+
        date.getSeconds().toString().padStart(2,"0");
    return nowTime;
}
const server = http.createServer((req,res)=>{
    //指明reg
    const pathname = url.parse(req.url).pathname
    if(pathname === '/'){
        fs.readFile('./ajax.html',(err,results)=>{
            res.end(results.toString())
        })
    }
    if(pathname === '/reg'){
        res.writeHead(200,{
            "content-type":"text/html;charset=utf-8"
        })
        const query = url.parse(req.url,true).query
        let str = ''
        if(query.userName.length){
            str += '姓名:'+query.userName +'\n'
        }
        str += '性别:'+sexEnum[query.sex] + '\n'
        if(query.isJieHun) str+='是否已婚:'+(query.isJieHun/1===1?'是':'否')+'\n'
        if(query.hobby){
            if(query.hobby instanceof Array) str +='爱好' + query.hobby.map(v=>hobbyEnum[v]).join('、') + '\n'
            else str+='爱好:' + hobbyEnum[query.hobby] +'\n'
        }
        str += '添加时间:'+ getNowTime() +'\n'
        str += '******************************\n'
        fs.writeFile('./data.txt',str,{flag:'a'},err=>{
            if (err) res.end(JSON.stringify({ok:-1,msg:"注册失败"}));
            else res.end(JSON.stringify({ok:1,msg:"注册成功"}));
        })
    }
})
server.listen(80,_=>{
    console.log('success')
})

10、乱入一个合并数组对象的方法

 const arr = [1,2,3,4];
 const arr2 = [5,6,7,8];
 const arr3 = arr.concat(arr2);
 const arr3 = [
    ...arr,
    ...arr2
 ]
 console.log(arr3);

const obj = {
    a:1
    }
 const obj2 = {
    b:2,
    a:3
}
 const obj3 = {
    ...obj,
    ...obj2
}
//obj3 a:3,b:2 后边的会覆盖前边的
// 第一个参数是目标对象,后面的若干参数是源对象。assign会将目标对象进行返回
// 将obj2合并到obj内,然后将obj进行返回
 const obj3 = Object.assign(obj,obj2);
 console.log(obj===obj3);

11、模块化

将具体某一功能的代码称为模块,也叫模组、依赖。

导出:module.exports

导入:require

demo.js

const mo = require('./mo.js')
console.log(mo.a,mo.b)
mo.run()

mo.js

module.exports.a = 1
module.exports.b = 2
module.exports.run = function(){
    console.log(this)
}

运行mo.js

demo2.js

// .js是可以省略的
const mo2 = require("./mo2");
console.log(mo2);

mo2.js

module.exports.userName = "dalao";
module.exports.age = 12;

运行mo2.js

判断js文件查找顺序 在同一目录下 新建一个文件夹mo3 一个demo3.js mo3.js demo3.js

// 先在当前目录下查找是否拥有mo3.js,如果有即用。如果没有则查找是否有名字为mo3的文件夹,该文件夹内是否有index.js.如果没有报错。
const mo3 = require("./mo3");
console.log(mo3);

mo3.js

module.exports.str = "module->mo3.js"

此时运行demo3.js 打印出来的是module->mo3.js, 删掉mo3.js mo3文件夹 新建一个index.js

module.exports.str = "module->mo3->index.js"

此时打印出来的是module->mo3->index.js 如果想改变 mo3文件夹默认js,新建一个package.json文件,一个home.js package.json

{
    "main":"home.js"
}

home.js

module.exports.str = "module->mo3->home.js"

此时打印出来 就是module->mo3->home.js

验证 多级依赖 能否实现

新建demo4.js mo4.js demo4.js

const mo4 = require("./mo4");
console.log(mo4)
//只需要str 可以 const {str} = require('./mo4')

mo4.js

const mo = require("./mo");
module.exports.str = "module->mo4.js";
module.exports.mo = mo;

运行demo4.js

如果不写地址前缀,则默认调用的是node_modules文件夹的内容

module.exports也可以导出一个函数

12、url

demo.js

const fs = require("fs");
// 相对地址:相对的是node运行目录,并非运行文件所在的目录
fs.readFile("./a.txt",(err,results)=>{
    if(err){
        console.log("失败",err)
    }else{
        console.log(results.toString());
    }
})

在test目录下运行 node url/demo.js 会报错,发现是没有找到a.txt的错误,得出结论:相对地址:相对的是node运行目录,并非运行文件所在的目录

引出 __dirname __filename

__dirname 当前文件所在的目录

__filename当前文件所在的完整地址(包含文件名)

path.resolve()得到node运行时的路径

demo2.js 实现访问上一级

// 同级,下一级。如何实现上一级
const path = require("path");
// 可以指定相对的地址
console.log(path.resolve());// 得到的是node运行的目录
console.log(path.resolve(__dirname));// 与dirname相同
// ../ 上一级]

console.log(path.resolve(__dirname,"../abc"));
console.log(path.resolve(__dirname,"./abc"));
console.log(path.resolve(__dirname,"/abc"));
console.log(path.resolve(__dirname,"abc"));

访问上一级demo

 const fs = require("fs");
const path = require("path");
fs.readFile(path.resolve(__dirname,"../bj.txt"),(err,results)=>{
    if(err){
        console.log("失败",err)
    }else{
        console.log(results.toString());
    }
})

目录结构

结果 可以访问到bj.txt 里的内容

注意: require相对的地址是当前文件所在的地址,与node运行的目录无关。

13、 浏览器请求一个服务器上页面的完整过程

文件夹目录

html

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>微博</title>
<link href="style/weibo.css" rel="stylesheet" type="text/css" />
</head>

<body>
<div class="jyArea">
<!--留言-->
     <div class="takeComment">
        <textarea name="textarea" class="takeTextField" id="tijiaoText"></textarea>
        <div class="takeSbmComment">
            <input type="button" class="inputs" value="" />
        </div>
    </div>
<!--已留-->
    <div class="commentOn">
        <div class="noContent">暂无留言</div>
        <div class="messList">
        	<div class="reply">
                <p class="replyContent">内容</p>
                <p class="operation">
                    <span class="replyTime">2020.03.10 01:01:01</span>
                    <span class="handle">
                    	<a href="javascript:;" class="top">0</a>
                        <a href="javascript:;" class="down_icon">9</a>
                        <a href="javascript:;" class="cut">删除</a>
                    </span>
                </p>
            </div>
        </div>
        <div class="page">
        	<a href="javascript:;" class="active">1</a>
        	<a href="javascript:;">2</a>
        	<a href="javascript:;">3</a>
        </div>
    </div>
</div>
</body>
</html>

server.js

const http = require("http");
const url = require("url");
const fs = require("fs");
// 当输入http://127.0.0.1  打开界面
const server = http.createServer((req,res)=>{
    const pathname = url.parse(req.url).pathname;
    console.log(pathname)
    // 路由
    if(pathname === "/"){
        fs.readFile(__dirname+"/weibo.html",function (err,results) {

            if(err) res.end("异常");
            else res.end(results);
        })
    }else if(pathname === "/favicon.ico" || pathname === "/style/weibo.css" || pathname === "/img/takeSbmComment.png" || pathname === "/img/icons.png"){
        fs.readFile(__dirname+pathname,function (err,results) {
            if(err) res.end("异常");
            else res.end(results);
        })
    }
    else{
        res.end("404")
    }
});
// listen 当中的127.0.0.1可以指定具体的IP
//第二个参数指定ip 指定之后,通过localhost访问跨域
server.listen(80,"127.0.0.1",function () {
    console.log("success");
})

14、百度模板的学习和使用

       1、引入
          <script src="baiduTemplate.js"></script>
       2、使用
            1、创建模板
                <script type="text/html" id="tp">
                    <%=%>
                </script>
            2、使用模板
                baidu.template("tp",{})

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--引入百度模板-->
    <script src="baiduTemplate.js"></script>
</head>
<body>
    <div id="wuxia"></div>
    <div id="yanqing"></div>
    <div id="xuanhuan"></div>
</body>
<!--创建模板-->
<script type="text/html" id="tp">
    <div>
        <h3><%=type%></h3>
        <%for(let i=0;i<bookList.length;i++){%>
            <p>《<%=bookList[i].bookName%>》作者:<%=bookList[i].author%></p>
        <%}%>
    </div>
    <hr/>
</script>
<script>
    <!--使用模板-->
    document.querySelector("#wuxia").innerHTML = baidu.template("tp",{
        type:"武侠小说",
        bookList:[
            {
                bookName:"天龙八部",
                author:"金庸"
            },
            {
                bookName:"小李飞刀",
                author:"古龙"
            }
        ]
    })
    document.querySelector("#yanqing").innerHTML = baidu.template("tp",{
        type:"言情小说",
        bookList:[
            {
                bookName:"还珠格格",
                author:"琼瑶"
            },
            {
                bookName:"情深深雨蒙蒙",
                author:"琼瑶"
            }
        ]
    })
    document.querySelector("#xuanhuan").innerHTML = baidu.template("tp",{
        type:"玄幻小说",
        bookList:[
            {
                bookName:"斗破苍穹",
                author:"天蚕土豆"
            },
            {
                bookName:"斗罗大陆",
                author:"唐家三少"
            }
        ]
    })
</script>
</html>

15、express 的学习

express node的一款框架

乱入 了解 egret.com 白鹭引擎

使用express

下载

    npm install express --save-dev:开发环境当中使用时
    npm i express -D

    npm install express --save:在生产环境当中也要使用
    npm i express -S
    安装cnpm  npm install -g cnpm --registry=https://registry.npm.taobao.org

引入

        const express = require("express");
const express = require("express");
const path = require("path");
const app = express();
// 将express运行的结果赋值给app;
// 静态资源:将指定的文件夹设置为静态资源(让该文件夹的内容拥有了容器的概念)
// static指定的是文件夹 //将上一级目录下的weibo文件夹设置为静态文件。
// 可以直接通过站点访问该文件夹的内容。
//path.resolve() 路径拼接
app.use(express.static(path.resolve(__dirname,"../weibo")));

// 快速搭建路由。
// 以get的形式访问地址/sum
app.get("/sum",(req,res)=>{
    res.end("sum")
})

// 当遇到第一个符合要求的路由时,它不会向下继续执行。页面渲染的是sum
app.get("/sum",(req,res)=>{
    res.end("sum")
})
app.get("/sum",(req,res)=>{
    res.end("sum2")
})

// next是一个函数,向下继续查找符合条件的路由
//页面渲染的是sum2
app.get("/sum",(req,res,next)=>{
    console.log("sum");
    next();
})
app.get("/sum",(req,res)=>{
    res.end("sum2")
})

// 以get的形式访问的所有地址
app.get("*",(req,res)=>{
    res.end("haha")
})
// all:不限制请求方式,*:不限制地址
app.all("*",(req,res)=>{

})

//传参的两种方式
//打印出来都是{ a: '1', b: '2' }
//http://127.0.0.1/sum?a=1&b=2
app.get("/sum",(req,res)=>{
//req.query接收参数
    console.log(req.query);
    res.end("sum");
})
// http://127.0.0.1/sum/1/2
app.get("/sum/:a/:b/:c",(req,res)=>{
//req.params接收参数
    console.log(req.params);
    res.end("sum ->params")
})


app.listen(80,function () {
    console.log("success");
})

补充一个js知识 find findIndex

// find: return 是一个布尔值。当布尔值为真则后面的不会继续运行
// 根据条件进行查找。只查找第一个满足条件的元素,并将元素进行返回。
// 如果没有找到符合的元素,则返回undefined
// const item = userList.find((v,i,arr)=>{
//     return v.id === id;
// })
// const item = userList.find(v=>v.id === id)
// item.userName = "老孔";
//会改变原数组的值  引用类型


// 根据条件进行查找。只查找第一个满足条件的元素,并将元素的下标进行返回。
// 如果没有找到符合条件的元素,则返回-1
const index = userList.findIndex(v=>v.id === id);

16、一个点击投票的小demo

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="baiduTemplate.js"></script>
</head>
<body>
    <h2>投票</h2>
    <div id="root">
    </div>
</body>
<script type="text/html" id="tp">
    <div>
        <%for(let i=0;i<userList.length;i++){%>
        <input type="button" onclick="sendVote(<%=userList[i].id%>)"  value="<%=userList[i].userName+userList[i].vote%>">
        <%}%>
    </div>
</script>
<script> 
     const init = ()=>{
        const xhr = new XMLHttpRequest();
        xhr.open("get","/getUserList")
        xhr.send()
        xhr.onload = ()=>{
           const  data = JSON.parse(xhr.responseText)
            console.log(data)
            document.querySelector("#root").innerHTML = baidu.template("tp",data)
        }
    }
    init()
    const sendVote = (id)=>{
        console.log(id)
       const xhr = new XMLHttpRequest()
       //传参的两种方式
        // xhr.open("get","/sendVote?id="+id);
        xhr.open('get','/sendVote/'+id)
        xhr.send()
        xhr.onload=()=>{
            console.log(xhr.responseText);
            
           const data = JSON.parse(xhr.responseText);
            if(data.ok ===1) init()
            else alert(data.msg)
        }
    }
</script>
</html>

server.js

const express = require('express')
const fs = require('fs')
const { resolve } = require('path')
const app = express()
/* 挂载静态资源*/
app.use(express.static(__dirname))

let  userList = JSON.parse(fs.readFileSync('./data.json').toString())
console.log( userList instanceof Array === true)

app.get("/getUserList",(req,res)=>{
    res.json({
        ok:1,
        userList
    })
})
/*接收参数的两种方式*/
/*app.get("/sendVote",(req,res)=>{
    console.log(req.query.id)
    res.json({"A":'1'})
 
 })*/

app.get("/sendVote/:id",(req,res)=>{
   const id = req.params.id/1
   const e = userList.find(v=>v.id===id)
   if(e){
       console.log(e)
       e.vote++
     fs.writeFile('./data.json',JSON.stringify(userList),err=>{
           if(err) console.log(err)
           else { res.json({ok:1,msg:"投票成功"})}
       })   
   }else{
    res.json({
        ok:-1,
        msg:"因未知原因错误"
    })
   }

})

app.listen(80,_=>{
    console.log('success')
})

data.json

[{
    "id": 1,
    "userName": "程1",
    "vote": 20
}, {
    "id": 2,
    "userName": "孔1",
    "vote": 7
}, {
    "id": 3,
    "userName": "袁1",
    "vote": 4
}, {
    "id": 4,
    "userName": "张1",
    "vote": 5
}]

17、 restful风格

掌握四种:

  • get:获取
  • post:增加(提交表单)
  • delete:删除
  • put:修改操作

html

</head>
<body>
<input type="button" value="get" onclick="get()">
<input type="button" value="post" onclick="post()">
<input type="button" value="delete" onclick="mydelete()">
<input type="button" value="put" onclick="put()">
</body>
<script>
     function get() {
        const xhr = new XMLHttpRequest();
        xhr.open("get","/weibo");
        xhr.send();
        xhr.onload = function () {
            console.log(xhr.responseText);
        }
     }
     //post 三种传值方式 json urlencoded formdata
     function post(){
         // json
         // const xhr = new XMLHttpRequest();
         // xhr.open("post","/weibo?d=12");
         // // setRequestHeader设置的位置必须是在open之后,send之前。 设置格式为JSON数据
         // xhr.setRequestHeader("content-type","application/json")
         // xhr.send(JSON.stringify({a:1,b:2}));// send内只允许写字符串
         // xhr.onload = function () {
         //     console.log(xhr.responseText);
         // }

         // urlencoded
         const xhr = new XMLHttpRequest();
         xhr.open("post","/weibo?d=12");
         // setRequestHeader设置的位置必须是在open之后,send之前。 设置格式为JSON数据
         xhr.setRequestHeader("content-type","application/x-www-form-urlencoded")
         xhr.send("a=10&b=20&c[0]=1&c[1]=2");// send内只允许写字符串
         xhr.onload = function () {
             console.log(xhr.responseText);
         }
     }
     function mydelete(){
         const xhr = new XMLHttpRequest();
         xhr.open("delete","/weibo");
         xhr.send();
         xhr.onload = function () {
             console.log(xhr.responseText);
         }
     }
     function put(){
         const xhr = new XMLHttpRequest();
         xhr.open("put","/weibo");
         xhr.send();
         xhr.onload = function () {
             console.log(xhr.responseText);
         }
     }
</script>

server.js

const express = require("express");
const bodyParser = require("body-parser");// 通过该模块可以获取POST传递过来的值
const app = express();
// app.use(bodyParser.json());// 设置接收的参数格式为json
app.use(bodyParser.urlencoded({
    extended:true,// 是否为深度解析。
}));// 设置接收的参数格式为urlencoded
app.use(express.static(__dirname));

// 以get方式请求/weibo
app.get("/weibo",function (req,res) {
    res.json({
        ok:1,
        msg:"get"
    })
})
// 以post方式请求/weibo
app.post("/weibo",function (req,res) {
    console.log(req.body,req.query);
    res.json({
        ok:1,
        msg:"post"
    })
})
// 以delete方式请求/weibo :传递参数相当于get
app.delete("/weibo",function (req,res) {
    res.json({
        ok:1,
        msg:"delete"
    })
})
// 以put方式请求/weibo  :传递参数相当于post
app.put("/weibo",function (req,res) {
    // req.body
    res.json({
        ok:1,
        msg:"put"
    })
})
app.listen(80,function () {
    console.log("success")
})

18、用restful实现一个留言板功能

html

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>微博</title>
<link href="style/weibo.css" rel="stylesheet" type="text/css" />
<script src="./baiduTemplate.js"></script>
</head>

<body>
<div class="jyArea">
<!--留言-->
    <div class="takeComment">
       <span>用户名:</span><input type="text" id="userName" value="">
        <textarea name="textarea" class="takeTextField" id="tijiaoText"></textarea>
        <div class="takeSbmComment">
            <input type="button" class="inputs" value="" />
        </div>
    </div>
<!--已留-->
    <div class="commentOn">
      
    </div>
</div>
</body>
<script type="text/html" id="pl">
      <%if (data.length){%>
        <div class="noContent">暂无留言</div>
      <%}%>
        <div class="messList">
            <%for(var i =0,len=data.length;i<len;i++){%>
            <%if(!data[i].flag){%>
            <div class="reply">
                <p class="replyContent"><%=data[i].context%></p>
                <p class="operation">
                    <span class="replyTime"><%=data[i].addTime%></span>
                    <span class="userName"><%=data[i].userName%></span>
                    <span class="handle">
                    	<a href="javascript:;"  onclick="upWeibo(<%=data[i].id%>,1)"  class="top"><%=data[i].topNum%></a>
                        <a href="javascript:;"  onclick="upWeibo(<%=data[i].id%>,2)"  class="down_icon"><%=data[i].downNum%></a>
                        <a href="javascript:;" onclick="deleteWeibo(<%=data[i].id%>)" class="cut">删除</a>
                    </span>
                </p>
            </div>
            <%}%>
            <%}%>
        
        </div>
        <div class="page">
        	<a href="javascript:;" class="active">1</a>
        	<a href="javascript:;">2</a>
        	<a href="javascript:;">3</a>
        </div>
</script>
<script src="weibo.js"></script>
</html>

weibo.js

//获取文本框
const context = document.querySelector("#tijiaoText")
//获取提交按钮
const btns = document.querySelector('.inputs')
//获取用户名
const userName = document.querySelector('#userName')

//获取微博列表
const getWeibo=()=>{
const xhr = new XMLHttpRequest();
xhr.open("get","/getWeibo")
xhr.send()
xhr.onload=()=>{
    const result = JSON.parse(xhr.responseText)
    const {data} = result
    if(result.ok===1)document.querySelector('.commentOn').innerHTML = baidu.template("pl",{data});
    else alert(result.data)
}
}
getWeibo()


//提交按钮 发送
btns.addEventListener("click",()=>{
   const xhr = new XMLHttpRequest()
   xhr.open("post","/addWeibo")
   xhr.setRequestHeader("content-type","application/json")
   xhr.send(JSON.stringify({context:context.value,userName:userName.value}))
   xhr.onload = ()=>{
       const result = JSON.parse(xhr.responseText)
      if(result.ok===1) {
           context.value = null
           userName.value = null
           alert(result.data)
           getWeibo()
       }else alert(result.data)
   }
})

// 赞 踩
const upWeibo = (id,type)=>{
    const xhr = new XMLHttpRequest()
    xhr.open("put","/upWeibo/"+id)
    xhr.setRequestHeader("content-type","application/json")
    xhr.send(JSON.stringify({type}))
    xhr.onload = ()=>{
        const result = JSON.parse(xhr.responseText)
       if(result.ok===1) {
            alert(result.data)
            getWeibo()
        }else alert(result.data)
    }
}
//删除
const deleteWeibo = (id)=>{
    const xhr = new XMLHttpRequest()
    xhr.open("delete","/deleteWeibo/"+id)
    xhr.send()
    xhr.onload = ()=>{
        const result = JSON.parse(xhr.responseText)
       if(result.ok===1) {
            alert(result.data)
            getWeibo()
        }else alert(result.data)
    }
}

server.js

const express = require("express");
const tools = require("./module/tools");
const bodyParser = require("body-parser");
const fs = require("fs");
const app = express();

app.use(bodyParser.json());

app.use(express.static(__dirname))

/**获取微博列表 */
app.get("/getWeibo",(req,res)=>{
    fs.readFile(__dirname+"/data.json",(err,results)=>{
        if(err)  tools.json(res)
        else  res.json({ok:1,data:JSON.parse(results.toString())})
    })
})

/**新增一条微博 */
app.post("/addWeibo",(req,res)=>{
    const {context,userName} = req.body
    fs.readFile(__dirname+"/data.json",(err,results)=>{
        if(err) tools.json(res)
        else{
            console.log(results)
            const contextList  = JSON.parse(results.toString())
            console.log(contextList)
            const index = contextList.findIndex(v=>v.context===context&&v.userName===userName)
            if(index>-1){
                tools.json(res,-1,"您已评论过相同内容")
            }else{
                contextList.unshift({
                    id:Date.now(),// 将时间戳设置为唯一标识
                   userName,
                    context,
                    topNum:0,
                    downNum:0,
                    addTime:tools.getNowTime() ,
                    flag:false 
                })
                fs.writeFile(__dirname+"/data.json",JSON.stringify(contextList),(err)=>{
                    if(err){
                        tools.json(res,-1,"写入失败")
                    }else{
                        tools.json(res,1,"写入成功")
                    }
                })
            }
        }
    })
})

/**赞 踩 */
app.put("/upWeibo/:id",(req,res)=>{
    /**type 在req.body里  id 在req.params里 */
    const {type}=req.body
    const id = req.params.id/1
   fs.readFile(__dirname+"/data.json",(err,results)=>{
       if(err) tools.json(res)
       else{
           const contextList = JSON.parse(results.toString())
           const contextInfo = contextList.find(v=>v.id===id)
        if(contextInfo){
            if(type===1) contextInfo.topNum++;
            else contextInfo.downNum++
            fs.writeFile(__dirname+"/data.json",JSON.stringify(contextList),err=>{
                if(err) tools.json(res)
                else tools.json(res,1,"修改成功")
            })
        }else tools.json(res)
       }
   })
   
})

/**删除 */
app.delete("/deleteWeibo/:id",(req,res)=>{
    const id = req.params.id/1
   fs.readFile(__dirname+"/data.json",(err,results)=>{
       if(err) tools.json(res)
       else{
           const contextList = JSON.parse(results.toString())
           const index = contextList.findIndex(v=>v.id===id)
        if(index>-1){
            contextList.splice(index,1)
            fs.writeFile(__dirname+"/data.json",JSON.stringify(contextList),err=>{
                if(err) tools.json(res)
                else tools.json(res,1,"删除成功")
            })
        }else tools.json(res)
       }
   })
   
})


app.listen(80,function () {
    console.log("success");
})

tool.js

// 获取当前时间
module.exports.getNowTime = function () {
    const date = new Date();
    const nowTime = date.getFullYear() + "-" +
        (date.getMonth() + 1).toString().padStart(2, "0") + "-" +
        date.getDate().toString().padStart(2, "0") + " " +
        date.getHours().toString().padStart(2, "0") + ":" +
        date.getMinutes().toString().padStart(2, "0") + ":" +
        date.getSeconds().toString().padStart(2, "0");
    return nowTime;
}
// 负责生成JSON数据
module.exports.json = function (res,ok=-1,data="由于未知错误没有拿到数据") {
    res.json({
        ok,
        data
    })
}

data.json

[{
    "id": 1592526769801,
    "userName": "涨薪",
    "context": "as",
    "topNum": 0,
    "downNum": 0,
    "addTime": "2020-06-19 08:32:49",
    "flag": false
}]

19、mongodb安装+介绍

mongodb:是一个非关系型数据库(非结构型数据库)。nosql 。

关系型数据库   库  表  行列
非关系型数据库 库 集合 文档
************************************************
mongodb
常见问题:
    1、 mongo 不是内部命令。
        设置环境变量:
            window10:
            我的电脑右击属性-》高级系统设置-》选 中高级-》环境变量-》系统变量-》打开 path
            新建: C:\Program Files\MongoDB\Server\4.2\bin

            window7:
                我的电脑右击属性-》高级系统设置-》选 中高级-》环境变量-》系统变量-》打开 path
                弹出一个对话框:
                    将 ;C:\Program Files\MongoDB\Server\4.2\bin追加到尾部,记得加上一个英文的分号
    2、mongo:计算机丢失api-ms-win-crt-runtime-l1-1-0.dll快速解决方案
        https://blog.csdn.net/u012149969/article/details/88768532
******************************************************************
设置:手动启动
    1、控制面板-》管理工具-》服务-》Mongodb Server--》选择禁用。
    2、重启电脑。
******************************************************************
1、手动挂载:要确保D盘下拥有mongo文件夹。如果没有,则手动创建一个mongo文件夹。
    mongod --dbpath d:\mongo
    挂载成功以后,将控制台最小化。
ctrl+c:退出mongo环境
mongo:进入到mongo环境。可以实现对数据的操作。
mongo --version:查看版本号。
show dbs:查看当前的数据列表。
use zhang:使用数据为zhang
db:查看当前所在的数据库
show collections:查看当前库的集合列表
db.dropDatabase():删除数据库
db.score.insert({userName:"laoxie",sex:1966}):将一条文件插入到当前库的score集合当中

20、mongo操作数据的命令

数据格式

{"userName":"张三","age":12,"sex":"男","score":{"yuwen":100,"shuxue":100,"yingyu":100}}
{"userName":"李四","age":23,"sex":"女","score":{"yuwen":100,"shuxue":100,"yingyu":100}}
{"userName":"王五","age":56,"sex":"男","score":{"yuwen":100,"shuxue":100,"yingyu":100}}
{"userName":"赵六","age":123,"sex":"女","score":{"yuwen":100,"shuxue":100,"yingyu":100}}
{"userName":"严七","age":12,"sex":"男","score":{"yuwen":100,"shuxue":100,"yingyu":100}}
{"userName":"沈八","age":211,"sex":"女","score":{"yuwen":100,"shuxue":100,"yingyu":100}}
{"userName":"钱九","age":12,"sex":"男","score":{"yuwen":100,"shuxue":100,"yingyu":100}}
{"userName":"张一","age":21,"sex":"女","score":{"yuwen":100,"shuxue":100,"yingyu":100}}
{"userName":"张二","age":345,"sex":"男","score":{"yuwen":10,"shuxue":5,"yingyu":0}}
{"userName":"张四","age":54,"sex":"女","score":{"yuwen":9,"shuxue":4,"yingyu":1}}
**********************增****************************************
db.score.insert({userName:"zhangsan",sex:2000}):将一条文件插入到当前库的score集合当中
// 导入一批数据
mongoimport --db user --collection score --file D:\2001\Lession05\data
--db:指定数据库
--collection:指定集合
--file:指定导入的数据文件
--drop:可选项。如果使用该项则会则原集合当中的内容覆盖掉。
**********************删****************************************
 db.score.remove({age:12}):删除所有年龄为12的记录
 db.score.remove({sex:"男"},{justOne:true}):删除满足条件的一条记录
 db.score.remove({}):删除所有记录。
 db.score.drop():删除集合。
**********************改****************************************
 db.score.update({userName:"李四"},{sex:"男"}):完整替换
 db.score.update({userName:"张四"},{$set:{sex:"男"}}):将满足条件的第一条记录。将性别修改为男。
 db.score.update({sex:"女"},{$set:{age:18}},{multi:true}):将满足条件的所有记录进行修改。
 db.score.update({userName:"张二"},{$inc:{age:-10}}):将年龄减10.
**********************查****************************************
db.score.find():显示当前库当中score集合的文档列表
db.score.count():查看当前库中score集合的文档数量
db.score.find({userName:"张三"}) :精确查找名字为张三的记录
db.score.find({sex:"男"}):查找性别为男的所有记录。
db.score.find({"score.yuwen":9}):查找语文成绩为9的记录
db.score.find({sex:"女","score.yuwen":100}):查找性别为女且语文成绩100
db.score.find({$or:[{age:12},{sex:"女"}]}):查找年龄为12或性别为女。
db.score.find({userName:/张/}):模糊搜索。
db.score.find({age:{$gt:21}}):查找年龄大于21
db.score.find({age:{$gt:21,$lt:100}}):大于21,小于100
$gt:大于
$lt:小于
$gte:大于等于
$lte:小于等于
$ne:非
db.score.find({sex:{$ne:"男"}}))
db.score.find({sex:{$ne:"男"}}).count():查找性别不是男的所有记录的数量
// 排序
// 按照年龄进行倒序,如果年龄相同,则按照语文成成绩的正序排列
db.score.find().sort({age:-1,"score.yuwen":1});
db.score.find().skip(0):跳过指定的文档数量
db.score.find().limit(1):指定显示的文档数量 0是所有
db.score.find().limit(2).skip(1).sort({age:1}):先排序,跳过,显示
// 轻松实现分页。
pageIndex:当前面  已知
pageSum:总页数  求出来:需要知道文档总数(count)
pageSize:每页显示的文档条数  已知
    已知:pageSize   count
    pageSum = Math.ceil( count/pageSize);// 10 3
    skip = (pageIndex-1)*pageSize;

21、将node操作数据的方法进行封装

const mongodb = require("mongodb");
const mongoClient = mongodb.MongoClient;
// 连接数据库并返回db
function connect(cb) {
    mongoClient.connect("mongodb://127.0.0.1:27017", {useUnifiedTopology: true}, (err, client) => {
        if (err) console.log("连接数据库失败");
        else {
            const db = client.db("weibo");
            cb(db);
        }
    })
}
// 可以通过该函数添加一条记录
/*
* coll:指定集合
* insertOne:插入的内容
* cb:回调函数,负责将结果进行返回的*/
module.exports.insertOne = function (coll,insertObj,cb) {
    connect(db=>{
        db.collection(coll).insertOne(insertObj,(err,results)=>{
            cb(err,results);
        })
    })
}
/*
* coll:指定集合
* find:搜索的条件
* sort:排序
* skip:跳过指定文档数
* limit:显示文档的数量
* cb:回调函数,负责将结果进行返回的*/
module.exports.find = function (coll,{find={},sort={},skip=0,limit=0},cb) {
    connect(db=>{
        db.collection(coll).find(find).sort(sort).skip(skip).limit(limit).toArray((err,results)=>{
            cb(err,results)
        })
    })
}
***********************************************************************
const mongodb = require("mongodb");
// 可以通过该属性连接数据库
const mongoClient = mongodb.MongoClient;
mongoClient.connect("mongodb://127.0.0.1:27017", {useUnifiedTopology: true},
    (err, client) => {
        if (err) console.log("连接数据库失败");
        else {
            console.log("连接数据库成功");
            // 往数据库内增加一条记录
            const db = client.db("shop");//  得到数据库shop

            // 插入一条
          //  goodsList 是集合
           // insertOne 第一个参数是你要插入的内容,第二个参数是一个回调,负责接收插入的结果
           /* db.collection("goodsList").insertOne({
                goodsName:"手机",
                goodsPrice:100
            },(err,results)=>{
                if(err) console.log("插入失败");
                else console.log("插入成功")
            })*/

            // 插入多条
           /* db.collection("goodsList").insertMany([{
                goodsName:"热水器",
                goodsPrice:10
            },{
                goodsName:"鼠标",
                goodsPrice:20
            }],(err,results)=>{
                if(err) console.log("插入失败");
                else console.log("插入成功",results)
            })*/

            // 读取多条信息,成功以后返回的是一个数组。
            db.collection("goodsList").find().sort({goodsPrice:1}).toArray((err,results)=>{
                if(err) console.log("读取失败");
                else{
                    console.log(results);
                }
            })

           // 返回一条信息
           /* db.collection("goodsList").findOne({goodsPrice:10},(err,results)=>{
                if(err) console.log("查询失败")
                else console.log(results);
            })*/
        }
    })

22、补充一点回调函数 Promise async await try catch 的知识点

function fn(){
    setTimeout(()=>{
        return 12
    },0)
}
console.log(fn())//undefined
/**回调函数**/
function fn(cb){
    setTimeout(()=>{
        cb( 12)
    },0)
}
fn(function(num){
    console.log(12)
})

/**Promise**/
const pro = new Promise((resolve,reject)=>{
    resove(12)
});
pro.then(()=>{
    console.log(1111)
},()=>{
//catch
//错误的时候执行
    console.log(2222)
})

function fn(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve(12)
        })
    })
}
fn().then((res)=>{
    console.log(res)
},err=>{
//调用reject的时候调用这个函数
    console.log(err)
})

fn().then((res)=>{
    console.log(res)
}).catch((err)=>{
    console.log(err)
})

回调

function one(cb){
    setTimeout(()=>{
        cb('one')
    },1000)
}
function two(cb){
    setTimeout(()=>{
        cb('two')
    },1000)
}
function three(cb){
    setTimeout(()=>{
        cb('three')
    },1000)
}
one(function(str){
    console.log(str);
    two(function(str){
        console.log(str);
        three(function(str){
            console.log(str);
        })
    })
})

Promise

function one  (){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve('one')
        },1000)
    }
)}
function two  (){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve('two')
        },1000)
    }
)}
function three  (){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve('three')
        },1000)
    }
)}
one.then(str=>{
    console.log(str);
    return two()
}).then(str=>{
    console.log(str)
    return three()
}).then(str=>{
    console.log(str)
}).catch(err=>{
    console.log(err)
})

async await

function one  (){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve('one')
        },1000)
    }
)}
async function my(){
//得到one函数当中 resolve 传递的参数
try{
     const str1 = await one()
    console.log(str1)
}catch(e){
    console.log(e)
}
   
}
my();

23、默认参数的问题

function fn(a=0,b=0){
console.log(a,b)
}
fn(1,1);