Node的介绍和基本使用(更新ing)
自己的有道云
一、什么是Node?
node是一个基于Chrome V8引擎的javascript运行环境,是运行在服务器端的javascript
可以使用node搭建服务器,连接数据库。让前端开发人员走向后端开发。
Node.js使用了一个事件驱动、非阻塞I/O口,使其轻量且高效
Node的包管理工具npm,是全球最大的开源库生态系统
二、为什么要学习node?
他很火
他很强
三、node的环境搭建参考笔记:
自己有道云
检测是否安装成功
四、交互式解析器
Node 自带了交互式解释器,可以执行以下任务:
读取 - 读取用户输入,解析输入了Javascript 数据结构并存储在内存中
执行 - 执行输入的数据结构
打印 - 输出结果
循环 - 循环操作以上步骤直到用户两次按下 ctrl-c 按钮退出
通过node命令进入交互式解析器
四、http模块创建服务
引入http模块
var http = require('http');
console.log(hhtp)
创建服务
/* 创建服务request请求 response响应*/
http.createServer(function(request,response){// writeHead设置响应请求头response.writeHead(200,{'content-type':'text/html;charset=utf-8'})//表示请求成功时设置能识别中文// end()响应请求 一个服务智能出现一个end,end后面的代码不执行response.end('<h1>hello world</h1>');//必须写end(),表示结束// listen监听端口号
}).listen(3000)//监听3000这个端口
设置响应请求头,并解决字符乱码
设置writeHead 响应请求头
参数一:http状态码 200 Ok
参数二:内容的类型text/plain 文本text/html html标记语言(建议使用)text/json json数据text/url-list url列表
response.writeHead(200,{'content-type':'text/html;charset=utf-8'})
response的方法
write() 写入数据到页面,可以重复使用,但不能放到end之后
end() 一个服务只能出现一次,且end后面的代码将不会被执行
4.1输出hello world例子
效果图
1.在node里面新建1.js文件
2.在1.js里面写下如下代码
// Node.js里面使用的是Common.js的语法 export导出 require导入
var http =require('http')
// console.log(http)/* 创建服务request请求 response响应*/
http.createServer(function(request,response){// writeHead设置响应请求头response.writeHead(200,{'content-type':'text/html;charset=utf-8'})//表示请求成功时设置能识别中文// end()响应请求 一个服务智能出现一个end,end后面的代码不执行response.end('<h1>hello world</h1>');//必须写end(),表示结束// listen监听端口号
}).listen(3000)//监听3000这个端口console.log('server is running at localhost:3000')
3.cmd里面进入node,并且输入node 1.js
4.浏览器打开localhost:3000
五、node中的阻塞和非阻塞
5.1阻塞
效果图
// 阻塞读取// 1.引入文件模块
var fs=require('fs')
// console.log(fs)// 阻塞代码 同步读取文件
// 2.使用
var data=fs.readFileSync('葵花宝典.txt')// 先执行
console.log(data.toString())// 后执行
console.log('读取完成.....,拿到内容后才执行我')
5.2非阻塞
效果图
// 非阻塞读取// 1.导入
var fs=require('fs')/* fs.readFile(path,callback)异步读取文件内容 data为异步读取的文件数据err为目录或路径写错*/
// 2.使用
fs.readFile('葵花宝典.txt',function(err,data){if(err){console.log(err)}else{console.log(data.toString())//toString() 将数据流转为字符串}
})console.log('我先执行')
六、事件循环
6.1介绍
Node.js 是单进程单线程应用程序,但是因为 V8 引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高。
Node的所有API都支持回调函数
Node.js 基本上所有的事件机制都是用设计模式中观察者模式
实现
事件的方法
on(event,listener) 为一个指定的事件注册监听器emit(event,[arg1],[arg2],[arg3]...)按监听器的顺序执行执行每个监听器addListener(event, listener)为指定事件添加一个监听器到监听器数组的尾部once(event,listener)为指定事件添加一个单次监听器removeListener(event,listener)移除指定事件的某一个监听器removeAllListeners(event)移除指定事件所有的监听器listeners(event)返回指定事件的监听器数组listenerCount(emitter,event)返回指定事件当前监听器的数量
语法:events.EventEmitter.listenerCount(emitter,event)setMaxListeners(n)设置最大的监听器个数 默认为10个
超过事件监听器的个数则报错如下
事件方法的例子
addListener
var event=require('events')var emitter=new event.EventEmitter();function listener1(){console.log('事件监听器1')
}function listener2(){console.log('事件监听器2')
}function listener3(){console.log('事件监听器3')
}
// 监听事件 addListener(eventName,listener)
// on和addListener的区别: on监听事件可以移除,addListener监听的事件可以移除,removeListener和removeAllListener移除事件监听
emitter.addListener('connect',listener1)
emitter.addListener('connect',listener2)emitter.emit('connect')
listeners(eventName)返回事件的数组
console.log(emitter.listeners('connect'))//[ [Function: listener1], [Function: listener2] ]
listenerCount(实例化对象,eventName)
var listenerNum=event.EventEmitter.listenerCount(emitter,'connect');
console.log(`监听器的数量${listenerNum}`)//2
removeListener(eventName,监听器名字)移除指定的单个监听器
emitter.removeListener('connect',listener2)
console.log(emitter.listeners('connect'))
removeAllListeners(eventName)移除所有的监听器
emitter.removeAllListeners('connect')
console.log(emitter.listeners('connect'))
6.2使用步骤
1、引入事件模块
var events=require('events');
2、创建一个eventEmitter对象
var emitter = new events.EventEmitter();
3、监听事件
eventEmitter.on(eventName,handler) 绑定事件,为该事件分配一个观察者
eventName为自定义的事件名 handler为触发事件时,执行的函数
4、触发事件
eventEmitter.emit(eventName,arg1,arg2...) 触发指定的自定义事件
6.3例子
效果图
// 1.引入事件event模块
var events=require('events');// 2.创建一个eventEmitter对象
var emitter = new events.EventEmitter();/* 3.emitter.on(eventName,eventHandler)监听事件 eventName为自定义事件名回调函数里面的参数为触发事件里面的内容*/
emitter.on('connect',function(a,b){console.log('服务器连接成功')console.log(a)console.log(b)
})// 4.emitter.emit(eventName,arg1,arg2,....)触发事件 eventName后面可以传入自定义参数
setTimeout(function(){emitter.emit('connect','张三','李四')
},1000)
6.4例子二
效果图
/*总结:on的执行是由于emit发生才执行*/// 1.引入事件event模块
var events=require('events');// 2.创建一个eventEmitter对象
var emitter = new events.EventEmitter();/* 3.emitter.on(eventName,eventHandler)监听事件 eventName为自定义事件名回调函数里面的参数为触发事件里面的内容eventEmitter的每个事件允许传入若干个参数*/
function listener1(){console.log('事件监听器1')
}function listener2(){console.log('事件监听器2')
}function listener3(){console.log('事件监听器3')
}function listener4(){console.log('事件监听器4')
}emitter.on('connect1',listener1)//事件监听器2
emitter.on('connect2',listener2)//事件监听器1emitter.on('connect3',listener3)//事件监听器3
emitter.on('connect3',listener4)//事件监听器4/* 注意:event事件的执行顺序跟其其触发的先后顺序有关event事件运行同一个事件名绑定多个监听器,且根据on的顺序依次触发*/emitter.emit('connect2')
emitter.emit('connect1')emitter.emit('connect3')
七、模块
7.1介绍
模块系统的作用主要体现在Node.js的文件的相互调用。模块系统是Node的基本组成部分,每一个Node.js文件则为一个模块常见的模块:http、fs、events、url、queryString
7.2使用步骤
1) 创建模块 导出的模块可以为函数、对象...
(2) 导出模块 exports module.exports
(3) 引入模块 require(属于Common.js的语法)
(4) 使用模块exports和module.exports的区别?exports是module.exports的抽象化代表,module.exports是exports的具体实现。
7.3例子
效果图
1.创建hello.js这个自定义模板和world.js
2.在world.js导入hello.js这个模板
调用对象里面的方法:
hello.hello()
7.4完整代码
hello.js
// 定义模块function hello(){console.log('hello 你好呀')
}// export.模块名 = 导出的内容
exports.hello = hello
world.js
// 导入自定义模块
var hello = require('./hello')// console.log(hello)hello.hello()
7.5自定义模块封装—实现学校有哪些班级
效果图
实现查询学校有哪些班级
1.文件目录
2.先写student.js
function add(studentName){console.log(`学生:${studentName}`)
}// add('张三')
exports.add = add
测试一下
3.teacher.js
function add(teacherName){console.log(`老师:${teacherName}`)
}// add('李四')
exports.add = add
测试一下
4.team.js
var student=require('./student')
var teacher=require('./teacher')function add(obj){// console.log(`班级名:${obj.team}`)teacher.add(obj.teacher)console.log(`班级:${obj.teamName}`)for(var i=0;i<obj.students.length;i++){student.add(obj.students[i])}console.log('==========================')
}// add({teamName:'前端',teacher:'吴老师',students:['鞠婧祎','诸绪丹','赵丽颖']})
exports.add =add;
测试一下
5.school.js
var team =require('./team')function add(obj){console.log(`学校名:${obj.school}`)for(var i=0;i<obj.teams.length;i++){team.add(obj.teams[i])}
}add({school:'文理',teams:[{teamName:'前端1',teacher:'吴老师',students:['鞠婧祎','赵丽颖','诸绪丹']},{teamName:'前端2',teacher:'吴老师2',students:['鞠婧祎2','赵丽颖2','诸绪丹2']}]})
测试一下
7.6url模块
7.6.1介绍
var url=require('url')
console.log(url)
console.log(url)的结果
7.6.2使用步骤
1.引入url
var url=require('url')
2.使用url的方法
7.6.3例子
1.parse重点
将字符串转为对象
/* // 2.使用parse*第一个参数写字符串*第二个参数表示query是否为对象:true->query变为对象 false->query变为字符串第三个参数是否需要识别无协议的网址, true->需要识别 false->不需要识别*/var url=require('url')
var str='http:www.taobao.com';
console.log(url.parse(str))
// 2.1parse有第二个参数
var str='https:www.jd.com:8080?name=aaa&pass=123'
var obj=url.parse(str,true)
console.log(obj)
console.log(obj.query.name)//aaa// 2.2parse()第三个参数 是否需要识别无协议的网址
2.format 将对象转为字符串
var url=require('url')var obj={protocol: 'http:',slashes: null,auth: null,host: null,port: null,hostname: null,hash: null,search: null,query: null,pathname: 'www.taobao.com',path: 'www.taobao.com',href: 'http:www.taobao.com'
}console.log(url.format(obj))//http:www.taobao.com
3.resolve() 将域名和路径拼接
var url=require('url')
var path=url.resolve('http://www.jd.com','login')
console.log(path)//http://www.jd.com/login
7.7querystring模块
7.7.1介绍
有以下方法
7.7.2escape例子
将中文编码
var str='鞠婧祎'
console.log(querystring.escape(str))//%E9%9E%A0%E5%A9%A7%E7%A5%8E
7.7.2unescape例子
将编码后的转换为中文
var str='%E9%9E%A0%E5%A9%A7%E7%A5%8E'
console.log(querystring.unescape(str))//鞠婧祎
7.7.3stringify例子
/* 3.stringify(obj,键值对的连接方式,键和值的连接方式,)序列化 将对象转为字符串第一个参数:对象第二个参数:默认为&第三个参数:默认为=*/var obj={name:'zhangsan',pass:123456
}console.log(querystring.stringify(obj))//name=zhangsan&pass=123456
7.7.4parse例子
parse(str,键值对的拆分方式,键和值的拆分方式)反序列化,将字符串转为对象
var str='name=zhangsan&pass=123456'
console.log(querystring.parse(str)) //{ name: 'zhangsan', pass: '123456' }
八、路由分配(封装的路由)
步骤
1.目录
2.写好四个页面
3.由于每次输入路径都要匹配对应页面,所以需要封装分配路由read.js
index.js
var fs=require('fs')function read(res,path){fs.readFile(path,function(err,data){if(err){var errpath='./views/error.html'//调用自己切换到错误页面read(res,errpath)}else{// 写在页面上res.write(data)res.end()}})
}exports.read = read
index.js
var http=require('http')
var url=require('url')
var fs=require('fs')
// console.log(http)// 导入切换页面的方法
var read=require('./read.js')
// console.log(read)// 设置首页路径
var index='./views/index.html'http.createServer(function(req,res){res.writeHead(200,{'content-type':'text/html;charset=utf-8'})// console.log(req.url)//// 解析req.urlvar reqpath=url.parse(req.url).pathname //在浏览器输入什么就是什么 例如输入/login,reqpath就是/login// console.log(reqpath)// 根据不同路径访问对应页面if(reqpath=='/favicon.ico'){return }else if(reqpath=='/'){console.log(reqpath)read.read(res,index)}// 切换到除了/和/favicon.ico的页面else{console.log(reqpath)var newpath=`./views${reqpath}.html`// console.log(newpath)read.read(res,newpath)}
}).listen(3000)
九、get/post
9.1、get传数据给后端
- 1.先写表单get.html
注意:input必须写name
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title></title></head><body><form action="http://localhost:3000" method="get">姓名:<input type="text" name="user"/>密码:<input type="password" name="pass"/><input type="submit" value="提交"/></form></body>
</html>
- 2.再写get.js
var http=require('http')
var url=require('url')
// console.log(http)http.createServer(function(req,res){// req.url拿到请求的路径及其参数// console.log(req.url) //?user=tianxu&pass=123// parse转为对象,query是对象里面的值console.log(url.parse(req.url,true).query) //'user=tianxu&pass=1213',res.writeHead(200,{'content-type':'text/html;charset=utf-8'})res.end()
}).listen(3000)
3.测试一下,在后端拿到了
9.2、post传值给后端
- 1.写post.html
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title></title></head><body><form action="http://localhost:3000" method="post">姓名:<input type="text" name="user"/>密码:<input type="password" name="pass"/><input type="submit" value="提交"/></form></body>
</html>
- 2.写post.js
var http=require('http')
var querystring=require('querystring')http.createServer(function(req,res){// 定义变量接收post传输的数据var post=''// data数据在有数据传输时,自定义触发// chunk为传输的数据流req.on('data',function(chunk){// console.log(chunk)//<Buffer 75 73 65 72 3d 74 69 61 6e 78 75 26 70 61 73 73 3d 31 31 31>post+=chunk// console.log(post)//user=12121&pass=21212})// end事件在数据传输完成后自动触发 req.on('end',function(){// 将传输的数据转为对象var data=querystring.parse(post)console.log(data)//{ user: 'tianxu', pass: '121212' }})res.writeHead(200,{'content-type':'text/html;charset=utf-8'})res.end()
}).listen(3000)
- 3.测试一下
十、递归读取文件
目录结构
效果图
思路:
1.按照目录结构写好
2.读取当前目录中的目录或则文件读出来这种[ 'index.js', 'js', 'read.js', 'views' ]
3.遍历这个数组先拼接地址/rou/index.js、/rou/js、/rou/views然后判断当前拼接的这个地址是否是文件是:直接输出否:继续递归
用到的方法:
1.fs.readdir():读取目录
2.fs.stat里面的isFile()检测是否为文件
read.js
var fs=require('fs')
function read(path){// 1.读取当前目录中的目录fs.readdir(path,function(err,files){if(err) return console.log(err)// console.log(files)//[ 'index.js', 'js', 'read.js', 'views' ]// 2.循环files得到每个文件路径files.forEach(function(file){// 2.拼接路径为./router/views这种var newPath=path+'/'+file;// console.log(newPath)// 3.检测当前的路径是否为文件,为文件则输出,否者继续读取fs.stat(newPath,function(err,stats){if(err) return console.log(err)if(stats.isFile()){// 该路径为文件console.log(newPath)}else{// 为文件夹/* 打开当前文件夹循环当前文件加内的文件判断是否为文件*/read(newPath)}})})})
}read('./rou')
十一、递归复制文件
思路
1.先创建建一个目录
2.若是文件,就读取文件,然后将读取的文件写入目标位置若不是文件,继续递归
用到的方法:
1.mkdir()创建目录
2.readdir()读取目录
3.readFile()读取文件
4.writeFile()写入文件
copy.js
var fs=require('fs')// dist为目标路径
function copy(path,dist){// 1.创建目录fs.mkdir(dist+path,function(err){if(err) return console.log(err)})// 1.读取当前目录中的目录fs.readdir(path,function(err,files){if(err) return console.log(err)// console.log(files)//[]// 2.循环files得到每个文件路径files.forEach(function(file){var newPath=path+'/'+file;// console.log(newPath)// 3.检测当前的路径是否为文件,为文件则输出,否者继续读取fs.stat(newPath,function(err,stats){if(err) return console.log(err)if(stats.isFile()){// 该路径为文件// console.log(newPath)// 读取文件fs.readFile(newPath,function(err,data){// console.log(dist+newPath)// 将读取的内容复制一份fs.writeFile(dist+newPath,data,function(err){if(err) return console.log(err)})})}else{// 为文件夹/* 打开当前文件夹循环当前文件加内的文件判断是否为文件*/copy(newPath,dist)}})})})
}copy('./rou','../../')
十二、递归删除文件
思路:(必须同步,因为不能保证谁先执行)
1.是文件就直接删除了
2.最后删除文件夹
delSync.js
/* 同步:因为这里要保证先删除文件,才能删除文件夹*/var fs=require('fs')function deleteDir(path){// 1.读取目录var files=fs.readdirSync(path)console.log(files)// 遍历文件夹或则文件files.forEach(function(file){// 判断当前文件是否为文件类型var newPath=path+'/'+filevar stats=fs.statSync(newPath)// console.log(file,stats.isFile())if(stats.isFile()){// 为是文件// 直接删除文件fs.unlinkSync(newPath)}else{// 为文件夹deleteDir(newPath)}})// 删除文件夹 rmdirSync只能删除空文件夹// console.log(path)fs.rmdirSync(path)
}deleteDir('../../rou')
十三、express框架(后面的笔记都需要express框架
)
13.1、express简介
Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具。
使用 Express 可以快速地搭建一个完整功能的网站
13.2、express框架的核心特性
- 可以设置中间件来响应 HTTP 请求。
- 定义了路由表用于执行不同的 HTTP 请求动作。
- 可以通过向模板传递参数来动态渲染 HTML 页面。
13.3、express的安装
1、安装前确认是否正确安装node,以及npm(包管理工具)
2、安装express
局部安装 npm install --save express
全局安装 npm install -g express (这里用全局)
3、安装所需要的模块(中间件)
- body-parser - node.js 中间件,用于处理
JSON, Raw, Text 和 URL 编码的数据
。 - cookie-parser -
这就是一个解析Cookie
的工具。通过req.cookies可以取到传过来的cookie,并把它们转成对象。 - multer - node.js 中间件,用于处理
enctype="multipart/form-data"
(设置表单的MIME编码)的表单数据。
安装body-parser
npm install -g body-parser
安装cookie-parser
npm install -g cookie-parser
安装multer
npm install -g multer
4、安装express脚手架工具 express-generator
npm install -g express-generator
此时多了这个
查看当前express的版本
npm list express
查看express是否安装成功
13.4、express创建项目
1.创建
express 项目名; //初始化express项目
2.进入创建的项目,并安装依赖
cd 项目名
npm install
此时多了这个
3.启动项目
npm start
4.打开浏览器访问:http://localhost:3000/
13.5、目录结构
bin--www node的服务的创建
node_modules 中间件
public 公共文件--images 项目的图片--javascripts 项目的js代码--stylesheets 项目的css代码
routes 路由--index.js index首页的路由配置
views 静态页面--index.jade
app.js node的主程序
package.json 配置文件
13.6、配置信息意思
routes种路由的配置
www文件
app.js
13.7、输入路径匹配页面
思路
1.先在routes里面写login.js
2.在app.js引入路由并且使用路由
3.在views里面写login.jade
十四、模板引擎的使用
常见的模板引擎有html ejs jade
14.1、jade模板引擎
jade在线转换工具
1、标签名不变,无需使用<>围绕
2、标签不具有嵌套性,使用缩进来表示嵌套关系
3、使用标签名后#id来表示id属性,不需要使用属性名 id='id值'
4、使用标签名后.class来表示class属性,多个class可以连续使用
5、对带有id或者class属性的div标签,可以省略div不写
6、对于除了class和id属性外,在标签名后面使用括号()编写,
与html的标签的属性使用方式相同,也可以使用逗号分隔
7、在标签名称和所有属性后使用一个空格来分割文本内容,也就是说每个标签名和属性后的第一个空格的内容都会被识别为文本内容
8、对于多行文本,标签的所有属性之后使用单独的'|',其下级的缩进内容都将视为文本
使用标签名后#id来表示id属性
使用标签名后.class来表示class属性,多个class可以连续使用
对于除了class和id属性外,在标签名后面使用括号()编写,
在标签名称和所有属性后使用一个空格来分割文本内容,
对于多行文本,标签的所有属性之后使用单独的’|’,其下级的缩进内容都将视为文本
关于js的写法
jade解析变量
1、标签内为变量则直接使用标签名紧跟'=',再写上变量名h1= 变量名
2、文本内需要拼接变量则使用#{变量名}的写法
p Welcome to #{变量名}
14.2、ejs模板引擎
14.2.1、ejs的语法
<%=变量%> 输出内容
<%js代码%> 输出Js代码
传值并显示的例子
index.js
var express = require('express');
var router = express.Router();/* GET home page. */
// '/'代表子路由 ,默认写'/' 可以写'/add'
router.get('/', function(req, res, next) {// res.render渲染页面,index为页面的名字 { title: 'Express' }传值过去res.render('index', { title: 'Express' ,students:['张三','李四']});
});// 将路由导出
module.exports = router;
页面
<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title></title>
</head>
<body><ul><%for(var i=0;i<student.length;i++){%><li><%=student[i]%></li><%}%></ul>
</body>
</html>
14.2.2、node中ejs的使用
效果图
1、安装ejs中间件
npm install ejs --save-dev
2、在app.js中引入ejs
// 引入ejs
var ejs=require('ejs')
3、在app.js修改模板引擎
// 修改模板引擎
app.engine('ejs',ejs.__express);
app.set('view engine','ejs')
4、在views下新建ejs后缀的页面
ejs.ejs
注意
:views下面页面的文件后缀
必须保证和设置的模板引擎的后缀一致
出现以下报错的多个原因
原因一
:页面后缀名与模板引擎不一样
原因二
:没有传参数,在页面上使用参数
<%=tiele%>
原因三
:页面上不能写注释
原因四
:多个路由跳转到同一个页面,必须两个路由都写传值
原因五
:表单中的method和后端的接收方式必须对应
<%=变量%>
<--<%=变量%>-->
14.3、html模板引擎
1、安装ejs中间件
npm install ejs --save-dev
2、在app.js中引入ejs
3、修改模板引擎
4、在views下新建html后缀的页面,重新访问http://localhost:3000
十五、模板引擎中静态资源的使用
express项目中,所有的静态资源文件都放置在public文件夹内
在app.js
内定义了静态资源文件在public文件夹内
15.1、模板内使用images
引入图片
注意:使用图片可以直接访问images文件夹,express会自动读取public文件
在css文件内引入背景图片
,仍然需要使用相对路径查找
15.2、模板内使用stylesheets
15.3、模板内使用javascripts
十六、express中路由的使用
16.1 路由使用的基本步骤
(1)在routes内定义路由文件,使用module.exports将路由进行导出(暴露)
(2)在app.js内引入routes导出的模块(.js的文件后缀可以省略)
(3)在app.js内分配路径所对应的路由
(4)在views内新建前端页面(注意文件后缀必须和模板引擎相同)
(5)启动项目,进入‘/login’路径则显示该静态页面
十七、路由请求(也叫发送给后端
)
重点:form的action的值为app父路由拼接上子路由
17.1、路由的get请求
通过req.url
获取get请求的信息
get传递的传输在query属性内,需要使用到url模块内的parse方法,进行获取get传递的参数
var data=url.parse(req.url,true).queryconsole.log(data)
例子
效果图
get.ejs
<form action="/get" method="get">姓名:<input type="text" name="user"/><br>密码:<input type="password" name="pass"/><input type="submit" value="提交"/>
</form>
get.js
var express = require('express');
var router = express.Router();var url=require('url')// 接收/get路径的数据
router.get('/', function(req, res, next) {// console.log(req.url)var data=url.parse(req.url,true).queryconsole.log(data)res.render('get');
});// 将路由导出
module.exports = router;
17.2、路由的post请求(推荐用
)
因为post在标题栏看不到用户信息
通过req.body
获取post请求的数据
例子
post.js
var express = require('express');
var router = express.Router();var url=require('url')// 接收/get路径的数据
router.post('/', function(req, res, next) {console.log(req.body)res.render('get',{user:req.body.user,pass:req.body.pass});
});// 将路由导出
module.exports = router;
post.ejs
<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title></title>
</head>
<body><form action="/get" method="post">姓名:<input type="text" name="user" value="<%=user%>"/><br>密码:<input type="password" name="pass" value="<%=pass%>"/><input type="submit" value="提交"/></form>
</body>
</html>
17.3、子路由的设置
跳转到该路由的路径为/login/add
例子
子路由页面
<form action="/get/add" method="post">姓名:<input type="text" name="user"/><br>密码:<input type="password" name="pass"/><input type="submit" value="提交"/>
</form>
get.js
// 接收/get/add的数据
router.post('/add', function(req, res, next) {console.log(req.body)// res.render('get',{user:req.body.user,pass:req.body.pass});
});
17.4 、动态路由的设置
在路由路径上设置动态参数‘/:
动态参数’,通过req.params
获取动态传参
例子
效果图
post.js
var express = require('express');
var router = express.Router();var url=require('url')// 接收/get路径的数据
router.get('/', function(req, res, next) {// console.log(req.url)var data=url.parse(req.url,true).queryconsole.log(data)res.render('get');
});router.post('/:id', function(req, res, next) {console.log(req.body)console.log(req.params)// res.render('get',{user:req.body.user,pass:req.body.pass});
});// 将路由导出
module.exports = router;
post.ejs
<form action="/get/1" method="post">姓名:<input type="text" name="user"/><br>密码:<input type="password" name="pass"/><input type="submit" value="提交"/></form>
17.5、路由的响应
res.send() 发送数据到页面
res.render(views,数据) 渲染页面,并将数据传递到页面
res.redirect() 重定向(跳转路由)
十八、模拟查询数据库判断注册账号是否存在
18.1、ajax异步验证手机号是否被注册(这里没有连数据库,后面加)
需求,在注册页表单失焦的时候进行正则验证并且异步请求后端看该数据有没有在数据库中存在相同的数据
效果图
- 1.正则验证
$(function(){$('input[name="username"]').blur(function(){console.log($(this).val())// 进行正则验证var pattern=/^1[3-9]\d{9}$/;// 手机号不为空if($(this).val()){// 手机号符合规范 这里需要把手机号发送给后端,后端查询数据库,把结果返回来,前端判断if(pattern.test($(this).val())){$(this).css({'color':'#ccc',});$(this).parent().css({'border':'solid 1px #ccc',});$(this).parent().next().children('span').html('手机号码不能为空');$(this).parent().next().hide();}else{// 手机号不符合正则规范$(this).css({'color':'red',});$(this).parent().css({'border':'solid 1px red',});$(this).parent().next().children('span').html('手机号码不符合规范,请仔细检查');$(this).parent().next().show();}}else{// 手机号码为空$(this).css({'color':'red',});$(this).parent().css({'border':'solid 1px red',});$(this).parent().next().children('span').html('手机号码不能为空');$(this).parent().next().show();}})
})
前端页面
<form action="/register" method="post"> <div class="form_text_ipt"><input name="username" type="text" placeholder="手机号"></div><div class="ececk_warning"><span>手机号/邮箱不能为空</span></div><div class="form_text_ipt"><input name="password" type="password" placeholder="密码"></div><div class="ececk_warning"><span>密码不能为空</span></div><div class="form_text_ipt"><input name="repassword" type="password" placeholder="重复密码"></div><div class="ececk_warning"><span>密码不能为空</span></div><!-- <div class="form_text_ipt"><input name="code" type="text" placeholder="验证码"></div> --><div class="ececk_warning"><span>验证码不能为空</span></div><div class="form_btn"><button type="button" onclick="javascript:window.location.href='/'">注册</button></div><!-- <input type="submit" value="提交"> --><div class="form_reg_btn"><span>已有帐号?</span><a href="/">马上登录</a></div>
</form>
测试一下:此时能简单的判断手机号是否符合规则和是否为空等
- 2.此时需要加入ajax和后台判断是否有相同的手机号
思路
必须在手机号符合规范后
把前端的值发送给后端,后端拿到值连接数据库并查询是否存在,若存在,通过send()方法返回给前端,前端把拿到的值拿来判断是否存在 - 3.在register.js增加
ajax
请求
$(function(){$('input[name="username"]').blur(function(){console.log($(this).val())// 进行正则验证var pattern=/^1[3-9]\d{9}$/;// 手机号不为空if($(this).val()){// 手机号符合规范 这里需要把手机号发送给后端,后端查询数据库,把结果返回来,前端判断if(pattern.test($(this).val())){$(this).css({'color':'#ccc',});$(this).parent().css({'border':'solid 1px #ccc',});$(this).parent().next().children('span').html('手机号码不能为空');$(this).parent().next().hide();// 查看当前手机号是否已经被注册 ajax异步提交手机号到后端,通过查询数据库验证手机号是否已存在$.ajax({url:'/register/selectUser',type:'post',data:{username:$(this).val()},success:(data)=>{// 根据后端返回的数据确定账号是否被注册 1默认为已注册 2为未注册console.log(data)// 已被注册if(data=='1'){$(this).css({'color':'red',});$(this).parent().css({'border':'solid 1px red',});$(this).parent().next().children('span').html('手机号码已被注册');$(this).parent().next().show();}else if(data == '2'){$(this).css({'color':'#ccc',});$(this).parent().css({'border':'solid 1px #ccc',});$(this).parent().next().children('span').html('手机号码不能为空');$(this).parent().next().hide();}}})}else{// 手机号不符合正则规范$(this).css({'color':'red',});$(this).parent().css({'border':'solid 1px red',});$(this).parent().next().children('span').html('手机号码不符合规范,请仔细检查');$(this).parent().next().show();}}else{// 手机号码为空$(this).css({'color':'red',});$(this).parent().css({'border':'solid 1px red',});$(this).parent().next().children('span').html('手机号码不能为空');$(this).parent().next().show();}})
})
配置后端
var express = require('express');
var router = express.Router();/* GET users listing. */
router.get('/', function(req, res, next) {res.render('register', { title: 'Express' });
});router.post('/selectUser', function(req, res, next) {// console.log(req.body)//获取前端当前需要注册的用户名var username=req.body.usernameconsole.log(username)// 连接数据库查询该用户名是否已经存在// res。send()发送数据到前端, 只要后端有输出 则为ajax请求成功的返回值if(true){res.send('1')}else{res.send('2')}
});module.exports = router;
测试一下:后端拿到值了
前端也拿到了后端的返回值
前端显示已被注册
18.2、Node.js连接mysql数据库
前期准备
1.安装数据库
mysql数据库安装参考网址
2.安装好了插入一条数据
先打开数据库
创建数据库
创建user表(这里我是在navicat.exe图形化创建,当然也可以使用命令行创建)
在命令框里面也能查到
3.项目连接数据库
1.在项目中安装mysql模块
npm install mysql
此时配置文件有了
2.引入mysql
var mysql = require('mysql');
3.创建mysql的连接(配置连接数据库的基本信息)
var connection = mysql.createConnection({host:'主机名',//localhostuser:'用户名',//用户名password:'密码',//自己设置的密码database:'数据库名'
})
4.连接数据库
connection.connect();
4.连接好了就可以增删改查了
node.js菜鸟的增删查改语法
注意
无论是增删查改,只需要更改sql语句就行了,其它地方配好了就不变
查询数据
1.新建select.js
select.js代码
// 引入mysql
var mysql = require('mysql'); // 创建mysql的连接(配置连接数据库的基本信息)
var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : 'root', //自己设置的密码 port: '3306', database: 'h5' //数据库名
}); // 连接数据库
connection.connect();var sql = 'SELECT * FROM user';
//执行sql语句
connection.query(sql,function(err,result){if(err) return console.error(err)console.log(result)
})connection.end();
2。运行select.js
插入数据
1.新建insert.js
insert.js
记得把id写为null,为了自增
// 引入mysql
var mysql = require('mysql'); // 创建mysql的连接(配置连接数据库的基本信息)
var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : 'root', //自己设置的密码 port: '3306', database: 'h5' //数据库名
}); // 连接数据库
connection.connect();var addSql = 'insert into user VALUES(null,?,?)';
var addSqlParams = ['18812346789','456789'];
//执行sql语句
connection.query(addSql,addSqlParams,function (err, result) {if(err) return console.log(err)console.log(result)
});connection.end();
测试一下
更新数据
注意
:
1.删除前端点击的那个目标时,需要用数组里面的值
来代替?
2.data数组的值与?一一
对应
//把15123341778的密码改为3
var data=[3,'15123341778']
var sql="update 表名 set pass=? where id=?"
update.js
// 引入mysql
var mysql = require('mysql'); // 创建mysql的连接(配置连接数据库的基本信息)
var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : 'root', //自己设置的密码 port: '3306', database: 'h5' //数据库名
}); // 连接数据库
connection.connect();var modSql = 'update user set pass =? where id=?';
var modSqlParams = ['111','2'];
//
connection.query(modSql,modSqlParams,function (err, result) {if(err) return console.log(err)console.log(result)
});connection.end();
测试一下
删除数据
注意
:
1.删除前端点击的那个目标时,需要用数组里面的值
来代替?
2.data数组的值与?一一
对应
//删除id=3的数据
var data=[3]
var sql="delect from 表名 where id=?"
delete.js
// 引入mysql
var mysql = require('mysql'); // 创建mysql的连接(配置连接数据库的基本信息)
var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : 'root', //自己设置的密码 port: '3306', database: 'h5' //数据库名
}); // 连接数据库
connection.connect();var Sql = 'delete from user where id=?';
var SqlParams = ['2'];
//执行sql语句
connection.query(Sql,SqlParams,function (err, result) {if(err) return console.log(err)console.log(result)
});connection.end();
测试一下
18.3、mysql+node实现注册功能(接着18.1
)
学了18.2就能实现这个功能了
经验:前端人员需要注意这个
需求
1.失焦时,查询电话号码是否存在,若存在,显示已被注册
2.当电话号码、密码、确认密码全部通过才能注册到数据库
步骤
1.给项目安装数据库
2.实现需求一
1.更改register.html为如下,这样才能提交数据过去
2.修改register.js
思路
:把前端输入的手机号码传到后端,后端拿这个值查询数据,若返回的是空数组
,则没注册,否者为注册了的
注意
result为数组 若长度为0,没有注册,长度不为0,为注册了
register.js
var express = require('express');
var router = express.Router();/* GET users listing. */
router.get('/', function(req, res, next) {res.render('register');
});// 检测电话号码是否被注册
router.post('/selectUser', function(req, res, next) {// console.log(req.body)//获取前端当前需要注册的用户名var username=req.body.usernameconsole.log(username)// 连接数据库查询该用户名是否已经存在// 引入mysqlvar mysql = require('mysql'); // 创建mysql的连接(配置连接数据库的基本信息)var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : 'root', //自己设置的密码 port: '3306', database: 'h5' //数据库名}); // 连接数据库connection.connect();var sql = 'SELECT * FROM user where username=?';var sqlparams=[username]//查connection.query(sql,sqlparams,function (err, result) {if(err) return console.log(err)// result为数组 若长度为0,没有注册,长度不为0,为注册了// console.log(result)// res.send()发送数据到前端, 只要后端有输出 则为ajax请求成功的返回值if(result.length){// 注册了res.send('1')}else{//没注册res.send('2')}});connection.end();
});
module.exports = router;
此时效果图
- 3.实现需求二
为了全部正确才能跳转,在register.js中设置三个值全为false
接下来就是全部正确后通过ajax发送数据给后台,后台拿到值后写进数据库 - 4.总结:
1)实现手机号通过,对应的flag为true的情况只能是在未被注册时
,而为false:不满足条件赋值为true
2)第二次密码不需要写正则,只判断是否与密码相等
3)实现手机号、密码、确认密码全部通过后点击注册才能有用更简单的写法
4)ajax请求和点击事件会冲突,即提交表单的时候用submit,不用ajax
18.4、mysql+node+express实现登录功能
前期准备 安装了mysql node express
效果图
功能需求
点击登录后,如果输入的信息与数据库不匹配,不会跳转到登录成功界面,否者,跳转到登录成功页面
思路:再表单里面把手机号、密码传到后端,后端根据手机号查询数据库,然后比较传过去的密码和查出来的密码,若相同,渲染页面,否者,重定向到登录页
步骤
1.更改form表单的action和提交方式
2.因为action指向的/loginsuccess,所以需要再routes新建/loginsuccess,然后引入app.js,再app.js使用
3.先在loginsuccess.js里面写让页面渲染
var express = require('express');
var router = express.Router();/* GET home page. */
router.get('/', function(req, res, next) {res.render('loginsuccess');
});router.post('/', function(req, res, next) {//res.render渲染页面res.render('loginsuccess')
});module.exports = router;
- 4.上一步过后就可以连接数据库了,然后查找输入的手机号对应的密码,并比较两个密码,一样就渲染页面
总结
1)自己第一次写这个功能,经验不足,反应慢
2)ajax请求要在局部刷新的时候用,当有表单的时候,一般提交给action的路径,不要用ajax
18.5、连接Mongodb
十九、前后端交互总结
19.1、当在表单中
前端传值通过action
后端通过res.body接收
后端传值给前端,通过对象
前端接收后端的值
<%=变量%>
19.2、ajax中
前端传给后端
后端通过res.body取得值
传给前端和前端接受值与19.1一样
19.3、路径问题
action的路径与ajax中的url都是父路由拼接子路由
Node的介绍和基本使用(更新ing)相关推荐
- CSAPP期末复习(更新ing)
CSAPP期末快速复习(更新ing) 本人有关CSAPP的博客链接: 私人博客 CSDN 内容基本上差不多 主要内容 概论 信息的表示 机器级的表示 链接 I/O 概论 上下文:上下文是一个状态,包含 ...
- Effective C++ 中文版(第三版)读书笔记 更新ing~
Effective C++ 中文版(第三版)持续更新ing 让自己习惯C++ 条款1 视c++为一个联邦 条款2 尽量以const,enum,inline替换#define 条款3 尽可能使用cons ...
- 【树模型与集成学习】(task2)代码实现CART树(更新ing)
学习心得 task2学习GYH大佬的回归CART树,并在此基础上改为分类CART树. 更新ing.. 这里做一些对决策树分裂依据更深入的思考引导:我们在task1证明离散变量信息增益非负时曾提到,信息 ...
- 北邮oj题库刷题计划(更新ing)
北邮oj题库刷题计划(更新ing) 83. A + B Problem 84 Single Number 85. Three Points On A Line 120 日期 121 最值问题 122 ...
- 自然语言处理数据集集锦(持续更新ing...)
诸神缄默不语-个人CSDN博文目录 最近更新时间:2023.6.27 最早更新时间:2023.4.25 文本摘要主题的数据集见我之前写的另一篇博文:文本摘要数据集的整理.总结及介绍(持续更新ing-) ...
- 适合入门自学服装裁剪滴书(更新ing)
适合入门自学服装裁剪滴书(更新ing) [♣]适合入门自学服装裁剪滴书(更新ing) [♣]适合入门自学服装裁剪滴书(更新ing) 适合入门自学服装裁剪滴书(更新ing) 来自: 裁缝阿普(不为良匠, ...
- 常用数据集整理(持续更新ing)
常用数据集整理(持续更新ing) 在做实验过程中经常用到的数据集整理一下,按照学习过程中遇到的数据集的先后顺序进行整理,希望能对科研有所帮助.本博文将随着学习过程持续性更新,有其他常用数据集的 ...
- Altium Designer(AD)使用技巧总结(更新ing)
Altium Designer 作为一款PCB绘制软件,凭借其简单易上手.功能强大等优点深受硬件工程师们的喜爱,作为一位AD初学者对AD中的功能进行一下总结(当然不是全部介绍,根据我学到的进行整理), ...
- 重拾CCNA,学习笔记持续更新ing......(4)
重拾CCNA,学习笔记持续更新ing......(4) 路由器作用功能的经典解说(笑)(非原创) 假设你的名字叫小不点,你住在一个大院子里,你的邻居有很多小伙伴,在门口传达室还有个看大门的李大爷,李大 ...
最新文章
- 第15届全国大学生智能汽车竞赛 人工智能挑战赛(百度)
- 用 Celery 实现邮件推送系统
- 企业如何测试邮件系统反垃圾反病毒的实际效果
- 聚类(序)——监督学习与无监督学习
- Java非访问修饰符
- 理解MySQL——复制(Replication)
- 赛码网算法: 上台阶 ( python3实现 、c实现)
- redis key设计技巧
- python移动平均线绘图_对python pandas 画移动平均线的方法详解
- java mvc 注解_Spring MVC注解开发入门
- Safari导入Chrome书签
- linux创建表空间 没有权限,ORA-12913: 无法创建字典管理的表空间
- 【已解决】戴尔笔记本电脑的卡顿问题.
- Skyline软件二次开发初级——11如何在WEB页面中的三维地图上加载和保存工程文件...
- 基于单片机智能交通灯控制系统设计外文文献_三种典型的微机控制系统
- Ubuntu 14.04解决minidwep-gtk无法启动问题
- 程序员才看得懂的祝福语(程序员送祝福啦)
- 解决微信公众号发布新的版本H5页面有缓存的问题
- 教资报名照片怎么弄成200k?照片大小怎么改到200k?
- 补色的视觉原理(转)
热门文章
- python:最大公约数和最小公倍数
- plex实现流媒体服务器_如何在Plex Media Center上使用自定义媒体插图
- 达观资讯推荐系统助力打造更懂用户的新闻客户端
- python pycrypto_Python PyCrypto,Paramiko模块安装和使用
- 七问“互联网+保险”:竞争力、核心价值何在?
- 红酒数据集分析(纯数字数据集)
- 【YOLOV5-6.x讲解】数据增强方式介绍+代码实现
- 非参数检验之K-S检验
- 【状态估计】电力系统状态估计中的异常检测与分类(Matlab代码实现)
- 认知功能神经网络模型的生物学约束