node
node定义
js的执行时环境
node环境安装
https://nodejs.org/en/ 下载相应版本并安装
系统环境变量
存储系统中的目录,在命令行中执行命令的时候系统会自动去这些目录中查找命令的位置
nodejs快速入门
node 执行js文件
用node执行js文件,在js所在的目录下 nonde xxx.js
注意:js文件名不能叫node.js 这样执行不了,js文件前几个字符,点tab键可以提示整个js文件名
浏览器中的js是没有文件操作能力的,但node中的js具有文件操作的能力
在fs这个核心模块中,就提供了所有的文件操作相关的API
node.js模块化开发
node.js中模块化开发规范
node.js规定一个JavaScript文件就是一个模块,模块内部定义的变量和函数默认情况下外部无法得到
模块内部可以使用exports对象进行成员到处,使用require方法导入其他模块
两种模块成员导出的方法
exports是module.exports的别名,导出对象以module.exports为主
使用module.exports={}给module.exports赋值以后,exports的值随之变化
使用exports={}是无效的,甚至是错误的
系统模块
fs核心模块
文件读写
1、读取文件
var fs = require('fs');
fs.readFile('data/hello.txt',function(reeor,data){
console.log(data);//这里输出的是16进制的,需要使用toString 方法转换成我们能认识的字符。
console.log(data.toString());
})
第一个参数就是要读取的文件路径,这个一般写绝对路径,因为这里的相对路径是相对于命令行所处的路径 __dirname获取当前文件所在的绝对路径
第二个参数文件编码,可选’utf-8’
第三个参数是一个回调函数
成功
data 数据 error null
失败
data null error错误对象
var fs = require(‘fs’)
2、文件写入
fs.writeFile('/data/hell0.md','我是node',function(error){
//第一个参数:文件路径,第二个参数:文件内容 第三个参数回调函数
//文件写入成功 error是null 文件写入失败:error就是错误对象
if(!error)console.log('文件写入成功');
})
系统模块path路径操作
路径拼写是因为不同系统的拼接符号不一样,path会根据系统拼接对应的符号
1 路径拼接写法
const path = require(“path”)
path.join(‘路径’,‘路径’,‘路径’,…)
第三方模块
1.npm
npm(node paxkage manager):node 的第三方模块管理工具
npm install 模块名称
2.第三方模块nodemon 文件保存时,自动重新执行
npm install nodemon -g
在命令行工具中用nodemon替代 node命令
3.第三方模块nrm
nrm:npm下载地址切换工具
下载 npm install nrm -g
查询可用下载地址列表nrm ls
切换npm下载地址nrm use下载地址名称
之后再使用npm使用的就是淘宝的下载地址了
4.第三方模块Gulp
基于node平台的前端构建工具
用于,压缩合并html,css,js ,转换es6 less 公共文件抽离 修改文件浏览器自动刷新
npm install gulp
在项目根目录下建立gulpfile.js
重构项目的文件夹结构src目录放置源代码文件dist目录放置构建后文件
在gulpfile.js文件中编写任务
在命令行工具中执行gulp任务
Gulp中提供的方法
gulp.src()获取任务要处理的文件
gulp.dest()输出文件
gulp.task(‘任务名称’,任务的回调函数);建立gulp任务
gulp.watch();监控文件的变化
实例代码 gulpfile.js
const gulp = require('gulp');
//使用gulp.task建立任务
//1.任务名称,2.任务的回调函数
//运行gulp命令需要安装gulp-cli npm install gulp-cli -g 然后运行gulp 任务 名称来运行任务
gulp.task('first', () => {
console.log("第一个guplp");
//使用gulp.src获取要处理的文件
gulp.src('./src/css/base.css')
.pipe(gulp.dest('dist/css'));
})
4.1gulp插件
- gulp-htmlmin html文件压缩
- gulp-csso 压缩css
- gulp-babel JavaScript语法转化
- gulp-less less语法转化
- gulp-uglify 压缩混淆JavaScript
- gulp-file-include 公共文件包含
- browsersync 浏览器实时同步
使用方法,下载对应插件,在gulpfile.js中引入,应用代码到官网看
//gulp插件使用
const less = require(" gulp-less")
const csso = require(" gulp-csso")
gulp.task('cssmin', () => {
//选择css目录下的说有less文件以及css文件
gulp.src(['./src/css/*.less', './src/css/*.css'])
//将less文件转换为css文件
.pipe(less())
//将css文件压缩
.pipe(csso())
//将css文件输出到dist下面的css文件
.pipe(gulp.dest('dist/css'))
})
//复制文件夹
gulp.task('copy', () => {
gulp.src('./src/images/*')
.pipe(gulp.dest('dist/images'));
gulp.src("./src/lib/*")
.pipe(gulp.dest('dist/lib'))
})
package.json
node_nodules文件夹的问题
1.文件夹以及文件过多过碎,
2.复杂的依赖关系需要被记录,确保模块的版本和当前保持一致
package.json文件的作用
项目描述文件,记录了当前项目信息,例如项目名称,版本作者,当前项目雨来了哪些第三方模块等
使用 npm init -y -y表示全部默认
项目依赖
- 在项目的开发阶段和线上运营阶段,都需要的第三方包,称为项目依赖
- 使用 npm install 包命 令下载的文件会默认被添加到package.json文件的dependencies字段中
- 使用npm install --production 下载项目依赖
开发依赖
- 在项目的开发阶段需要,线上运营阶段不需要的第三方包,称为开发依赖(如:gulp )
- 使用 npm install 包名 --save-dev命令下载的文件会默认被添加到package.json文件的devDependencies字段中
package-lock.json文件的作用
- 锁定报的版本,确保再次下载是不会因为包版本不同而产生问题
- 加快下载速度,因为该文件中已经记录了项目所依赖第三方报的树状结构和报的下载地址,重新安装时只需下载即可,不需要做额外的工作
Node.js中模块化加载机制
模块查找规则—当模块拥有路径单没有后缀时
require('./find.js')
require('./find')
1.require方法根据模块路径查找模块,如果时候完整路径,直接引入模块
2.如果模块后缀省略,先找到同名js文件,如果没有再找同名文件夹
3.如果找到了同名文件夹,找文件夹中的index.js
4.如果文件夹中没有inde.js就会去当前文件夹(这里的当前文件夹指find文件)中的package.js文件中查找main选项中的入口文件
5.如果找指定的入口文件不存在或者没有制定入口文件就会报错,模块没有找到
模块查找规则—当模块没有路径单没有后缀时
require('find')
1.Node.js会假设它是系统模块
2.Node.js会去node_modules文件夹中
3.先找到同名js文件没有找到的话,再找同名文件夹
4.如果找到了同名文件夹,找文件夹中的index.js
4.如果文件夹中没有inde.js就会去当前文件夹(这里的当前文件夹指find文件)中的package.js文件中查找main选项中的入口文件
5.如果找指定的入口文件不存在或者没有制定入口文件就会报错,模块没有找到
node.js全局对象global
在浏览器中全局对象是window,在node中全局对象是global,
Node中全局对象有以下方法,可以在任何地方使用,global可以省略
- global.console.log()
- global.setTimeout()
- global.clearTimeout()
- global.setInterval()
- global.clearInterval()
服务器端基础概念
网站的组成
客户端和服务器端
Node网站服务器
能够提供网站访问服务的机器就是网站服务器,它能够接受客户端的请求,能够对请求做出响应
IP地址
互联网中设备的唯一标识(互联网协议地址)
域名
由于ip地址难于记忆,所以蚕食了域名的概念,所谓域名就是平时上网所使用的网址,虽然在地址栏中输入的是网址,但是最终还是会将域名 装换为ip次啊能访问到指定的网站服务器
http://www.baidu.com => http://111.111.111.100/
端口
端口是计算机与外检通讯交流的出口,用来区分服务器电脑中提供的不同的服务。
URL
统一资源定位符,又叫URL ,是专为标识internet网上资源位置而设的一种编址方式
组成
传输协议://服务为ip或者域名:端口号/资源所在位置标识
使用node构建一个服务器
- 加载http核心模块
var http = require(‘http’);
2.使用http.createServer()方法创建一个Web服务器 返回一个server实例
var server = http.createServer();
3.服务器要,提供对数据的服务,发请求,接受请求,处理请求,给个反馈(发送响应)注册request请求事件, 当客户请求过来,就会自动触发服务器的request请求事件,然后执行第二个参数:回调函数处理
var http = require('http');
var server = http.createServer();
//当客户端有请求来的时候
server.on('request',function(req,res){
console.log('收到客户端的请求了'+resquest.url)
res.write("hello");
//告诉客户端响应结束,
res.end('<h1> hello user</h1>');
//req.url获取请求地址
//req.method 获取请求方式
//req.headers 获取请求报文
//设置响应头
res.writeHead(400,{
'content-type':'text/plain;charset=utf8'
})
if(req.url == '/'||response.url =='/index'){
res.end('welcome home')
}else{
res.end('not find')
}
})
4.绑定端口号,启动服务器
//监听3000端口
server.listen(3000,function(){
console.log("服务器启动成功了,可以通过 http://127.0.0.1:3000/ 来进行访问")
})
HTTP协议
HTTP协议的概念
超文本传输协议,规定了如何从网站服务器传输超文本到本地浏览器,它基于客户端服务器架构工作,是客户端(用户)和故武器端(网站)请求和应答的标准
报文
在http请求和响应的过程中传递的数据块叫报文,包括要出传送的数据和一些附加信息,并且要遵守规定好的格式。
请求报文
1,请求方式
- get 请求数据
- post 发送数据
响应报文
1.HTTP状态码
- 200请求成功
- 404请求的资源没有被找到
- 500服务器端错误
- 400客户端请求有语法错误
2.内容类型 - text/html
- text/css
- application/javascript
- image/jpeg
- application/json
HTTP请求与响应处理
get请求参数
- 参数被放置在浏览器地址栏中
var http = require('http');
var server = http.createServer();
//用于处理url地址
//当客户端有请求来的时候
const url = require('url);
server.on('request',function(req,res){
console.log('收到客户端的请求了'+req.url)
res.write("hello");
//告诉客户端响应结束,
res.end('<h1> hello user</h1>');
//req.url获取请求地址
//req.method 获取请求方式
//req.headers 获取请求报文
//设置响应头
res.writeHead(200,{
'content-type':'text/plain;charset=utf8'
})
//url.parse(要解析的url地址,是否将查询参数解析成对象形式),第二个参数为true时, .query获取到的是参数对象 如{name:"lili",age:18}
//let params = url.parse(req.url,true).query;
//对象解构方式
let {query,pathname} = url.parse(req.url,true);
//pathname是不包括请求参数的请求地址
if(pathname == '/'||pathname =='/index'){
res.end('welcome home')
}else{
res.end('not find')
}
})
post请求参数
- 参数被放置在请求体重进行传输
- 获取post参数需要使用data事件的end事件
- 使用querystring系统模块将参数转换为对象格式
var http = require('http');
//处理请求参数方法
const querystring = require('querystring)
var server = http.createServer();
//当客户端有请求来的时候
server.on('request',function(req,res){
//pist参数是通过时间的方式接受的
//data 当请求参数传递的时候触发data事件
//end 当参数传递完成的时候触发end事件
let postParams = '';
req.on('data',params=>{
postParams+= params;
})
req.on('end',()=>{
console.log(querystring.parse(postParams))
})
res.end('收到参数,请等待')
})
server.listen(3000);
console.log('网站服务器启动成功')
静态资源
服务器端不需啊哟处理,可以直接响应给客户端的资源就是静态资源,如css,html
var http = require('http');
//处理请求参数方法
const querystring = require('querystring);
const url = require('url');
const path = require('path');
const fs = require('fs');
const mime = require('mime');
var server = http.createServer();
//当客户端有请求来的时候
server.on('request',function(req,res){
//获取用户的请求路径
let pathname = url.parse(req.url).pathname;
pathname = pathname == '/'?'/default.htmt':pathname;
//将用户的请求路径转换为实际的服务器硬盘路径,静态资源放在public文件夹下
let realPath = path.join(__dirname,'public'+pathname);
//使用第三方模块mime,根据文件返回文件资源类型
let type = mime.getType(realPath)
//读取文件
fs.readFile(realPath,(err,res)=>{
if(!err){
res.writeHead(200,{
//由于一个网页的资源类型有多种,不能一概而论统统写死,我们需要用第三方模块mime,来根据文件返回资源的类型
'content-type':type;
})
res.end(res)
}else{
//指定编码格式
res.writeHead(404,{
'content-type':'text/html;charset=utf8'
})
res.end("文件读写失败")}
});
}) ;
server.listen(3000);
console.log('网站服务器启动成功')
动态资源
相同的地址不同的响应资源,这种资源就是动态资源
路由
路由是指客户端请求地址与服务器端程序代码的对应关系。简单的说,就是请求什么响应什么。
var http = require('http');
//处理请求参数方法
const querystring = require('querystring);
const url = require('url');
var server = http.createServer();
//当客户端有请求来的时候
server.on('request',function(req,res){
//获取客户端的请求方式
const metnod = req.method.toLowerCase();
//获取请求地址
const {pathname} = url.parse(req.url);
res.writeHead(200,{
'content-type':'text/html;charset=utf8'
})
if(metnod == 'get'){
if(pathname == '/'|| pathname =='/index'){
res.end('欢迎来到首页')
}else if(pathname == '/list'){
res.end('欢迎来到列表页');
}else{
res.end('页面不存在');
}
}else if(method == 'post'){
}
}) ;
server.listen(3000);
console.log('网站服务器启动成功')
Node.js异步编程
同步API,异步API
同步API:只有当前API执行完成后,才能继续执行下一个API
异步API:当前API的执行不会阻塞后续代码的执行;
区别
1.同步API可以从返回值中拿到API的执行的结果,但是异步API是不可以的,异步API的返回值,需要回调函数来拿到。
2.执行顺序不同,同步API依次执行,前面API会阻塞后面代码的执行,异步API不会等待API执行万抽再乡下执行代码
回调函数
//一个函数当做另外一个函数的参数传入
function getData(callback){
callback('123');
}
getData((n)=>{
console.log("回调函数打印内容"+n)
})
//上例我们这么使用回调函数,当异步API执行完成,执行回调函数,把异步API执行的结果当做回调函数的实参,这样就可以把异步结果返回到函数里面了
function getData(callback){
setTimeout(function(){
callback({msg:'hello '});
},2000)
}
getData((data)=>{
console.log("回调函数打印内容"+data)
})
Node.js中的异步API
fs.readFile('./demo.txt',(err,res)=>{});
var server = http.createServer();
server.on('request',(req,res)=>{});
问题:如果异步API后面代码的执行依赖当前异步API的执行结果,但实际上后续代码再执行的时候异步API还没有返回结果,这个问题怎么解决呢?
使用回调函数,但是回调类型操作过多,回调函数嵌套过深,产生回调地狱,不易维护。
Promise
解决Node.js中异步编程中回调地狱的问题
let promise = new Promise((resolve,reject)=>{
setTimeout(()=>{
if(true){
resolve({name:"张三"})
}else{
reject("失败了")
}},2000)
})
promise.then(result=>console.log(result))//{name:‘张三’}
.catch(error => console.log(error));//失败了
const fs = require('fs');
let promide = new Promise((resolve,reject)=>{
fs.readFile("./text1.text","utf8",(err,result)=>{
if(err != null){
reject(err);
}else{
resolve(result);
}
})
})
promise.then(res=>{
console.log(res);
}).catch((err)=>{
console.log(err)
})
Promise解决回调地狱问题
//Promise解决回调地狱问题,实现依次读取1.txt,2.txt,3.txt
const fs = require("fs")
function p1 (){
return new Promise ((resolve,reject)=>{
fs.readFile('./1.txt','utf8',(err,data)=>{
resolve(data)
})
})
}
function p2 (){
return new Promise ((resolve,reject)=>{
fs.readFile('./2.txt','utf8',(err,data)=>{
resolve(data)
})
})
}
function p3 (){
return new Promise ((resolve,reject)=>{
fs.readFile('./3.txt','utf8',(err,data)=>{
resolve(data)
})
})
}
p1().then((r1)=>{
console.log(r1);
return p2();
}).then((r2)=>{
console.log(r2);
return p3();
}).then((r3)=>{
console.log(r3)
})
异步函数
异步函数是异步编程的终极解决方案,他可以让我们将异步代码写成同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了
//async
//1.在普通函数定义个前面加上async关键字 普通函数就变成了异步函数
//2.异步函数默认的返回值是一个promise对象
//3.在异步函数内部使用return关键字进行结果返回 结果会被包裹的promise对象中 return关键字代替resolve方法
//4.在异步函数的内部使用throw关键字进行错误的抛出
//5.调用异步函数再练市调用太狠方法获取异步函数执行结果
//6.调用异步函数再链式调用catch方法获取异步函数执行的错误信息
//await关键字
//1.它只能出现在异步函数中
//2.await后面只能写promise对象 写其他类型的API是不可以的
//3.await promise 它可以暂停异步函数的执行,等待promise对象返回结果后再执行
async function p1(){
return "p1"
}
async function p2(){
return "p2"
}
async function p3(){
return "p1"
}
async function run(){
let r1 = await p1();
let r2 = await p2();
let r3 = await p3();
console.log(r1);
console.log(r2);
console.log(r3);
}
run();
异步函数解决回调地狱问题。
const fs = require('fs');
//promisify函数改造现有异步函数api 让其返回promise对象,吃从而支持异步函数语法
const promisify = require('util').promisify;
//调用promisify方法改造现有异步API 让其返回promise对象
const readFile = promisify(fs.readFile);
async function run (){
let r1 = await readFile('./1.txt','utf8')
let r2 = await readFile('./2.txt','utf8')
let r3 = await readFile('./3.txt','utf8')
console.log(r1)
console.log(r2)
console.log(r3)
}
run();
数据库概述及环境搭建
什么是数据库
数据库就是存储数据的仓库,可以将数据进行有序的分门别类的存储。他是独立于语言之外的软件,可以通过API去操作它。
常见的数据库软件有:mysql,mongodB,oracle。
数据库相关概念
在一个数据库软件中可以包含多个数据仓库,在每个数据长裤中可以包含多个数据集合,每个数据集合中可以包含多条文档(具体的数据)
术语 | 解释说明 |
---|---|
database | 数据库,mongoDB数据库软件可以建立多个数据库 |
collection | 集合,一个数据的集合,可以立减为js中的数组 |
decoment | 文档,一条具体的数据,可以立减为js中的对象 |
field | 字段,文档中的属性名称,可以理解为js中的对象属性 |
MongoDB数据库下载安装
https://www.mongodb.com
下载tools-compass (可视化软件)图形界面软件
Mongoose第三方包
下载mongoose
启动MongoDB
在命令行工具运行 net start mongodb 启动服务器
使用net stop mongodb 关闭服务器
数据库连接
使用mongoose提供的connect方法即可连接数据库。
//mongodb://localhost/playground 数据库地址
//mongodb://localhost由于当前数据库是安装在自己的电脑上所以这里是localhost/数据库名称(没有会自动创建)
//.connect 的第二个参数是选项,具体选项内容,要根据提示添加,如果没有这个参数,会输出提示信息
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/playground',{useNewUrelParser:true})
.then(()=>{console('数据库连接成功')})
.catch(err => console.log("数据库连接失败",err));
创建数据库
在MongoDB中不需要显示创建数据库,如果正在使用的数据库不存在,mongoDB会自动创建。
创建集合
创建集合分为两步,一时对集合设定规则,二是创建集合,创建mongoose.Schema构造函数的实例即可创建集合
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/playground',{useNewUrelParser:true})
.then(()=>{console('数据库连接成功')})
.catch(err => console.log("数据库连接失败",err));
//创建集合规则
const courseSchema = new mongoose.Schema({
name:String,
author:String,
isPublished:Boolean
});
//创建集合并应用规则
cost Course = mongoose.model('Course',courseSchema);//数据库实际的集合名字为courses
做完以上操作可能是看不到是数据库的,应为数据库中的集合是空的,接下来我们为集合添加文档
创建文档
创建文档事假上就是向集合中插入数据
分为两步:
1,创建集合实例。
2,调用实例对象下的save方法将数据保存到数据库中
//第一种方式
//创建文档
const course = new Course({
name:'Node.js course',
author:'咸鱼拌菜鸡',
tags:['node','backend'],
isPublished:true
})
//将数据保存到数据库中
course.save();
//第二种方法
Course.create({name:'Javascript',author:'黑马讲师',isPublished:false},(err,res)=>{
console.log(err);
console.log(res)
})
//第三种方式
Course.create({name:'Javascript',author:'黑马讲师',isPublished:false}).then(doc=>console.log(doc)).catch(err=>{console.log(err)})
mongoDB数据库导入数据
mongoimport -d数据库名称 -c 集合名称 --file 要导入的数据文件
使用:先配置环境变量 如C:\Program\MongoDB\Server\4.1\bin
关闭命令行工具,重新切换到项目文件
命令行输入 mongoimport -d playground -c userr --file ./user.json
查询文档
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/playground',{useNewUrelParser:true})
.then(()=>{console('数据库连接成功')})
.catch(err => console.log("数据库连接失败",err));
//创建集合规则
const courseSchema = new mongoose.Schema({
name:String,
author:String,
isPublished:Boolean
});
//创建集合并应用规则
cost Course = mongoose.model('Course',courseSchema);//数据库实际的
//根据条件查找文档(条件为空则查找所有文档)
//查询Course集合中的所有文档 find()返回一个数组,当没有符合条件的数据时返回空数组
Course.find().then(result => console(result))
//通过_id查找数据
Course.find({_id:"11011"}).then(result => console(result))
//findOne方法返回一条文档 默认返回Course集合中的第一条数据
Course.findOne().then(result => console.log(res));
Course.findOne(name:"张三").then(result => console.log(res))
//匹配大于 小于
Course.find({age:{$gt:20,$lt:40}}).then(res=>{console.log(res)}});
//匹配包含 in
Course.find({hobbies:{$in:['唱歌']}}).then(res=>{console.log(res)})
//匹配字段 多个字段用空格分隔
Course..find().select('name email').then(res=>{console.log(res)})
删除文档
//删除单个 返回删除的文档 如果查询条件匹配了多个文档 那么将会删除第一个匹配的文档
Course.findOneAndDelete({_id:"11011"}).then(res=>{console.log(res)})
//删除多个 符合条件的全部删除 返回{n:删除的文档数量,ok:1表示成功}
Course.deleteMany({}).then(res =>console.log(res))
更新文档
//Course.updateOne({查询条件},{要修改的值}).then(res=>console.log(res));
Course.updateOne({name:"一枝花"},{name:"一个饼"}).then(res=>console.log(res));
//更改多个
Course.updateMany({},{age:18}).then(res=>console.log(res));
mongoose验证
在穿件集合规则时,可以设置当前字段的验证规则,验证失败就输入插入失败
- require:true 验证必填
- minlength :n 字符串最小长度
- maxlength:n 字符串最大长度
- trim:true 去除字符串首尾空格
- min:n 数字最小
- max: n 数字最大
- default:"" 默认值
- enum:[‘选项1’,‘选项2’] 枚举类型 添加的值必须为数字包含的选项
- 自定义验证规则
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/playground',{useNewUrelParser:true})
.then(()=>{console('数据库连接成功')})
.catch(err => console.log("数据库连接失败",err));
//创建集合规则
const postSchema = new mongoose.Schema({
title:{
type:String,
//required:true,
require:[treu,'title为必填字段'],
minlength:[2,'最小长度不能小于2'],
maxlength:10
}
age:{
type:Number,
min:18,
max:100
}
//自定义验证规则
author:{
type:String,
validator:v=>{
//返回布尔值
//true 验证成功
// false 验证失败
// v 要验证的值
return v && v.length>4
},
message:"传入的值不符合验证规则"
}
});
//创建集合并应用规则
cost Post= mongoose.model('Course',postSchema);//数据库实际的
Post.create({}).then(res => console.log(res)).catch(err=>{
console.log(err)
//获取错误信息对象
const error = err.errors;
for (var attr in error){
//获取每一条错误信息
console.log(err[attr]['meddage']);
}
});
集合关联
通常不同集合的数据之间是有关系的。想要拿到一条数据的其他集合中的信息,就需要用到集合关联。
//用户集合
const User = mongoose.model('User',new mongoode.Schema({
name:{type:String}
}));
//文章集合
const Post= mongoose.model('Post',new mongoode.Schema({
title:{type:String},
//mongoose.Schema.Types.objectId 固定写法mongoosedb中,用来存放id字段,ref:'要关联的集合名'}
author:{type:mongoose.Schema.Types.objectId,ref:'User'}
}));
//联合查询
Post.find().populate('author').
then((err,result) => console.log(result));
模板引擎
模板引擎的
模板引擎是第三方模块
让开发者以更加友好的方式拼接字符串,石代马更加清晰,更加易于维护
- 1.下载 npm install art-template 命令进行下载
- 2.使用conse template = require(‘art-temolate’)引入模板引擎
- 告诉模板引擎要拼接的数据和模板在哪 const html = template(‘模板路径’,数据);
//app.js
//导入 模板引擎
const template = require('art-template');
const path = require('path');
const views = path.join(__dirname,'viwes','index.art');
//template 方法是用来拼接字符串的
//1.模板路径要写绝对路径,用到path.join来拼接路径
//2.要在模板中显示的数据 对象类型
// 返回拼接好的字符串
const html = template(views,{
name:"张三",
age:18
})
console.log(html);
//模板文件 index.art
<!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>Document</title>
</head>
<body>
<div>
{{name}}
{{age}}
</div>
</body>
</html>
模板语法
- art-template 同时支持两种模板语法:标准语法和原始语法。
- 标准语法可以让模板更容易读写,原始语法具有强大的逻辑处理能力。
标准语法:{{数据}}
原始语法: <%= 数据%>
原文输出
如果数据中写到HTML标签,默认引擎不会解析标签,会将其转义后输出
- 标准语法:{{ @ 数据}}
- 原始语法 : <%- 数据%>
条件判断
在末班中可以根据条件来决定显示哪个HTML代码
<!--标准语法--!>
{{if 条件}} ...{{/if}}
{{if 条件}}
...
{{else if 条件}}
...
{{else}}
...
{{/if}}
<!--原始语法--!>
<% if(value){%> ...<%}>
<% if(v1){%> ...<%} else if(v2){ %>...<%}> %>
//index.art
{{if age >18}}
年龄大于18
{{else if age>15}}
年龄小于15
{{else}}
年龄超出范围
{{/if}}
<% if(age >18){%>
年龄大于18
<%} else if(age>15){ %>
年龄小于15
<% }else{%>
年龄超出范围
<%}> %>
循环