一、了解Node.js
- Node.js 是一个基于Chrome V8引擎的JavaScript 运行时环境,在这个环境下可以执行JS代码(Node.js并不是一种语言也不是框架,而是一个可以运行JS文件的平台。就像是在Windows系统中运行一个exe程序,Windows系统为exe程序的运行提供各种支持,JS文件就相当于这个exe,Node.js就相当于Windows系统)。
- Node.js提供了大量的工具(API),能够让我们完成文件读写、Web服务器创建等功能。
1.nodejs和浏览器的关系:
相同之处:
- 都可以运行js(严格来讲是ECMAScript)代码
不同之处:
- 安装了浏览器(Broswer)这个软件,它不但可以执行ECMAScript,浏览器这个软件内置了window对象,所以浏览器有处理DOM和BOM的能力。
- 安装了NodeJs这个软件,它不但可以执行ECMAScript,NodeJS这个软件也内置了一些东西,包括全局成员和模块系统,同时还可以载入第三方模块来完成更强大的功能,但是NodeJs里没有DOM和BOM,没有图形界面一些可视化的东西。
2.学习node的意义
-
大前端必备技能
-
使得JS能够和操作系统 “互动” (读取文件,写入文件等,管理进程)
-
为JavaScript提供了服务端编程的能力
-
文件IO
-
网络IO
-
数据库
-
-
了解接口开发,进一步理解Web开发,了解后端同学的工作内容
二、Node的模块化
1.介绍Node的模块化
在项目的开发过程中,随着功能的不断增强,代码量、文件数量也急剧增加,我们需要把一个大函数拆成小函数,把一个大文件拆成小文件,把一个大功能拆成若干个小功能。这里很自然地就涉及到模块化的想法:一个复杂的系统分成几个子系统,体现在几个小的文件在一起组成一个大的文件,集成强大的功能。
遗憾的是es5不支持模块化:就是在一个js文件内不能引入其他js文件。不能通过一个大文件去集成若干个小文件。(不是说一个html文件中不能包含多个js文件)。这样就会带来多个问题:文件的加载先后顺序,不同的文件内部定义的变量共享。
2.nodejs模块的分类
核心模块、自定义模块、第三方模块
2.1nodemon
nodemon是一种批处理的工具,可以自动检测到目录中的文件更改时通过重新启动应用程序来调试基于node.js的应用程序。
- 安装
npm i -g nodemon i指的是install -g代表全局安装
- 使用
nodemon test.js
2.2核心模块
官网文档 Index | Node.js v10.24.1 Documentation
中文文档 API 文档 | Node.js 中文网
就是nodejs自带的模块,需要通过唯一的标识名称来进行获取, 在安装完nodejs之后,就可以随意使用,使用的时候就可以直接引入。相当于学习js时使用的Array对象。
-
核心模块就是 Node 内置的模块,需要通过唯一的标识名称来进行获取。
-
每一个核心模块基本上都是暴露了一个对象,里面包含一些方法供我们使用
-
一般在加载核心模块的时候,变量的起名最好就和核心模块的标识名同名即可
-
例如:
const fs = require('fs')
-
注意:require()中直接写模块的名字
-
不要加.js
-
不要加其它路径
-
fs模块
- fs模块是文件操作模块。fs是 FileSystem的简写。它用来对文件,文件夹进行操作。
文件内容读取 - readFile
文件夹读取-readdir
fs.readFile(path[, options], callback)
path:读取文件的路径,[, options]读文件同时进行的可选参数的设置
callback:回调函数,读取的结果,有两个参数err、data
// 引入模块。
// 可以使用var、let,但是建议使用const,因为我们不希望它被改变
var fs = require('fs')
fs.readFile('./02.txt',function(err,data){
//err代表readFile这个方法读取文件的时候是否成功
//data读取成功后将文件存到data中
if(err){
console.log('读取失败');
}
else{
console.log(data.toString());
}
})
//终端里的buffer是字节流需要tostring转换成我们想要的命令
文件写入-覆盖写入 writeFile()
fs.writeFile(file, data[, options], callback)
file:要往哪个文件里写,若文件不存在,则会创建一个新的。
data:要写的内容
callback:回调函数,确定写入成功或者失败,err
==>writeFile会把原来写的内容清空,用写入的内容替换
//writeFile会把原来写的内容清空,用写入的内容替换
var fs = require('fs')
fs.writeFile('./02.text', 'la写入', 'utf-8', function (err) {
if (err) {
console.log('写入失败');
} else {
console.log('写入成功');
}
})
文件写入-追加写入 appendFile()
fs.appendFile
(file, data[, options], callback)
==>追加写入,不覆盖原来的内容
fs.appendFile('./02.text', '追加', 'utf-8', function (err) {
if(err){
console.log('追加失败');
}
else{
console.log('追加成功');
}
})
http模块
- http是nodejs的核心模块,让我们能够通过简单的代码创建一个Web服务器,就可以在服务器上挂页面,处理http请求。
-http-快速搭建Web服务器
1.新建文件,写入如下代码。
var http=require('http')
//创建一个服务对象
var server=http.createServer()
监听用户的请求,根据不同的请求做反馈
server.on('request',function(req,res){
//request请求 response响应
//形参 req前端页面发送给服务器的请求,ajax可以传数据
//res服务器响应给前端的
console.log(req);
//结束响应,这样前端才能接收到
res.end('hello world');
})
//启动服务
server.listen(5000,function(){
console.log('running');//证明服务已经跑起来了
})
2.打开终端,运行代码node http.js
。
3.在浏览器地址栏中输入:localhost:8081 观察效果。
注意:
1.如果你修改了代码,必须先停止服务,然后再启动。这样才能生效。ctrl+c 停止服务。
2.更改res.end()的内容,重启后,再次观察。
-http-为不同的文件类型设置不同的 Content-Type
html:
res.setHeader('content-type', 'text/html;charset=utf-8')
text:
res.setHeader('content-type', 'text/plain;charset=utf-8')
css:
res.setHeader('content-type', 'text/css;charset=utf-8')
js:
res.setHeader('content-type', 'application/javascript')
png:
res.setHeader('content-type', 'image/png')
var fs = require('fs');
var http = require('http');
var server = http.createServer();
server.on('request', function (req, res) {
//req是个对象里边有各种属性还有方法,其中包括URL
if (req.url === '/') {
res.setHeader('content-type','text/plain;charset=utf8')
res.end('这里是index')
} else if (req.url === '/png') {
fs.readFile('./1.png', function (err, data) {
if(err){
res.end('404')
}else{
res.setHeader('content-type','image/png')
res.end(data)
}
})
}else if(req.url === '/txt'){
res.setHeader('content-type','text/plain;charset=utf8')
res.end('中文文本')
}else if(req.url === '/html'){
fs.readFile('./index.html',function (err,data) {
if(err){
res.end('404')
}else{
res.end(data)
}
})
}
})
server.listen(3000, function () {
console.log('running...');
})
-http模块-实现接口功能
先判断请求的类型,再判断请求的地址。利用url发送的请求默认是get类型。
地址:/gettime(端口号后边拼的东西)
-
get类型的接口-无参数
var http=require('http')
var url=require('url')
http.createServer(function(req,res){
var obj=url.parse(req.url,true)
console.log(obj.pathname);//输入http://127.0.0.1:4000/aa/bb/cc :aa/bb/cc
}).listen(4000,function(){
console.log('running');
})
- get类型的接口-带参数
var http=require('http')
var url=require('url')
http.createServer(function(req,res){
var obj=url.parse(req.url,true)
console.log(obj.pathname);//输入http://127.0.0.1:4000/aa/bb/cc?k=v :aa/bb/cc
console.log(obj.query);//{ k: 'v' }
}).listen(4000,function(){
console.log('running');
})
- 例子:留言板
访问根目录渲染index.html,显示所有人的留言,包括姓名、留言内容以及时间戳。点击“发表留言”,跳转到post.html,输入姓名、留言内容,点击“发表”,跳转回index.html并将新的内容显示在最上边。
- post类型接口
通过表单提交,可以设置form的method为post
path模块
- path模块提供了用于处理文件和目录的路径的实用工具。 它是一个核心模块,用来处理路径问题:拼接,分析,取后缀名。可以使用以下方式访问它:
var path = require('path')
var str = 'http://nodejs.com/api/aaa.html'
console.log('basename',path.basename(str));//文件名称aaa.html
console.log('extname',path.extname(str));//扩展名.html
console.log('dirname',path.dirname(str));//http://nodejs.com/api
理解URL
- 作用: 定位资源(css,html,js,png, avi......)
- 格式:
协议://主机地址(127.0.0.1)[:端口(300)]/路径?查询字符串#锚点
协议
http
https
主机地址
IP地址 或者 域名(www.baidu.com)
端口
http请求,默认端口80
https请求,默认端口443
MySQL默认端口3306
路径
服务器文件夹上的资源。(.html/.css/.images/.js/接口)
参数(查询字符串)
? 后面的部分,是键值对的形式
锚点
网页内部的锚点链接
url模块
url模块用来对url(例如:http://itcast.cn:80/schools/students?id=18&name=zs#photo)进行解析,进而得到各种信息。
步骤:
-
引入
const url = require('url');
-
使用它的方法
obj = url.parse(地址栏中输入的url,true) (如果为true
,则query
属性将始终设置为 querystring 模块的parse()
方法返回的对象。 如果为false
,则返回的 URL 对象上的query
属性将是未解析、未解码的字符串。 默认值:false
))
var http=require('http')
var url=require('url')
http.createServer(function(req,res){
//req是个对象里边有各种属性还有方法
// Url {
// protocol: null,
// slashes: null,
// auth: null,
// host: null,
// port: null,
// hostname: null,
// hash: null,
// search: '?key=value',
// query: 'key=value',
// pathname: '/aaa/bbb/ccc/ddd.html',
// path: '/aaa/bbb/ccc/ddd.html?key=value',
// href: '/aaa/bbb/ccc/ddd.html?key=value'
// }
var obj=url.parse(req.url,true)//里的query: [Object: null prototype] { key: 'value' }
//var obj=url.parse(req.url)//默认是false 里的query: 'key=value'
console.log(obj.query.key);
}).listen(3000,function(){
console.log('running');
})
2.2自定义模块
1.程序员自己写的模块。就相当于我们在学习js时的自定义函数。
2.exports 相当于一个对象中的一个属性,使用时可以不使用原对象,直接可以使用
3.eports可以添加属性、方法等,无法替换对象。
4.module.exports 可以用其他对象替换,用于自定义模块传递对象。exports返回的是模块函数、属性,module.exports返回的是模块对象。
//模块
var str='hello'
function fn(a,b){
console.log(a+b);
}
exports.str=str//在这里,可以把exports看做一个对象,给exports添加一个属性str,然后给str赋值
exports.fn=fn
//exports={str:1}不可以直接用一个对象替代exports
module.exports={str:1}//这样可以
//主文件
var demo=require('./01export-demo.js')//导入自定义模块时需要将路径文件名加扩展名写全 是个对象
console.log(demo);//{ str: 'hello', fn: [Function: fn] }
console.log(demo.str);//hello
console.log(demo.fn(1,2));//3
art-template模板语法
- 通过npm安装:
npm install art-template (--save)
{{value}}
{{data.key}}
{{data["key"]}}
{{a?b:c}}
{{a || b }}
{{a + b}}
// 将模板源代码编译成函数并立刻执行
template.render(source, data, options);
示例:在页面内显示文件夹下内容
- 法一:普通方法,采用字符串替换
const http = require('http');
const fs = require('fs');
var dir = 'E:\\';// \为转义字符
http.createServer(function (req, res) {
//function里默认拿到的是字节流,下方需tostring()
//没写request默认访问根目录
fs.readFile('./views/02index.html', function (err, data) {
if (err) {
return res.end('html error')
}
//读取本地的文件
fs.readdir(dir, function (err, dirs) {
//dirs所有读出来的文件夹
if (err) {
return res.end('dirs error')
}
// console.log(dirs);//返回的是个数组
var str = ''
//对数组进行循环
dirs.forEach(function (item) {
str += ` <tr>
<td data-value="49/"><a class="icon dir" href="/E:/49/">${item}</a></td>
<td class="detailsColumn" data-value="0"></td>
<td class="detailsColumn" data-value="1650617423">2022/4/22 16:50:23</td>
</tr>`
})
data = data.toString();
data = data.replace('filelist', str)
res.end(data)//返回data(html)之前需要将路径里的文件读取出来拼接到html里
})
})
}).listen(3000, function () {
console.log('running...');
})
- 法二:art-template模板
//利用art-template模板将数组dirs传到html页面中,在html里通过模板语法把数组进行遍历,然后显示出来
var http=require('http')
var fs=require('fs')
var template=require('art-template')
http.createServer(function(req,res){
fs.readFile('./views/02index-template.html',function(err,data){
if(err){
return res.end('html error')
}
fs.readdir('E:\\',function(err,dirs){
if(err){
return res.end('dir error')
}
//利用template.render()把{dirs:dirs}数据渲染到html页面中,渲染结束的页面是str(即封装好的页面)
var str=template.render(data.toString(),{dirs:dirs})
res.end(str)
})
})
}).listen(3000,function(){
console.log('running');
})
<tbody id="tbody">
{{each dirs}}
<tr>
<td data-value="$RECYCLE.BIN/"><a class="icon dir" href="/E:/$RECYCLE.BIN/">{{$value}}</a></td>
<td class="detailsColumn" data-value="0"></td>
<td class="detailsColumn" data-value="1614969072">2021/3/6 02:31:12</td>
</tr>
{{/each}}
</tbody>
-
第三方模块
相当于别人写好的函数或者库。例如我们前面学习的JQuery库,art-template等。
Express框架
(10条消息) Node.js-Express框架_m0_53456432的博客-CSDN博客
三、MongoDB
1、书写
1.安装MongoDB
2.在集成终端安装中间件mongoose:npm init -y ==> npm i mongoose
Mongoose v6.3.4: (mongoosejs.com)
//先安装mongoose:npm init -y npm i mongoose
//引入mongoose
const mongoose=require('mongoose')
//创建一个连接,连接到本地的数据库,同时指定数据库名称(如果没有就建立,如果有就连接)
mongoose.connect('mongodb://localhost/m')//m:数据库的名称叫m
//创建mogoose数据的模型(如下:模型叫Cat)
//在相应数据库中建表(如下:表叫Cat),mongoose会把表名全变成小写,并会在后边追加小写s
//对数据表进行约束
const Cat=mongoose.model('Cat',{name:String})
//创建具体数据
const Kitty=new Cat({name:'qq'})
//将数据保存到数据库里
Kitty.save(function(error){
if(error){
console.log(error);
}else{
console.log('yes');
}
})
//或者
// Kitty.save().then(()=>{console.log('res');})
//cmd mongo>show db>use m>show collections
2、利用MongoDB写学生列表
模型上的API
- Model.find()查询所有
- 实例.save()添加信息
- Model.findByIdAndRemove()根据ID删除数据
- Model.findById根据ID查询数据
- Model.findByIdAndUpdate()根据ID更新数据 注意:必须传入数据的ID 如:
curd.findByIdAndUpdate(obj.id,obj,function(err){})
(10条消息) Node.js-Express框架_m0_53456432的博客-CSDN博客
四、补充模板语法
1.include抽取公共部分
例如html文件的头部分是一样的,可以把其抽取出来,在所需的文件里直接引用。
- {{include '公共部分文件的路径'}}
- header.html公共部分
<!-- 抽取公共部分 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>header</title>
</head>
- index1.html
{{include './header.html'}}
<body>
<h1>index1</h1>
</body>
</html>
- index2.html
{{include './header.html'}}
<body>
<h1>index2</h1>
</body>
</html>
- main.js
var express=require('express')
var app=express()
app.engine('html',require('express-art-template'))
app.get('/',function(req,res){
res.render('index1.html')
})
app.get('/two',function(req,res){
res.render('index2.html')
})
app.listen(3000,function(){
console.log('run');
})
2.extend继承、插槽
- extend继承{{extend '被继承文件的路径'}}
继承于某个页面 但是本页面需要一些个性化的东西 可以用插槽修改,而不改变被继承的那个文件的内容。
- {{block key}}内容{{/block}}
header.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- <title>header</title> -->
<title>{{block 'xtitle'}}header{{/block}}</title>
</head>
{{block 'tbody'}}{{/block}}
index3.html
<!-- 继承 -->
{{extend './header.html'}}
<!-- 'xtitle'是key -->
{{block 'tbody'}}
<body>
body
</body>
</html>
{{/block}}
五、__dirname、__filename
- __dirname获取当前文件所在的路径
- __filename获取当前文件绝对路径
main.js
console.log(__dirname);//C:\Users\HP\Desktop\Node\08-dirname,filname
console.log(__filename);//C:\Users\HP\Desktop\Node\08-dirname,filname\main.js
var fs=require('fs')
var path=require('path')
//path.join()拼接路径
fs.readFile(path.join(__dirname,'/a.text'),function(err,data){
if(err){
return console.log(err);
}
console.log(data.toString());
})