Node.js学习(express+node项目实战)
一. 什么是node.js?JavaScript 运行时环境既不是语言,也不是框架,它是一个平台node中的javascript没有BOM、DOM在 Node 中为 JavaScript 提供了一些服务器级别的 API文件操作的能力http 服务的能力二. node中的模块化开发在node中每个js都是一个独立的文件,相互之间并不干扰,他们之前的通信是通过exports 向外暴露,然后在通过req
一. 什么是node.js?
- JavaScript 运行时环境
- 既不是语言,也不是框架,它是一个平台
- node中的javascript没有BOM、DOM
- 在 Node 中为 JavaScript 提供了一些服务器级别的 API
- 文件操作的能力
- http 服务的能力
二. node中的模块化开发
在node中每个js都是一个独立的文件,相互之间并不干扰,他们之前的通信是通过exports
向外暴露,然后在通过 require
引入。
事例
a.js
var bEpt = require('./b')
console.log(bEpt.fo) //会报错 因为 b.js中未暴露该变量
console.log(bEpt.foo) //控制台会输出打印 hello
b.js
var fo = 'bbb'
exports.foo = 'hello' //exports 表示向外暴露
三. 文件的读取与写入
// 浏览器中的 JavaScript 是没有文件操作的能力的
// 但是 Node 中的 JavaScript 具有文件操作的能力
// 1. 使用 require 方法加载 fs 核心模块
var fs = require('fs') //fs 是 file-system 的简写,就是文件系统的意思
//读取文件
// 第一个参数就是要读取的文件路径
// 第二个参数是一个回调函数
//
// 成功
// data 数据
// error null
// 失败
// data undefined没有数据
// error 错误对象
fs.readFile('./data/a.txt', function (error, data) {
// <Buffer 68 65 6c 6c 6f 20 6e 6f 64 65 6a 73 0d 0a>
// 文件中存储的其实都是二进制数据 0 1
// 这里为什么看到的不是 0 和 1 呢?原因是二进制转为 16 进制了
// 但是无论是二进制01还是16进制,人类都不认识
// 所以我们可以通过 toString 方法把其转为我们能认识的字符
// 在这里就可以通过判断 error 来确认是否有错误发生
if (error) {
console.log('读取文件失败了')
} else {
console.log(data.toString()) //data中的数据默认是二进制的<Buffer 68 65 6c 6c 6f 20 6e 6f 64 65 6a 73 0d 0a> toString转成 utf8编码格式显示
}
})
// 第一个参数:文件路径
// 第二个参数:文件内容
// 第三个参数:回调函数
// error
//
// 成功:
// 文件写入成功
// error 是 null
// 失败:
// 文件写入失败
// error 就是错误对象
//写入文件
fs.writeFile('./data/a.md', '大家好,给大家介绍一下,我是Node.js', function (error) {
// console.log('文件写入成功')
// console.log(error)
if (error) {
console.log('写入失败')
} else {
console.log('写入成功了')
}
})
四. node中搭建服务器
// 1. 加载 http 核心模块
var http = require('http')
// 2. 使用 http.createServer() 方法创建一个 Web 服务器
// 返回一个 Server 实例
var server = http.createServer()
server.on('request', fuction(request, response){
console.log('收到客户端的请求了,请求路径是:' + request.url)
// response 对象有一个方法:write 可以用来给客户端发送响应数据
// write 可以使用多次,但是最后一定要使用 end 来结束响应,否则客户端会一直等待
response.write('hello')
response.write(' nodejs')
// 告诉客户端,我的话说完了,你可以呈递给用户了
response.end()
})
//开启端口号
server.listen(3000, function () {
console.log('服务器启动成功了,可以通过 http://127.0.0.1:3000/ 来进行访问')
})
//可以配置路由 通过判断请求过来的路径,响应相应的数据
var server = http.createServer()
server.on('request', fuction(request, response){
var url = request.url
if (url === '/') {
// 如果你发送的是 html 格式的字符串,则也要告诉浏览器我给你发送是 text/html 格式的内容 // text/plain 就是普通文本
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.write('<p>hello html <a href="">点我</a></p>')
res.end()
} else if (url === '/login') {
res.end('登录页')
} else if (url === '/products') {
var products = [{
name: '苹果',
price: 8888
},
{
name: '牛奶',
price: 5000
},
{
name: '电视机',
price: 1999
}
]
// 响应内容只能是二进制数据或者字符串
// 数字
// 对象
// 数组
// 布尔值
res.end(JSON.stringify(products))
} else {
res.end('404')
}
response.end()
})
//开启端口号
server.listen(3000, function () {
console.log('服务器启动成功了,可以通过 http://127.0.0.1:3000/ 来进行访问')
})
https://tool.oschina.net/
Content-Type可以查找有关资源对应的头部信息
其他核心模块
// 用来获取机器信息的
var os = require('os')
// 用来操作路径的
var path = require('path')
// 获取当前机器的 CPU 信息
console.log(os.cpus())
// memory 内存
console.log(os.totalmem())
// 获取一个路径中的扩展名部分
// extname extension name
console.log(path.extname('c:/a/b/c/d/hello.txt'))
读取文件目录
var fs = require('fs')
fs.readdir('D:/', function (err, files) {
if (err) {
return console.log('目录不存在')
}
console.log(files)
})
五. 模板引擎
//首先:npm install art-template 第三方模块
// 该命令在哪执行就会把包下载到哪里。默认会下载到 node_modules 目录中
//引入模块
var template = require('art-template')
var str = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<p>姓名:{{ name }}</p>
<p>年龄: {{ age }} </p>
<h1>地址: {{ province }}</h1>
<p>爱好:{{each hobbies}} {{ $value }} {{/each}}</p>
</body>
</html>
`
//使用 语法 template.render(字符串,对象)
var ret = template.render(str,{
name:'小明',
age:20,
province:'长沙',
hobbies:['唱歌','跑步','打篮球']
})
console.log(ret)
在浏览器中使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>在浏览器中使用art-template</title>
</head>
<body>
<!--
注意:在浏览器中需要引用 lib/template-web.js 文件
强调:模板引擎不关心你的字符串内容,只关心自己能认识的模板标记语法,例如 {{}}
{{}} 语法被称之为 mustache 语法
-->
<script src="node_modules/art-template/lib/template-web.js"></script>
<script type="text/template" id="tpl">
<p>姓名:{{ name }}</p>
<p>年龄: {{ age }} </p>
<h1>地址: {{ province }}</h1>
<p>爱好:{{each hobbies}} {{ $value }} {{/each}}</p>
</script>
<script>
var ret = template.render(str,{
name:'小明',
age:20,
province:'长沙',
hobbies:['唱歌','跑步','打篮球']
})
console.log(ret)
</script>
</body>
</html>
示例
编写留言板
app.js
var http = require('http') // 用于创建服务器的模块
var fs = require('fs') //用于操作文件模块
var template = require('art-template') //使用模板引擎 需要 npm install art-template
//引入url 模块
var url = require('url')
var comments = [
{
name: '张三',
message: '今天天气不错!',
dateTime: '2020-10-16'
},
{
name: '张三2',
message: '今天天气不错!',
dateTime: '2020-10-16'
},
{
name: '张三3',
message: '今天天气不错!',
dateTime: '2020-10-16'
},
{
name: '张三4',
message: '今天天气不错!',
dateTime: '2020-10-16'
},
{
name: '张三5',
message: '今天天气不错!',
dateTime: '2020-10-16'
}
]
//创建服务
http.createServer(function(req,res){
// 使用 url.parse 方法将路径解析为一个方便操作的对象,第二个参数为 true 表示直接将查询字符串转为一个对象(通过 query 属性来访问)
var parseObj = url.parse(req.url,true)
//获取请求路径 配置路由 返回相应数据
//parseObj.pathname 不包含?之后的内容
if(parseObj.pathname==='/'){
//读取首页并返回
fs.readFile('./views/index.html',function(err,data){
if(err){
return res.end('404')
}
var datas= template.render(data.toString(),{comments:comments}) //使用模板引擎进行渲染
res.end(datas)
})
} else if(parseObj.pathname==='/post'){
//读取评论页并返回
fs.readFile('./views/post.html',function(err,data){
if(err){
return res.end('404')
}
res.end(data)
})
} else if(parseObj.pathname == '/pinglun'){
//点击了评论按钮
// 我们已经使用 url 模块的 parse 方法把请求路径中的查询字符串给解析成一个对象了
//获取到参数对象
var comment = parseObj.query
comment.dateTime = '2020-11-2 17:01:01'
comments.unshift(comment) //把 comment对象 添加到数据源中
//1. 状态码设置为 302 临时重定向
// statusCode
// 2. 在响应头中通过 Location 告诉客户端往哪儿重定向
// setHeader
res.statusCode = 302 //状态码 302 表示重定向
res.setHeader('Location', '/') //跳转到首页
res.end()
} else if(parseObj.pathname.indexOf('/public/')===0){ //配置静态资源路径 如果以此文件为入口文件 相当于这个服务器的根目录 / 表示与此文件在同一级的目录
//'.'+parseObj.pathname 会在程序根目录下的相对路径 这里因为我吧静态文件放在public下 public又与此程序入口文件在同级目录下 所以要加./
fs.readFile('.'+parseObj.pathname,function(err,data){
if(err){
return res.end('404')
}
res.end(data)
})
}
}).listen(3000,function(){
console.log('running...')
})
首页: index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>留言本</title>
<!--
浏览器收到 HTML 响应内容之后,就要开始从上到下依次解析,
当在解析的过程中,如果发现:
link script img
等带有 src 或者 href(link) 属性标签(具有外链的资源)的时候,浏览器会自动对这些资源发起新的请求。
-->
<!--
注意:在服务端中,文件中的路径就不要去写相对路径了。
因为这个时候所有的资源都是通过 url 标识来获取的
我的服务器开放了 /public/ 目录
所以这里的请求路径都写成:/public/xxx
/ 在这里就是 url 根路径的意思。
浏览器在真正发请求的时候会最终把 http://127.0.0.1:3000 拼上
不要再想文件路径了,把所有的路径都想象成 url 地址
-->
<link rel="stylesheet" href="/public/css/bootstrap.css">
</head>
<body>
<div class="header container">
<div class="page-header">
<h1>Example page header <small>Subtext for header</small></h1>
<a class="btn btn-success" href="/post">发表留言</a>
</div>
</div>
<div class="comments container">
<ul class="list-group">
{{each comments}}
<li class="list-group-item">{{ $value.name }}说:{{ $value.message }} <span class="pull-right">{{ $value.dateTime }}</span></li>
{{/each}}
</ul>
</div>
</body>
</html>
评论页:post.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="/public/css/bootstrap.css">
</head>
<body>
<div class="header container">
<div class="page-header">
<h1><a href="/">首页</a> <small>发表评论</small></h1>
</div>
</div>
<div class="comments container">
<form action="/pinglun" method="get">
<div class="form-group">
<label for="input_name">你的大名</label>
<input type="text" class="form-control" required minlength="2" maxlength="10" id="input_name" name="name" placeholder="请写入你的姓名">
</div>
<div class="form-group">
<label for="textarea_message">留言内容</label>
<textarea class="form-control" name="message" id="textarea_message" cols="30" rows="10" required minlength="5" maxlength="20"></textarea>
</div>
<button type="submit" class="btn btn-default">发表</button>
</form>
</div>
</body>
</html>
404 界面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<h1>抱歉! 您访问的页面失联啦...</h1>
</body>
</html>
静态资源
我这里使用的是bootstrap.css的样式下载地址如下
http://getbootstrap.com
六. Express(第三方 Web 开发框架)
模块系统
- 核心模块
- 第三方模块
- 自己写的模块
- 加载规则以及加载机制
- 循环加载
导出多个成员 必须在对象中
exports.fo="hello"
exports.foo="hellos"
导出单个成员 得到的就是字符串函数
module.exports="aaa"
//后者会覆盖前者
module.exports=fuction(a,b){
return a+b
}
也可以用 module.exports
导出多个成员
module.exports = {
fo:"hello",
fuc:function(a+b){ return a+b }
}
在 Node 中,每个模块内部都有一个自己的 module 对象该 module 对象中,有一个成员叫:exports 也是一个对象也就是说如果你需要对外导出成员,只需要把导出的成员挂载到 module.exports 中
console.log(exports === module.exports) //true
优先从缓存加载
a加载b,在b中加载c,a又加载c
由于 在 b 中已经加载过 c了,所以a不会重复加载,可以拿到其中的接口对象,但是不会重复执行里面的代码,这样做的目的是为了避免重复加载,提高模块加载效率
npm
npm init
- npm init -y 可以跳过向导,快速生成 package.json 依赖信息文件
npm install
- 一次性把dependencies选项中的依赖项全部安装
npm install 包名
- 只下载到node_modules
npm install --save 包名
- 下载并保存依赖信息(package.json中的dependencies中)
npm uninstall 包名
- 只删除,依赖信息还在
npm uninstall 包名 --save
- 删除包的同时删除依赖信息
npm install 包名 --global
表示全局安装 任意目录下都可执行此命令
Express
- 第三方 Web 开发框架
- 高度封装了 http 模块
- 更加专注于业务,而非底层细节
安装
npm init -y //生成一个package.json
npm i expree // 默认会保存依赖信息到package.json中
重写上面的事例 留言功能
// 1. 引包
var express = require('express')
// 2. 创建你服务器应用程序
// 也就是原来的 http.createServer
var app = express()
// 当以 /public/ 开头的时候,去 ./public/ 目录中找找对应的资源
// 这种方式更容易辨识,推荐这种方式
// app.use('/public/', express.static('./public/'))
// 必须是 /abc/d/puiblic目录中的资源具体路径
// app.use('/abc/d/', express.static('./public/'))
// 当省略第一个参数的时候,则可以通过 省略 /public 的方式来访问
// 这种方式的好处就是可以省略 /public/
//app.use(express.static('./public/'))
app.use('/public/', express.static('./public/'))
// 配置使用 art-template 模板引擎
// 第一个参数,表示,当渲染以 .art 结尾的文件的时候,使用 art-template 模板引擎
// express-art-template 是专门用来在 Express 中把 art-template 整合到 Express 中
// 虽然外面这里不需要记载 art-template 但是也必须安装
// 原因就在于 express-art-template 依赖了 art-template
app.engine('html', require('express-art-template'))
// body-parser 专门用来解析表单post提交
const bodyParser = require('body-parser')
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
var comments = [
{
name: '张三',
message: '今天天气不错!',
dateTime: '2015-10-16'
},
{
name: '张三2',
message: '今天天气不错!',
dateTime: '2015-10-16'
},
{
name: '张三3',
message: '今天天气不错!',
dateTime: '2015-10-16'
},
{
name: '张三4',
message: '今天天气不错!',
dateTime: '2015-10-16'
},
{
name: '张三5',
message: '今天天气不错!',
dateTime: '2015-10-16'
}
]
//当以get请求时 执行处理回调函数 app.get 相当于增加了一个路由
app.get('/', function (req, res) {
// Express 为 Response 相应对象提供了一个方法:render
// render 方法默认是不可以使用,但是如果配置了模板引擎就可以使用了
// res.render('html模板名', {模板数据})
// 第一个参数不能写路径,默认会去项目中的 views 目录查找该模板文件
// 也就是说 Express 有一个约定:开发人员把所有的视图文件都放到 views 目录中
res.render('index.html', { comments: comments })
})
app.get('/post', function (req, res) {
res.render('post.html')
})
// app.get('/pinglun',function(req,res){
// var comment = req.query //get 请求通过.query获取参数 只能拿 get 请求参数
// comment.dateTime = '2017-11-2 17:11:22'
// comments.unshift(comment)
// res.redirect('/')
// })
app.post('/pinglun', function (req, res) {
var comment = req.body //post 取值 .body
console.log(comment)
comment.dateTime = '2020-11-2 17:11:22'
comments.unshift(comment)
res.redirect('/') //重定向到首页
})
//开启端口
app.listen(3000, function () {
console.log('running...')
})
Express 封装路由
实例
//创建服务
var express = require('express')
//引入封装的路由
var router = require('./router')
//解析post请求 npm i body-parser
var bodyParser = require('body-parser')
var app = express()
//处理静态资源路径
app.use('/node_modules/', express.static('./node_modules/'))
app.use('/public/', express.static('./public/'))
//express使用模板引擎
app.engine('html', require('express-art-template'))
// 配置模板引擎和 body-parser 一定要在 app.use(router) 挂载路由之前
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
// 把路由容器挂载到 app 服务中
app.use(router)
app.listen(3000, function () {
console.log('running 3000...')
})
module.exports = app
router.js
//处理路由
// 根据不同的请求方法+请求路径设置具体的请求处理函数
var fs = require('fs')
var Student = require('./student')
// Express 提供了一种更好的方式
// 专门用来包装路由的
var express = require('express')
// 1. 创建一个路由容器
var router = express.Router()
// 2. 把路由都挂载到 router 路由容器中
/*
* 渲染学生列表页面
*/
router.get('/students', function (req, res) {
Student.find(function (err, students) {
if (err) {
return res.status(500).send('Server error.')
}
res.render('index.html', {
fruits: [
'苹果',
'香蕉',
'橘子'
],
students: students
})
})
})
/*
* 渲染添加学生页面
*/
router.get('/students/new', function (req, res) {
res.render('new.html')
})
/*
* 处理添加学生
*/
router.post('/students/new', function (req, res) {
// 1. 获取表单数据
// 2. 处理
// 将数据保存到 db.json 文件中用以持久化
// 3. 发送响应
Student.save(req.body, function (err) {
if (err) {
return res.status(500).send('Server error.')
}
res.redirect('/students')
})
})
/*
* 渲染编辑学生页面
*/
router.get('/students/edit', function (req, res) {
// 1. 在客户端的列表页中处理链接问题(需要有 id 参数)
// 2. 获取要编辑的学生 id
//
// 3. 渲染编辑页面
// 根据 id 把学生信息查出来
// 使用模板引擎渲染页面
Student.findById(parseInt(req.query.id), function (err, student) {
if (err) {
return res.status(500).send('Server error.')
}
res.render('edit.html', {
student: student
})
})
})
/*
* 处理编辑学生
*/
router.post('/students/edit', function (req, res) {
// 1. 获取表单数据
// req.body
// 2. 更新
// Student.updateById()
// 3. 发送响应
Student.updateById(req.body, function (err) {
if (err) {
return res.status(500).send('Server error.')
}
res.redirect('/students')
})
})
/*
* 处理删除学生
*/
router.get('/students/delete', function (req, res) {
// 1. 获取要删除的 id
// 2. 根据 id 执行删除操作
// 3. 根据操作结果发送响应数据
Student.deleteById(req.query.id, function (err) {
if (err) {
return res.status(500).send('Server error.')
}
res.redirect('/students')
})
})
// 3. 把 router 导出
module.exports = router
student.js
var fs = require('fs')
var dbPath = './db.json'
/**
* 获取学生列表
* @param {Function} callback 回调函数
*/
exports.find = function (callback) {
fs.readFile(dbPath, 'utf8', function (err, data) {
if (err) {
return callback(err)
}
callback(null, JSON.parse(data).students)
})
}
/**
* 根据 id 获取学生信息对象
* @param {Number} id 学生 id
* @param {Function} callback 回调函数
*/
exports.findById = function (id, callback) {
fs.readFile(dbPath, 'utf8', function (err, data) {
if (err) {
return callback(err)
}
var students = JSON.parse(data).students
var ret = students.find(function (item) {
return item.id === parseInt(id)
})
callback(null, ret)
})
}
/**
* 添加保存学生
* @param {Object} student 学生对象
* @param {Function} callback 回调函数
*/
exports.save = function (student, callback) {
fs.readFile(dbPath, 'utf8', function (err, data) {
if (err) {
return callback(err)
}
var students = JSON.parse(data).students
// 添加 id ,唯一不重复
student.id = students[students.length - 1].id + 1
// 把用户传递的对象保存到数组中
students.push(student)
// 把对象数据转换为字符串
var fileData = JSON.stringify({
students: students
})
// 把字符串保存到文件中
fs.writeFile(dbPath, fileData, function (err) {
if (err) {
// 错误就是把错误对象传递给它
return callback(err)
}
// 成功就没错,所以错误对象是 null
callback(null)
})
})
}
/**
* 更新学生
*/
exports.updateById = function (student, callback) {
fs.readFile(dbPath, 'utf8', function (err, data) {
if (err) {
return callback(err)
}
var students = JSON.parse(data).students
// 注意:这里记得把 id 统一转换为数字类型
student.id = parseInt(student.id)
// 你要修改谁,就需要把谁找出来
// EcmaScript 6 中的一个数组方法:find
// 需要接收一个函数作为参数
// 当某个遍历项符合 item.id === student.id 条件的时候,find 会终止遍历,同时返回遍历项
var stu = students.find(function (item) {
return item.id === student.id
})
// 这种方式你就写死了,有 100 个难道就写 100 次吗?
// stu.name = student.name
// stu.age = student.age
// 遍历拷贝对象
for (var key in student) {
stu[key] = student[key]
}
// 把对象数据转换为字符串
var fileData = JSON.stringify({
students: students
})
// 把字符串保存到文件中
fs.writeFile(dbPath, fileData, function (err) {
if (err) {
// 错误就是把错误对象传递给它
return callback(err)
}
// 成功就没错,所以错误对象是 null
callback(null)
})
})
}
/**
* 删除学生
*/
exports.deleteById = function (id, callback) {
fs.readFile(dbPath, 'utf8', function (err, data) {
if (err) {
return callback(err)
}
var students = JSON.parse(data).students
// findIndex 方法专门用来根据条件查找元素的下标
var deleteId = students.findIndex(function (item) {
return item.id === parseInt(id)
})
// 根据下标从数组中删除对应的学生对象
students.splice(deleteId, 1)
// 把对象数据转换为字符串
var fileData = JSON.stringify({
students: students
})
// 把字符串保存到文件中
fs.writeFile(dbPath, fileData, function (err) {
if (err) {
// 错误就是把错误对象传递给它
return callback(err)
}
// 成功就没错,所以错误对象是 null
callback(null)
})
})
}
packge-lock.json
npm 5 以后才加入这个文件
当你npm install的时候会自动生成packge-lock.json
这个文件会保存node_modules中所有的信息(版本、下载地址)这样npm install 的时候速速就可以提升
lock 称为锁
所以此文件还可以用来锁定版本 防止自动升级
promise
ECMAscript 6 原生提供了 Promise 对象。
Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息。
1、对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:
- pending: 初始状态,不是成功或失败状态。
- fulfilled: 意味着操作成功完成。
- rejected: 意味着操作失败。
var promise = new Promise(function(resolve, reject) {
// 异步处理
// 处理结束后、调用resolve 或 reject
});
实例
var fs = require('fs')
var p1 = new Promise(function (resolve, reject) {
//读取文件 异步操作
fs.readFile('./data/a.txt', 'utf8', function (err, data) {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
var p2 = new Promise(function (resolve, reject) {
fs.readFile('./data/b.txt', 'utf8', function (err, data) {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
var p3 = new Promise(function (resolve, reject) {
fs.readFile('./data/c.txt', 'utf8', function (err, data) {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
p1
.then(function (data) {
console.log(data)
return p2
}, function (err) {
console.log('读取文件失败了', err)
})
.then(function (data) {
console.log(data)
return p3
})
.then(function (data) {
console.log(data)
console.log('end')
})
封装promise
var fs = require('fs')
function pReadFile(filePath) {
return new Promise(function (resolve, reject) {
fs.readFile(filePath, 'utf8', function (err, data) {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
}
pReadFile('./data/a.txt')
.then(function (data) {
console.log(data)
return pReadFile('./data/b.txt')
})
.then(function (data) {
console.log(data)
return pReadFile('./data/c.txt')
})
.then(function (data) {
console.log(data)
})
node中的模块
在每个模块中除了require、exports等相关api模块外,还有两个特殊成员
- __dirname 可以用来获取文件的所属目录
- __filename 可以用来获取文件的绝对路径
path 模块
参考文档:https://nodejs.org/docs/latest-v13.x/api/path.html
path.basename:获取路径的文件名,默认包含扩展名
path.dirname:获取路径中的目录部分
path.extname:获取一个路径中的扩展名部分
path.parse:把路径转换为对象
root:根路径
dir:目录
base:包含后缀名的文件名
ext:后缀名
name:不包含后缀名的文件名
path.join:拼接路径
path.isAbsolute:判断一个路径是否为绝对路径
var fs = require('fs')
var path = require('path')
// 模块中的路径标识和文件操作中的相对路径标识不一致
// 模块中的路径标识就是相对于当前文件模块,不受执行 node 命令所处路径影响
require('./b')
// ./a.txt 相对于当前文件路径
// ./a.txt 相对于执行 node 命令所处的终端路径
// 这不是错误,Node 就是这样设计的
// 就是说,文件操作路径中,相对路径设计的就是相对于执行 node 命令所处的路径
// fs.readFile('C:/Users/lpz/Desktop/nodejs/06/code/foo/a.txt', 'utf8', function (err, data) {
// if (err) {
// throw err
// }
// console.log(data)
// })
// console.log(__dirname + '/a.txt')
// C:\Users\lpz\Desktop\nodejs\06\code
fs.readFile(path.join(__dirname, './a.txt'), 'utf8', function (err, data) {
if (err) {
throw err
}
console.log(data)
})
art-template模板继承和子模板
header.html
<div>
<h1>公共的头部</h1>
</div>
footer.html
<div>
<h1>公共的底部</h1>
</div>
layout.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.css">
{{ block 'head' }}{{ /block }} <!--相当于一个插槽里面填什么东西由子组件决定-->
</head>
<body>
{{ include './header.html' }} <!--引入公共头部-->
<!--相当于一个插槽里面填什么东西由子组件决定-->
{{ block 'content' }}
<h1>默认内容</h1>
{{ /block }}
{{ include './footer.html' }} <!--引入公共的底部-->
<script src="/node_modules/jquery/dist/jquery.js"></script>
<script src="/node_modules/bootstrap/dist/js/bootstrap.js"></script>
{{ block 'script' }}{{ /block }}
</body>
</html>
content.html
{{extend './layout.html'}} <!--继承父组件的所有东西-->
<!--根据父组件定义插槽的位置来填写属于自己的内容-->
{{ block 'content' }}
<div>
<h1>列表页自己的内容</h1>
</div>
{{ /block }}
更多推荐
所有评论(0)