一、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
// 先在当前目录下查找是否拥有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
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、 浏览器请求一个服务器上页面的完整过程
文件夹目录
<!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);