模块化开发
模块的导出与导入
第一种导出、导入的方法:
导出:
const greeting = name =>`hello ${name}`
exports.greeting = greeting
导入:
const b = require('模块的文件目录')
console.log(b.greeting('张三'));
另一种写法:module.exports.属性值 = 导出的对象
const greeting = name =>`hello ${name}`
module.exports.greeting = greeting
那么module.exports和exports有什么区别呢?
怎么样理解呢?
当module.exports 与 exports指向同一个内存空间,module.exports 与 exports是等价的
const greeting = name =>`hello ${name}`
const x = 100
module.exports.greeting = greeting
exports.x = x;
const b = require('./hh')
console.log(b);
//{ greeting: [Function: greeting], x: 100 }
但是如果module.exports指向了一个新的内存空间,最终的导出结果就是module.exports指向的内存空间的值。
const greeting = name =>`hello ${name}`
const x = 100
const y = 50
module.exports.greeting = greeting
exports.x = x;
module.exports ={
name:"张三"
}
exports.y = y
const b = require('./hh')
console.log(b);
//{ name: '张三' }
系统模块
文件读取模块
fs.readFile的三个参数,第一个参数是读取文件的位置,第二个参数的是文件的编码(可选),第三个文件是回调函数,因为文件读取需要时间,当文件读取完毕之后,readFile函数会调用回调函数,将读取的结果作为参数,进行回调,回调函数的第一个参数是err,第二个参数是doc
//1、通过模块的名字fs对模块进行引用
const fs = require('fs')
//2、通过模块内部的readFile读取文件内容
fs.readFile('./style.css','utf-8',(err,doc)=>{
//如果文件读取出错err是一个对象,包含错误信息
//如果文件读取正确err是null
//doc是文件读取的结果
console.log(err);
console.log(doc);
})
路径模块path
const path = require('path')
const finalPath = path.join('public','uploads','avatar')
console.log(finalPath);
路径模块和文件模块的结合
当使用文件模块的时候,是推荐使用绝对路径,为什么上述可以使用相对路径?因为读取的文件是相对于命令行工具的当前工作目录下,如果读取的文件与命令行工具不在同级呢?
可以使用__dirname获取当前文件所在的绝对路径
const path = require('path')
const fs = require('fs')
let finalPath = fs.readFile(path.join(__dirname,"style.css"),'utf-8',(err,doc)=>{
if(err !== null) return
console.log(path.join(__dirname,"style.css"));
console.log(__dirname);
})
第三方模块
Gulp
基于node平台开发的前端构建工具
- 项目上线,HTML、CSS、JS文件压缩合并
- 语法转换
- 公共文件抽离
- 修改文件浏览器自动刷新
Gulp使用
- 使用npm install gulp下载gulp库文件
- 在项目根目录下建立gulpfile.js文件
- 重构项目的文件夹结构src目录放置源代码文件dist目录放置构建后文件
- 在gulpfile.js文件中编写任务
- 在命令行工具中执行gulp任务
Gulp中提供的方法
- gulp.src() : 获取任务要处理的文件
- gulp.dest():输出文件
- gulp.task():建立gulp任务
- gulp.watch():监控文件的变化
上述将Gulp安装完成,并且文件夹都建立好之后就可以使用Gulp了
//gulpfile.js
const gulp = require('gulp');
gulp.task('first',()=>{
console.log('人生中的第一个gulp任务执行了');
gulp.src('./src/hh.js')
.pipe(gulp.dest('dist/'));
});
想要执行上述代码,首先要在命令行中输入 npm install gulp-cli -g
全局安装gulp-cli
之后在命令行输入 gulp first (其实就是gulp+任务名字,也就是task的第一个参数)
输出的结果:
注意看最后一句:忘记了加入async,所以要修改上述代码,只需要在回调函数前面加入async
//gulpfile.js
const gulp = require('gulp');
gulp.task('first', async ()=>{
console.log('人生中的第一个gulp任务执行了');
gulp.src('./src/hh.js') // 获取任务要处理的文件
.pipe(gulp.dest('dist/')); //输出文件
});
此时就不报错了,在dist文件下也复制了hh.js文件
Gulp插件
Gulp提供的方法非常少,如果想实现其他的功能,就需要用到Gulp的插件
1、实现html文件的压缩
- 压缩html文件中代码的压缩操作
首先下载压缩html插件npm install gulp-htmlmin
const gulp = require('gulp');
const htmlmin = require('gulp-htmlmin');
gulp.task('htmlmin', async ()=>{
gulp.src('./src/简历.html').pipe(htmlmin({ collapseWhitespace : true }))
.pipe(gulp.dest('dist'))
});
2、css任务
- less语法转换
- css代码压缩
首先要下载npm install gulp-less
用于代码转换
npm install gulp-csso
用于代码压缩
const gulp = require('gulp');
const less = require('gulp-less');
const csso = require('gulp-csso');
gulp.task('csso', async ()=>{
gulp.src(['./src/css/*.css','./src/css/*.css']).pipe(less()).pipe(csso())
.pipe(gulp.dest('dist/css'))
});
3、执行多个任务
如果想只输入一个命令就可以执行多个任务,第二个参数改成gulp.series([任务名])
这样只需要输入一个命令就可以执行多个任务
const gulp = require('gulp');
const htmlmin = require('gulp-htmlmin');
const less = require('gulp-less');
const csso = require('gulp-csso');
gulp.task('csso', async ()=>{
gulp.src(['./src/css/*.css','./src/css/*.css']).pipe(less()).pipe(csso())
.pipe(gulp.dest('dist/css'))
});
gulp.task('htmlmin', async ()=>{
gulp.src('./src/简历.html').pipe(htmlmin({ collapseWhitespace : true }))
.pipe(gulp.dest('dist'))
});
gulp.task('default', gulp.series(['csso','htmlmin']))
package-lock.json文件
- 锁定包的版本,确保再次下载时不会因为包版本不同而产生问题
- 加快下载速度,因为该文件已经记录了项目所依赖第三方包的树状结构和包的下载地址,重新安装时按需下载即可,不需要做额外的工作
Node.js中模块加载机制
require('./find.js')
- require方法根据模块路径查找模块,如果是完整路径,直接导入模块
require('./find')
- 如果模块后缀省略,先找同名JS文件再找同名JS文件夹
- 如果找到了同名文件夹,找文件夹中的index.js
- 如果文件夹中没有index.js,就会去find文件夹中的package.json文件中查找main选项中的入口文件
- 如果找指定的入口文件不存在或者没有指定入口文件就会报错,模块没有被找到
require('find')
- Node.js会假设它是系统模块
- Node.js会去node_modules文件中,首先查看是否有该名字的JS文件,再看是否有同名的文件夹,如果进入文件夹就看里面是否有index.js,否则报错
服务器
创建web服务器
get
//用于创建网络服务器的模块
const http = require('http');
//app对象就是网站服务器对象
const app = http.createServer();
//当客户端有请求来的时候
app.on('request',(req,res) => {
res.end('<h2>hello,user</h2>')
});
//监听端口
app.listen(3000);
console.log('网站服务器启动成功');
在网址输入localhost:3000
在上述代码中,本想让h2作为一个标签反应在页面上,但是却是显示的纯文本内容,这就需要指定一下服务器返回的内容应该是个html文件
//用于创建网络服务器的模块
const http = require('http');
//app对象就是网站服务器对象
const app = http.createServer();
//当客户端有请求来的时候
app.on('request',(req,res) => {
//写入响应头
res.writeHead(200,{
'content-type':'text/html'
})
res.end('<h2>hello,user</h2>')
});
app.listen(3000);
console.log('网站服务器启动成功');
post
//用于创建网络服务器的模块
const http = require('http');
//app对象就是网站服务器对象
const app = http.createServer();
//当客户端有请求来的时候
app.on('request',(req,res) => {
let postParams="";
req.on('data',params => {
postParams += params
});
req.on('end',() => {
console.log(postParams);
})
res.end('ok')
});
app.listen(3000);
console.log('网站服务器启动成功');
<!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>
<!-- method:指定当前表单提交方式
action:指定当前表单提交的地址 -->
<form action="http://localhost:3000" method="post">
<input type="text" name="username">
<input type="password" name="password">
<input type="submit">
</form>
</body>
</html>
路由
const http = require('http');
const app = http.createServer();
app.on("request",(req,res) => {
const myURL = new URL(`http://localhost:8080${req.url}`)
const method = req.method.toLowerCase()
const pathname = myURL.pathname
res.writeHead(200,{
'content-type':'text/html;charset=utf8'
});
if (method == 'get'){
if(pathname == '/' || pathname == '/index'){
res.end('欢迎来到首页')
}else if(pathname == '/list'){
res.end('欢迎来到列表')
}else{
res.end('页面不存在')
}
}
})
app.listen(8080)
console.log('服务器8080启动成功!');
异步Api
同步API可以从返回值拿到API执行的结果,但是异步不可以
同步:
function sum(a1,a2){
return a1+a2
}
console.log(sum(20,30))
//50
异步:
function getMsg(){
setTimeout(function(){
return {msg:"hello node"}
},2000)
}
console.log(getMsg());
//undefined
异步api的返回值怎么拿到?
通过回调函数,什么是回调函数?
自己定义了,被别人调用了的函数,或者是函数被作为参数传入到另一个函数中。
function getData(callback){
callback()
};
getData(function(){
console.log('callback函数被调用了');
})
//callback函数被调用了
通过回调函数,拿到异步api返回值
function getData(callback){
setTimeout(()=>{
callback({
msg:"hello nodejs"
})
},2000)
};
getData(data => console.log(data))
//{ msg: 'hello nodejs' }
避免缓存的问题的写法:
AJAX 能提高页面载入的速度主要的原因是通过 AJAX 减少了重复数据的载入,也就是说在载入数据的同时将数据缓存到内存中,一旦数据被加载其中,只要我们没有刷新页面,这些数据就会一直被缓存在内存中,当我们提交的 URL 与历史的 URL 一致时,就不需要提交给服务器,也就是不需要从服务器上面去获取数据,虽然这样降低了服务器的负载提高了用户的体验,但是我们不能获取最新的数据。为了保证我们读取的信息都是最新的,我们就需要禁止他的缓存功能。解决方式有以下几种:
在 URL 后面加上一个随机数:Math.random()。
在 URL 后面加上时间戳:new Date().getTime()。
在使用 AJAX 发送请求前加上 ajax.setRequestHeader(‘Cache-Control’, ‘no-cache’)
JQuery中的ajax方法
GET请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>首页</title>
<link rel="stylesheet" href="../css/index.css">
<script src="../js/jquery-3.4.1.js"></script>
</head>
<body>
<h1>jquery_get</h1>
<h1>首页标题</h1>
<hr>
<p>欢迎来到我们网站!</p>
<a href="/detail.html">跳转到详情页</a>
<br><br>
<button id="obtn">点击按钮加载更多</button>
<div id="odiv"></div>
<script>
$('#obtn').click(()=> {
$.ajax({
url:"/get_Data",
success:(resp)=>{
$("#odiv").html(resp)
}
})
})
</script>
</body>
</html>
服务器代码:
const http = require("http");
const fs = require("fs");
const path = require("path");
const port = 8081;
const server = http.createServer((request,response)=>{
//每来一个请求就执行一次这里的代码
//判断浏览器需要哪个资源文件??
let reqUrl = request.url;
if(reqUrl==="/" || reqUrl==="/index.html" ){
// 读取页面内容,返回信息
let filePath = path.join(__dirname, "assets", "html", "index.html");
let content = fs.readFileSync(filePath)
response.end(content)
}
else if(reqUrl==="/jquery_login.html"){
// 读取页面内容,返回信息
let filePath = path.join(__dirname, "assets", "html", "jquery_login.html");
let content = fs.readFileSync(filePath)
response.end(content)
}
else if(reqUrl==="/js/jquery-3.4.1.js"){
// 读取页面内容,返回信息
let filePath = path.join(__dirname, "assets", "js", "jquery-3.4.1.js");
let content = fs.readFileSync(filePath)
response.end(content)
}
else if(reqUrl==="/get_Data"){
// 读取页面内容,返回信息
response.end('接收到了ajax的get请求,这是响应回客户端的字符串')
}
})
server.listen(port,(error)=>{
console.log(`WebServer is listening at port ${port}!`);
})
POST
服务器代码:
const http = require("http");
const fs = require("fs");
const path = require("path");
const port = 8081;
const pwd = '666';
const uname = 'zhangs';
const server = http.createServer((request,response)=>{
//每来一个请求就执行一次这里的代码
//判断浏览器需要哪个资源文件??
let reqUrl = request.url;
if(reqUrl==="/" || reqUrl==="/index.html" ){
// 读取页面内容,返回信息
let filePath = path.join(__dirname, "assets", "html", "index.html");
let content = fs.readFileSync(filePath)
response.end(content)
}
else if(reqUrl==="/jquery_login.html"){
// 读取页面内容,返回信息
let filePath = path.join(__dirname, "assets", "html", "jquery_login.html");
let content = fs.readFileSync(filePath)
response.end(content)
}
else if(reqUrl==="/js/jquery-3.4.1.js"){
// 读取页面内容,返回信息
let filePath = path.join(__dirname, "assets", "", "jquery-3.4.1.js");
let content = fs.readFileSync(filePath)
response.end(content)
}
else if(reqUrl==="/login.html"){
// 读取页面内容,返回信息
let filePath = path.join(__dirname, "assets", "html", "login.html");
let content = fs.readFileSync(filePath)
response.end(content)
}
else if(reqUrl==="/login_post"){
// 读取页面内容,返回信息
request.on('data',(data) => {
let{username,password} = JSON.parse(data.toString());
if(username ===uname&&password === pwd){
response.end('登录成功')
}else{
response.end('用户名或者密码错误,登录失败')
}
})
}
})
server.listen(port,(error)=>{
console.log(`WebServer is listening at port ${port}!`);
})
前端代码:
<!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>
<script src="../js/jquery-3.4.1.js"></script>
</head>
<body>
<div>jquery_post</div>
<form>
用户名:<input type="text" name="username" id="username"><br><br>
密 码:<input type="password" name="password" id="password"><br><br>
<input type="button" value="提交" id="obtn">
</form>
<div id="odiv"></div>
<script>
$("#obtn").click(()=>{
let params = {
username: $('#username').val(),
password: $('#password').val()
}
$.ajax({
url:"/login_post",
type:"POST",
data:JSON.stringify(params),
success:(resp)=>{
$("#odiv").html(resp)
}
})
})
</script>
</body>
</html>