1.初始Node与Node的安装
1.1.Node.js是什么
Node.js是一个Javascript运行环境(runtime),发布于2009年5月,由Ryan Dahl开发,实质是对Chrome V8引擎进行了封装
1 ECMAScript是JavaScript的标准
2 JavaScript在浏览器端依赖于DOM和BOM提供的接口,有了这些接口可以操作网页中的元素和浏览器
3 JavaScript在后端也需要运行环境那就是Node.js,它扩展了一些模块,让js有后端开发的能力
4 相关的规范组织 W3C、ECMA、CommonJs
node的两大特性:
事件驱动和非阻塞式IO
事件驱动:去餐馆点菜,厨房根据我们点的餐制作对应的菜品
非阻塞式IO:大家在餐桌等待上菜,如果餐桌不够坐,就排队等待
1.2.Node.js安装
根据自己的平台和操作系统位数选择下载,下载完成后双击安装,一直点下一步就可以,最好安装在默认位置,以免出现未知问题
安装好后测试是否安装成功:
node -v
如果出现node的版本号说明安装成功
2.初始NPM与NPM的使用
2.1.NPM是什么。
NPM的全称是Node Package Manager,是一个NodeJS包管理和分发工具,这里要搞清楚包的概念,通俗的说,包就是具有一定功能的工具(软件),本质上呢这些包就是很多文件的集合
2.2.如何使用NPM
npm通过命令行的方式来管理包,常用的命令如下:
1 初始化项目
npm init
这条命令运行后,会在项目文件夹下生成一个package.json的文件,记录一些关于项目的信息,如果加上 -y 参数,表示默认所有配置项目
npm init -y
2 安装包
npm install 包名称 --save-dev
实例:安装jquery
npm install jquery --save
其中,jquery就是非常著名的库,--save表示安装的是项目依赖包,你可以理解为项目上线以后还需要使用的包,我们就用加 --save这个参数,如果一些开发的时候辅助开发的工具,我们需要用--save-dev来保存,例如:安装babel-cli
npm install bable-cli --save-dev
注意:babel是一个编译转换工具 把ES6代码转换成ES5代码的
--save 和 --save-dev 它们记录包的位置也不一样,在package.json文件中,它们的记录的位置如下:
//--save记录在这
"dependencies":{
"jquery":"^3.2.1"
},
//--save-dev记录在这
"devDependencies":{
"babel":"^6.23.0"
}
3.HTTP服务器
3.1.相关前置知识
1 什么是url?
url就是统一资源定位符,是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它
2 url包含的内容
url的形式是这样的: http://nodeing.com/cloud/search?q=html 其中,http://表示协议, nodeing.com表示域名,/cloud/search表示路由,?号后面的叫做查询字符串,还有一个默认的值80,表示端口,他应该加在域名的后面 http://nodeing.com:80/
2.1 模式/协议(scheme):它告诉浏览器如何处理将要打开的文件。最常用的模式是超文本传输协议(Hypertext Transfer Protocol,缩写为HTTP),这个协议可以用来访问网络,这里我们要理解一下协议, 通常协议就是双方都需要遵守的规则,不同的协议有不同的约束,互联网中使用的这些协议也是一样,两台计算机之间通信,可以采用不同的协议(规则),都遵循同一种协议,才能完成某些事情,例如,我们常用的超文本传输协议(http)就是在网络访问的时候用的,ftp协议,文件传输用的协议,Telnet协议,远程连接用的协议等等,总之,你只要记住他们是一些都要遵守的规则就行了
2.2 域名/ip地址:互联网中ip地址就相当于门牌号,你想象一下你要给某个人寄快递,首先是不是应该知道对方的地址呢?ip地址的作用就是门牌号,ip地址的格式是这样的: 192.168.1.123 ,互联网上ip地址成千上万,如果让你去记住每个网站的ip地址,肯定是记不住的除非你是天才,因此,就有域名和ip的一种映射关系,你可以去注册一个域名,和你的电脑(服务器)ip地址绑定,例如:baidu.com <===> 119.75.217.109/,这样我们就不用记ip而只需要记住域名就可以访问一些常用网站了,这就是域名和ip的关系。
2.3 端口: 这里我们说的端口指的就是协议端口,如果把计算机看作是一栋房子,那么端口就是房子的门,一个IP地址的端口有65536(2的16次方)个,这些端口是通过端口号来标记的,范围是0~65535,既然我们把每个端口看作是房子的门,你可以想象一下,一栋政府的办公大楼里面,有各种各样的服务窗口,各种各样的科室,每个科室的智能不同,提供的服务也不同,那么同样的道理,计算机上的这些端口也对外提供服务,想要获得服务也必须找到正确的端口才行,例如:http服务的默认端口是80,ftp协议的默认端口是21,Telnet协议的默认端口是23,https协议的默认端口是443等等
2.4 文件路径/文件名: url的第四部分是你访问资源的文件路径和文件名,本质上说一个网站就是放在服务器上的文件夹和文件组成的,我们开发一个网站会有很多的目录和文件,里面有我们写好的各种功能,例如:我们在一台服务器(互联网上的远程电脑)上部署了我们开发出来的网站,实际上就是把我们开发的网站放到了特定的目录下,假如说这个目录是这样的:
我们要访问到这个目录下的图片文件怎么访问呢?我们假设这台服务器的域名就是http://nodeing.com, 那么意味着我们在浏览器中输入http://nodeing.com 这个地址的时候就能够访问到这个文件夹了,这个目录我们称为网站根目录,这个目录下 还有其他的目录和文件, 这个时候我们要访问图片的话我们需要 这样写: http://nodeing.com/img/html_logo.png, 在域名后面加的内容img/html_logo.png就是目录和文件的路径
2.5 查询字符串(url参数):当我们要想服务器发送数据请求的时候,我们可以把数据加在问号后面以一定的格式发送到后台,例如:http://nodeing.com/cloud/search?q=html, 其中q = html 表示发送到后台的数据,如果有多个url参数,则用&连接。
3.2.http模块是什么
通常一台电脑作为服务器,需要安装相应的服务器软件来提供服务,例如,常用的服务器软件有Aphche、Nginx、IIS,他们会响应前端的请求,根据不同的请求做不同的事情,而在node中你不需要单独去安装这些服务器软件,可以直接使用内置的http模块来实现简单的服务器,所以简单的说,http模块就是node内置的提供http服务的模块
3.3.创建一个http服务器
下面我们就创建一个http服务器程序来体验一下它到底是做什么的?
index.js文件中,写入下面代码:
//引入http模块
var http = require('http');
//创建一个服务实例
var app = http.createServer(function (req, res) {
res.write("hello world");
res.end();
});
// 设置监听端口
app.listen(3000);
接下来,在你的浏览器中输入,[http://localhost:3000](http://localhost:3000/)
查看效果
如果你不明白localhost怎么回事,别着急,我们下面深入的讲讲
1 当用户在浏览器输入网址的时候,首先会去查找本地的hosts文件,在这个文件中去看看有没有域名和ip地址的映射(对应关系)关系,如果有就直接访问这个ip地址对应的电脑,如果没有接着往下找 注意: window系统的本地hosts文件位置在 C:\Windows\System32\drivers\etc目录下 , mac系统本地hosts文件在 /etc 目录下 ,下面是hosts文件内容
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting. Do not change this entry.
##
127.0.0.1 localhost
255.255.255.255 broadcasthost
::1 localhost
# 后面的这些都是自己配置的
127.0.0.1 www.cdx.com
127.0.0.1 location.cdx.com
127.0.0.1 test.yii.com
127.0.0.1 admin.yii.com
从这个文件中我们发现有一个localhost名字对应着127.0.0.1,这就是域名和ip的对应关系,所以我们在浏览器中输入[http://localhsot:3000](http://localhsot:3000/)
就相当于我们输入了[http://127.0.0.1:3000](http://127.0.0.1:3000/)
, 这里的127.0.0.1比较特殊,它是本机的ip回环地址。
2 当这个本地的hosts文件中,并没有记录你访问的域名和ip的对应关系,那么就会去DNS服务器上找,DNS是域名解析系统,根据你的域名解析对应的ip地址,一般来说DNS配置正确,你访问的这个网站能正常提供服务,那么你输入域名都是能访问到网站的。
3.4.获取get方式的数据
1 根据请求,返回不同的页面
//引入http模块
var http = require('http');
//创建一个服务实例
var app = http.createServer(function (req, res) {
res.setHeader("content-type", "text/plain;charset=utf-8");
//req 表示请求对象 一些请求信息会放在这个对象下
//res 表示响应对象 一些响应的信息会放在这个对象下
//一次http请求 会有一次响应
//req.url记录了请求的路径,我们可以打印出来看看
console.log(req.url);
//根据不同的请求,做不同的事情
if(req.url === '/'){
res.write("欢迎来到网站首页");
res.end();
}else if(req.url === '/login'){
res.write("欢迎来到登录页面");
res.end();
}else if(req.url === '/register'){
res.write("欢迎来到注册页面");
res.end();
}else if(req.url === '/admin'){
res.write("欢迎来到后台管理页面");
res.end();
}else{
res.write("404 你找的页面飞了");
res.end();
}
});
// 设置监听端口
app.listen(3000);
2 返回一个html网页
index.html文件内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login" method="get" id="form">
用户名: <input type="text" name="username"/>
密码: <input type="text" name="password" />
<input type="submit" value="登录" id="btn">
</form>
</body>
</html>
index.js文件内容
//引入fs模块,用来处理文件
var fs = require('fs');
//引入http模块
var http = require('http');
//创建一个服务实例
var app = http.createServer(function (req, res) {
if(req.url === '/login'){
fs.readFile('./index.html', 'utf-8', function (err, data) {
res.setHeader("content-type", "text/html;charset=utf-8");
if(!err){
res.write(data);
res.end();
}
})
}
});
// 设置监听端口
app.listen(3000);
运行index.js文件,在浏览器输入<http://localhost:300/login>
查看效果
3 url模块和querystring模块的使用
//引入url模块, 把url字符串解析成对象
var url = require('url');
//url字符串
var url_str = 'http://nodeing.com/search/?q=html';
//url字符串被解析成了对象
var urlObj = url.parse(url_str);
console.log(urlObj);
//从对象中获取查询字符串 query: 'q=html',
var query_str = urlObj.query;
//把查询字符串解析成对象
// 引入queryString模块
var queryString = require('querystring');
var queryObj = queryString.parse(query_str)
console.log(queryObj);
//取出html字符串
console.log(queryObj.q)
4 修改表单提交路径,发送数据到后台并且把发送的数据打印出来
index.html需要修改的内容
//把原来action改为 /user_login
<form action="/user_login" method="get" id="form">
index.js中的内容
//引入fs模块,用来处理文件
var fs = require('fs');
// 引入url模块 可以把url解析成对象
var url = require('url');
// 引入querystring模块,可以把q=html这种查询字符串转换成对象
var queryString = require('querystring');
//引入http模块
var http = require('http');
//创建一个服务实例
var app = http.createServer(function (req, res) {
//用url模块,把请求的url解析成对象
var urlObj = url.parse(req.url);
//打印出来看看是啥?
console.log(urlObj);
if(urlObj.pathname === '/login'){
fs.readFile('./index.html', 'utf-8', function (err, data) {
res.setHeader("content-type", "text/html;charset=utf-8");
if(!err){
res.write(data);
res.end();
}
})
}
//如果请求的是 /user_login 就返回查询字符串
if(urlObj.pathname === '/user_login'){
//把这种格式 q=html 转换成 {q: 'html'}
var query_obj = queryString.parse(urlObj.query);
//打印出来
console.log(query_obj);
//返回查询字符串
res.write(urlObj.query);
res.end();
}
});
// 设置监听端口
app.listen(3000);
3.5.获取post方式的数据
post方式提交的数据,在后端获取的方式不一样,需要监听两个事件,data和end,当请求发送数据会触发data事件,当数据接收完成会触发end事件,具体代码如下
//引入fs模块,用来处理文件
var fs = require('fs');
// 引入url模块 可以把url解析成对象
var url = require('url');
// 引入querystring模块,可以把q=html这种查询字符串转换成对象
var queryString = require('querystring');
//引入http模块
var http = require('http');
//创建一个服务实例
var app = http.createServer(function (req, res) {
//用url模块,把请求的url解析成对象
var urlObj = url.parse(req.url);
//打印出来看看是啥?
console.log(urlObj);
if(urlObj.pathname === '/login'){
fs.readFile('./index.html', 'utf-8', function (err, data) {
res.setHeader("content-type", "text/html;charset=utf-8");
if(!err){
res.write(data);
res.end();
}
})
}
//如果请求的是 /user_login 就返回查询字符串
if(urlObj.pathname === '/user_login' && req.method === 'POST'){
var postData = '';
req.on('data', function (datachunk) {
postData += datachunk
});
req.on('end', function () {
//返回查询字符串
res.write(postData);
res.end();
});
}
});
// 设置监听端口
app.listen(3000);
注意: 你需要把index.html中到请求方式改成post
//把method 改成post
<form action="/user_login" method="post" id="form">
4.静态资源渲染
当我们访问一个文件,需要配置一个对应的路由去进行处理和渲染,但是当静态文件请求增多时,代码将变得很臃肿,显然,我们需要封装一个函数来自动进行处理。
我们可以把所有的静态文件模板都放到template文件夹中去,当收到一个url请求时,我们解析出pathname,然后根据template+pathname去自动拼接处文件路径,去进行自动渲染。
一般情况下当请求路径是"/"时,应该去渲染index.html文件,这是个特殊点,需要单独处理。
做出静态资源渲染的处理后,以下是app.js的代码
var http = require('http');
var url = require('url');
var app = http.createServer(function (req, res) {
// 解析url
var url_obj = url.parse(req.url);
// 拼接请求中的文件地址
var path = './template'+url_obj.pathname
// “/” 返回index.html页面
if(url_obj.pathname === "/"){
// 读取文件内容 返回
render("./template/index.html", res);
}
//请求哪个文件就返回哪个文件内容
render(path, res)
})
app.listen(3000)
//输入文件路径,返回给前端
function render(path,res){
fs.readFile(path, 'binary', function (err, data) {
if(!err){
res.write(data, "binary");
}
res.end();
})
}
3.用户注册实现
3.1.注册用户功能的实现逻辑
- 1 用户在表单上输入注册信息
- 2 点击注册后,收集用户在表单上输入的注册信息并且发送给后台
- 3 后台接收用户发送过来的注册信息
- 4 后台需要处理数据并且去连接数据库
-
5 后台把接收到的用户信息写入到数据库中
3.2.收集用户输入的信息并且发送这些信息到后台
在register.html文件中加入js代码
<script>
var oReg = document.getElementById('reg');
var oUser = document.getElementById('username');
var oPass = document.getElementById('password');
var oRePass = document.getElementById('repassword');
oReg.onclick = function () {
if(oPass.value !== oRePass.value){
alert('两次密码不一致,请重新输入')
return;
}
ajax({
method: 'post',
data: 'username='+oUser.value+'&password='+oPass.value+'&repassword='+oRePass.value,
url: '/register',
success: function (data) {
//后台返回数据 根据后台返回的数
if(data.status === 0){
window.location.href = '/login.html';
}else {
alert(data.message);
}
}
})
}
</script>
3.3.后台接收用户信息并且做处理
在index.js文件中加入js代码
if(url_obj.pathname === '/register' && req.method === 'POST'){
var user_info = '';
req.on('data',function (chunk) {
user_info+=chunk;
});
req.on('end', function (err) {
console.log(user_info);
res.setHeader('content-type', 'text/html;charset=utf-8');
var user_obj = queryString.parse(user_info);
//判断两次输入密码是否一致
if(user_obj.password !== user_obj.repassword ){
res.write('{"status":1, "message": "两次输入密码不一致"}', 'utf-8');
res.end();
return;
}
//判断用户名或者密码是否为空
if(user_obj.password == '' || user_obj.username == ''){
res.write('{"status":1, "message": "用户名和密码不能为空"}', 'utf-8');
res.end();
return;
}
});
return;
}
3.4.连接数据库并且实现数据保存
- 在连接数据库之前,需要先创建数据库,并且设计好对应的表,这里我们去数据库中创建一个ajaxdemo的数据库,并且在里面创建一张数据表,数据表的结构为:
id int primary key auto_crement
username varchar not null
password varchar not null
- 在indexjs文件头部引入mysql模块,并且连接数据库
mysql模块是一个第三方的模块,不是nodejs内置的模块,所以需要通过npm来安装
npm install mysql --save-dev
接下来就可以使用mysql模块了
//引入数据库模块 创建连接对象
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'root',
database : 'ajaxdemo'
});
connection.connect();
- 拼接mysql命令并且发送命令插入数据
if(!err){
var sql = 'INSERT INTO admin(username, password) VALUE("'+user_obj.username+'", "'+user_obj.password+'")';
connection.query(sql, function (error, result) {
if(!error && result.length !== 0) {
res.write('{"status":0, "message": "注册成功"}')
res.end();
}
});
}
- 完整的index.js文件注册逻辑代码
var http = require("http");
var url = require("url");
var fs = require("fs");
var querystring = require("querystring");
//引入数据库
var mysql = require('mysql');
//创建一个连接的到一个对象
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'root',
database: 'ajaxdemo'
});
//连接数据库
connection.connect(function(err) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
console.log('connected as id ' + connection.threadId);
});
var app = http.createServer(function (req, res) {
// 需求: 当用户访问 "/" 返回index.html 用户访问 /login-bak.html 返回login.html文件
var url_obj = url.parse(req.url);
//每次调用render 是根据请求的 url_obj.pathname 有一个pathname出现就会执行一次render
// pathname -- 用户的请求 ----> render
//1 "/" url_obj.pathname "/" render("./template"+ "/", res)
//2 "/css/index-bak.css" render("./template"+"/css/index-bak.css", res);
//3 "/login-bak.html" render("./template"+"/login-bak.html", res);
if(url_obj.pathname === "/"){
render("./template/index.html", res);
//直接返回 不会去执行后面的代码
return;
}
//处理注册功能逻辑
if(url_obj.pathname === "/register" && req.method === "POST"){
//1 接收前台发送过来的数据
var user_info = '';
req.on("data", function (chunk) {
user_info += chunk;
});
req.on("end", function (err) {
if(!err){
console.log(user_info);
var user_obj = querystring.parse(user_info);
res.setHeader('content-type', 'text/html;charset=utf-8');
//判断是否为空
if(user_obj.username === '' || user_obj.password === ''){
res.write('{"status":1, "message":"用户名和密码不能为空"}', 'utf-8');
res.end();
return;
}
//判断密码是否一致
if(user_obj.password !== user_obj.repassword){
res.write('{"status":1, "message":"两次密码输入不一样"}', 'utf-8');
res.end();
return;
}
// 把信息写入到数据库
console.log(user_obj);
var sql = 'INSERT INTO admin(username, password) VALUE("'+user_obj.username+'", "'+user_obj.password+'")';
connection.query(sql,function (error, result) {
//如果没有错误 并且result长度不为0 返回注册成功
// console.log("error:", error);
// console.log("result:", result);
// 如果没有出错 error 是null--false, result 是一个数组
// 如果出错 error有东西对象 !就变成false result --undifined
if(!error && result && result.length !== 0){
res.write('{"status":0, "message":"注册成功"}', 'utf-8');
res.end();
return;
}
})
}
})
// res.write('{"name":"hello world!"}');
// res.end();
return;
}
render("./template"+url_obj.pathname, res);
});
app.listen(5000, function (err) {
if(!err){
console.log("listening on 5000...");
}
})
function render(path, res) {
//binary 二进制
fs.readFile(path, 'binary', function (err, data) {
if(!err){
res.write(data, 'binary');
res.end();
}
})
}
3.5.前端根据后台返回的数据进行自己的业务逻辑处理
<script>
var oReg = document.getElementById('reg');
var oUser = document.getElementById('username');
var oPass = document.getElementById('password');
var oRePass = document.getElementById('repassword');
oReg.onclick = function () {
if(oPass.value !== oRePass.value){
alert('两次密码不一致,请重新输入');
return;
}
ajax({
method: 'post',
data: 'username='+oUser.value+'&password='+oPass.value+'&repassword='+oRePass.value,
url: '/register',
success: function (data) {
//data为后台返回数据 根据后台返回的数据做具体的业务逻辑
if(data.status === 0){
//如果没有错误就跳转到登录页让用户登录
window.location.href = '/login.html';
}else {
//如果注册失败就弹出对应的消息
alert(data.message);
}
}
})
}
</script>
4.用户登录实现
4.1.用户登录实现思路
- 1 用户输入登录信息,点击登录的时候把用户登录的这些信息收集起来,然后组装数据通过ajax方式发送到后台
- 2 后台接到用户输入的登录信息,把这些信息拿去和数据库中的数据做比对,如果成功返回成功信息,如果失败返回失败信息
- 3 后台返回信息给前台页面,在前台页面中做相应的逻辑处理
4.2.收集用户登录信息并且发送到后台
<script>
var oBtn = document.getElementById('btn');
var oPass = document.getElementById('password');
var oUser = document.getElementById('username');
oBtn.onclick = function () {
ajax({
method: 'post',
url: '/login',
data: 'username='+oUser.value+'&password='+oPass.value,
success: function (result) {
console.log(result)
}
})
}
</script>
4.3.接收用户登录信息和后台做比对
if(url_obj.pathname === '/login' && req.method === 'POST'){
var user_info = '';
req.on('data',function (chunk) {
user_info+=chunk;
});
req.on('end', function (err) {
res.setHeader('content-type', 'text/html;charset=utf-8');
var user_obj = queryString.parse(user_info);
if(!err){
var sql = 'SELECT * FROM admin WHERE username="'+user_obj.username+'" AND password="'+user_obj.password+'"';
connection.query(sql, function (error, result) {
if(!error && result.length !== 0) {
res.write('{"status":0, "message": "登录成功"}');
}else{
res.write('{"status":1, "message": "用户名或者密码不正确"}')
}
res.end();
});
}
})
return;
}
4.4.前端收到后台发送的信息,根据信息做具体业务处理
var oBtn = document.getElementById('btn');
var oPass = document.getElementById('password');
var oUser = document.getElementById('username');
oBtn.onclick = function () {
ajax({
method: 'post',
url: '/login',
data: 'username='+oUser.value+'&password='+oPass.value,
success: function (result) {
if (result.status === 0){
window.location.href = '/admin';
}else{
alert(result.message);
}
}
})
}
5.客户列表渲染
5.1.新建数据表
数据表user的规划字段如下:
id int primary key auto_increment,
username varchar(30) not null,
email varchar(30) not null,
phone char(11) not null,
qq char(11) not null
新建完成后手动添加几条数据
5.2.发送请求获取数据
在admin.html文件中发送ajax请求
<script>
//获取表格数据
ajax({
method: 'get',
url: '/list',
success: function (result) {
console.log(result)
}
});
</script>
5.3.后台接收请求,并从数据库中查询出数据,返回给前端页面
// 返回整个表格数据
if(url_obj.pathname === '/list' && req.method === 'GET'){
var sql = 'SELECT * FROM user';
connection.query(sql, function (error, result) {
if(!error && result){
res.setHeader('content-type','text/plain;charset=utf-8');
res.write(JSON.stringify(result));
res.end();
}else {
console.log(error)
}
})
return;
}
5.4.前端接收到后台返回的数据,生成表格
//获取表格数据
ajax({
method: 'get',
url: '/list',
success: function (result) {
for(var i=0; i<result.length;i++){
var oTr = document.createElement('tr');
for(var item in result[i]){
var oTd = document.createElement('td');
oTd.innerHTML = result[i][item];
oTr.appendChild(oTd);
}
var oP = document.createElement('td');
oP.innerHTML = '<button class="btn btn-primary ">修改</button>\n' +
'<button class="btn btn-danger">删除</button>';
oTr.appendChild(oP);
oTable.appendChild(oTr);
}
}
});
6.添加客户
6.1.点击添加按钮,弹出表单框
// 添加用户 显示对话框
var addBtn = document.getElementById('add-btn');
var addUser = document.getElementById('adduser');
addBtn.onclick = function () {
addUser.style.display = "block";
addUser.style.left = document.documentElement.clientWidth / 2 - addUser.offsetWidth / 2 + "px";
addUser.style.top = document.documentElement.clientHeight / 2 - addUser.offsetHeight / 2 + "px";
return false;
};
6.2.点击表单框上的保存按钮,发送数据到后台
// 点击保存
var saveBtn = document.getElementById('save-btn');
var cancelBtn = document.getElementById('cancel-btn');
saveBtn.onclick = function () {
var username = document.getElementById('username');
var email = document.getElementById('email');
var phone = document.getElementById('phone');
var qq = document.getElementById('qq');
ajax({
method: 'post',
url: '/adduser',
data: 'username='+username.value+"&email="+email.value+"&phone="+phone.value+"&qq="+qq.value,
success:function (result) {
console.log(result)
}
})
};
6.3.点击表单框上取消按钮,隐藏表单框
//点击取消 隐藏添加用户的对话框
cancelBtn.onclick = function () {
addUser.style.display = "none";
}
6.5.后台接收到前端发过去的数据,报数据写入数据库,并且返回结果给前端
// 添加数据
if(url_obj.pathname === '/adduser' && req.method === 'POST'){
var user_info = '';
req.on('data', function (chunk) {
user_info += chunk;
});
req.on('end', function (err) {
if(!err){
var user_obj = queryString.parse(user_info);
var sql = 'INSERT INTO user VALUE('+null+',"'+user_obj.username+'","'+user_obj.email+'", "'+user_obj.phone+'", "'+user_obj.qq+'")';
connection.query(sql, function (error, result) {
if(!error && result){
res.write('{"status":0,"message":"添加成功"}');
res.end();
}
})
}
})
return;
}
6.4.前端拿到后台返回的数据,做对应的逻辑处理
//点击保存
var saveBtn = document.getElementById('save-btn');
var cancelBtn = document.getElementById('cancel-btn');
saveBtn.onclick = function () {
var username = document.getElementById('username');
var email = document.getElementById('email');
var phone = document.getElementById('phone');
var qq = document.getElementById('qq');
ajax({
method: 'post',
url: '/adduser',
data: 'username='+username.value+"&email="+email.value+"&phone="+phone.value+"&qq="+qq.value,
success:function (result) {
if(result.status === 0){
addUser.style.display = "none";
alert(result.message);
window.location.reload();
}
}
})
};
7.编辑客户
编辑用户信息和添加用户非常相似,只是说编辑用户的时候多了一个数据回显的步骤
7.1.点击编辑弹出编辑框并且回显数据
var editUsername = document.getElementById('edit-username');
var editEmail = document.getElementById('edit-email');
var editPhone = document.getElementById('edit-phone');
var editQq = document.getElementById('edit-qq');
var editId = document.getElementById('edit-id');
oTable.onclick = function (ev) {
var ev = ev || event;
var aTd = ev.target.parentNode.parentNode.children
//如果点击的是修改 需要回显编辑框
if(ev.target.innerHTML === "修改"){
editUser.style.display = "block";
editUser.style.left = document.documentElement.clientWidth / 2 - editUser.offsetWidth / 2 + "px";
editUser.style.top = document.documentElement.clientHeight / 2 - editUser.offsetHeight / 2 + "px";
// 把当前行的数据显示到表单中
editUsername.value = aTd[1].innerHTML;
editEmail.value = aTd[2].innerHTML;
editPhone.value = aTd[3].innerHTML;
editQq.value = aTd[4].innerHTML;
editId.value = aTd[0].innerHTML;
}
};
7.2.点击保存发送数据,点击取消隐藏对话框
//点击编辑框中的保存 和 取消
var editSaveBtn=document.getElementById('edit-save-btn');
var editCancelBtn = document.getElementById('edit-cancel-btn');
//点击取消按钮的时候需要隐藏编辑框
editCancelBtn.onclick = function () {
editUser.style.display = "none";
}
//点击保存按钮的时候需要发送数据到后台
editSaveBtn.onclick = function () {
ajax({
method: 'post',
url: '/update',
data:'username='+editUsername.value+"&phone="+editPhone.value+"&email="+editEmail.value+"&qq="+editQq.value+"&id="+editId.value,
success: function (result) {
console.log(result)
}
})
}
7.3.后台接收数据并且更新数据库中的数据
在index.js中增加代码
// 修改数据
if(url_obj.pathname === '/update' && req.method === 'POST'){
var user_info = '';
req.on('data', function (chunk) {
user_info += chunk;
});
req.on('end', function (err) {
if(!err){
var user_obj = queryString.parse(user_info);
var sql = 'UPDATE user SET username="'+user_obj.username+'", email="'+user_obj.email+'",' +
' phone="'+user_obj.phone+'", qq="'+user_obj.qq+'" WHERE id='+Number(user_obj.id);
console.log(sql);
connection.query(sql, function (error, result) {
if(!error && result){
res.write('{"status":0,"message":"修改成功"}');
res.end();
}
})
}
})
return;
}
8.删除客户
8.1.发送id到后台
删除用户信息比较简单,只需要把对应行的id发送到后台就可以了
oTable.onclick = function (ev) {
var ev = ev || event;
var aTd = ev.target.parentNode.parentNode.children
// 点击删除按钮 删除对应的行
if(ev.target.innerHTML === "删除"){
ajax({
method: 'post',
url: '/delete',
data: 'id='+aTd[0].innerHTML,
success: function (result) {
if(result.status === 0){
alert('删除成功');
window.location.reload();
}
}
})
}
//如果点击的是修改 需要回显编辑框
if(ev.target.innerHTML === "修改"){
editUser.style.display = "block";
editUser.style.left = document.documentElement.clientWidth / 2 - editUser.offsetWidth / 2 + "px";
editUser.style.top = document.documentElement.clientHeight / 2 - editUser.offsetHeight / 2 + "px";
// 把当前行的数据显示到表单中
editUsername.value = aTd[1].innerHTML;
editEmail.value = aTd[2].innerHTML;
editPhone.value = aTd[3].innerHTML;
editQq.value = aTd[4].innerHTML;
editId.value = aTd[0].innerHTML;
}
};
8.2.后台接收数据并且删除数据库中符合条件的记录
// 删除数据
if(url_obj.pathname === '/delete' && req.method === 'POST'){
var user_info = '';
req.on('data', function (chunk) {
user_info += chunk;
});
req.on('end', function (err) {
if(!err){
var user_obj = queryString.parse(user_info);
var sql = 'DELETE FROM user WHERE id='+Number(user_obj.id);
connection.query(sql, function (error, result) {
if(!error && result){
res.write('{"status":0,"message":"删除成功"}');
res.end();
}
})
}
})
return;
}
9.退出登录
9.1.cookie
首先,我们要搞明白cookie是什么?Cookie 是在 HTTP 协议下,服务器或脚本可以维护客户工作站上信息的一种方式。Cookie 是由 Web 服务器保存在用户浏览器(客户端)上的小文本文件,它可以包含有关用户的信息。无论何时用户链接到服务器,Web 站点都可以访问 Cookie 信息
下面是cookie在用户登录中的应用
9.2.验证登录权限
在node中使用cookie,我们可以去安装一个cookie包,这个包中封装了一下方法方便我们设置和获取cookie,首先需要安装这个包
npm install cookie --save
在index.js文件中,"/login"这个路由判断内添加设置cookie的代码
//需要先在index.js头部引入cookie模块
var cookie = require("cookie")
// 在login返回数据前设置cookie
if(!error && result && result.length !== 0){
// 这里是新加的内容 返回一个是否登录的标识
res.setHeader('Set-Cookie', cookie.serialize('isLogin', "true"));
res.write('{"status":0, "message":"登录成功"}', 'utf-8');
res.end();
}else{
res.write('{"status":1, "message":"用户名或者密码错误"}', 'utf-8');
res.end();
}
接下来,需要新增一个渲染后台页面的路由,并根据cookie来决定是否渲染
//加载后台首页
if(url_obj.pathname === "/admin.html" && req.method === "GET"){
var cookie_obj = cookie.parse(req.headers.cookie || '')
if(cookie_obj.isLogin === "true"){
render("./template/admin.html", res);
}else {
render('./template/error.html', res);
}
return;
}
9.3.退出操作
//退出
if(url_obj.pathname === "/logout" && req.method === "GET"){
// 修改cookie中登录的标识
res.setHeader('Set-Cookie', cookie.serialize('isLogin', ""));
render("./template/index.html", res);
return
}