目录
0 说明
代码敲时方恨少,边学边练亏不了
B站黑马视频教程链接
github代码笔记
1 AJAX
Asynchronous JavaScript And XML:异步的JS和XML。
1.1 axios库
基于XMLHttpRequest对象
标准代码段示例:
axios({
url:'http://hmajax.itheima.net/api/register',
method:'post',
data:{
username:'ithei202308',
password:'123456'
}
}).then((result) => {
console.log(result);
}).catch(error => {
alert(error.response.data.message)
})
})
1.2 响应状态码
1信息
2成功
3重定向
4客户端错误
5服务端错误
1.3 API文档使用
1.4 form-serialize插件
插件根据元素的name
属性来获取
// 3.2 使用form插件的 serialize函数,收集登录表单里用户名和密码
// 3.2.1 获取表单对象
const form = document.querySelector('.login-form')
// 3.2.2 表单对象传入serialize函数,并传入对象参数,获取表单的属性对象
const data = serialize(form, { hash: true, empty: true })
// console.log(data)
// {username: 'itheima007', password: '7654321'}
// 学习阶段为了省略而省略的做法,代码自己都难读懂,着实不建议
// const { username, password } = data:对象的解构&赋值
// 解构&赋值的语法:旧变量名:新变量名
const { username:username, password:password } = data
1.4.1 案例01 登录框案例
p12视频中的alert相关bootstrap链接
案例中涉及到的方法属性:
函数传参,匿名函数(带参)
三元表达式:
let bgc_style = is_success ? 'alert-success' : 'alert-danger'
ajax的axios方法then,catch,
对象获取querySelector与绑定addEventListener,
定时器setTimeout等
1.4.2 案例02 图书管理
1.4.2.1 添加逻辑
坑:点击新增后的清除表单,关闭modal弹窗,获取刷新之后的逻辑应该在回调函数
中体现,否则影响事件监听的异步代码的执行顺序
axios({
url: 'http://hmajax.itheima.net/api/books',
method: 'post',
data: {
// 不用解构,直接展开运算符就行
...addBook,
creator: creator,
}
}).then(result => {
addForm.reset()
addModal.hide()
// 点击事件异步,所以需要在里面刷新请求
getBooksList()
})
1.4.2.2 删除逻辑
// 活动添加的html标签,用父级的委托来实现点击事件监听
document.querySelector('.list').addEventListener('click',e=>{
// data-id自定义的id属性保存在dataset属性里
const theId = e.target.dataset.id
1.4.2.3 修改逻辑
axios({
url: `http://hmajax.itheima.net/api/books/${editBookInfo.id}`,
method: 'put',
data: {
// 添加图书逻辑中的 addBook不含id,可以直接展开。这里的包括id,不能直接展开运算符,可以做解构,直接点方法也可以更直白
bookname: editBookInfo.bookname,
author: editBookInfo.author,
publisher: editBookInfo.publisher,
creator
}
1.4.2.4 案例总结
1、bootstrap插件和form-serialize插件的基本使用:
// bootstrap
const addModalDom = document.querySelector('.add-modal')
const addModal = new bootstrap.Modal(addModalDom)
// form
const editDom = document.querySelector('.edit-form')
const editBookInfo = serialize(editDom, { hash: true, empty: true })
2、几种ajax下axios的请求methods;修改逻辑结合了添加的逻辑,对象的解构,展开运算符等方法
1.4.3 案例03 图片上传处理
FormData()方法生成图片对象,
const fd = new FormData()
fd.append('img',e.target.files[0])
对应的post方法上传时的data参数直接填对象fd
就行,绑定upload上传的change事件
const fd = new FormData()
fd.append('img',e.target.files[0])
// 提交
axios({
url:'http://hmajax.itheima.net/api/uploadimg',
method:'post',
data:fd,
})
案例里设计本地存储与读取方法的使用:
// 本地存储地址链接
localStorage.setItem('imgUrl',result.data.data.url)
}).catch((err) => {
pass
});
})
const imgUrl = localStorage.getItem('imgUrl')
imgUrl && (document.body.style.backgroundImage = `url(${imgUrl})`)
1.4.4 案例04 个人信息管理
1.4.4.1 获取个人信息
同案例02的图书管理里的修改内容的获取逻辑类似,也有返回结果对象的foreach遍历,展示部分代码:
const userObj = result.data.data
const keys = Object.keys(userObj)
keys.forEach(key=>{
此外,针对性别代码的单选框的选定状态,也借由中间变量来过渡确定checked属性,这部分算是目前阶段比较好理解的处理方法,部分代码:
const genderList =document.querySelectorAll('.gender')
const genderNum = userObj[key]
genderList[genderNum].checked = true
1.4.4.2 修改个人信息
修改类似图书管理的修改,不同之处使用了bootstrap的Toast
方法弹窗,使用方法类似Modal
方法
1.5 XMLHttpRequest(XHR)对象
1.5.1 XHR基础
axios的基础,简单的get请求使用XHR,记得open方法
配置请求方法和url后紧接着send调用
,然后再写loadend的回调监听
,不然容易忘记:
const myxhr = new XMLHttpRequest()
// 使用open方法配置请求,send发送请求
myxhr.open('GET', 'http://hmajax.itheima.net/api/province')
// loadend事件接收响应
myxhr.addEventListener('loadend', () => {
console.log(myxhr.response);
// 得到的是json字符串,浏览器控制台显示为黑色,需要JSON.parse转换成对象的数据结构
const prov = JSON.parse(myxhr.response).list
document.querySelector('.my-p').innerHTML = prov.join('<br>')
})
myxhr.send()
1.5.2 XHR带参post
相比基础的xhr请求,参数post需要多设置几处,setRequestHeader
,send( JSON.stringify后的json字符串)
如代码所示:
myxhr.setRequestHeader('Content-type','application/json')
const data = {
'username':'heima20230831',
'password':'123456'
}
const mydata = JSON.stringify(data)
myxhr.send(mydata)
1.6 Promise方法-请求状态管理
Promise后边的vue会涉及到
创建对象,携带参数resolve,reject
promise对象的3种状态(promiseState):pendding,resolve(fulfilled),reject(rejected),对象new创建时候立即执行
,然后进如pedding,等待执行的状态结果,再进行then和catch回调函数的逻辑运行
XHR和Promise结合的方法实现了404错误页面的展示,部分代码如下:
if (myxhr.status>=200 && myxhr.status<300) {
resolve(JSON.parse( myxhr.response))
} else{
reject(new Error(myxhr.response))
}
})
myxhr.send()
})
// 3. p对象针对xhr请求结果进行逻辑处理
p.then(result=>{
document.querySelector('.pname').innerHTML=result.list.join('<br>')
}).catch(error=>{
console.dir(error);
document.querySelector('.pname').innerHTML=error.message
})
1.6.1 案例05 自己封装myAxios方法
主要是XHR对象的4步走
:new,open,监听loadend,send;Promise的resolve,reject判断借由then和catch方法控制响应状态
;
处理参数/响应
的JSON.parse与stringify转换,URLSearchParams对象及toString方法等;
这些使用流程逻辑理清,即可简单的实现自己的myAxios方法
1.6.2 案例06 天气预报
涉及的知识点:
1、list的map,join遍历
2、事件绑定动态生成元素时,监听父级,利用(自定义)属性判断点击对象区域
3、搜索栏切换地址,是目前前后端区分的最大感受:前端js只是呈现逻辑的实现,后端处理的数据返回逻辑
1.6.3 promise链式调用
在axios中return
一个axios对象,返回的axios对象再链式调用
then方法处理成功后的逻辑
1.6.4 async函数和await
强制等待,更符合代码阅读习惯
// 1. 定义async修饰函数
async function getData() {
// 2. await等待axios请求的Promise对象成功的结果
const pObj = await axios({url:'http://hmajax.itheima.net/api/province'})
配合try…catch捕获异常,error一般配合console.dir(非log)打印console.dir(error)
1.7 事件循环
可以认为是假的多线程,es6后promise对象让js引擎也可以发起“异步”任务
微任务:js引擎执行的异步任务
promise对象的then和catch方法
宏任务:浏览器环境执行的异步任务
script里的js脚本,定时器setTimeout、setInterval,ajax请求,用户交互事件等。
执行时,微任务队列里的逻辑代码 优先于宏任务队列
1.7.1 案例07 一二级商品展示
案例精髓在于promise.all方法和map的多层嵌套返回待渲染的字符串
1.7.2 案例08 学习反馈 省市区三级联动
async函数和await就近原则,放在箭头函数和对应的axios请求前就可以。
这里的嵌套map方法,如果单独出去再把结果的str拼接回来会更容易读懂
return `<div class="item">
<h3>${dataObj.name}</h3>
<ul>
${dataObj.children.map(item2 => {
return `<li>
<a href="javascript:;">
<img src=${item2.picture}>
<p>${item2.name}</p>
</a>
</li>`
}).join('')
}
</ul>
</div>`
1.8 案例09 后台管理
0、项目目录
1、登录token验证
2、axios统一的请求响应拦截器
// 请求拦截器
axios.interceptors.request.use(config => {
// Do something before request is sent
const token = localStorage.getItem('token')
token && (config.headers.Authorization = `Bearer ${token}`)
return config;}
3、wangeditor富文本编辑器的使用
4、querySelectorAll查询出来的伪数组的foreach
遍历,check单选框的change监听
事件
// 筛选状态标记数字->change事件->绑定到查询参数对象上
document.querySelectorAll('.form-check-input').forEach(radio => {
radio.addEventListener('change', e => {
// console.log(e.target.value);
queryObj.status = e.target.value
})
})
5、编辑回显
- location和URLSearchParams方法获取查询参数字符串
- 注意对象的forEach遍历参数位置对应的是value和key
- Object.keys来遍历keys,判断筛选,赋值:
Object.keys(dataObj).forEach(key => {...}
,这里的结果已经是列表了,所以后边是对keys列表的遍历 - 非id,class的属性选择器用
[]
:
document.querySelector(`[name=${key}]`).value = dataObj[key]
回显有点绕,展示完整代码:
; (function () {
// location和URLSearchParams方法获取查询参数字符串
const paramsStr = location.search
const params = new URLSearchParams(paramsStr)
// 注意对象的forEach遍历参数位置对应的是value和key
params.forEach(async (value, key) => {
if (key === 'id') {
document.querySelector('.title span').innerHTML = '修改文章'
document.querySelector('.send').innerHTML = '修改'
// 回显
const res = await axios({
url: `/v1_0/mp/articles/${value}`
})
console.log(res);
// 根据id返回的文章对象,构建需要返回显示的对象内容
const dataObj = {
channel_id: res.data.channel_id,
title: res.data.title,
rounded: res.data.cover.images[0],
content: res.data.content,
id: res.data.id
}
// Object.keys来遍历keys,判断筛选,赋值
Object.keys(dataObj).forEach(key => {
if (key === 'rounded') {
// 判断封面是否有
if (dataObj[key]) {
// 类似发布时候的属性设置
document.querySelector('.rounded').src = dataObj[key]
document.querySelector('.rounded').classList.add('show')
document.querySelector('.place').classList.add('hide')
} else if (key === 'content') {
editor.setHtml(dataObj[key])
} else {
// 非id,class的属性选择器用[]
document.querySelector(`[name=${key}]`).value = dataObj[key]
}
}
})
}
})
})()
6、同一个按钮,两种逻辑发布和修改,用条件判断来实现排他逻辑:
if (e.target.innerHTML !== '修改') return
2 node&webpack
node和浏览器v8的区别:
浏览器:document,window,XMLHttpRequest
node:fs,path,http
公有:ECMAScript语法:String,Number,setTimeout,console,Promise这些
2.1 fs文件模块
Node.js 代码中,相对路径是根据终端所在路径来查找的.
__dirname 内置变量(获取当前模块目录-绝对路径),path.join() 会使用特定于平台的分隔符使绝对路径和相对路径相结合。
const path = require('path')
// console.log(__dirname);
fs.readFile(path.join(__dirname,'../test.txt'),(err,data)=>{.....}
fs.writeFile(path.join(__dirname,'disk/index.html'),resStr,err=>{....}
需要说明的是,这个命令是__dirname
是要写在js文件中,运行时才会执行。直接在终端的node交互式运行环境REPL里,__dirname is not defined.是不行的.
__dirname
相关链接:我也是傻傻的在终端执行__dirname
,结果报错,查了好久的报错帖子,嘿嘿,蠢的要死哟。链接里重点理解就ok:
他抱怨在node的交互式运行环境REPL里,__dirname is not defined.
原因其实很简单,其他网友也提到了:__dirname意思是当前脚本文件所在的目录,在REPL下,连脚本文件都不存在,自然也不存在__dirname了。
2.2 配置web服务
// 1. 引入http,创建服务应用
const http = require('http')
const server = http.createServer()
// 2.监听request请求,设置响应头和响应体
server.on('request', (req, res) => {
// 响应头
res.setHeader('Content-Type', 'text/plain;charset=utf-8')
// 响应体
res.end('hello node.js')
})
// 3.配置端口,启动服务
server.listen(3001, () => console.log('node启动web服务'))
2.3 node模块化标准
2.3.1 CommonJS 标准
导出:module.exports = {}
导入:require(‘模块名或路径’)
2.3.2 ECMAScript 标准 - 默认导出和导入
导出:export default {}
导入:import 变量名 from ‘模块名或路径’
注意:Node.js 默认支持 CommonJS 标准语法
如需使用 ECMAScript 标准语法,在运行模块所在文件夹新建 package.json 文件,并设置 { “type” : “module” }
2.3.2 ECMAScript 标准 - 命名导出和导入
命名标准使用:
导出:export 修饰定义语句
导入:import { 同名变量 } from '模块名或路径‘
如需使用 ECMAScript 标准语法,在运行模块所在文件夹新建 package.json 文件,并设置 { “type” : “module” }
2.4 npm包管理器
初始化项目清单文件 package.json 命令
npm init -y
下载软件包的命令
npm i 软件包名字
删除
npm -uni 包name
初始化根据package.json文件里的dependencies包名,用npm i
下载对应的包
2.4.1 全局软件包 nodemon
软件包区别:
本地软件包:当前项目内使用,封装属性和方法,存在于 node_modules
全局软件包:本机所有项目使用,封装命令和工具,存在于系统设置的位置
nodemon 作用:替代 node 命令,检测代码更改,自动重启程序
使用:
安装:npm i nodemon -g(-g 代表安装到全局环境中)
2.5 webpack 前端工程化
npm i webpack webpack-cli --save-dev
,package.json文件里需要配置:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build":"webpack"
},
npm run 名字(build)运行webpack打包程序
2.5.1 入口与出口
外层目录下的webpack.config.js文件设置
module.exports = {
// 入口
entry: path.resolve(__dirname,'./src/login/index.js'),
// 出口
output: {
path: path.resolve(__dirname, 'dist'),
filename: './login/index.js',
clean:true
},
};
2.5.2 html自动打包插件
HtmlWebpackPlugin插件
npm i html-webpack-plugin --save-dev
打包html的引用配置:
plugins:[
new HtmlWebpackPlugin({ // Also generate a test.html
// 绝对路径
filename: path.resolve(__dirname,'dist/login/index.html'),
template: path.resolve(__dirname,'public/login.html')
})
]
2.5.3 css加载器
1、引入css到对应的js文件中,
2、配置,这里的配置遵从output的规则:
module: {
rules: [
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
],
},
2.5.3.1 css抽离打包
交互多为js请求,为了单独抽离css,也可多线程分别下载
MiniCssExtractPlugin,配置不写了,详见官方文档
2.5.3.2 css抽离压缩打包
css-minimizer-webpack-plugin
2.5.3.3 less
npm install --save-dev less-loader
开发文档
小做更改,因为前面用到了mini的css,MiniCssExtractPlugin.loader进行替换style-loader:
{
test: /\.less$/i,
use: [
// compiles Less to CSS
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader',
],
}
2.5.3.4 资源打包
内置模块,部分配置展示,详见开发文档
{
test: /\.(png|jpg|jpeg|gif)$/i,
type: 'asset',
generator: {
filename: 'static/[hash][ext][query]'
}
},
2.5.4 开发环境
npm install --save-dev webpack-dev-server
package.json文件里自定义script属性的dev值
module.exports 里设置
// 开发模式,默认找public文件夹的资源
mode:‘development’,
2.5.5 两种开发模式
在 package.json 命令行设置 mode 参数
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "cross-env NODE_ENV=production webpack --mode=production",
"dev": "cross-env NODE_ENV=development webpack serve --open --mode=development"
},
注意:命令行设置的优先级高于配置文件中的,推荐用命令行设置
下载 cross-env 软件包到当前项目
配置自定义命令,传入参数名和值(会绑定到 process.env 对象下)
在 webpack.config.js 区分不同环境使用不同配置
use: [process.env.NODE_ENV = 'development' ? 'style-loader' : MiniCssExtractPlugin.loader, "css-loader"],
2.5.6 前端参数注入
webpack 中配置 DefinePlugin 插件
2.5.7 source-map开发环境调错
问题:error 和 warning 代码的位置和源代码对不上,不方便我们调试!
- 解决:启动 webpack 的 source-map 资源地图功能
- 在 webpack.config.js 配置 devtool 选项和值开启功能(注意:只在开发环境下使用)
2.5.8 cdn
在 html 中引入第三方库的 CDN 地址并用模板语法判断
<% if(htmlWebpackPlugin.options.useCdn){ %>
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.2.3/css/bootstrap.min.css">
<% } %>
配置 webpack.config.js 中 externals 外部扩展选项(防止某些 import 的包被打包)
// 生产环境下使用相关配置
if (process.env.NODE_ENV === 'production') {
// 外部扩展(让 webpack 防止 import 的包被打包进来)
config.externals = {
// key:import from 语句后面的字符串
// value:留在原地的全局变量(最好和 cdn 在全局暴露的变量一致)
'bootstrap/dist/css/bootstrap.min.css': 'bootstrap',
'axios': 'axios',
'form-serialize': 'serialize',
'@wangeditor/editor': 'wangEditor'
}
}
new HtmlWebpackPlugin({ // Also generate a test.html
// 绝对路径
useCdn: process.env.NODE_ENV === 'production', // 生产模式下使用 cdn 引入的地址
2.5.9 多页面打包发布
目标16 多页面打包
准备源码(html,css,js)放入相应位置,并改用模块化语法导出
下载 form-serialize 包并导入到核心代码中使用(略过)
配置 webpack.config.js 多入口和多页面的设置
重新打包观察效果
2.5.10 分割公共部分打包
// 代码分割公共部分打包
splitChunks: {
chunks: 'all', // 所有模块动态非动态移入的都分割分析
cacheGroups: { // 分隔组
commons: { // 抽取公共模块
minSize: 0, // 抽取的chunk最小大小字节
minChunks: 2, // 最小引用数
reuseExistingChunk: true, // 当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用
name(module, chunks, cacheGroupKey) { // 分离出模块文件名
const allChunksNames = chunks.map((item) => item.name).join('~') // 模块名1~模块名2
return `./js/${allChunksNames}` // 输出到 dist 目录下位置
}
}
}
}
总结:webpack太杂了,一塌糊涂,后边碰到了再补吧
3 git
3.1 初始配置
初始配置:用户名和邮箱,应用在每次提交代码版本时表明自己身份
命令:
git config --global user.name “itheima”
git config --global user.email “itheima@itcast.cn”
3.2 Git 仓库(repository)
:记录文件状态内容的地方,存储着修改的历史记录
创建:
1、把本地当前的文件夹转换成 Git 仓库:命令 git init
2、从其他服务器上克隆 Git 仓库
3.3 3个主要区域
git pull—>(工作区)git add—> git ls -files ,git status -s(查看暂存区,文件均为跟踪状态)—>git commit -m “注释” (版本库)—> git push (远端)
git restore 暂存区恢复原来版本,覆盖工作区
git rm --cached 目标文件: 取消暂存,不更改工作区
git log --onelline
git reflog --oneline 查看提交历史的版本号,包括hard回退过的版本号
3.4 回退
git reset --soft 退回版本,工作区和暂存区的文件尽量保留,未被跟踪的状态
git reset --hard 退回版本,工作区和暂存区的文件消失
git reset --mixed 退回版本,工作区的文件尽量保留,未被跟踪的状态,暂存区相应记录消失
3.5 分支
git branch 创建分支名字
git checkout 切换分支名字
git branch -d 要删除的分支
- 合并分支
选定现有分支,git merge 要合并进来的分支 ,遇到冲突先解决再提交
3.6 远程仓库
1、添加 :git remote add 远程仓库别名 .git地址
2、推送/拉取:git push/pull -u 远程仓库别名 本地和远程分支名
3、查看远端链接:git remote -v
4、删除远程仓库 : git remote remove 远程仓库别名
5、本地从0开始:git clone 远程仓库地址
3.6.1 git新手容易碰到的问题
本地init代码,网站创办远程仓库(添加readme等基本文件),本地添加远端后,git push不成提示先git pull,结果还是不行,因为两部分的.init不能识别彼此,认为两者是完全不同的项目,不能合并导致的冲突问题。
此时在本地运行如下命令:
// git pull --rebase 远程仓库别名 分支名
git pull --rebase ori master
rebase强制合并并把两部分代码文件合并为新的commit版本