获取第三方模块
(1)npmjs.com:第三方模块的存储和分发仓库
下载:npm install 模块名称
卸载:npm uninstall package 模块名称
全局安装和本地安装
命令行工具:全局安装
库文件:本地安装
(2)nodemon:是一个命令行工具,用以辅助项目开发;每次修改文件都要在命令行工具中重新执行该文件,非常繁琐
使用步骤:
使用npm install nodemon -g 下载它
在命令行工具中用nodemon命令替代node命令执行文件
(3)nrm:npm下载地址切换工具
使用步骤:
使用npm install nrm -g 下载
查询可用下载地址列表nrm ls
切换npm 下载地址nrm use下载地址名称
(4)Gulp:项目上线(html、css、js文件压缩合并)语法转换、公共文件抽离、修改文件浏览器自动刷新
使用步骤:
使用npm install gulp下载gulp库文件
在项目根目录下建立gulpfile.js文件
重构项目的文件夹结构src目录放置源代码文件dist目录放置构建后文件
在gulpfile.js文件中编写任务
在命令行工具中执行gulp任务
提供方法:
gulp.src():获取任务要处理的文件
gulp.dest():输出文件
gulp.task():建立gulp任务
gulp.watch():监控文件的变化
url.parse(req.url,true).query 第一个参数是解析的url地址,第二个参数是将查询参数解析成为对象形式
{query,pathname}=url.parse(req.url,true) pathname是不加参数的url地址
post请求参数
参数被放置在请求体中进行传输
获取post参数需要使用data事件和end事件
使用querystring系统模块将参数转换为对象格式(querystring.parse(postData))
router中的js:
1.引入系统模块http
2.创建网站服务器
3.为网站服务器对象添加请求事件
4.实现路由功能(1.获取客户端的请求方式2.获取客户端的请求地址)
promise:目的是解决node.js异步编程中回调地狱的问题
异步函数:是异步编程终极解决方案,将异步代码写成同步的形式,不再有回调函数嵌套(async,await)
async:1.在普通函数定义的前面加上async关键字 普通函数就变成了异步函数
2.异步函数默认的返回值是promise对象
3.在异步函数内部使用retrun关键字进行结果返回 结果会被包裹的promise对象中 retrun关键字代替了resolve方法
4.在异步函数内部使用throw关键字进行错误的抛出
5.调用异步函数再链式调用then方法获取异步函数执行结果
6.调用异步函数再链式调用catch方法获取异步函数执行的错误信息
await:1.它只能出现在异步函数中
2.await promise await后面只能写promise对象 写其他类型的API是不可以的
2.await promise 它可以暂停异步函数的执行 等待promise对象返回结果后再向下执行函数
const promisify = require('util').promisify; 改造现有的异步函数api 让其返回promise对象 从而支持异步函数语法
const readFile = promisify(fs.readFile); 调用promisify 方法改造现有异步api 让其返回promise对象
setTimeout() 设置超时定时器
clearTimeou() 清除超时时定时器
setInterval() 设置间歇定时器
clearInterval() 清除间歇定时器
express框架
send()功能:
1.send方法内部会检测响应内容的类型
2.send方法会自动设置http状态码
3.send方法会帮我们自动设置响应的内容类型及编码
try catch 可以捕获异步函数以及其他同步代码在执行过程中发生的错误,但是不能处理其他类型的API发生错误(回调函数、promise对象)
render()功能:
1.拼接模板路径
2.拼接模板后缀
3.哪一个模板和哪一个数据进行拼接
4.将拼接结果响应给了客户端
将变量设置到app.locals对象下面,这个数据在所有的模板中都可以获取到
密码加密bcrypt 依赖环境:
1.python 2.x
2.node-gyp (npm install -g node-gyp)
3.windows-build-tools (npm install --global --production windows-build-tools)
genSalt 方法接收一个数值做为参数,数值越大,生成的随机字符串复杂度越高;数值越小,生成的随机复杂度越低,默认值是10,返回生成的随机字符串
对密码进行加密:1.要进行加密的明文 2.随机字符串 返回值是加密后的密码
对密码加密:const pass = await bcrypt.hash('密码的明文',salt); 生成随机字符串:salt=await bcrypt.genSalt(10);
密码比对: let isEqual = await bcrypt.compare('明文密码','加密密码'); true:比对成功 false:比对失败
cookie:浏览器在电脑硬盘中开辟的一块空间,主要供服务器端存储数据
数据是以域名的形式进行区分的;数据是有过期时间的,超过时间会被浏览器自动删除;数据会随着请求被自动发送到服务器端
session:实际就是一个对象,存储在服务器端的内存中,在session对象中也可以存储多条数据,每一条数据都有一个sessionid做为唯一标识
引入formidable第三方模块 文件上传
1.创建表单解析对象 const form = new formidable.IncomingForm();
2.配置上传文件的存放位置 form.uploadDir = path.join(__dirname,'../','../','public','uploads');
3.保留上传为文件的后缀 form.keepExtensions = true
4.解析表单:form.parse(req,(err,fields,files)=>{})
1.err错误对象 如果表单解析失败 err里面存储错误信息 如果表单解析成功 err将会是null
2.fields 对象类型 保存普通表单数据
3.files 对象类型 保存了和上传文件相关的数据
文件读取
选择文件上传控件 var file = document.querySelectior('#file')
当用户选择完文件以后 file.onchange = function(){
1.创建为媒介读取对象 var reader = new FileReader();
2.读取文件 reader.readAsDataURL(this.files[0])
3.监听onload事件 reader.onload = function(){ console.log(reader.result 将文件读取的结果显示在页面中 preview.src = reader.result ) }}
数据分页mongoose-sex-page达到分页的效果
const pagination = require('mongoose-sex-page')
page() 指定当前页
size 指定每页显示的数据条数
display 指定客户端要显示的页码数量
exec 向数据库中发送查询请求
pagination(集合构造函数).page(1).size(20).display(8).exec();
mongoDB数据库添加账户
1.以系统管理员的方式运行powershell
2.链接数据库 mongo
3.查看数据库 show dbs
4.切换到admin数据库 use admin
5.创建超级管理员账户 db.createUser()
6.切换到blog数据 use blog
7.创建普通账户 db.createUser()
8.卸载mongodb服务: (1.停止服务 net stop mongodb 2.mongod --remove)
9.创建mongodb服务 (mongod --logpath="C:\Program Files\MongoDB\Server\4.1\log\mongod.log" --dbpath="C:\Program Files\MongoDB\Server\4.1\data" --install -auth)
10.启动mongodb服务 net start mongodb
第三方模块config模块
模块内部自动判断当前应用的运行环境,并读取对应的配置信息
使用步骤:
1.使用npm install config命令下载模块
2.在项目的根目录下新建config文件夹
3.在config文件夹下面新建default.json、development.json、production.json文件
4.在项目中通过require方法,将模块进行导入
5.使用模块内部提供的get方法获取配置信息
将敏感配置信息存储在环境变量中
1.在config文件夹中建立custom-environment-variable.json文件
2.配置项属性的值填写系统环境变量的名字
3.项目运行时config模块查找系统环境变量,并读取其值作为当前配置项属于的值
解决多级合联合查询:populate('字段')
正则表达式:写在//的里面 eg:去掉内容中的html标签 /<[^>]+>/g 除了大于号以外的字符至少出现一次所以用+ 因为有多个html标签,所以用g
当用户退出,仍未删除cookile,需要配置session中的saveUninitialized为false eg:app.use(session({ secret:'secret key',saveUninitialized:false}))
但是此时重新打开页面,仍没有cookie,需要设定cookie的有效时间 cookie:{,maxAge:24 *60 *60 *1000}以毫秒为单位
Ajax
运行原理: Ajax相当于浏览器发送请求与接收响应的代理人,以实现在不影响用户浏览页面的情况下,局部更新页面数据,从而提高用户体验
实现步骤: 1.创建Ajax对象: var xhr = new XMLHttpRequest();
2.告诉Ajax请求地址以及请求方式: xhr.open('get','http://www.example.com');
3.发送请求 xhr.send();
4.获取服务器端给与客户端的响应数据: xhr.onload = function (){ console.log(xhr.reasponseText); }
服务器端响应的数据格式: 在真实的项目中,服务器大多数情况下会以JSON对象作为响应数据的格式。当客户端拿到响应数据时,要将JSON数据和HTML字符串进行拼接,然后将拼接结果展示在页面中
在http请求与响应的过程中,无论是请求参数还是响应内容,如果是对象类型,最终都会被转换为对象字符串进行传输 JSON.parse() //将字符串转换为json对象
请求参数传递: GET请求方式:请求放在请求地址中 xhr.open('get','http://www.example.com?name=zhangsan&age=20')
POST请求方式: 请求放在请求体(报文体)中 xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')(设置请求参数格式的类型,post请求必须要设置) xhr.send('name=shangsan&age=20')
请求参数的格式:1.application/x-www-form-urlencoded name=zhangsan&sex='男'
2.application/json {name:'zhangsan',age:'20',sex:'男'}
在请求头中指定Content-Type 属性的值是application/json,告诉服务器端当前请求参数的格式是json JSON.stringify()//将json对象转换为json字符串
注意:get请求是不能提交json对象数据格式的,传统网站的表单提交也是不支持json对象数据格式的
获取服务器端的响应:Ajax状态码:在创建ajax对象,配置ajax对象,发送请求,以及接收完服务器端响应数据,这个过程中的每一个步骤都会对应一个数值,这个数值就是ajax状态码
0:请求未初始化(还没有调用open()) 1:请求已经建立,但是还没发送(还没有调用send()) 2:请求已经发送 3:请求正在处理中,通常响应中有部分数据可以用了 4:响应已经完成,可以获取并使用服务器的响应了
xhr.readyState //获取Ajax状状态码
onreadystatechange 事件: 当Ajax状态码发生变化时将自动触发该事件
两种获取服务器端响应方式的区别:
区别描述 onload事件 onreadystatechange事件
是否兼容IE低版本 不兼容 兼容
是否需要判断Ajax状态码 不需要 需要
被调用次数 一次 多次
Ajax错误处理:1.网络畅通,服务器端能接收到请求,服务器端返回的结果不是预期结果。 可以判断服务器端返回的状态码,分别进行处理。xhr.status获取http状态码
2.网络畅通,服务器端没有接收到请求,返回404状态码。 检查请求地址是否错误。
3.网络畅通,服务器端能接收到请求,服务器端返回500状态码。 服务器端的错误,找后端程序员沟通
4.网络中断,请求无法发送到服务器端。 会触发xhr对象下面的onerror事件,在onerror事件处理函数中对错误进行处理。(断网时,无法触发onload)
Ajax状态码:表示Ajax请求的过程状态 ajax对象返回的
Http状态码:表示请求的处理结果 时服务器端返回的
低版本IE浏览器的缓存问题:问题:在低版本的IE浏览器中,Ajax请求会有严重的问题,即在请求地址不发生变化的情况下,只有第一次请求会真正发送到服务器端,后续的请求都会从浏览器的缓存中获取结果。即使服务器端的数据更新了,客户依然拿到的是缓存中的旧数据。
解决方案:在请求地址的后加请求参数,保证每一次请求中的请求参数的值不相同。 xhr.open('get','http://www.example.com?t='+Math.random);
Ajax封装:
问题:发送一次请求代码过多,发送多次请求代码冗余且重复
解决方案:将请求代码封装到函数中,发请求时调用函数即可
请求参数要考虑的问题:
1.请求参数位置的问题: 将请求参数传递到Ajax函数内部,在函数内部根据请求方式的不同将请求参数位置放置在不同的位置
get 放在请求地址的后面 post 放在send方法中
2.请求参数格式的问题: application/x-www-form-urlencoded 参数名称=参数值 & 参数名称=参数值 eg:name=zhangsan&age=30
application/json eg:{name: 'zhangsan ', age: 20}
1.传递对象数据类型对于函数的调用者更加友好
2.在函数内部对象数据类型转换为字符串数据类型更加方便
Object.assign(defults,option) 对象覆盖(用option对象中的属性覆盖defults对象中的属性)
模板引擎:
作用:使用模板引擎提供的模板语法,可以将数据和HTML拼接起来
官方地址:https://aui.github.io/art-template/zh-cn/index.html
使用步骤:
1.下载art-template模板引擎库文件并在HTML页面中引入库文件
<script src="./js/template-web.js"></script>
2.准备art-template模板
<script id="tpl" type="text/html" >
<div class="box"></div>
</script>
3.告诉模板引擎将哪一个模板和哪个数据进行拼接
var html = template('tpl',{username: 'zhangsan', age: '20'})
4.将拼接好的html字符串添加到页面中
document.getElementById('container').innerHTML = html;
5.通过模板语法告诉模板引擎,数据和html字符串要如何拼接
<script id="tpl" type="text/html">
<div class="box">{{ username }}</div>
</script>
案例一:验证邮箱地址唯一性
1.获取文本框并为其添加离开焦点事件
2.离开焦点时,检测用户输入的邮箱地址是否符合规则(规则:/^[A-Za-z\d]+([-_.][A-Za-z\d]+)*@([A-Za-z\d]+[-.])+[A-Za-z\d]{2,4}$/
3.如果不符合规则,阻止程序向下执行并给出提示信息
4.向服务器端发送请求,检测邮箱地址是否被别人注册
5.根据服务器端返回值决定客户端显示何种提示信息
案例二:搜索框内容自动提示
1.获取搜索框并为其添加用户输入事件(oninput )
2.获取用户输入的关键字
3.向服务器端发送请求并携带关键字作为请求参数
4.将响应数据显示在搜索框底部
案例三:省市区三级联动
1.通过接口获取省份信息
2.使用JavaScript获取到省市区下拉框元素
3.将服务器端返回的省份信息显示在下拉框中
4.为下拉框元素添加表单值改变事件(onchange)
5.当用户选择省份时,根据省份id获取城市信息
6.当用户选择城市时,根据城市id获取县城信息
FormData:
FormData对象的使用
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);
FormData对象的实例方法
1.获取表单对象中属性的值
formData.get('key');
2.设置表单对象中属性的值(如果设置的表单属性不存在 将会创建这个表单属性)(如果设置的表单属性存在 将会覆盖这个表单属性原有的值)
formData.set('key','value');
3.删除表单对象中属性的值
formData.delete('key');
4.向表单对象中追加属性值
formData.append('key','value');
注意:set方法与append方法的区别是,在属性名已存在的情况下,set会覆盖已有键名的值,append会保留两个值
FormData二进制文件上传
<input type="file" id="file" />
var file = document.getElementById('file')
当用户选择文件时,file添加onchange事件
创建空表单对象 var formData = new FormData(form);
将用户选择的二进制文件追加到表单对象中 fomData.append('attrName',this.files[0])
配置ajax对象,请求必须为post xhr.open('post','www.example.com')
xhr.send(formData)
实现文件上传路由
app.post('/upload',(req,res) => {
//创建formidable表单解析对象
const form = new formidable.IncomingForm();
//设置客户端上传文件的存储路径 (__dirname:绝对路径)
form.uploadDir = path.join(__dirname,'public','uploads');
//保留上传文件的后缀名字
form.keepExtensions = true;
//解析客户端传递过来的FormData对象
form.parse(req,(err,fields,files) => {
res.send('ok');
});
});
FormData文件上传进度展示
当用户选择文件之后,文件上传过程中持续触发onprogress事件
xhr.upload.onprogress = function (ev) {
//当前上传文件大小loaded/文件总大小total再将结果转换为百分数 将结果赋值给进度条的宽度属性
bar.style.width = (ev.loaded / ev.total) * 100 + '%';
}
同源政策:
什么是同源:如果两个页面拥有相同的协议、域名和端口,那么这两个页面就属于同一个源,其中只要有一个不相同,就是不同源
同源政策的目的:
同源政策是为了保证用户信息的安全,防止恶意的网站窃取数据。最初的同源政策是值A网站在客户端设置的Cookie,B网站是不能访问的。
随着互联网的发展,同源政策也越来越严格,在不同源的情况下,其中有一项规定就是无法向非同源地址发送Ajax请求,如果请求,浏览器就会报错。
Ajax请求限制
Ajax请求只能向自己服务器发送请求。比如现在有一个A网站、有一个B网站,A网站中的HTML文件只能向A网站服务器中发送Ajax请求,B网站中的HTML文件只能向B网站发送Ajax请求,但是A网站是不能向B网站发送Ajax请求的,同理,B网站也不能向A网站发送Ajax请求。
使用JSONP解决同源限制问题:
jsonp是json with padding的缩写,它不属于Ajax请求,但它可以模拟Ajax请求。
1.将不同源的服务器端请求地址写在script标签的src属性中
<script src="www.example.com"></script>
<script src=``https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js``></script>
2.服务器端响应数据必须是一个函数的调用,真正要发送给客户端的数据需要作为函数调用的参数。
const data = 'fn({name:"张三",age:"20"})';
res.send(data);
3.在客户端全局作用域下定义函数fn(并且将其写在script前面)
function fn (data) { }
4.在fn函数内部对服务器端返回的数据进行处理
function fn (data) { console.log(data); }
JSONP代码优化:
1.客户端需要将函数名称传递到服务器端
2.将script请求的发送变成动态请求
3.封装jsonp函数,方便请求发送
路由:
app.get(''/better',(req,res) => {
//接收客户端传递过来的函数的名称
const fnName = req.query.callback;
//将函数名称对应的函数调用代码返回给客户端
const data = JSON.stringify({name:"张三"});
const result = fnName + '('+data+')';
setTimeout(() => {
res.send(result);
},1000)
});
CORS跨域资源共享:
CORS:全称为Cross-origin resource sharing,即跨域资源共享,它允许浏览器向跨域服务器发送Ajax请求,克服了Ajax只能同源使用的限制
在路由中设置:
//1.允许哪些客户端访问我 *代表允许所有的客户端访问我
res.header('Access-Control-Allow-Origin','*')
//2.允许客户端使用哪些请求方法访问我
res.header('Access-Control-Allow-Methods','get,post')
访问非同源数据 服务器端解决方案
同源政策是浏览器给予Ajax技术的限制,服务器端是不存在同源政策限制。
所以使用A服务器端请求B服务器端,然后将内容响应给A浏览器端
在A服务器端的路由:
//向其他服务器端请求数据的模块
const request = require('request')
app.get('/server',(req,res) => {
request('http://localhost:3001/cross',(err,response,body) => {
send(body)
})
})
cookie复习:
就是客户端和服务器端进行身份识别的技术(第一次客户端请求服务器端,服务器端响应cookie,再次客户端就请求自动发送cookie给服务器端)
withCredentials属性:
在使用Ajax技术发送跨域请求时,默认情况下捕获在请求中携带cookie信息
withCredentials:指定在涉及到跨域请求时,是否携带cookie信息,默认值为false(客户端设置)
Access-Control-Allow-Credentials:true允许客户端发送请求时携带cookie(服务器端设置)
$.ajax
作用:发送Ajax请求
$.ajax({
type: 'get', //请求方式
url: 'http://www.example.com' //请求地址
data :{name: 'zhangsan',age: '20'},
contentType: 'application/x-www-form-urlencoded',
beforeSend: function() { return false //请求不会被发送 } //在请求发送之前调用
success: function (response){} //请求成功以后函数被调用
error: function (xhr) {} //请求失败以后函数被调用
})
serialize方法:
作用:将表单中的数据自动拼接成字符串类型的参数
var params = $('#form').serialize();
将表单中用户输入的内容转换为对象类型:
function serializeObject(obj) {
var result = {}; //处理结果对象
var params = obj.serializeArray(); // [{name: 'username', value: '用户输入的内容'},{name: 'password', value: '123456'}]
$.each(params,function (index,value) { //循环数组 将数组转换为对象类型
result[value.name] = value.value;
})
return result;
}
作用:发送jsonp请求
$.ajax({
url: 'http://www.example.com',
dataType: 'jsonp', // 指定当前发送jsonp请求
jsonp: 'cb', //修改callback参数名称
jsonpCallback: 'fnName', //指定函数名称
success: function (response){} //请求成功以后函数被调用
})
$.get()、$.post:
作用:$.get方法用于发送get请求,$.post方法用于发送post请求
$.get('http://www.example.com',{name: 'zhangsan', age: 30}, function (response) {} )
$.post('http://www.example.com',{name: 'zhangsan', age: 30}, function (response) {} )
Todo案例:
为todo数据库添加账户
1.使用mongo命令进入mongodb数据库
2.使用use admin 命令进入到admin数据中
3.使用db.auth('root','root')命令登录数据库
4.使用use todo命令切换到todo数据库
5.使用db.createUser({user.'itcast', pwd: 'itcast', roles:['readWrite']})创建todo数据库账户
6.使用exit命令退出mongodo数据库
展示任务列表
1.准备一个放置任务列表的数组
2.向服务器端发送请求,获取已存在的任务
3.将已存在的任务存储在任务列表数组中
4.通过模板引擎将任务列表数组中的任务显示在页面中
添加任务
1.为文本框绑定键盘抬起事件,在事件处理函数中判断当前用户敲击的是否是回车键
2.当用户敲击回车键的时候,判断用户在文本框中是否输入了任务名称
3.向服务器端发送请求,将用户输入的任务名称添加到数据库中,同时将任务添加到任务组中
4.通过模板引擎将任务列表数组中的任务显示在页面中
删除任务
1.为删除按钮添加点击事件
2.在事件处理函数中获取到要删除任务的id
3.向服务器端发送请求,根据ID删除任务,同时将任务数组的相同任务删除
4.通过模板引擎将任务列表数组中的任务重新显示在页面中
更改任务状态
1.为任务复选框添加onchange事件
2.在事件处理函数中获取复选框是否选中
3.向服务器端发送请求,将当前复选框的是否选中状态提交到服务器端
4.将任务状态同时也更新到任务列表数组中
5.通过模板引擎将任务列表数组中的任务重新显示在页面中并且根据任务是否完成为li元素添加completed类名
修改任务名称
1.为任务名称外层的label标签添加双击事件,同时为当前任务外层的li标签添加editing类名,开启编辑状态
2.将任务名称显示在文本框中并让文本框获取焦点
3.当文本框离开焦点时,将用户在文本框中输入值提交到服务器端,并且将最新的任务名称更新到任务列表数组中
4.使用模板引擎重新渲染页面中的任务列表
计算未完成任务数量
1.准备一个用于存储未完成任务数量的变量
2.将未完成任务从任务数组中过滤出来
3.将过滤结果数组的长度赋值给任务数量变量
4.将结果更新到页面中
全局事件
只要页面中有Ajax请求被发送,对应的全局事件就会被触发
.ajaxStart() //当请求开始发送时触发
.ajaxComplete() //当请求完成时触发
NProgress: 官宣:纳米级进度条,使用逼真的涓流动画来告诉用户正在发生的事情
<link rel='stylesheet' href='nprogress.css' />
<script src='nprogress.js'></script>
NProgress.start(); //进度条开始运动
NProgress.done(); //进度条结束运动
XML基础:
XML的全称是extensible markup language,代表可扩展标记语言,它的作用是传输和存储数据
XMLDOM 即XML文档对象模型,是w3c组织定义的一套操作XML文档对象的API。浏览器会将XML文档解析成文档对象模型
Git:
## 1. Git基础
### 1.1 版本管理
#### 1.1.1 什么是版本管理
版本管理是一种记录文件变化的方式,以便将来查阅特定版本的文件内容。
![](assets/01.png)
#### 1.1.2 人为维护文档版本的问题
1. 文档数量多且命名不清晰导致文档版本混乱
2. 每次编辑文档需要复制,不方便
3. 多人同时编辑同一个文档,容易产生覆盖
![](assets/04.png)
### 1.2 Git 是什么
Git是一个版本管理控制系统(缩写VCS),它可以在任何时间点,将文档的状态作为更新记录保存起来,也可以在任何时间点,将更新记录恢复回来。
![](assets/19.png)
### 1.3 Git 安装
[下载地址](https://git-scm.com/downloads)
在安装的过程中,所有选项使用默认值即可。
### 1.4 Git 基本工作流程
| git仓库 | 暂存区 | 工作目录 |
| ---------------- | ------------------ | ------------------- |
| 用于存放提交记录 | 临时存放被修改文件 | 被Git管理的项目目录 |
![](assets/05.png)
### 1.5 Git 的使用
#### 1.5.1 Git 使用前配置
在使用 git 前,需要告诉 git 你是谁,在向 git 仓库中提交时需要用到。
1. 配置提交人姓名:`git config --global user.name 提交人姓名`
2. 配置提交人姓名:`git config --global user.email 提交人邮箱`
3. 查看git配置信息:`git config --list`
**注意**
1. 如果要对配置信息进行修改,重复上述命令即可。
2. 配置只需要执行一次。
#### 1.5.2 提交步骤
1. `git init` 初始化git仓库
2. `git status` 查看文件状态
3. `git add 文件列表` 追踪文件
4. `git commit -m 提交信息` 向仓库中提交代码
5. `git log` 查看提交记录
#### 1.5.3 撤销
- 用暂存区中的文件覆盖工作目录中的文件: `git checkout 文件`
- 将文件从暂存区中删除: `git rm --cached 文件`
- 将 git 仓库中指定的更新记录恢复出来,并且覆盖暂存区和工作目录:`git rest --hard commitID`
![](assets/07.png)
## 2. Git进阶
### 2.1 分支
为了便于理解,大家暂时可以认为分支就是当前工作目录中代码的一份副本。
使用分支,可以让我们从开发主线上分离出来,以免影响开发主线。
![](assets/08.png)
#### 2.1.1 分支细分
1. 主分支(master):第一次向 git 仓库中提交更新记录时自动产生的一个分支。
![](assets/06.png)
2. 、开发分支(develop):作为开发的分支,基于 master 分支创建。
![](assets/09.png)
3. 功能分支(feature):作为开发具体功能的分支,基于开发分支创建
![](assets/10.png)
**功能分支 -> 开发分支 -> 主分支**
#### 2.1.2 分支命令
- `git branch` 查看分支
- `git branch 分支名称` 创建分支
- `git checkout 分支名称` 切换分支
- `git merge 来源分支` 合并分支
- `git branch -d 分支名称` 删除分支(分支被合并后才允许删除)(-D 强制删除)
### 2.2 暂时保存更改
在git中,可以暂时提取分支上所有的改动并存储,让开发人员得到一个干净的工作副本,临时转向其他工作。
使用场景:分支临时切换
- 存储临时改动:`git stash`
- 恢复改动:`git stash pop`
## 3. Github
在版本控制系统中,大约90%的操作都是在本地仓库中进行的:暂存,提交,查看状态或者历史记录等等。除此之外,如果仅仅只有你一个人在这个项目里工作,你永远没有机会需要设置一个远程仓库。
只有当你需要和你的开发团队共享数据时,设置一个远程仓库才有意义。你可以把它想象成一个 “文件管理服务器”,利用这个服务器可以与开发团队的其他成员进行数据交换。
### 3.1 注册
1. 访问[github](https://github.com/)首页,点击 Sign up 连接。(注册)
![](assets/11.png)
2. 填写用户名、邮箱地址、GitHub登陆密码
![](assets/12.png)
3. 选择计划
![](assets/13.png)
4. 填写 GitHub 问题
![](assets/14.png)
5. 验证邮箱
![](assets/15.png)
6. GitHub 个人中心
![](assets/16.png)
### 3.2 多人协作开发流程
- A在自己的计算机中创建本地仓库
- A在github中创建远程仓库
- A将本地仓库推送到远程仓库
- B克隆远程仓库到本地进行开发
- B将本地仓库中开发的内容推送到远程仓库
- A将远程仓库中的最新内容拉去到本地
![](assets/20.png)
![](assets/21.png)
### 3.3 创建仓库
1. 填写仓库基本信息
![](assets/17.png)
2. 将本地仓库推送到远程仓库
![](assets/18.png)
1. git push 远程仓库地址 分支名称
2. git push 远程仓库地址别名 分支名称
3. git push -u 远程仓库地址别名 分支名称
-u 记住推送地址及分支,下次推送只需要输入git push即可
4. git remote add 远程仓库地址别名 远程仓库地址
### 3.4 拉取操作
#### 3.4.1 克隆仓库
克隆远端数据仓库到本地:`git clone 仓库地址`
#### 3.4.2 拉取远程仓库中最新的版本
拉取远程仓库中最新的版本:`git pull 远程仓库地址 分支名称`
### 3.5 解决冲突
在多人同时开发一个项目时,如果两个人修改了同一个文件的同一个地方,就会发生冲突。冲突需要人为解决。
### 3.6 跨团队协作
1. 程序员 C fork仓库
2. 程序员 C 将仓库克隆在本地进行修改
3. 程序员 C 将仓库推送到远程
4. 程序员 C 发起pull reqest
5. 原仓库作者审核
6. 原仓库作者合并代码
### 3.7 ssh免登陆
https协议仓库地址:https://github.com/itcast-frontEnd/git-demo.git
![](assets/22.png)
生成秘钥:`ssh-keygen`
秘钥存储目录:C:\Users\用户\\.ssh
公钥名称:id_rsa.pub
私钥名称:id_rsa
![](assets/23.png)
![](assets/24.png)
### 3.8 GIT忽略清单
将不需要被git管理的文件名字添加到此文件中,在执行git命令的时候,git就会忽略这些文件。
git忽略清单文件名称:**.gitignore**
将工作目录中的文件全部添加到暂存区:`git add .`
模板引擎
Ajax项目中存在的问题:
1.数据和HTML字符串拼接导致代码混乱,拼接容易出错,增加修改难度
2.业务逻辑和用户界面混合,代码不易维护
## 1. 模板引擎
文档:http://aui.github.io/art-template/zh-cn/
Github: https://github.com/aui/art-template
### 1.1 Ajax 项目中存在的问题
1. 数据和HTML字符串拼接导致代码混乱,拼接容易出错,增加修改难度。
2. 业务逻辑和用户界面混合,代码不易维护。
```javascript
for (var i = 0; i < result.length; i++) {
html += '<!DOCTYPE html>\
<html lang="en">\
<head>\
<meta charset="UTF-8">\
<title>'+ title +'</title>\
</head>\
<body>\
<h1 οnclick="sayHi('+name+')">你好,'+name+' 我今年 '+age+'岁</h1>\
<ul>\
<li title="'+hobbies[0]+'">'+hobbies[0]+'</li>\
</ul>\
</body>\
</html>
### 1.2 模板引擎的作用
1. 使用模板引擎提供的模板语法可以使数据和HTML字符串拼接的更加美观,代码易于维护。
2. 模板引擎能够使用户界面的数据拼接和JavaScript业务逻辑分离,增加程序的可扩展性。
3. 使用模板引擎可以提高开发效率。
```html
<h1>你好, {{name}}, 我今年{{age}}岁</h1>
<ul>
{{each}}
<li>{{$value.hobbies}}</li>
{{/each}}
</ul>
```
### 1.3 模板渲染
```html
<script src="./js/template-web.js"></script>
<script type="text/html" id="tpl">
<div>
<span>{{name}}</span>
<span>{{age}}</span>
</div>
</script>
```
```javascript
// 将特定模板与特定数据进行拼接
const html = template('tpl',{
name: '张三',
age: 20
});
```
## 2. 模板语法
模板语法的作用是告诉模板引擎数据和模板要如何进行拼接。
### 2.1 输出
将数据显示在模板中。
```ejs
<h2>{{value}}</h2>
<h2>{{a ? b : c}}</h2>
<h2>{{a + b}}</h2>
```
### 2.2 原文输出
如果数据中携带HTML标签,默认情况下,模板引擎不会解析标签,会将其转义后原文输出。
```ejs
<h2>{{@ value }}</h2>
```
### 2.3 条件判断
```ejs
{{if 条件}} ... {{/if}}
{{if v1}} ... {{else if v2}} ... {{/if}}
```
```ejs
{{if 条件}}
<div>条件成立 显示我</div>
{{else}}
<div>条件不成立 显示我</div>
{{/if}}
```
### 2.4 循环
```ejs
{{each target}}
{{$index}} {{$value}}
{{/each}}
```
### 2.5 导入模板变量
```ejs
<div>$imports.dataFormat(time)</div>
```
```javascript
template.defaults.imports.变量名 = 变量值;
$imports.变量名称
```
```javascript
function dateFormat(未格式化的原始时间){
return '已经格式化好的当前时间'
}
template.defaults.imports.dateFormat = dateFormat;
```
案例: 阿里百秀
阿里百秀,内容管理系统,分为内容管理和内容展示两大核心功能。
## 1. 功能模块
#### 1.1 内容管理
| 模块 | 功能 |
| -------- | ------------------------------ |
| 用户 | 登录、退出、用户增删改查 |
| 文章 | 文章管理 |
| 分类 | 分类管理 |
| 评论 | 评论管理 |
| 网站设置 | 关键字、描述、网站logo、轮播图 |
#### 1.2 内容展示
| 模块 | 功能 |
| ------ | ------------------------------ |
| 首页 | 导航、文章数据展示 |
| 列表页 | 根据分类显示文章列表 |
| 详情页 | 文章详情数据展示、实现评论功能 |
## 2. 开发模式
#### 2.1 前后端混合开发模式
所有HTML代码和数据在服务器端拼接好,一次性将所有内容发送到客户端,浏览器执行代码,将内容呈现给用户
![](assets/02.png)
问题:
1. 前后端开发人员对互相的代码都不是别熟悉,混合开发两者在处理互相的代码时非常困难
2. 在开发的过程中难免会出现代码互相覆盖,导致工作量倍增
#### 2.2 前后端分离开发模式
![](assets/03.png)
好处:职责、分工明确,独立开发,互不影响。
## 3. 项目架构
| 系统分层 | 使用技术 |
| -------- | ----------------------------------------- |
| 数据层 | mongoDB |
| 服务层 | node.js (express) |
| 客户端 | art-template、jQuery、font-awesome、swipe |
## 4. 项目运行环境搭建
1. 安装node.js软件并测试其是否安装成功
1. win + R 开启windows系统中的运行程序,在运行程序中输入powershell回车,打开命令行程序
2. 输入`node -v`命令查看node.js的版本,在命令行程序中输出了版本号没有报错即说明安装成功
2. 安装mongodb、mongodb-compass软件
3. 将阿里百秀项目文件夹复制到硬盘中(服务器端程序)
4. 在命令行工具中进入到项目根目录中
1. 按住shift键,点击鼠标右键,选择在此处打开powershell窗口
5. 使用`npm install`命令安装项目所需依赖文件
6. 将阿里百秀静态页面复制到public文件夹中
7. 在命令行工具中输入node app.js开启项目
# 登录功能
1. 为登录按钮添加点击事件
2. 获取用户在文本框中输入的用户名和密码
3. 验证用户是否输入了用户名和密码,如果没有输入,阻止程序向下执行,提示用户输入用户名和密码
4. 调用实现登录功能的接口,登录成功,跳转到数据管理的首页,登录失败,提示用户名或密码错误
# 登录拦截
1. 使用script标签加载服务器端提供的接口地址
2. 判断isLogin变量的值,如果值为false,跳转到登录页面
# 添加用户
1. 为添加用户功能的每一个表单项添加name属性,且name属性值需要和接口文档中要求的参数名称保持一致
2. 为表单绑定提交事件,在事件处理函数中阻止表单默认提交的行为
3. 在事件处理函数中获取到用户在表单中输入的内容
4. 调用添加用户接口,将获取到的内容通过接口发送给服务器端,操作成功刷新页面,操作失败给出用户提示
# 展示用户列表
1. 向服务器端发送Ajax请求,索要用户列表数据
2. 第二步,使用模板引擎将数据和html模板进行拼接
3. 第三步就是将拼接好的内容展示在页面中
# 用户头像上传
1. 为文件选择控件添加onchange事件,在事件处理函数中获取到用户选择到的文件
2. 创建formData对象用于实现图片文件上传
3. 调用图片文件上传接口,实现图片上传
4. 在添加新用户表单中新增一个隐藏域,将图片地址存储在隐藏域中
# 用户列表展示
1. 在页面加载时向服务器端发送Ajax请求,索要用户列表数据
2. 使用模板引擎将数据和html模板进行拼接
3. 将拼接好的内容展示在页面中
# 用户信息修改
1. 通过事件委托的形式为编辑按钮点击添加事件
2. 在事件处理函数中获取到当前点击用户的id值
3. 根据用户id获取用户的详细信息,并且通过模板引擎将用户的详细信息渲染到左侧的表单中
4. 为修改按钮添加点击事件,在事件处理函数中获取到用户在表单中输入的内容,调用修改用户信息接口实现用户信息修改功能。
# 删除用户
1. 为删除按钮添加点击事件
2. 确认用户是否要进行删除操作
3. 获取到当前被点击用户的id
4. 调用删除用户接口根据id删除用户,如果删除成功,刷新当前页面,让页面显示最新的内容
# 批量删除用户
1. 管理复选框的选中状态
1. 当全选按钮被选中时,所有用户要被选中,当全选按钮取消选中时,所有用户要被取消选中
2. 当用户前面的复选框按钮状态被改变时,要检查是否有用户处于未选中状态,如果有,取消全选按钮的选中状态,如果没有,就意味着所有用户都处于选中状态,此时将全选按钮设置为选中状态
2. 管理批量删除按钮的状态
1. 当全选按钮被选中时,显示批量删除按钮,当全选按钮被取消选中时,隐藏批量删除按钮
2. 当用户前面的复选框按钮状态改变时,检查所有用户的选中状态,如果有用户被选中,显示批量删除按钮,如果所有用户都没有处于选中状态,隐藏批量删除按钮
3. 实现批量删除用户功能
1. 批量删除按钮添加点击事件,在点击事件处理函数中,将所有被选中的用户id执行存储在一个数组中
2. 调用用删除用户接口,实现删除用户功能
# 修改密码
1. 为修改密码表单中的每一个表单项添加name属性,name属性的值要和接口中的参数名称保持一致
2. 为修改密码表单添加表单提交事件,在事件处理函数中,阻止表单的默认提交行为
3. 获取到用户在表单中输入的内容
4. 调用修改密码接口,实现密码修改功能,如果密码修改成功,跳转到登录页面,让用户重新登录
# 添加分类
1. 为表单中的每一个表单项添加name属性,name属性的值要和接口文档中要求的参数名称保持一致
2. 为表单添加表单提交事件,在事件处理函数中,阻止表单提交的默认行为
3. 获取到用户在表单中输入的内容
4. 调用分类添加接口,实现添加分类功能
# 分类数据展示
1. 向服务器端发送Ajax请求,索要分类页面数据
2. 使用模板引擎将服务器端返回的数据和HTML模板进行拼接
3. 将拼接好的内容展示在页面中
# 分类数据修改
1. 通过事件委托为编辑按钮添加点击事件,在事件处理函数中获取到要修改的分类数据id
2. 根据id调用接口,获取分类数据的详细信息
3. 利用模板引擎将分类数据和HTML字符进行拼接,拼接完成以后将内容渲染到页面中
4. 为修改按钮添加点击事件,在事件处理函数中获取到管理员在表单中输入的内容
5. 调用修改分类数据接口,实现分类数据修改功能。
# 分类数据删除
1. 通过事件委托的方式为删除按钮添加点击事件,在点击事件处理函数弹出删除确认框
2. 在用户点击了确认删除后,获取要删除的分类数据的id
3. 调用删除分类数据接口,实现删除分类数据功能,如果分类删除成功,刷新页面
# 添加文章
1. 获取文章分类数据,并将数据显示在所属分类的下拉列表中供管理员选择
2. 实现文章封面图片的上传,并将上传后的图片地址保存在一个隐藏域中
3. 为添加文章表单中的每一个表单项添加name属性,并且name属性值要和接口中要求的参数名称保持一致
4. 为添加文章表单绑定表单提交事件,在事件处理函数中阻止表单默认提交的行为
5. 获取到管理员在表单中输入的内容
6. 向服务器端发送添加文章的请求,实现文章添加功能,文章添加成功以后要跳转到文章列表页面
# 文章列表数据展示
1. 在页面一上来的时候向服务器端发送请求索要文章列表数据
2. 通过模板引擎将文章列表数据和HTML进行拼接,拼接完成以后将内容显示在页面中
3. 根据分页数据实现列表数据分页功能
# 文章数据列表筛选
1. 向服务器端发送请求,索要文章分类数据,并将数据显示在所属分类的下来列表中
2. 为筛选按钮添加点击事件,在事件处理函数中获取到用户选择到的内容
3. 向服务器端发送请求,索要管理员要求的文章列表数据,并将数据显示在页面中
# 文章编辑
1. 为编辑按钮添加链接,并将文章id作为链接的查询参数传递到文章编辑页面
2. 在文章编辑页面获取地址栏中的id参数
3. 根据id获取文章详细信息,并将文章信息显示在文章编辑表单中
4. 为修改文章表单绑定表单提交事件,在事件处理函数中阻止表单默认提交的行为
5. 获取到用户在表单中输入的内容
6. 向服务器端发送请求,实现修改文章信息功能,如果文章信息修改成功,跳转到文章列表页面
# 文章删除
1. 通过事件委托为删除按钮添加点击事件,在事件处理函数中弹出一个删除确认框,跟管理员确认删除操作
2. 在事件处理函数中获取要要删除的文章的id
3. 发送Ajax请求,执行删除操作,删除操作成功,刷新页面
# 评论列表展示
1. 向服务器端发送请求,获取评论列表数据
2. 使用模板引擎将评论列表数据和HTML模板进行拼接,拼接完成以后再将内容展示在页面中
3. 根据分页数据实现分页功能
# 评论审核
1. 根据当前评论的状态更改审核按钮中的文字。如果当前评论是未审核状态,按钮中显示批准,如果当前评论是已审核状态,按钮中显示驳回
2. 通过事件委托的方式为审核按钮添加点击事件,在事件处理函数中获取到当前评论的状态
3. 向服务器端发送请求,告诉服务器端评论要更改为什么状态,如果修改成功,刷新页面,让页面中显示最新的数据
# 评论删除
1. 通过事件委托的方式为删除按钮添加点击事件,在事件处理函数中弹出删除确认框
2. 获取到管理员要删除的评论id值
3. 向服务器端发送请求,执行删除评论操作,评论如果删除成功,刷新页面
# 图片轮播数据添加
1. 实现图片上传功能,并且将上传后的图片地址保存在一个隐藏域中
2. 为图片轮播表单中的每一个表单项添加name属性,name属性的值要和接口中要求的参数名称保持一致
3. 为图片轮播表单绑定表单提交事件,在事件处理函数中阻止表单默认提交的行为
4. 获取到管理员在表单中输入的内容
5. 向服务器端发送请求,实现图片轮播数据添加功能,如果数据添加成功,刷新页面
# 轮播图数据展示
1. 向服务器端发送请求索要图片轮播列表数据
2. 使用模板引擎将图片轮播列表数据和HTML模板进行拼接,拼接完成以后将内容展示在页面中
# 图片轮播数据删除
1. 通过事件委托的方式为删除按钮添加点击事件
2. 在事件处理函数中弹出删除确认框
3. 获取到要删除的轮播图数据的id
4. 向服务器端发送请求,执行删除操作,删除操作成功,刷新页面
# 网站设置
1. 实现网站logo图片的上传,并且将上传后的图片地址保存在一个隐藏域中
2. 为表单中的每一个表单项添加name属性,name属性的值要和接口文档中要求的参数名称保持一致
3. 为表单绑定提交事件,在事件处理函数中阻止表单默认提交的行为
4. 获取到管理员在表单中输入的内容
5. 向服务器端发送请求,实现网站设置数据的添加功能
# 显示网站设置数据
1. 向服务器端发送请求,获取网站设置数据
2. 判断服务器端返回的数据是否为真,如果为真,将数据展示在表单中
# 展示登录用户信息
1. 根据userId变量的值,向服务器端获取当前登录用户的信息
2. 将用户信息显示在页面的左侧
# 轮播图数据展示
1. 向服务器端发送请求索要轮播图数据
2. 使用模板引擎将数据和HTML字符串进行拼接,将拼接好的内容显示在页面中
3. 将原有的实现轮播图效果的JavaScript代码挪到ajax方法的success函数的最后面
# 热门推荐
1. 向服务器端发送请求,索要热门推荐数据
2. 使用模板引擎将数据和html模板进行拼接,将拼接好的内容显示在页面中
```javascript
var str = '<div>{{name}}</div>';
var obj = {name: '张三'}
var html = template.render(str, obj);
```
# 搜索
1. 为搜索表单绑定表单提交事件
2. 在事件处理函数中阻止表单默认提交行为并且获取到用户输入的搜索关键字
3. 跳转到搜索结果页面并且将用户输入的搜索关键字传递到搜索结果页面
4. 在搜索结果页面中,从地址栏的查询参数中获取到用户输入的关键字
5. 根据用户输入的搜索关键字调用搜索接口,当服务器端返回数据以后,将搜索结果数据和HTML模板进行拼接,最终将拼接好的内容展示在页面中
代码: