安装Node
首先是安装node.js
由于Node.js平台是在后端运行JavaScript代码,所以,必须首先在本机安装Node环境。首先,从Node.js官网下载对应平台的安装程序。node.js的官方网址是:(https://nodejs.org/en/)。
在Windows上安装时务必选择全部组件,包括勾选Add to Path。
安装完成后,在Windows环境下,请打开命令提示符,然后输入node -v,如果安装正常,你应该看到这样的输出,版本号要在v7.6.0之上:
继续在命令提示符输入node,此刻你将进入Node.js的交互环境。在交互环境下,你可以输入任意JavaScript语句,例如100+200,回车后将得到输出结果。
要退出Node.js环境,连按两次Ctrl+C
安装npm
要安装npm.
npm是Node.js的包管理工具(package manager)。
为啥我们需要一个包管理工具呢?因为我们在Node.js上开发时,会用到很多别人写的JavaScript代码。如果我们要使用别人写的某个包,每次都根据名称搜索一下官方网站,下载代码,解压,再使用,非常繁琐。于是一个集中管理的工具应运而生:大家都把自己开发的模块打包后放到npm官网上,如果要使用,直接通过npm安装就可以直接用,不用管代码存在哪,应该从哪下载。
我们在命令提示符或者终端输入npm -v,应该看到类似的输出:
什么是node
官方: 基于 Chrome V8 的 JS 运行时环境
私人: 就是一个 "软件", 只不过这个软件是用来执行 js 文件
学习node
1.node 是咋运行js文件
1.1打开命令行, 输入 node 回车
表示已经运行 node 这个 "软件"
你就可以再命令行输入 js 代码来执行
缺点: 代码留不下来
1.2打开命令行, 输入 node 你要执行的文件 回车
把 js 代码写在一个 .js 后缀的文件里面
通过命令行运行
2.模块化开发
每一个 js 文件都是相对独立的,互相之间没有任何关系,我们没有一个统一调配的东西,我们只能靠模块化开发。
3.模块化
3.1什么是模块
一个 js 文件就是一个模块
我们把一类方法放在一个 js 文件里面, 这个 js 文件就变成了一个模块
再需要哪一类方法的时候, 引入这个 js 文件就好了
3.1.1使用模块有什么好处?
最大的好处是大大提高了代码的可维护性。其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。
我们在编写程序的时候,也经常引用其他模块,包括Node内置的模块和来自第三方的模块。
使用模块还可以避免函数名和变量名冲突。相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。
3.2什么是模块化
再开发的过程中, 尽可能把开发方式趋近于模块的方式,
把我们所有的内容都按照类别分好文件,按需引入
3.3模块化的分类
3.3.1自定义模块(module)
1.为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,
很多编程语言都采用这种组织代码的方式。在Node环境中,一个.js文件就称之为一个模块(module)。
2.自己定义模块, 自己再需要的时候导入模块使用
3.自己决定模块内哪些内容向外暴露
我们这个文件定义好以后, 你想让别人使用的东西, 就放在 module.exports 里面
1. 给 module.exports 重新赋值
赋值为一个新的对象或者数组或者任何其他数据类型
2. exports 也是每一个 js 文件天生自带的一个变量
每一个 js 文件里面相当于有一句代码 var exports = module.exports
注意: 如果你需要给 module.exports 从新赋值, 那么不能使用 exports
// 我自己的变量和方法
const num = 100
const str = 'hello world'
function fn() {
console.log('我是 fn 方法')
}
导出方式:
- 标准导出
module.exports.fn1 = fn1
module.exports.num = 100
此时 module.exports = { fn1: function () {}, num: 100 }
- 给 module.exports 从新赋值
module.exports = {
fn1: fn1,
num: 100
}
输出的为: exports: { fn1: [Function: fn1], num: 100 },
- 利用 exports 向外暴露内容
注意: 如果你需要给 module.exports 从新赋值, 那么不能使用 exports
exports.fn1 = fn1
exports.num = 200
exports.str = 'hello world'
exports = {
fn1: fn1,
num: 100,
str: 'hello world'
}
使用模块
1.使用模块就是把其他模块导入到自己的文件里面,使用另一个文件导出的内容
2.每一个 js 文件里面天生自带一个方法叫做 require()
语法: require('要导入的 js 文件路径')
如果后缀是 .js 可以省略不写
返回值: 被导入文件里面的 module.exports
导入以后, 你就可以使用 这个文件里面向外暴露的内容
// 导入我们定义好的模块
const modA = require('./01_定义模块')
console.log(modA)
modA.fn1()
3.3.2内置模块
node 这个环境天生自带的一些模块("一个一个的 js 文件"),你需要使用的时候, 直接引入使用就好了
每一个 js 文件里面自带两个变量
1. __dirname: 表示该文件所在的文件夹的绝对路径
2. __filename: 表示该文件的绝对路径
执行后的:
console.log(__dirname) ------->D:\WEB\Node\0831\01_代码\03_内置模块
console.log(__filename)--------->D:\WEB\Node\0831\01_代码\03_内置模块\02_path模块.js
1.fs模块
file system 文件系统模块,node 天生自带的一个模块,我们直接导入使用
这个模块里面封装的方法都是和操作 文件 和 文件夹 相关的内容
使用fs模块:
// 0. 导入 fs 模块
const fs = require('fs')
// 1. readFile()---异步读取文件
=> 语法: fs.readFile(路径, 读取格式, 回调函数)
=> 路径: 你要读取的文件的路径, 如果路径不存在, 会出现错误
=> 读取格式: 选填, 默认是 buffer, 我们可以选填 'utf8'
=> 回调函数: 读取成功以后会执行的函数
代码如下:
fs.readFile('./test.txt', 'utf8', function (err, data) {
// err 就是读取失败的时候的错误信息
// data 就是读取成功的时候的读取内容
if (err) return console.log(err)
console.log('读取成功')
console.log(data)
})
//2. readFileSync()---同步读取文件
=> 语法: fs.readFileSync(路径, 读取格式)
=> 返回值: 读取的文件内容
=> 注意: 读取路径不存在, 或者没有权限的时候, 会报错, 打断程序的继续执行
代码如下:
const res = fs.readFileSync('./test.txt','utf8')
console.log('读取完成')
console.log(res)
// 3. writeFile()---异步写入文件
=> 语法: fs.writeFile(路径, 要写入的内容, 回调函数)
=> 路径: 你要写入文件的路径, 如果路径文件不存在, 会创建一个这个文件再写入
=> 写入的内容: 自己定义
=> 回调函数: 写入成功以后执行的函数, 必填
=> 注意: 完全覆盖式的写入
代码如下:
fs.writeFile('./test.txt', '你好 世界', function () {
console.log('写入完成')
})
// 4. writeFileSync()---同步写入文件
=> 语法: fs.writeFileSync(路径, 要写入的内容)
=> 注意: 完全覆盖式的写入
代码如下:
fs.writeFileSync('./test.js', 'hello node')
console.log('写入完成')
// 5. appendFile()---异步追加内容
=> 语法: fs.appendFile(路径, 追加的内容, 回调函数)
=> 路径: 写入文件的路径, 没有该路径, 自己创建
=> 追加的内容
=> 回调函数: 必填
代码如下:
fs.appendFile('./test1.txt', 'hello world', () => {})
// 6. appendFileSync()---同步追加内容
=> 语法: fs.appendFileSync(路径, 追加的内容)
代码如下:
fs.appendFileSync('./test1.txt', '你好 世界')
// 7. readdir()---异步读取文件夹
=> 语法: fs.readdir(路径, 回调函数)
代码如下:
fs.readdir('../02_自定义模块', (err, data) => {
if (err) return console.log(err)
console.log('读取文件夹成功')
console.log(data)
})
// 8. readdirSync()---同步读取文件夹
=> 语法: fs.readdirSync(路径)
代码如下:
const res = fs.readdirSync('../02_自定义模块')
console.log(res)
// 9. mkdir()---异步创建文件夹
=> 语法: fs.mkdir(路径, 回调函数)
代码如下:
fs.mkdir('./a', (err) => {
if (err) return console.log(err)
console.log('创建文件夹成功')
})
// 10. mkdirSync()---同步创建文件夹
=> 语法: fs.mkdirSync(路径)
代码如下:
fs.mkdirSync('./b')
// 11. rmdir()---异步删除文件夹
=> 语法: fs.rmdir(路径, 回调函数)
代码如下:
fs.rmdir('./a', err => {
if (err) return console.log(err)
})
// 12. rmdirSync()---同步删除文件夹
=> 语法: fs.rmdirSync(路径)
代码如下:
fs.rmdirSync('./b')
// 13. unlink()---异步删除文件
=> 语法: fs.unlink(路径, 回调函数)
代码如下:
fs.unlink('./test1.txt', err => {
if (err) return console.log(err)
})
// 14. unlinSync()---同步删除文件
=> 语法: fs.unlinkSync(路径)
代码如下:
fs.unlinkSync('./test123.txt')
// 15. stat()---异步查看
=> 语法: fs.stat(路径, 回调函数)
=> 回调函数里面可以接收一个 data
=> 表示你查看的这个路径的内容
代码如下:
fs.stat('./test.txt', (err, data) => {
if (err) return console.log(err)
console.log(data)
console.log(data.isFile())
console.log(data.isDirectory())
})
// 16. statSync()---同步查看
=> 语法: fs.statSync(路径)
=> 返回值: 查看该路径的结果
代码如下:
const res = fs.statSync('../02_自定义模块')
console.log(res)
console.log(res.isFile())
console.log(res.isDirectory())
17. isFile()
=> 注意: 只有 stats 可以调用
-> stat 的 回调函数中的 data
-> statSync 的返回值
=> 语法: stats.isFile()
=> 返回值: 一个布尔值
18: isDirectory()
=> 注意: 只有 stats 可以调用
-> stat 的 回调函数中的 data
-> statSync 的返回值
=> 语法: stats.isDirectory()
=> 返回值: 一个布尔值
2.path模块
node 自带的一个内置模块,里面封装的都是一些操作路径的或者和路径相关的方法
// 0. 导入 path 模块
const path = require('path')
// 1. join()---拼接相对路径
=> 语法: path.join(路径1, 路径2, 路径3, ...)
=> 返回值: 拼接好的路径结果
=> 注意: 拼接规则是后一个参数是前一个参数的子级,除非你写 ../
代码如下:
const path1 = path.join('a', './b', '/c', 'd')
console.log(path1) //输出结果:a\b\c\d
const path2 = path.join('a', './b', '/c', 'd', '../e')
console.log(path2) //输出结果:a\b\c\e
// 2. resolve()---拼接绝对路径
=> 语法: path.resolve(路径1, 路径2, 路径3, ...)
=> 返回值: 拼接好的绝对路径
=> 注意:拼接规则是每一个参数都是相对独立的一个参数
=> 如果你写 /xx, 直接回到根目录
-> xx 当前目录下
-> ./xx 当前目录下
-> ../xx 上一级目录
代码如下:
const path1 = path.resolve('a', './b')
console.log(path1) //\a\b
const path2 = path.resolve('a', './b', '/c')
console.log(path2) //D:\c
// 3. extname()---获取文件后缀名
=> 语法: path.extname(文件名)
=> 返回值: 该文件的后缀名
代码如下:
const ext = path.extname('abc.html')
console.log(ext) //.html
// 4. isAbsolute()---判断路径是不是绝对路径
=> 语法: path.isAbsolute(路径)
=> 返回值: 一个布尔值
=> 路径区分:
=> 绝对路径: 从根目录开始的路径
=> 相对路径: 不是从根目录开始的路径
代码如下:
const res = path.isAbsolute('/a/b')
console.log(res) //true
// 5. parse()---解析路径信息
=> 语法: path.parse(路径)
=> 返回值: 一个对象, 里面包含该路径的所有信息
代码如下:
const res = path.parse(__filename)
console.log(res)
{ root: 'D:\\',
dir: 'D:\\WEB\\Node\\0831\\01_代码\\03_内置模块',
base: '02_path模块.js',
ext: '.js',
name: '02_path模块'
}
3.url 内置模块
node 自带的一个内置模块, 里面封装的都是和 url 地址栏相关的方法,使用的时候直接导入使用
0. 导入 url 模块
const url = require('url')
1. parse()----解析 url 地址的方法
=> 语法: url.parse(url 地址, 是否解析查询字符串)
=> 地址: 要解析的地址
=> 是否解析查询字符串: 默认是 false, 选填 true
=> 会把地址里面的查询字符串解析成一个对象的形式
=> 返回值: 是一个对象, 里面包含整个 url 地址的所有信息
代码如下:
const res = url.parse('http://www.guoxiang.com:8080/a/b/c/hello.html?a=100&b=200#abc', true)
console.log(res)
结果如下:
Url {
protocol: 'http:',
slashes: true,
auth: null,
host: 'www.guoxiang.com:8080',
port: '8080',
hostname: 'www.guoxiang.com',
hash: '#abc',
search: '?a=100&b=200',
query: { a: '100', b: '200' },
pathname: '/a/b/c/hello.html',
// 路径标识符, 前后端配套的一个标识符(暗号)
path: '/a/b/c/hello.html?a=100&b=200',
href:
'http://www.guoxiang.com:8080/a/b/c/hello.html?a=100&b=200#abc'
}
小知识:
// post 请求是在请求体携带参数
// a=100&b=200&c=300
const str = 'a=100&b=200&c=300'
const res = url.parse('?' + str, true)
console.log(res.query) //{ a: '100', b: '200', c: '300' }
console.log(res.query.a); //100
4. http 模块
http模块是 node 内置的一个 模块 , 主要是用来创建一个 http 服务的模块 ,需要使用的时候直接导入使用
// 0. 导入 http 模块
const http = require('http')
// 1. createServer()----创建服务的方法
=> 语法: http.createServer(function () {})
=> 每一个请求进来的时候, 都会触发函数
=> 返回值: 一个服务
// 2. listen()
=> 注意: 需要使用 服务(createServer 的返回值) 来调用
=> 语法: 服务.listen(端口号, 回调函数)
=> 端口号: 0 ~ 65535, 尽量不使用 1024 以下
=> 域名: 默认是本机 localhost || 127.0.0.1
=> 当 listen 执行以后
=> 你的 命令行, 就会被变成了一个服务器
=> 一个什么都没有的服务器
=> 当你访问 localhost:8080 的时候, createServer 后面的函数就会执行
代码如下:
// 0. 导入 http 模块
const http = require('http')
const fs = require('fs')
// 1. createServer()
const server = http.createServer(function (req, res) {
// 这个函数接收两个参数
// req: request 本次请求的所有信息
//req. 里面有一个信息叫做 url 就是路径信息
// res: response 本次的响应对象
// res 里面有一个方法叫做 end()
// 专门给前端返回信息的方法
console.log('有请求进来了')
if (req.url === '/abcss') {
// 读取 index.html
fs.readFile('./index.html', (err, data) => {
if (err) return console.log(err)
// 把 data 返回给前端
res.end(data)
})
}
})
// 2. 监听端口号
server.listen(8080, () => {
console.log('running at port 8080! ^_^ ')
})
3.3.3第三方模块
第三方插件有好多,我就不多介绍了,介绍两三个意思一下了。
// 1.moment 用来格式化时间的
官方网站:https://momentjs.com/
使用:moment(时间对象).format(格式化规则)
在你导入包以后, 使用方法之前, 设置一下语言环境
// 1.导入moment
const moment = require('moment')
// 2.把格式化包换成中文
moment.locale('zh-cn')
// 3.拿到当前时间
const time = new Date()
// 4.把当前时间进行格式化
const res = moment(time).format('MMMM Do YYYY, h:mm:ss a')
console.log(time)
console.log(res)
// 2.nodemailer第三方模块, 专门用来发邮件
使用:
1. 使用 nodemailer 创建一个 发送器(邮差)
=> 语法: nodemailer.createTransporter(配置文件{})
=> 参数位置: 需要一些内容
=> 对邮件发送放的配置
=> 直接在包里面找到 -> nodemailer -> lib -> well-known
=> 返回值: 就是一个发送器
2. 使用发送器去发送邮件
=> sendmail(邮件的配置{}, 回调函数) 方法
=> from
=> to
=> subject: '标题'
=> text: '' 文本内容
=> html: 超文本内容
代码如下:
const nodemailer = require('nodemailer')
const transporter = nodemailer.createTransport({
"host": "smtp.qq.com",
"port": 465,
"secure": true,
auth: {
user: '787306841@qq.com',
pass: 'mrkxgkfaeomwbaic'
}
})
transporter.sendMail({
from: '787306841@qq.com',
// to: '1911124543@qq.com',
to: ['1911124543@qq.com', '313612895@qq.com'],
subject: '来给你个神秘大礼',
text: '你想知道这啥吗?', // 文本内容
html: '', // 超文本内容
}, function (err, info) {
if (err) return console.log(err)
console.log('发送成功')
console.log(info)
})
// 3.mysql模块,专门用来连接 mysql 数据库
=> 使用
=> mysql 包给我们提供了两个连接数据库的方式
=> 1. createConnection()
=> 语义趋近于单次连接单次使用
=> 连接, 执行 sql 语句, 关闭
=> 最好是执行一次 数据库操作关闭一次
=> 2. cretaePool()
=> 创建一个连接池
=> 语义趋近于打开就不关了
使用 db 模块执行 sql 语句
1. db.query(sql, 回调函数)
2. db.query(sql, [], 回调函数)
-> 在 sql 语句里面预埋好多 问号(?)
-> 你在数组里面依次传递参数
// 0. 导入 mysql
const mysql = require('mysql')
// 1. 连接数据库----返回值就是连接好的模块
const db = mysql.createConnection({
host: 'localhost', // 127.0.0.1
port: '3306',
user: 'root',
password: 'root',
database: 'goodslist' // 操作哪一个库
})
// 2. 使用 db 模块执行 sql 语句
const username = 'wangze'
db.query('SELECT * FROM `users` WHERE `username`="' + username + '"', (err, data) => {
if (err) return console.log(err)
console.log(data)
})
另一种方法:
db.query(
'SELECT * FROM `users` WHERE `username`=? AND `password`=?',
[username, password],
(err, data) => {
if (err) return console.log(err)
console.log(data)
})
// 3. 关闭数据库连接
db.end()
=> 2. cretaePool()
=> 创建一个连接池
=> 语义趋近于打开就不关了
// 1. 连接数据库
const db = mysql.createPool({
host: '127.0.0.1',
port: 3306,
user: 'root',
password: 'root',
database: 'gp19'
})
// 2. 操作数据库
const sql = 'INSERT INTO `users` VALUES(null, ?, ?)'
db.query(sql, ['张思锐', '123456'], (err, data) => {
if (err) return console.log(err)
console.log(data)
})
欲知后事如何,请看下回分解。