作者主页:仙女不下凡
前言介绍:以下 内容都是我个人对于前端知识的总结,会定期更新欢迎持续关注!
欢迎点赞 收藏 ⭐留言 如有错误敬请指正!
学习视频地址:https://www.bilibili.com/video/BV1j5411K7EH?from=search&seid=650434603315537295
学习进度:该视频适用于有css、html、JavaScript基础的同学
学习方法总结:如何从零自学成为前端工程师,怎么学习?怎么选老师?
⑴ 为什么学习Node
(服务器开发)?
❶需要掌握一些后端技术,能够和后端程序员紧密配合;
❷网站业务逻辑前置,学习前端技术需要后端技术支撑(ajax
);
❸扩宽视野,能够站在更高的角度审视整个项目;
❹Node
使用JavaScript
语法开发后端应用。
⑵ 服务器端开发要做的事情: ❶实现网站业务逻辑,比如登录功能;❷数据的增删改查。
⑶ Node
是什么? Node
是一个基于Chrome V8
引擎的JavaScript
代码运行环境,主要作用就是运行JavaScript
代码。
⑴ Node
运行环境搭建步骤: ❶ Node.js
运行环境安装❷检查Node
是否安装成功,命令node -v
⑵ 如下表格 为Node
环境安装失败解决办法
错误代码 | 失败原因 | 解决办法 |
---|---|---|
2502、2503 | 系统账户权限不足 | 以管理员身份运行powershell 命令行工具, msiexec/package node安装包位置 |
执行命令报错 | Node 安装目录写入 环境变量 失败 |
将Node 安装目录添加到 环境变量 中 |
⑴Node.js
的组成:Node.js
是有 ECNAScript
及 Node
环境 提供的一些附加API
组成的,包括读取文件、网络路径等一些更强大的API
。
Node.js
基础语法: ECNAScript
的语法都可以使用。
Node.js
全局对象: 浏览器中全局对象是window
,Node
中全局对象是global
,所以Node.js
全局对象中有以下方法,与JavaScript
方法非常类似,方法前面global
对象可以省略。
方法 | 作用 |
---|---|
global.console.log() | 在控制台输出 |
global.setTimeout() | 设置超时定时器 |
global.clearTimeout() | 清除超时定时器 |
global.setInterval() | 设置间歇定时器 |
global.clearInterval)() | 清除间歇定时器 |
Node.js
模块化开发存在的原因: 解决JavaScript开发中文件依赖和命名冲突的弊端;
⑴Node.js
的基本使用:Node.js
规定一个JavaScript
文件就是一个模块,模块内部定义的变量和函数默认情况下外部无法得,模块内部可以使用exports
对象或module.exports
对象进行成员导出,使用require
方法导入其他模块。,示例代码如下
/该文件为module-a.js文件/
const add = (n1,n2) => n1 + n2;
exports.add = add; /或者module.exports.add = add;/
/该文件名为module-b.js文件/
const a = require('./module-a.js'); /导入模块.js可以省略/
console.log(a.add(10,20)); //执行结果 30
⑵exports
与module.exports
关系:exports
是module.exports
的别名,当exports
与module.exports
指向不同的地址时,导出对象最终以module.exports
为准,代码示例如下
/module-a.js文件-当指向相同时/
const x = 100;
exports.x = x;
module.exports.greeting = greeting;
/module-b.js文件/
const a = require('./module-a.js'); /导入模块.js可以省略/
console.log(a); //执行结果 {x: 100, greeting: greeting}
/module-a.js文件-当指向不同时/
const x = 100;
exports.x = x;
module.exports.greeting = greeting;
module.exports = { name: '张三'; }
/module-b.js文件/
const a = require('./module-a.js');
console.log(a); //执行结果 { name: '张三' }
什么是系统模块: Node
运行环境提供的API
是以模块化的方式进行开发的,所以又称Node
运行环境为系统模块。接下来会学习一下常用的系统模块(常用API
)。
常用系统模块之fs
文件操作系统
/语法格式/
const fs = require('fs'); /引入文件操作系统模块/
fs.reaFile('文件路径/文件名称', ['文件编码'], callback); /读取文件内容/
fs.reaFile('文件路径/文件名称', ['文件编码'], callback); /写入文件内容/
常用系统模块之path
路径操作系统
const path = require('path'); /导入path模块/
path.join('路径1','路径2',...); /路径拼接/
相对路径VS绝对路径: 使用__dirname
获取当前文件所在的绝对路径
先思考几个问题: 什么是第三方模块?第三方模块是干什么的?
答:第三方模块是别人写好的、具有特定功能的、可以直接使用的模块,第三方模块一般以js
文件形式或以命令行工具形式存在。
获取第三方模块:npmjs.com
第三方模块存储和分发仓库 npm
第三方模块模块管理工具,
下载:npm install 模块名称
卸载:npm unintall package 模块名称
,下面了解几个非常常用的第三方模块。
nodemon
的作用: 是命令行工具,用来辅助项目开发,每次修改重新自动执行。
/使用步骤/
/1.全局下载/
npm install nodemon -g
/2.在命令行工具中使用nodemon命令替代node/
nrm的作用: 下载地址切换工具,npm
默认下载地址在国外。
/使用步骤/
npm install nrm -g /1.全局下载/
nrm ls /2.查询可用下载地址列表/
下载地址 nrm use 下载地址名称 /3.切换/
⑴Gulp
的定义: 基于node
平台开发的前端构建工具,将机械化操作编写成任务,想要执行机械化操作时执行一个命令行命令任务就能自动执行了,用机器代替手工,提高开发效率。
⑵Gulp
能做什么?
❶项目上线,HTML、CSS、JS
文件压缩合并;
❷语法装换,如ES6
转换成ES5
、less
文件转换成普通js
文件 …
❸公共文件抽离;
❹修改文件浏览器自动刷新。
⑶Gulp
使用:
❶安装,使用npm install --save-dev gulp
下载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模块
// 使用gulp.task()方法建立任务
gulp.task('first', () => { //'first'是任务名字
gulp.src('./src/css/base.css') // 获取要处理的文件
.pipe(gulp.dest('./dist/css')); // 将处理后的文件输出到dist目录,链式操作
});
//执行gulpfile.js文件中'first'任务
//1.先安装npm install gulp-cli -g
//2.在执行任务gulp first
⑸Gulp
插件: Gulp
的其他功能(压缩,语法转换等)需要通过插件来完成,所以其他功能依赖于插件
常用插件 | 作用 | 命令 |
---|---|---|
gulp-htmlmin |
html 文件压缩 |
npm install --save gulp-htmlmin |
gulp-csso |
压缩css |
npm install gulp-csso --save-dev |
gulp-babel |
JavaScript 语法转化 |
npm install --save-dev gulp-babel @babel/core @babel/preset-env |
gulp-less |
less 语法转化 |
npm install gulp-less |
gulp-uglify |
压缩混淆JavaScript |
npm install --save-dev gulp-uglify |
gulp-file-include |
公共文件包含(提取) | npm install --save-dev gulp-file-include |
browsersync |
浏览器实时同步 | ---- |
⑹插件的使用步骤:
❶npm insatll
下载对应的插件;
❷require
引入插件
❸调用插件,用的时候去查这个插件的文档的使用方法。
⑺在gulpfile.js文件中编写gulp任务:html
任务(抽取公共代码、压缩html
文件)。
⑻抽取头部公共代码的步骤: 在src
下新建一个common
文件夹用来存放公共代码,接着新建一个header.html
文件,一个空白文件不需要骨架。然后将其他页面中用到的公共header
部分放到这里。最后将通过gulp-file-include
的语法将头部引入到要用到的地方。引入写法是 @@include(‘头部路径/头部文件名’)
,再执行gulp
任务就可以了。
示例代码-html
任务(抽取公共代码、压缩html
文件)
//const gulp = require('gulp');
const less = require('gulp-less');
const csso = require('gulp-csso');
gulp.task('cssmin',done=>{
gulp.src(['./src/css/*.less','./src/css/*.css']) //选择css目录下的所有less文件和css文件
.pipe(less())
.pipe(csso())
.pipe(gulp.dest('dist/css'));
done();
})
示例代码-css
任务(less
语法转换、压缩css
代码)
//const gulp = require('gulp');
const less = require('gulp-less');
const csso = require('gulp-csso');
gulp.task('cssmin',done=>{
gulp.src(['./src/css/*.less','./src/css/*.css']) //选择css目录下的所有less文件和css文件
.pipe(less())
.pipe(csso())
.pipe(gulp.dest('dist/css'));
done();
})
示例代码-js
任务(es6
代码转换、代码压缩)
//const gulp = require('gulp');
const babel = require('gulp-babel');
const uglify = require('gulp-uglify');
gulp.task('jsmin',async ()=>{
await gulp.src('./src/js/*.js')
.pipe(babel({
//它可以判断当前代码的运行环境 将代码转换为当前运行环境所支持的代码
presets: ['@babel/env']
}))
.pipe(uglify())
.pipe(gulp.dest('dist/js'))
})
示例代码-复制任务(将项目中images、lib
文件复制去dist
目录)
//const gulp = require('gulp');
gulp.task('copy',done=>{
gulp.src('./src/images/*')
.pipe(gulp.dest('dist/images'));
gulp.src('./src/lib/*')
.pipe(gulp.dest('dist/lib'));
done();
})
示例代码-构建任务(一次性执行上面写的任务)
gulp.task('default',gulp.parallel('htmlmin','cssmin','jsmin','copy'));
示例代码-运行时可以直接写gulp
,就是默认执行这个任务。
gulp.parallel(); //可以并行计算
gulp.series(); //按照顺序执行
/*例子-----------*/
gulp.task('default',gulp.series(gulp.series('htmlmin','cssmin'),'jsmin','copy')); //一部分是顺序任务,一部分是可以并行的任务
⑴node_modules
文件夹问题
❶文件夹以及文件过多过碎,拷贝项目传输速度过慢;
❷复杂的模块依赖关系需要被记录,确保模块的版本和当前一直,否则容易报错。
⑵package.json
文件作用
package.json
文件用来解决以上两个问题,使用npm init -y
生成package.json文件。
项目依赖:写在package.json文件中dependencies
字段中,安装命令npm install 包名 --production
开发依赖:写在package.json文件中devDependencies
字段中,安装命令npm install 包名 --save-dev
❶记载了模块与模块的依赖关系等;
❷锁定包的版本:确保再次下载时不会因为包版本不同而产生问题;
❸加快下载速度:该文件中记录了项目所依赖第三方模块的树状结构和包的下载地址,重新安装时直接下载即可,不需要做额外的工作。
require('./find');
如果模块后缀省略:❶ 先找同名.js
文件;
❷若❶没有,找同名文件夹中的index.js
文件;
❸若❷没有,找package.js
文件中main
选项中入口文件;
❹若❸还找不到,报错。
require('./find');
当模块没有路径也没有后缀时:
❶假设它为系统模块,去node_modules
文件夹中找同名js文件;
❷若❶没有,找同名文件夹中的index.js
文件;
❸若❷没有,找package.js
文件中main
选项中入口文件;
❹若❸还找不到,报错。
网站组成:客户端(浏览器端)与服务器端
Node
网站服务器: 通过 IP地址 找到服务器,通过发送请求来接收响应。但是由于 IP地址 难于记忆,所以目前都使用 域名(网址)。本机域名:localhost,本机IP:127.0.0.1。
端口:用来区分服务器电脑中提供的不同服务。
URL
组成:传输协议://服务器IP或域名:端口//资源所在位置标识。
/示例代码-创建web服务器/;
/1.引用系统模块/
const http = require('http');
/2.创建web服务器/
const app = http.createServer(); //createServer()方法
/3.当客户端发送请求时/
app.on('request', (req,res) => {
res.end(<h2>网页响应内容</h2>); //响应
})
/监听3000端口/
app.listen(3000)
//1.网站打开localhost:3000
//2.页面执行结果写响应内容
不识别HTML标签
HTTP
协议概念(超文本传输协议)
请求报文的请求方式:GET 请求数据;POST 发送数据。
const http = require('http');
const app = http.createServer();
app.on('request', (req,res) => {
console.log(req.method); //执行结果为请求方式
console.log(req.url); //执行结果为请求地址
console.log(req.headers); //执行结果为请求报文
res.end(<h2>网页响应内容</h2>); //响应
})
app.listen(3000)
响应报文HTTP
状态码:-200请求成功、404请求的资源没有找到、500服务器端错误、400客户端请求有语法错误。
响应报文内容类型:text/html、text/css;application/javascript、image/jpeg、application/json
用 mime模块 处理判断当前接收的模块类型使用getType()
方法。
const http = require('http');
const app = http.createServer();
app.on('request', (req,res) => {
res.end(<h2>网页响应内容</h2>); //响应
res.writeHead(400, {
'conten-type': 'text/html;charset=utf8' //内容类型
});
})
app.listen(3000)
//1.网站打开localhost:3000
//2.页面显示 写响应内容 可以识别HTML标签
请求参数:GET请求参数;POST请求参数
⑴GET请求参数
GET请求参数在url中传输,需要使用req.url和专门的内置模块url获取参数,代码示例如下。
const http = require('http');
//引入专门解析url的模块
const url = require('url');
const app = http.createServer();
app.on('request', (req,res) => {
res.end(<h2>网页响应内容</h2>); //响应
url.parse(req.url) //parse('url地址','布尔值:将参数解析为对象形式')解析 返回参数是对象包含所有参数
})
app.listen(3000)
⑵POST请求参数
POST请求参数在请求报文中传输,数据量较大,需要使用专门的内置模块querystring转换成对象格式,代码示例如下。
const http = require('http');
const querystring = request('querystring') //引入内置模块querystring
const app = http.createServer();
app.on('request', (req,res) => {
let postData = '';
//post参数是通过事件的方式接收的,data参数开始传递触发,end参数传递结束触发
req.on('data', (chunk) => postData += chunk; ); //监听参数传输事件
req.on('end', () => { //监听参数传输完毕事件
querystring.parse(postData)
});
res.end(<h2>网页响应内容</h2>);
})
app.listen(3000)
⑶路由:指客户端请求地址与服务器程序代码的对应关系。
⑷静态资源与动态资源
⏭静态资源:服务器不需要处理,可以直接响应给客户端的资源,例如CSS、JavaScript、image
文件。
⏭动态资源:相同的请求地址参数或其他不同的响应资源。
⑴同步API
、异步API
区别(返回值取值方式)
⏭区别1: 同步API
可以从返回值中拿执行结果,而异步API
不是通过返回值,是通过回调函数拿到返回结果。
/同步/
function sum(n1 + n2){
return n1 + n2;
}
const result = sum(10, 20);
console.log(result); //执行结果:30;
/异步/
function getMsg(){
setTimeout(function(){
return{ msg: '你好' }
}, 2000);
/原因 return undefined;异步执行时不阻塞下面的函数,所以先返回了undefined/
}
const msg = getMsg();
console.log(msg) //执行结果:undefined
/什么是回调函数:自己定义函数让别人去调用。/
//getData函数定义
function getData(callback){}
//getData函数调用
getData( ()=>{} ); /这个就是回调函数/
/上面异步拿不到函数返回值的解决方式/
function getMsg(callback){
setTimeout(function(){
callback({ msg: '你好' })
}, 2000);
}
const msg = getMsg(function(data){
console.log(data);
}); //执行结果:msg: '你好'
⏭区别2:(代码执行顺序) 同步API
从上到下依次执行,前面代码会阻塞后面代码;异步API
不会等待API
执行完成后在向下执行代码。
⑵Node.js
中的异步API
/Node.js中的异步API示例/
fs.readFile('路径',(err,result) => {});
var server = http.createServer();
server.on('request', (req,res) => {});
⑶Promise
构造函数: 出现的目的是解决Node.js
异步编程中回调地域的问题。
/语法结构/
let promise = new Promise((resolve,reject) => {});
/用then和catch方法在示例对象中取结果/
promise.then(result => {}).catch(err => {})
/示例代码:实际应用 依次执行文档1,2,3中的内容/
const fs = require('fs')
function p1(){
return new Promise((resolve,reject) => {
fs.readFile('./1.txt','utf8',(req,res) => {
resolve(res)
})
});
}
function p2(){
return new Promise((resolve,reject) => {
fs.readFile('./2.txt','utf8',(req,res) => {
resolve(res)
})
});
}
function p3(){
return new Promise((resolve,reject) => {
fs.readFile('./3.txt','utf8',(req,res) => {
resolve(res)
})
});
}
p1().then((r1) => {
console.log(r1);
return p2();
}).then((r2) => {
console.log(r2);
return p3();
}).then((r3) => {
console.log(r3);
}) /这样就按照顺序执行了,采用链式编程,但是还有return这样的嵌套,所以衍生出异步函数/
⑷async
异步函数: 基于Promise
基础上进行有一次封装,是异步编程语法的终极解决方案,使异步代码写成同步的形式,让代码不再有回调嵌套,使代码更加清晰。
/语法格式/
const fn = async() => {};
async function fn(){};
/1.在普通函数前面加上async关键字后,普通函数就变成了异步函数/;
/2.异步函数默认返回值为promise对象/;
/3.在异步函数内部使用throw关键字进行错误抛出/;
/4.异步函数正常使用then和catch方法取结果/
相较于promise
改善:❶让代码不再有回调嵌套,使代码更加清晰;❷不用声明实例对象代码简洁;❸引入了await
关键字。
await
关键字:❶只能出现在异步函数中;❷可以赞同异步函数执行,等待promise
对象返回结果再向下执行。
⑴动态网站中的数据都是存储在数据库中
⑵数据库可以用来持久存储客户端通过表单收集的用户信息
⑶数据库软件本身可以对数据库进行高效的管理
⑴数据库:是独立于语言之外的软件,可以通过API
去操作。
-⑵常见数据库软件:mysql、momgoDB、oracle
。
在一个数据库软件中可以包含多个数据库,每个数据库包含多个数据集合,每个数据集合包含多条文档。
术语 | 备注 |
---|---|
database | 数据库,MongoDB数据库软件中可以建立多个数据库 |
collection | 集合,一组数据集合,可以理解为JavaScript中的数组 |
document | 文档,一条具体的数据,可以理解为JavaScript中的对象 |
field | 字段,文档中的属性名,可以理解为JavaScript中的对象属性 |
//未使用模板引擎
var ary = [{name: '张三',age: 20}];
var str = '';
for(var i = 0; i <ary.length; i++) {
str +=`- \
` + arr[i].name + `\
` + arr[i].age + `\
`;
}
str += '
'
<ul>
{{each ary}}
<li>{{$value.name}}li>
<li>{{$value.age}}li>
{{/each}}
ul>
npm install art-template
;❷引入const template = require('art-template')
;❸告诉模板引擎拼接位置const html = template('模板路径', 数据)
。示例代码:app.js
const template = require('art-template')
const path = require('path')
const views = path.join(__dirname, 'views', 'index.art')
const html = template(views, {
name: '张三',
age: 18
})
console.log(html)
//示例代码:index.art
DOCTYPE html>
<html>
<body>
{{ name }}
{{ age }}
body>
html>
//标准语法
<h2>{{value}}h2>
<h2>{{a ? b : c}}h2>
<h2>{{a + b}}h2>
//原始语法
<h2><%= value %>h2>
<h2><%= a ? b : c %>h2>
<h2><%= a + b %>h2>
//标准语法
{{if条件}} ... {{/if}}
{{if 条件1}} ... {{else if 条件2}} ... {{/if}}
//原始语法
<% if(value) { %> ... <% } %>
<% if(条件1) { %> ... <% }else if(条件2) { %> ... <% } %>
{{each 数据}} {{/each}}
;//原始语法<% for() { %> <% } %>
=//标准语法
{{each target}}
{{$index}}{{$value}}
{{/each}}
//原始语法
<% for(var i = 0; i < target.length; i++){ %>
<%= i %><%= target[i] %>
<% } %>
{{include '模板路径'}}
;原始语法<% include('模板路径')%>
。{{block '名字'}}{{/block}}
//示例代码-模板layout.art
DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>HTML骨架模板title>
{{block 'head'}}{{/block}}
head>
<body>
{{block 'content'}}{{/block}}
body>
html>
//引用模板
{{extend './layout.art'}}
{{block 'head'}} <link rel="stylesheet" href="custom.css"> {{/block}}
{{block 'content'}} <p>这是首页!p> {{/block}}
template.defaults.imports.变量名 = 变量值;
;❷设置模板根目录template.defaults.imports.root;
;❸设置默认模板后缀template.defaults.extname = '.art';
。向模板中导入变量-示例代码:app.js
const template = require('art-template')
const path = require('path')
const dataFormat = require('dataFormat') //这个是一个处理时间戳的第三方模块
template.defaults.imports.dataFormat = dataFormat;
template.defaults.imports.root = path.join(__dirname, 'views');
template.defaults.extname = '.art';
const html = template('index',{
time: new Date()
})
console.log(html)
//在模板中调用方法-index.art'
{{ dataFormat(time, 'yyyy-mm-dd')}}
//node执行结果为年月日
Express框架: 是一个基于Node
平台的web
应用开发框架,也是node
第三方模块。❶使用npm install express
下载;❷引入const express = require('express')
;
❶提供了方便简洁的路由定义方式;
❷对获取HTTP
请求参数 进行了 简化处理;
❸对模板引擎支持度高,方便渲染HTML页面;
❹提供了中间件机制有效控制HTTP请求;
❺拥有大量第三方中间件对功能进行扩展。
⑴原生Node.js
与引入Express
框架后对比-路由
app.on('request', (req,res) => {
//获取客户端的请求路径
let { pathname } = url.parse(req.url);
//对请求路径进行判断 不同路径地址响应不同内容
if(pathname == '/'||pathname = 'index'){
res.end('欢迎来到首页');
} else if(pathname = '/list'){
res.end('欢迎来到列表页面');
} else if(pathname = '/about'){
res.end('欢迎来到关于我的页面');
} else {
res.end('抱歉,您访问的页面找不到');
}
});
//当客户端以get方式访问时
app.get('/',(req,res) => {
res.send('欢迎来到首页'); //对客户端做出响应
});
//当客户端以post方式访问/add路由时
app.post('/add',(req,res) => {
res.send('欢迎来到/add页');
});
⑵原生Node.js
与Express
框架对比-获取请求参数
app.on('request', (req,res) => {
//获取GET参数
let { pathname } = url.parse(req.url, true);
//获取POST参数
let postData = '';
req.on('data', (chunk)=> {
postData += chunk;
})
req.on('end', (chunk)=> {
console.log(querystring.parse(postData))
});
});
app.get('/',(req,res) => {
console.log('req.query'); //获取GET参数
});
app.post('/',(req,res) => {
console.log('req.body'); //获取POST参数
});
const express = require('express');
/1.创建网站服务器,这时就不用了http模块了/
const app = express();
app.get('/', (req,res) => {
res.send('你好,首页!');
})
app.post('/', (req,res) => {
res.send('你好,首页!');
})
app.listen(3000);
console.log('网站服务器启动成功');
send()方法
: ❶内部会检测响应内容的类型;❷自动设置http状态码;❸自动设置响应的内容类型及编码。
中间件: 就是一堆方法可以接收客户端发来的请求、可以对请求做出回应、也可以将请求交给下一个中间件继续处理。
中间件组成:中间件方法和请求处理函数。
中间件方法: 由Express提供,负责拦截请求,请求处理函数由开发人员提供,负责处理请求。
app.get('请求路径','处理函数'); //用来接收get请求
app.post('请求路径','处理函数'); //用来接收post请求
next()
app.get('/', (req,res) => {
res.send('你好,首页!');
next(); //没有next中间匹配成功后下一个中间件就执行了
})
app.get('/', (req,res) => {
res.send('你好,首页!');
})
app.use
匹配所有的请求方式,可以直接传入请求处理函数,代表接收所有的请求。
app.use((req,res,next) => {
console.log(req.url);
next();
})
app.use
第一个参数也可以传入请求地址,表示无论什么请求方式,只要是请求这个请求地址就接收这个请求。
app.use('/admin',(req,res,next) => { //next将请求交给下一个中间件
console.log(req.url);
next();
})
路由保护,客户端访问需要登录的页面时,未登录则拦截请求。
const express = require('express');
const app= express();
app.use((req,res,next) => {
console.log(req.url);
next();
})
app.listen(3000);
console.log('网站服务器启动成功');
网站维护公告,在所有路由最上面定义中间件,直接为客户端响应网站正在维护中。
错误处理中间件:是一个集中处理错误的地方。
app.use((err,req,res,next) => {
res.status(500).send('服务器发生未知错误');
})
异步函数出错时,需要利用next()
手动触发错误处理中间件
/示例代码/
const express = require('express');
const fs = require('fs');
const app = express();
app.get('/index', (req, res,next) => {
fs.readFile('./index.html','utf8',(err,result) => {
if(err != null){
next(err)
} else {
res.send(result)
}
})
})
在node.js
中,异步API
的错误信息是通过回调函数callback
捕获的,支持promise
对象的异步API
发生错误通过catch
方法捕获,异步函数执行发生错误呢?
try catch
可以捕获异步函数以及同步代码在执行过程中发生的错误。
/语法使用/
app.get('/', async(req,res,next) => {
try{
await User.find({name: '张三'}); //可能出错的代码
} catch(ex) {
next(ex); //ex为错误信息
}
})
const express = require('express')
const app = express();
//创建路由对象
const home = express.Router(); //Router()方法
//将路由的请求路径进行匹配
app.use('/home', home);
//在home路由下继续创建二级路由 /home/index
home.get('/index', () => {
res.send('欢迎来到首页');
});
modules.exports = home; //导出
home.js-路由模块
const express = require('express')
const home = express.Router();
home.get('/index', () => {
res.send('欢迎来到首页');
});
modules.exports = home; //导出
admin.js-路由模块
const express = require('express')
const admin= express.Router();
admin.get('/index', () => {
res.send('欢迎来到管理页');
});
modules.exports = admin; //导出
app.js-使路由模块生效
const express = require('express')
const app = express();
const home = require('./route/home'); //导入-('路径')
const admin = require('./route/admin'); //导入-('路径')
app.use('/home', home); //匹配路径,访问/home/index
app.use('/admin', admin); //匹配路径,访问/admin/index
app.listen(3000);
GET参数的获取:Express
框架中使用req.query获取,框架内部会将GET
参数转换成对象并返回。意义就是不再需要解析url
来获取GET
参数。
const express = require('express')
const app = express();
//接收请求
app.get('/index', (req, res) => {
//接收请求参数
console.log(req.query); /req.query就是参数{}但是需要用?传递/
})
Express路由参数
app.get('/find/:id', (req,res) => {}); /:id就是请求参数{id: 123}/
localhost:3000/find/123
代码示例:
const express = require('express')
const app = express();
const bodyParser = require('body-parser');
app.get('/index/:id/:name', (req,res) => {
res.send(req.params) //req.params就是路由参数,需要用/传递
})
app.listen(3000);
POST参数的获取:Express
中接收post
请求参数需要借助第三方模块body-parser
。
const express = require('express')
const app = express();
//引入body-parser模块
const bodyParser = require('body-parser');
//配置body-parser模块
app.use(bodyParser.urlencoded({ extended: false })); //urlencoded()方法
//接收请求
app.post('/add', (req, res) => {
//接收请求参数
console.log(req.body); //req.body就是参数
})
静态资源的处理:通过Express
内置的express.static可以方便的托管静态文件,例如img、CSS、JavaScript
文件等。
app.use(express.static('public')); //public是目录
现在,public
目录下面的文件就可以访问了,示例代码如下
const express = require('express')
const app = express();
const path = require('path');
//实现静态资源访问功能
app.use(express.static(path.join(__dirname, 'public')))
app.listen(3000);
模板引擎:为了使art-template
模板引擎能够更好的Express
框架结合,模板引擎官方在原art-template
基础上封装了express-art-template
。
安装:使用npm install art-template express-art-template
命令进行安装。
const express = require('express')
const app = express();
const path = require('path');
//当渲染后缀为art模板时,使用express-art-template
app.engine('art', require('express-art-template'));
//设置模板存放目录
app.set('views', path.join(__dirname, 'views')); /app.set('views','文件夹路径')/
/渲染模板时不写后缀,默认拼接art后缀/
/设置以上信息是为了使用render()方法/
app.get('/', (req, res) => {
渲染模板
res.render('index'); //res.render('模板名',{模板的值});
})
app.listen(3000);
render()作用:将所有配置拼接,将拼接结果响应给客户端。
app.local作用:将公共变量设置到app.local
对象下,这个数据在所有的模板中都可以获取到,不需要重复加载。
//示例代码
const express = require('express')
const app = express();
const path = require('path');
app.engine('art', require('express-art-template'));
app.set('views', path.join(__dirname, 'views'));
app.local.users = [{ name: '张三', age: 25 },{ name: '李四', age: 19 }]
app.get('/index', (req, res) => {
res.render('index', {msg: '首页'});
})
app.get('/list', (req, res) => {
res.render('list', {msg: '列表页'});
})
app.listen(3000);
//index.art文件
{{msg}}
<ul>
{{each users}}
<li>
{{$value.name}}
{{$value.age}}
li>
{{each}}
ul>
//list.art文件
{{msg}}
<ul>
{{each users}}
<li>
{{$value.name}}
{{$value.age}}
li>
{{each}}
ul>
项目部分我没有看,后续有时间会再补全
1.创建Ajax对象
var xhr = new XMLHttpRequest();
2.告诉Ajax请求地址及请求方式
xhr.open('get', 'http://www.example.com'); /('请求方式','请求地址')/
3.发送请求
xhr.send(); /服务器响应时间受网速影响故不确定何时收到响应,就不能直接用send()拿到响应结果因此衍生出4/
4.获取服务器端给与客户端的响应数据
xhr.onload = function() {
console.log(xhr.responseText); /responseText属性保存的就是响应文本/
}
(window.)JSON.parse()
//示例代码-服务器返回数据客户端如何处理
var xhr = new XMLHttpRequest();
xhr.open('get', 'http://www.example.com');
xhr.send();
xhr.onload = function() {
var responseText = JSON.parse(xhr.responseText); /将json字符串转换成json对象/
var str = '' + responseText.name + '
'
document.body.innerHTML = str; //显示到页面中
}
<form method='get' action='http://www.example.com'>
<input type='text' name='username'>
<input type='pessword' name='pessword'>
form>
xhr.open('get', 'http://www.example.com?name=zhangsan$age=18');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
,xhr.send('name=zhangsan&age=20');
固定,设置请求报文setRequestHeader(‘报文属性名’,‘值’)。//示例代码-HTML
<p><input type='text' id='username'>p>
<p><input type='text' id='age'>p>
<p><input type='button' value='提交' id="btn">p>
//示例代码-GET请求方式.js
var btn = dcunment.getElementById('btn');
var username = dcunment.getElementById('username');
var age = dcunment.getElementById('age');
btn.onclick = function(){
var xhr = new XMLHttpRequest();
var nameValue = username.value;
var ageValue = age.value;
var parmas = 'username=' + nameValue + '&age=' + ageValu; /传统表单是自己拼接好的,但在ajax里需要自己拼接/
xhr.open('get', 'http://www.example.com/get?' + parmas );
xhr.send();
xhr.onload = function() {
var responseText = JSON.parse(xhr.responseText);
console.log(responseText)
}
}
//示例代码-post请求方式.js
var btn = dcunment.getElementById('btn');
var username = dcunment.getElementById('username');
var age = dcunment.getElementById('age');
btn.onclick = function(){
var xhr = new XMLHttpRequest();
var nameValue = username.value;
var ageValue = age.value;
var parmas = 'username=' + nameValue + '&age=' + ageValu;
xhr.open('post', 'http://www.example.com/post');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); /post特有/
xhr.send(parmas);
xhr.onload = function() {
var responseText = JSON.parse(xhr.responseText);
console.log(responseText)
}
}
name=zhangsan&age=20&sex=男; /字符串格式/
JSON.stringfy()
。{name: 'zhangsan', age: '20', sex: '男'} /字符串格式/
//示例代码
var xhr = new XMLHttpRequest();
xhr.open('post', 'http://www.example.com/post');
/通过请求头告诉服务器端,客户端段向服务器传递的请求参数的格式是什么/
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringfy({name: 'zhangsan', age: '20'}));
xhr.onload = function() {
console.log(xhr.responseText);
}
状态码 | 含义 |
---|---|
0 | 请求未初始化( 还没有调用open() ) |
1 | 请求已经建立,但是还没有发送( 还没有调用send() ) |
2 | 请求已经发送 |
3 | 请求正在处理中,通常响应中已经有部分数据可以用了 |
4 | 响应已经完成,可以获取并使用服务器的响应 |
onreadystatechange
事件,获取Ajax状态码:xhr.readyState
;//示例代码
var xhr = new XMLHttpRequest();
console.log(xhr.readyState); //执行结果依次为 0
xhr.open('get', 'http://www.example.com/post');
console.log(xhr.readyState); //执行结果依次为 1
xhr.onreadystatechange = function(){
console.log(xhr.readyState); //执行结果依次为 2 3 4
if(xhr.readyState == 4){
console.log(xhr.responseText);
}
}
xhr.send();
//xhr.onload = function() {
//console.log(xhr.responseText);
//}
区别描述 | onload事件(推荐) | onreadystatechange事件 |
---|---|---|
是否兼容IE低版本 | 不兼容 | 兼容 |
是否需要判断Ajax状态码 | 不需要 | 需要 |
被调用次数 | 一次 | 多次 |
可以判断服务器端返回的状态码,分别进行处理,xhr.status获取http状态码。
<button id="btn">发送Ajax请求button>
<script type="text/javascript">
var btn = dcunment.getElementById('btn');
btn.onclick = function(){
var xhr = new XMLHttpRequest();
xhr.open('get', 'http://www.example.com/get');
xhr.send();
xhr.onload = function() {
if(xhr.status == 400){
alert('请求出错!')
}
console.log(xhr.responseText);
}
}
script>
检查请求地址是否错误。
服务器端错误,找到后端程序员进行沟通。
触发xhr.onerror事件,在onerror事件处理函数中对错误进行处理。
解决方案:在请求地址的后面加请求参数,保证每一次请求中的请求参数的值不同。
//示例代码
xhr.open('get', 'http://www.example.com?get=' + Math.random());
//封装好的代码
<script type="text/javascript">
function ajax(options){
//创建ajax对象
var xhr = new XMLHttpRequest();
var params = '';
//循环用户传递进来的格式参数
for(var attr in options.data){
//将参数装换成字符串雷幸福
params += attr + '=' + options.data[attr] + '&';
}
params = params.substr(0, params.length - 1)
if(options.type == 'get') options.url = options.url + '?' + params;
//配置ajax对象
xhr.open('options.type', 'options.url');
if(options.type == 'post'){
var contentType = options.header['Content-Type']
xhr.setRequestHeader('Content-Type', options.header['Content-Type']);
if(contentType == 'application/json'){
xhr.send(JSON.stringify(options.data));
} else {
xhr.send(params);
}
} else xhr.send();
xhr.onload = function(){
//判断请求是否成功
if(xhr.status == 200){
options.success(xhr.responseText, xhr); //成功
} else {
options.error(xhr.responseText, xhr); //失败
}
}
}
script>
//调用
ajax({
type: 'get',
url: 'http://www.example.com',
data: {
name: 'zhangsan',
age: 18
},
header: {
'Content-Type': 'application/json'
},
success: function(data){
console.log(data);
}
})
var html = template('tpl', {username: 'zhangsan', age: '20' }); //template('id', "数据")
document.getElementById('container').innerHTML = html; //container容器,自定义
1.准备HTML表单
<form id="form">
<input type="text" name="username" />
<input type="password" name="password" />
<input type="button" />
form>
2.将HTML表单转化为formData对象
var form = document.getElementById('form');
var formData = new FormData(form);
3.提交表单对象
xhr.send(formData);
示例代码-客户端
<body>
<form id="form">
<input type="text" name="username" />
<input type="password" name="password" />
<input type="button" value="提交" id="btn" />
form>
<script>
var btn = document.getElementById('btn');
var form = document.getElementById('form');
btn.onclick = function(){
var formData = new FormData(form); /不用获取每个input中的值可以直接提交,这就是FormData的作用/
var xhr = new XMLHttpRequest();
xhr.open('post', 'http://www.example.com'); /这里请求方式不能为get,不知道为什么有点白学了/
xhr.send(formData); //发送请求
xhr.onload = function(){
if(xhr.status == 200){
console.log(xhr.responseText, xhr);
}
}
}
script>
body>
1.准备HTML表单
<input type="file" id="file">
2.将HTML表单转化为formData对象,提交
var file = document.getElementById('file');
//当用户选择文件的时候
file.onchange = function(){
//创建空表单对象
var formData = new FormData(form);
//将用户选择的二进制文件追加到表单对象中
formData.append('attName', this.files[0]); /attName为自定义,文件存在file对象中的file属性中/
//配置ajax对象,请求方式必须为post
var xhr = new XMLHttpRequest();
xhr.open('post', 'http://www.example.com'); /请求方式必须为post/
xhr.send(formData);
xhr.onload = function(){
if(xhr.status == 200){
console.log(xhr.responseText, xhr);
}
}
}
示例代码-客户端
<body>
<div class="container">
<div class="form-group">
<label>请选择文件label>
<input type="file" id="file">
div>
div>
<script type="text/javascript">
var file = document.getElementById('file');
file.onchange = function() {
var formData = new FormData(form);
formData.append('attName', this.files[0]); /attName为自定义,文件存在file对象中的file属性中/
var xhr = new XMLHttpRequest();
xhr.open('post', 'http://www.example.com');
xhr.send(formData);
}
script>
body>
//当用户选择文件的时候
file.onchange = function(){
/文件上传过程中持续触发onprogress事件(progress进度)/
xhr.upload.onprogress = function(ev){
//当前上传文件大小/文件总大小,再将结果转换为百分数
//将结果赋值给进度条的宽度属性
bar.style.width = (ev.loaded/ev.total) * 100 + '%';
}
}
示例代码-客户端
<body>
<div class="container">
<div class="form-group">
<label>请选择文件label>
<input type="file" id="file">
<br/>
<div class="progress">
<div class="progress-bar" style="width: 0%" id="bar">0%div>
div>
div>
div>
<script type="text/javascript">
var file = document.getElementById('file');
var dar = document.getElementById('bar');
file.onchange = function() {
var formData = new FormData(form);
formData.append('attName', this.files[0]); /attName为自定义,文件存在file对象中的file属性中/
var xhr = new XMLHttpRequest();
xhr.open('post', 'http://www.example.com');
file.onchange = function(){
xhr.upload.onprogress = function(ev){ /upload对象保存上传相关的事件,ev事件对象/
var result = (ev.loaded/ev.total) * 100 + '%';
bar.style.width = result;
bar.innerHTML = result;
}
}
xhr.send(formData); //发送请求
}
script>
body>
formData.get('key');
formdata.getAll("username");
formData.set('key', 'value');
formData.delete('key');
formData.append('key', 'value');
formdata.has(key);
<body>
<form id="form">
<input type="text" name="username" />
<input type="password" name="password" />
<input type="button" value="提交" id="btn" />
form>
body>
<script>
var btn = document.getElementById('btn');
var form = document.getElementById('form');
btn.onclick = function(){
var formData = new FormData(form);
formData.get('username'); //获取表单对象中属性的值
var xhr = new XMLHttpRequest();
xhr.open('post', 'http://www.example.com');
xhr.send(formData);
xhr.onload = function(){
if(xhr.status == 200){
console.log(xhr.responseText, xhr);
}
}
}
script>
<script src="www.example.com">script>
<script src="https://cdn.example.com/jquery/jquery.min.js">script>
const data = ' fn({name: "张三", age:"20"})';
res.send(data);
function fn(data) {}
function fn(data){ console.log(data); }
示例代码-客户端
<body>
<script>
function fn(data){
console.log('客户端的fn函数被调用了') //执行结果客户端显示 客户端的fn函数被调用了 {name: "张三", age:"20"}
console.log(data)
}
script>
<script src="http://localhost:3001/tast">script>
body>
示例代码-非同源服务器端3001
const express = require('express');
const path = require('path');
const app = express(); //创建web服务器
app.use(express.static(path.join(__dirname, 'public')));
app.get('/test', (req,res) => {
const result = 'fn({name: "张三", age:"20"})'; /立即调用/
res.send('result');
})
app.listen(3001);
console.log('服务器启动成功');
代码示例-客户端 点击按钮之后才触发请求
<body>
<button id="btn">点我发送请求button>
<script>
function fn2(data){
console.log('客户端的fn函数被调用了');
console.log(data)
}
script>
<script type="text/javascript">
var btn = document.getElementById('btn');
btn.onclick = function(){
var script = document.createElement('script');
script.src = 'http://localhost:3001/better';
document.body.appendChild(script);
/当请求加载完毕时将script去掉,防止反复点击造成浪费/
script.onload = function(){
document.body.removeChild(script);
}
}
script>
body>
示例代码-服务器端
app.get('/better', (req,res) => {
const result = 'fn2({nama: "张三"})';
res.send(result);
})
代码示例-客户端 点击按钮之后才触发请求
<body>
<button id="btn">点我发送请求button>
<script>
function fn2(data){
console.log('客户端的fn函数被调用了');
console.log(data)
}
script>
<script type="text/javascript">
var btn = document.getElementById('btn');
btn.onclick = function(){
var script = document.createElement('script');
script.src = 'http://localhost:3001/better?callback=fn2'; /callback方法/
document.body.appendChild(script);
script.onload = function(){
document.body.removeChild(script);
}
}
script>
body>
示例代码-服务器端
app.get('/better', (req,res) => {
const fnNama = req.query.callback; /接收客户端传递的名称fn2/
const result = fnNama + '({nama: "张三"})';
res.send(result);
})
<body>
<button id="btn">点我发送请求button>
<script>
//function fn2(data){
//console.log('客户端的fn函数被调用了');
//console.log(data);
//} 放在了success中
script>
<script>
var btn = document.getElementById('btn');
btn.onclick = function(){
jsonp({
url: 'http://localhost:3001/better',
data: { age: '18' },
success: function(){
console.log('客户端的fn函数被调用了');
console.log(data);
},
})
};
function jsonp(options){
var script = document.createElement('script');
//拼接字符串的变量
var parmas = '';
for(var attr in options.data){
params += '&' + attr + '=' + options.data[attr];
}
/因为options.success现在已经不是全局函数了,请求返回结果时会找不到响应函数,故要将他变成全局函数/
var fnName = 'myJsonp' + Math.random().toString().replace('.',''); //生成随机名
script.src = options.url + '?callback=' + fnName + parmas;
window[fnNme] = options.success; /不能将函数名定义死,容易出现覆盖问题/
document.body.appendChild(script);
script.onload = function(){
document.body.removeChild(script);
}
}
script>
body>
//请求地址为http://localhost:3001/better?myJsonp1894586655445&age=18
//执行结果 客户端的fn函数被调用了 {nama: "张三"}
示例代码-服务器端
app.get('/better', (req,res) => {
//const fnNama = req.query.callback;
//将参数转换成字符串进行响应
//const data = JSON.stringify({nama: "张三"});
//const result = fnNama + '(' + data ')';
//res.send(result);
res.jsonp({nama: "张三"}); /jsonp方法就是上述一些列代码的作用,即服务器端代码优化/
})
示例代码-A浏览器端
<body>
<button id="btn">点我发送请求button>
<script src="/js/ajax.js">script>
<script>
var btn = document.getElementById('btn');
btn.onclick = function(){
ajax({
type: 'get',
url: 'http://localhost:3000/server',
success: function(data){
console.log(data);
}
})
};
script>
body>
//控制台执行结果为asd,页面响应ok
示例代码-A服务器端
const express = require('express');
const path = require('path');
const request = request('request'); /用于发送跨服务器请求,返回request方法/
const app = express(); //创建web服务器
app.use(express.static(path.join(__dirname, 'public'))); //静态资源访问服务功能
app.get('/server', (req, res) => {
request('http://localhost:3001/cross', (err,response,body) => {
console.log(err); /在node中执行结果为null没有错误/
console.log(response); /在node中执行结果为服务器响应信息/
console.log(body); /在node执行结果为B服务器端响应结果/
res.send('asd');
})
})
app.listen(3000);
console.log('服务器启动成功');
示例代码-B服务器端
const express = require('express');
const path = require('path');
const app = express(); //创建web服务器
app.use(express.static(path.join(__dirname, 'public'))); //静态资源访问服务功能
app.get('/cross', (req, res) => {
res.send('ok');
})
app.listen(3001);
console.log('服务器启动成功');
代码示例-客户端
<body>
<div class="container">
<form id="loginForm">
<div class="form-group">
<label>用户名label>
<input type="text" name="username" class="form-control" placeholder="请输入用户名">
div>
<div class="form-group">
<label>密码label>
<input type="password" name="password" class="form-control" placeholder="请输入密码">
div>
<input type="button" class="btn" value="登录" id="loginBtn" />
<input type="button" class="btn" value="检测用户登录状态" id="checkLogin" />
form>
div>
<script type="text/javascript">
var loginBtn = document.getElementById('loginBtn');
var checkLogin = document.getElementById('checkLogin');
var loginForm = document.getElementById('loginForm');
loginBtn.onclick = function(){
var formData = new FormData(loginForm);
var xhr = new XMLHttpRequest();
xhr.open('post', 'http://localhost:3001/login');
xhr.withCredentials = true; /当发送跨域请求时,携带cookie信息/
xhr.send(formData);
xhr.onload = function(){
console.log(xhr.responseText); //输出服务器返回结果
};
};
//检测用户登录状态
checkLogin.onclick = function(){
var formData = new FormData(loginForm);
var xhr = new XMLHttpRequest();
xhr.open('get', 'http://localhost:3001/checkLogin');
xhr.send();
xhr.onload = function(){
console.log(xhr.responseText);
};
};
script>
body>
示例代码js-服务器端代码,3001端口
const express = require('express');
const path = require('path');
const app = express(); //创建web服务器
//拦截所有请求
app.use((req, res, next) => {
//1.允许哪些客户端访问我,*代表允许所有客户端访问我
//注意:如果跨域请求中涉及cookie信息传递,值不可以为*
res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
res.header('Access-Control-Allow-Methods', 'get,post');
res.header('Access-Control-Allow-Credentials', true); /允许跨域请求携带cookie/
next();
});
app.get('/login', (req, res) => {
var form = formidable.IncomingForm(); //创建表单解析对象
//解析表单
form.parse(req, (err,fields,file) => {
//接收客户端传递过来的用户名和密码
const { username, password } = fields;
if(username == 'itheima' && password == '123456'){
//设置session
req.session.isLogin = true;
res.send({ message: '登录成功' });
} else {
res.send({ message: '登录失败' });
}
})
res.send('ok');
});
app.listen(3001);
console.log('服务器启动成功');
语法结构js
$.ajax({
type: 'get', /请求类型/
url: 'http://www.example.com', /请求地址/
data: { name: 'zhangsan', age: '20' }, /向服务器端发送的参数,格式{data:'name=zhangsan&age=20'}/
contentType: 'application/x-www-form-urlencoded', /设置向服务器端发送参数的格式类型/
beforeSend: function(){ /请求发送之前做处理,例如对请求参数值的格式进行验证提高用户体验/
//return false
},
success: function(response){}, /函数请求成功以后被调用/
error: function(xhr){} /请求失败时触发/
});
data: JSON.stringify({ name: 'zhangsan', age: '20' }), /向服务器端发送的参数json格式/
contentType: 'application/json', /设置向服务器端发送参数的格式类型/
<body>
<button id="btn">点我发送请求button>
<script src="/js/jquery.min.js">script>
<script>
$('btn').on('click', function(){
$.ajax({
type: 'get',
url: 'http://localhost:3000/base',
data: { name: 'zhangsan', age: '20' },
contentType: 'application/x-www-form-urlencoded',
success: function(response){
console.log(respons); /respons为服务器返回数据,方法内部会自动将json字符串转换为json对象/
},
error: function(xhr){}
});
})
script>
body>