flex:1
实际代表的是三个属性的简写:
flex-grow是用来增大盒子的,比如:当父盒子的宽度大于子盒子的宽度,父盒子的剩余空间可以利用flex-grow来设置子盒子增大的占比
<style>
* {
margin: 0;
padding: 0;
}
.box {
display: flex;
width: 800px;
height: 150px;
border: 2px solid purple;
}
.box p {
width: 200px;
height: 150px;
text-align: center;
line-height: 150px;
font-size: 30px;
color: #fff;
background-color: orange;
}
/* 将剩余的宽度全部分配给第一个 p 标签 */
.box p:nth-child(1) {
flex-grow: 1;
}
style>
<body>
<div class="box">
<p>1p>
<p>2p>
<p>3p>
div>
body>
flex-shrink
是用来设置子盒子超过父盒子的宽度后,超出部分进行缩小的取值比例
<style>
* {
margin: 0;
padding: 0;
}
.box {
display: flex;
width: 800px;
height: 150px;
border: 2px solid purple;
}
.box p {
width: 300px;
height: 150px;
text-align: center;
line-height: 150px;
font-size: 30px;
color: #fff;
background-color: orange;
}
/* 超出部分将按照比例分配给各个弹性盒子 */
.box p:nth-child(1) {
flex-shrink: 1;
}
.box p:nth-child(2) {
flex-shrink: 2;
}
.box p:nth-child(3) {
flex-shrink: 1;
}
style>
<body>
<div class="box">
<p>1p>
<p>2p>
<p>3p>
div>
body>
flex-basis是用来设置盒子的基准宽度,并且basis和width同时存在basis会把width干掉
<style>
* {
margin: 0;
padding: 0;
}
.box {
display: flex;
width: 800px;
height: 150px;
border: 2px solid purple;
}
.box p {
width: 100px;
/* 覆盖掉 width 属性 */
flex-basis: 200px;
height: 150px;
text-align: center;
line-height: 150px;
font-size: 30px;
color: #fff;
background-color: orange;
}
style>
<body>
<div class="box">
<p>1p>
<p>2p>
<p>3p>
div>
body>
回顾常见布局方案:
BFC概念: BFC
即 Block Formatting Contexts (块级格式化上下文), 是 W3C CSS2.1 规范中的一个概念。属于普通流布局方案
BFC特性: 具有 BFC
特性的元素可以看作是隔离的独立容器,容器里面的元素不会在布局上影响到外面的元素。
简单理解: BFC
是一个封闭的大箱子,箱子内部的元素无论如何变换都不会影响到箱子外边的元素
如何触发BFC:
BFC应用场景:
1、清除盒子垂直方向上外边距合并,同一个 BFC
下垂直方向外边距会发生折叠
<style>
p {
width: 100px;
height: 100px;
background-color: purple;
margin: 100px 0;
}
style>
<body>
<p>p>
<p>p>
body>
解决方案:可以给其中一个盒子再包裹一个盒子父元素,并触发其BFC功能(例如添加overflow:hidden;)这样垂直方向的两个盒子就不在同一个BFC中了,因此也不会发生垂直外边距合并的问题了。
<style>
div {
overflow: hidden;
}
p {
width: 100px;
height: 100px;
background-color: purple;
margin: 100px 0;
}
style>
<body>
<div>
<p>p>
div>
<div>
<p>p>
div>
body>
2、在子元素设置成浮动元素的时候,会产生父元素高度塌陷的问题
解决方案:给父元素设置overflow:hidden;的时候会产生BFC。由于在计算BFC高度时,自然也会检测浮动的子盒子高度。所以当子盒子有高度但是浮动的时候,通过激发父盒子的BFC功能,会产生清除浮动的效果。
<style>
ul {
border: 1px solid purple;
padding: 0;
overflow: hidden;
}
ul li {
float: left;
margin-right: 30px;
list-style: none;
width: 100px;
height: 100px;
background: orange;
}
style>
<body>
<ul>
<li>li>
<li>li>
<li>li>
ul>
body>
方式一:flex布局
<style>
* {
margin: 0;
padding: 0;
}
.box {
display: flex;
justify-content: center;
align-items: center;
width: 800px;
height: 500px;
margin: 100px auto;
border: 2px solid purple;
}
.minibox {
width: 300px;
height: 200px;
background-color: purple;
}
style>
<body>
<div class="box">
<div class="minibox">div>
div>
body>
方式二:flex + margin
原理:传统的display: block
BFC(块格式化上下文)下,margin: auto
在水平方向可以居中元素在垂直方向不行。要使单个元素使用 margin: auto
在垂直方向上能够居中元素,需要让该元素处于 FFC(flex formatting context),或者 GFC(grid formatting context) 上下文中
<style>
* {
margin: 0;
padding: 0;
}
.box {
display: flex;
width: 800px;
height: 500px;
margin: 100px auto;
border: 2px solid purple;
}
.minibox {
margin: auto;
width: 300px;
height: 200px;
background-color: purple;
}
style>
<body>
<div class="box">
<div class="minibox">div>
div>
body>
方式三:定位 + margin
<style>
* {
margin: 0;
padding: 0;
}
.box {
position: relative;
width: 800px;
height: 500px;
margin: 100px auto;
border: 2px solid purple;
}
.minibox {
position: absolute;
left: 50%;
top: 50%;
margin-left: -150px;
margin-top: -100px;
width: 300px;
height: 200px;
background-color: purple;
}
style>
<body>
<div class="box">
<div class="minibox">div>
div>
body>
方式四:定位 + translate
<style>
* {
margin: 0;
padding: 0;
}
.box {
position: relative;
width: 800px;
height: 500px;
margin: 100px auto;
border: 2px solid purple;
}
.minibox {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 300px;
height: 200px;
background-color: purple;
}
style>
<body>
<div class="box">
<div class="minibox">div>
div>
body>
盒子模型组成:
盒子模型分类:
content-box
,也就是标准盒模型,标准盒模型 width 设置了内容的宽,所以盒子实际的大小要加上 padding 和 borderbox-sizing: border-box;
的盒模型为ie盒模型,也称为怪异盒模型,设置了 width 后,实际盒子的宽度就固定为该宽度,包含了 内容+padding+border。ie盒模型主要表现在ie浏览器,当然其他浏览器也保留了ie盒模型的支持css3中新增的属性有(常用):
box-sizing
px: 长度单位,是相对于显示器的屏幕分辨率而言的
em: 相对单位,基准点为父节点字体的大小
rem: 相对单位,可理解为”root em”,相对根节点html的字体大小来计算
vw: viewpoint width,视窗宽度,1vw等于浏览器窗口宽度的1%
vh: viewpoint height,视窗高度,1vh等于浏览器窗口高度的1%
vmin: vw和vh中较小的那个
vmax: vw和vh中较大的那个
方法一: 定位+缩放
<style>
.box {
position: relative;
}
.box::after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 1px;
background-color: red;
transform: scale(1, 0.5);
}
style>
<body>
<div class="box">div>
body>
方式二: 线性渐变 linear-gradient,(会有分辨率问题导致显示不出来)
<style>
.box {
margin-top: 20px;
height: 1px;
background: linear-gradient(#f00 50%, transparent 50%);
}
style>
<body>
<div class="box">div>
body>
rem 是 相对长度单位
。相对于根元素(即html元素)font-size
计算值的倍数的一个css单位
rem的移动适配原理:
在移动端的页面开发中,需要根据不同的手机去适配页面,让页面可以自适应的展示。
也就是说根据屏幕宽度的大小,改变元素和字体的大小,屏幕越宽元素和字体越大。
这个时候我们通常会用到rem作为单位,rem用作非根元素的时候,是相对于根元素设定的字体大小,用于根元素的时候,相对于初始字体的大小
移动端app / 移动端网页: 都是需要用到网络的,它们利用设备商的浏览器(比如iPhone的safari)来运行,不需要在设备上下载后安装。
原生app: 是专门针对某一类移动设备而生的,它们都是被直接安装到设备里,而用户一般也是通过网络商店或者卖场来获取,开发起来不支持跨平台,每种平台得单独开发相同应用。
混合app / 内嵌h5: 就是介于 移动app
和 原生app
之间的折中方案。在许多情况下,它能集两者之长,再通过中间件包装成一个可发布到应用商店的应用程序。
方式一:zoom
<style>
p {
font-size: 12px;
zoom: 0.8;
}
style>
方式二:transform: scale()
<style>
p {
font-size: 12px;
transform-origin: left top;
transform: scale(0.8);
}
style>
两者区别:
rem
viewport(vw/vh)
媒体查询
数据类型分类:
基本数据类型:undefined - - (未定义)、null- - (空的)、number - - (数字)、boolean- - (布尔值)、string- - (字符串)、Symbol - - (符号)、BigInt- -(大数字);
引用数据类型(对象类型):Object- - (对象),比如:array - - (数组)、function - - (函数)、date - - (时间)等;
检测数据类型:
typeof 检测一些基本的数据类型
let num = 1;
console.log(typeof num); // number
instanceof 一般用来检测引用数据类型。注:undefined和null无法检测。
let arr = [];
console.log(arr instanceof Array); // true
constructor 用于检测引用数据类型。注:undefined和null没有constructor属性,无法判断。
let arr = [];
console.log(arr.constructor === Array); // true
Object.prototype.toString.call() 适用于所有类型的判断检测
let arr = [];
console.log(Object.prototype.toString.call(arr)); // [object Array]
问题:
0.1 + 0.2 !== 0.3
这个属于JS运算中 精度
的缺失问题。这两个数的二进制都是无限循环的数。JavaScript使用Number类型表示数字(整数和浮点数),它的实现遵循IEEE754标准,在 IEEE754 标准中常见的浮点数数值表示有:单精准度(32位)和双精准度(64位),而JS采用的是双精度版本,也就是通过64位来表示一个数字;在二进制科学表示法中,双精度浮点数的小数部分最多只能保留52位,再加上前面的1,其实就是保留53位有效数字,剩余的舍去,遵从“0舍1入”的原则。根据这个原则,0.1和0.2的二进制数相加,再转化为十进制数就是:0.30000000000000004。
解决方法:
作用域: 作用域就是变量的可用性的代码范围,就叫做这个变量的作用域。简单理解,就是在这个范围内,变量是可以使用的,超过这个范围,变量就无法使用,这个范围就是作用域。
作用域链: 当你要访问一个变量时,首先会在当前作用域下查找,如果当前作用域下没有查找到,则返回上一级作用域进行查找,直到找到全局作用域,这个查找过程形成的链条叫做作用域链。
作用域:
变量提升:
变量能在声明之前使用,就是变量提升
var 存在变量提升,let 和 const 不存在变量提升
console.log(num);
var num = 10;
// 转换为
var num
console.log(num);
num = 10;
全局属性:
浏览器的全局对象是window
**重复声明: **
var 声明变量时,可以重复声明变量,后声明的同名变量会覆盖之前声明的遍历。const 和 let 不允许重复声明变量。
var 声明的变量同名只会打印最后一次声明的值
let 和 const 同一个作用域下不能重名
暂时性死区:
初始值设置:
指针指向:
应用场景:
cookie:
localstorage:
优点:
缺点:
无法像 cookie一样设置过期时间
只能存入字符串,无法直接 存入对象
sessionStorage:
注意:localstorage、sessionStorage存储对象或数组时,需要将其更换为JSON字符串,然后再进行存储。
indexDB(了解):
区别:
应用场景:
JavaScript
在设计之初便是单线程,即指程序运行时,只有一个线程存在,同一时间只能做一件事
为什么要这么设计,跟JavaScript
的应用场景有关
JavaScript
初期作为一门浏览器脚本语言,通常用于操作 DOM
,如果是多线程,一个线程进行了删除 DOM
,另一个添加 DOM
,此时浏览器将无法处理
为了解决单线程运行阻塞问题,JavaScript
用到了计算机系统的一种运行机制,这种机制就叫做事件循环(Event Loop)
在JavaScript
中,所有的任务都可以分为:
ajax
网络请求,setTimeout
定时函数等,这些任务会交给 宿主环境 来执行,将执行完成的回调函数交给主线程执行BOM
(Browser Object Model,浏览器对象模型,提供了独立于内容与浏览器窗口进行交互的对象
其作用就是跟浏览器做一些交互效果,比如如何进行页面的后退,前进,刷新,浏览器的窗口发生变化,滚动条的滚动,以及获取客户的一些信息如:浏览器品牌版本,屏幕分辨率
常见BOM对象:
Bom
的核心对象是window
,它表示浏览器的一个实例URL
的历史记录,可以通过参数向前,向后,或者向指定URL
跳转预解析:提前解析代码
**变量提升:**即将变量声明提升到它所在作用域的最开始的部分,会在代码执行之前将变量的声明提升
**函数提升:**函数声明式会在代码执行之前将函数的声明提升,不会提升调用。函数表达式可以理解为一个普通变量的提升,在js代码执行之前会把fun提升带最前面,在函数赋值之前,fun是undefined,如果调用fun(),将会报错。
Set和Map都是es6新增的 数据结构。
Set:
Map:
Map和Set区别:
作用:
for of 用法:
// 遍历数组
const arr = [1, 2, 3, 4, 5, 6, 7];
for (const item of arr) {
console.log(item);
}
// 遍历对象
const obj = {
uname: "张三",
age: 18,
};
const ks = Object.keys(obj)
for (const item of ks) {
console.log(item);
}
区别:
for:break退出循环,continue 退出本次循环
forEach:用return、break、continue的方式都不能终止forEach循环,return
在forEach里相当于for循环里的continue,能够退出本次循环
,可以使用try...catch
终止foreach循环
例:
try{
var array = ["first","second","third","fourth"];
// 执行到第3次,结束循环
array.forEach(function(item,index) {
if(item === "third"){
throw new Error("EndIterative");
}
console.log(item); // first second
});
}catch(e){
if(e.message != "EndIterative") throw e;
}
// 下面的代码不影响继续执行
console.log("继续执行。。。");
map:终止map循环的方式和forEach相同
for in:break退出循环,continue 退出本次循环
for of:break退出循环,continue 退出本次循环
some:相当于或,只要有一个满足条件,就return true
every:相当于且,只要有一个不满足条件,就return false,只有都满足条件才会返回true
方式一:利用 Set() + Array.from()
const arr = [1, 2, 3, 5, 3, 2, 5];
const res = Array.from(new Set(arr));
console.log(res);
**注意:**以上去方式对NaN和undefined类型去重也是有效的,是因为NaN和undefined都可以被存储在Set中, NaN之间被视为相同的值
方式二:利用两层循环 + 数组的splice方法,此方法对NaN是无法进行去重的,因为进行比较时NaN !== NaN
// 通过两层循环对数组元素进行逐一比较,然后通过splice方法来删除重复的元素。
function removeDuplicate(arr) {
let len = arr.length;
for (let i = 0; i < len; i++) {
for (let j = i + 1; j < len; j++) {
if (arr[i] === arr[j]) {
arr.splice(j, 1);
len--; // 减少循环次数提高性能
j--; // 保证j的值自加后不变
}
}
}
return arr;
}
方式三:利用数组的 indexOf 方法,此方法也无法对NaN去重
// 新建一个空数组,遍历需要去重的数组,将数组元素存入新数组中,存放前判断数组中是否已经含有当前元素,没有则存入。
function removeDuplicate(arr) {
const newArr = [];
arr.forEach((item) => {
if (newArr.indexOf(item) === -1) {
newArr.push(item);
}
});
return newArr; // 返回一个新数组
}
方式四:利用数组的 includes 方法,可以对 NaN 去重
// 原理和 方式三 一至
function removeDuplicate(arr) {
const newArr = [];
arr.forEach((item) => {
if (!newArr.includes(item)) {
newArr.push(item);
}
});
return newArr;
}
// 注意:为什么includes能够检测到数组中包含NaN,其涉及到includes底层的实现。
const testArr = [1, 'a', NaN]
console.log(testArr.includes(NaN)) // true
方式五:利用数组的 filter() + indexOf()
,此方法也无法对NaN去重
function removeDuplicate(arr) {
return arr.filter((item, index) => {
return arr.indexOf(item) === index;
});
}
方式六:利用 Map(),可以对 NaN 去重
function removeDuplicate(arr) {
const map = new Map();
const newArr = [];
arr.forEach((item) => {
if (!map.has(item)) {
// has()用于判断map是否包为item的属性值
map.set(item, true); // 使用set()将item设置到map中,并设置其属性值为true
newArr.push(item);
}
});
return newArr;
}
**注意:**使用Map()也可对NaN去重,原因是Map进行判断时认为NaN是与NaN相等的,剩下所有其它的值是根据 === 运算符的结果判断是否相等。
方式七:利用对象,实现方式和 Map() 差不多
function removeDuplicate(arr) {
const newArr = [];
const obj = {};
arr.forEach((item) => {
if (!obj[item]) {
newArr.push(item);
obj[item] = true;
}
});
return newArr;
}
方式一:将对象转换成字符串,再判断是否等于“{}”
let obj={};
console.log(JSON.stringify(obj)==="{}");
方式二:for in循环
let result = function (obj) {
// 如果是空对象则不会执行循环
for (let key in obj) {
return false; //若不为空,可遍历,返回false
}
return true;
};
console.log(result({}));
方式三:Object.keys()方法,返回对象的属性名组成的一个数组,若长度为0,则为空对象(ES6的写法)
console.log(Object.keys(obj).length==0);
方式四:Object.getOwnPropertyNames() 方法获取对象的属性名,存到数组中,若长度为0,则为空对象
console.log(Object.getOwnPropertyNames(obj).length==0);
闭包概念:有权访问另一个函数作用域中变量的函数,闭包 = 内层函数 + 外层函数的变量
闭包作用: 延长变量作用范围
闭包的特性:
垃圾回收算法说明
所谓垃圾回收,核心思想就是如何判断内存是否已经不再会被使用了,如果是,就视为垃圾,释放掉
下面介绍两种常见的浏览器垃圾回收算法: 引用计数法 和 标记清除法
引用计数
IE采用的引用计数算法, 定义“内存不再使用”的标准很简单,就是看一个对象是否有指向它的引用。
算法:
标记清除法
现代的浏览器已经不再使用引用计数算法了。
现代浏览器通用的大多是基于标记清除算法的某些改进算法,总体思想都是一致的。
核心:
标记清除算法将“不再使用的对象”定义为“无法达到的对象”。
就是从根部(在JS中就是全局对象)出发定时扫描内存中的对象。 凡是能从根部到达的对象,都是还需要使用的。
那些无法由根部出发触及到的对象被标记为不再使用,稍后进行回收。
https://blog.csdn.net/xuanzhuan365/article/details/109481552
箭头函数的特点:
相比普通函数,箭头函数有更加简洁的语法。
箭头函数不绑定this,会捕获其所在上下文的this,作为自己的this。
箭头函数是匿名函数,不能作为构造函数,不可以使用new命令,否则后抛出错误。
箭头函数不绑定arguments,可以使用剩余参数
使用call,apply,bind并不会改变箭头函数中的this指向。
箭头函数没有原型对象prototype这个属性
不能使用yield关键字,不能用作Generator(生成器)函数
箭头函数的优点:
数组方法:
一、 改变原数组的方法 (常用)
二、其他数组方法(常用)
对象方法(常用):
构造函数:有 prototype 属性指向原型对象,可以通过 new 得到实例对象
原型对象:原型对象用来共享属性和方法,原型对象上有 constructor 属性指向构造函数
实例对象:通过 new 构造函数来得到实例对象,实例对象身上有 __proto__
属性指向原型对象
原型链:就是实例对象和原型对象之间的链接,每一个对象都有原型,原型本身又是对象,原型又有原型,以此类推形成一个链式结构称为原型链。
原型链提供了对象属性和方法的查找规则,先查看自身有没有,如果没有会按照原型链向上查找
https://blog.csdn.net/wuliyouMaozhi/article/details/125905733
相同点:
区别点:
call 和 apply 会调用函数,并且改变函数内部this指向
call 和 apply 传递的参数不一样,call 传递参数 aru1, aru2… 形式 apply 必须数组形式[arg]
bind 不会调用函数,可以改变函数内部this指向
主要应用场景:
call 调用函数并且可以传递参数
apply 经常跟数组有关系,比如借助于数学对象实现数组最大值最小值
bind 不调用函数,但是还想改变this指向。比如改变定时器内部的this指向
**浅拷贝: ** 浅拷贝只会拷贝对象的第一层属性,如果这些属性是对象,则不会对这些对象进行拷贝,而是直接复制对象的引用。这意味着,对于浅拷贝后的对象,如果原对象的属性值发生了变化,浅拷贝后的对象的属性值也会跟着发生变化。
深拷贝: 在进行深拷贝时,会拷贝所有的属性,并且如果这些属性是对象,也会对这些对象进行深拷贝,直到最底层的基本数据类型为止。这意味着,对于深拷贝后的对象,即使原对象的属性值发生了变化,深拷贝后的对象的属性值也不会受到影响。
一个函数在它的函数体内调用它自身称为递归调用,这种函数称为递归函数。执行递归函数将反复调用其自身,每调用一次就进入新的一层,当最内层的函数执行完毕后,再一层一层地由里到外退出。
所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间,短时间高频率触发只有最后一次触发成功
**开发使用场景: **搜索框防抖
所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数
开发使用场景:小米轮播图点击效果、鼠标移动、页面尺寸缩放 resize、滚动条滚动就可以加节流
新增了块级作用域(let,const)
提供了定义类的语法糖(class)
新增了一种基本数据类型(Symbol)
新增了变量的解构赋值
函数参数允许设置默认值,引入了rest参数(剩余参数),新增了箭头函数。
数组新增了一些API,如isArray / from / of 方法;数组实例新增了 entries(),keys() 和 values() 等方法。
对象和数组新增了扩展运算符
ES6新增了模块化(import / export)
ES6新增了Set和Map数据结构。
ES6原生提供Proxy构造函数,用来生成Proxy实例
ES6新增了生成器(Generator)和遍历器(Iterator)
foreach和map的区别:
相同点:
都是循环遍历数组中的每一项。
每次执行匿名函数都支持三个参数,参数分别为item(当前每一项),index(索引值),arr(原数组)。
匿名函数中的this都是指向window。
只能遍历数组。
不同点:
map()会分配内存空间存储新数组并返回,forEach()不会返回数据。
forEach()允许callback更改原始数组的元素。map()返回新的数组。
some和every的区别:
相同点:
some和every都有三个参数,item为当前项,index为当前项的索引值,arr为数组本身;
都可循环遍历数组
不同点:
every相当于逻辑关系中的且(&&),只有所有参数满足条件的时候,才会返回true,如果有一个不满足,就会逻辑中断,返回false,
some相当于逻辑关系中的或(||),只要有一个参数满足条件,就会中断逻辑,返回true,遍历结束,没有找到合适的参数,就返回false
通俗说:every就是找假,一假则假;some就是找真,一真则真
熟练使用
步骤:
1xx:这一类型的状态码,代表请求已被接受,需要继续处理。这类响应是临时响应,只包含状态行和某些可选的响应头信息,并以空行结束。
2xx:这一类型的状态码,代表请求已成功被服务器接收、理解、并接受。
3xx:这类状态码代表需要客户端采取进一步的操作才能完成请求。通常,这些状态码用来重定向,后续的请求地址(重定向目标)在本次响应的location域中指明。
4xx:这类的状态码代表了客户端看起来可能发生了错误,妨碍了服务器的处理。
5xx:这类状态码代表了服务器在处理请求的过程中有错误或者异常状态发生,也有可能是服务器意识到以当前的软硬件资源无法完成对请求的处理。
axios是一个基于Promise的方法,可以发送get、post等请求,并且前后端都可以使用。
axios可以用在浏览器和 node.js 中是因为,它会自动判断当前环境是什么,如果是浏览器,就会基于XMLHttpRequests实现axios。如果是node.js环境,就会基于node内置核心模块http实现axios简单来说,axios的基本原理就是
axios还是属于 XMLHttpRequest, 因此需要实现一个ajax。或者基于http 。
还需要一个promise对象来对结果进行处理。
promise:
async/await:
generator:
// 其中 * 用来表示函数为 Generator 函数,yield 用来定义函数内部的状态。
function* fn() {
console.log("one");
yield "1";
console.log("two");
yield "2";
console.log("three");
yield "3";
}
import axios from 'axios'
import store from '@/store'
import router from '@/router'
// baseURL 超时时间配置
const instance = axios.create({
// 设置请求的响应时间,超时直接结束
timeout: 5000,
// 设置请求的基本地址
baseURL: 'http://pcapi-xiaotuxian-front-devtest.itheima.net'
})
// 全局注入token
// 请求拦截器=》发请求前
instance.interceptors.request.use(config => {
// 在请求头统一添加token
const { token } = store.state.user.profile
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
}, e => Promise.reject(e))
// 处理返回数据 token失效跳回到登录页
// 响应拦截器=》成功请求
instance.interceptors.response.use(
(response) => {
// 请求200进入到这里
// 把data数据返回给页面,剥离数据
return response.data
},
(error) => {
// 200以外进入
// 处理401
if (error?.response.status === 401) {
/**
* 1. 获取当前出现401的页面路径(目的:成功登陆之后,回到上次访问的页面)
* 2. 跳回登录页带上401页面的地址
*/
const redirectUrl = router.currentRoute.value.fullPath
router.replace(`/login?redirectUrl=${redirectUrl}`)
}
return Promise.reject(error)
}
)
请求拦截器:
// use(两个参数)
axios.interceptors.request.use(req => {
// 在发送请求前要做的事儿
...
return req
}, err => {
// 在请求错误时要做的事儿
...
// 该返回的数据则是axios.catch(err)中接收的数据
return Promise.reject(err)
})
响应拦截器:
// use(两个参数)
axios.interceptors.reponse.use(res => {
// 请求成功对响应数据做处理
...
// 该返回的数据则是axios.then(res)中接收的数据
return res
}, err => {
// 在请求错误时要做的事儿
...
// 该返回的数据则是axios.catch(err)中接收的数据
return Promise.reject(err)
})
Javascript语言的执行环境是"单线程"(一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推)。
这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死),往往就是因为某一段Javascript代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。这样设计本身是因为操作dom的需要。
为了解决这个问题,Javascript语言将任务的执行模式分成两种:同步和异步。
“同步模式" 就是上一段的模式,后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的;"异步模式"则完全不同,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。
“异步模式" 非常重要。在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操作。在服务器端,"异步模式"甚至是唯一的模式,因为执行环境是单线程的,如果允许同步执行所有http请求,服务器性能会急剧下降,很快就会失去响应。
最常见的就是post与get方法,下面详细介绍一下二者的区别:
1、URL形式
get将表单中数据按照name=value的形式,添加到action 所指向的URL 后面,并且两者使用”?”连接,而各个变量之间使用”&”连接
post请求:post请求会把请求的数据放置在HTTP请求包的包体中,传递到action所指向URL。上面的item=bandsaw就是实际的传输数据。
因此,get请求的数据会暴露在地址栏中,而POST请求则不会。
get请求用来从服务器上获得资源,而post是用来向服务器提交数据;
2、传输数据的大小
在HTTP规范中,没有对URL的长度和传输的数据大小进行限制。但是在实际开发过程中,对于get,特定的浏览器和服务器对URL的长度有限制。因此,在使用get请求时,传输数据会受到URL长度的限制。
对于post,由于不是URL传值,理论上是不会受限制的,上传文件通常要使用post方式;但是实际上各个服务器会规定对POST提交数据大小进行限制,Apache、IIS都有各自的配置。
3、安全性
post的安全性比get的高。这里的安全是指真正的安全,而不同于上面get提到的安全方法中的安全,上面提到的安全仅仅是不修改服务器的数据。比如,在进行登录操作,通过get请求,用户名和密码都会暴露再URL上,因为登录页面有可能被浏览器缓存以及其他人查看浏览器的历史记录的原因,此时的用户名和密码就很容易被他人拿到了。除此之外,get请求提交的数据还可能会造成Cross-site request frogery攻击。
如果这些数据不是敏感数据,那么可以使用get;对于敏感数据还是应用使用post;
即时通信:
WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信,即允许服务器主动发送信息给客户端。因此,在WebSocket中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输,客户端和服务器之间的数据交换变得更加简单。
例:
传统模式:
api/getstate.aspx- 获取状态信息
api/updatestate.aspx - 更新状态信息
api/deletestate.aspx - 删除该状态的数据
RESTful模式:
api/state 只需要这一个接口
GET 方式请求 api/state- 获取该状态的数据
POST 方式请求 api/state- 更新该状态的数据
更多内容:https://worktile.com/kb/ask/22890.html
axios官网:https://www.axios-http.cn/docs/cancellation
https://blog.csdn.net/jiang_ziY/article/details/123818243
https://www.shuzhiduo.com/A/q4zVbNvGzK/
在开发的过程中,会遇到后端文档出来了但接口没出来,或者是联调的时候接口有问题,那么前端的调试就有困难了。这个时候需要进行 mock 数据(自己实现一些测试数据)
官网:http://mockjs.com/
const Mock = require("mockjs");
var Random = Mock.Random;
const res = Mock.mock({
// 属性 list 的值是一个数组,其中含有 1 到 10 个元素
"list|1-10": [
{
// 属性 id 是一个自增数,起始值为 1,每次增 1
"id|+1": 1,
"username": Random.cname(),
"createTime": Random.date()
},
],
});
console.log(res);
get请求:
//1、创建一个 xhr 的对象
let xhr = new XMLHttpRequest()
//2、调用xhr中的open()函数,创建一个Ajax的请求
xhr.open('GET', 'http://www.liulongbin.top:3006/api/getbooks')
//3、调用xhr的send函数,发起请求
xhr.send()
//4、监听 onreadystatechange 事件
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) { //固定写法
//数据获取成功,获取服务器响应的数据
console.log(xhr.responseText)
}
}
Post请求:
//1、创建xhr的对象
let xhr = new XMLHttpRequest()
//2、调用open函数('请求类型','url')
xhr.open('POST', 'http://www.liulongbin.top:3006/api/addbook')
//3、设置 Content-Type属性(固定写法)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
//4、调用send函数
xhr.send('bookname=落日听风&author=我我我&publisher=个人出版社')
//5、监听事件
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText)
}
}
跨域: 出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议,主机和端口号。
解决方案:
命令 | 说明 |
---|---|
git init |
初始化git仓库 |
git clone |
克隆远程仓库项目 |
git config --list |
查看git配置信息 |
git add |
跟踪文件或将文件加入暂存区 |
git commit -m [message] |
提交暂存区到仓库区 |
git branch |
查看所有本地分支 |
git branch [branch-name] |
创建新分支 |
git checkout -b [branch] |
创建并切换分支 |
git merge [branch] |
合并指定分支到当前分支 |
git push |
向远程推送代码 |
git pull |
拉取远程代码 |
git status |
查看文件状态 |
git log |
查看提交日志 |
http://jianshu.io/p/e1086dcd6b42
http://jianshu.io/p/e1086dcd6b42
相同点:
不同点:
比如现在在某个子分支执行git rebase(merge) master操作。
merge:将在子分支的所有提交记录成一次commit,保留在记录中。
rebase:不会保留commit记录,直接将分支中的内容排到master的记录之后。
最明显的特点就是rebase是一条直线,merge是很多条分支合并在一起。
https://blog.csdn.net/qq_48106051/article/details/127065222
云效:云效,创立于2012年,是阿里巴巴旗下一站式研发提效产品。通过项目流程管理和专项提效自动化工具,真正实现24小时持续集成持续交付。
gitlab:GitLab是由GitLabInc.开发,使用MIT许可证的基于网络的Git仓库管理工具,且具有wiki和issue跟踪功能。使用Git作为代码管理工具,并在此基础上搭建起来的web服务。
git fetch:是将远程主机的最新内容拉到本地,用户在检查了以后决定是否合并到工作本机分支中。
git pull: 则是将远程主机的最新内容拉下来后直接合并,即:git pull = git fetch + git merge,这样可能会产生冲突,需要手动解决。
https://zhuanlan.zhihu.com/p/414171010
Javascript 把异步任务又做了进一步的划分,异步任务又分为两类,分别是:宏任务 和 微任务
执行顺序:每一个宏任务执行完之后,都会检查是否存在待执行的微任务,如果有,则执行完所有微任务之后,再继续执行下一个宏任务
分类
宏任务:
微任务:
Promise.all 方法
// 实现 Promise.all() 方法
const myAll = (arr) => {
// 存放结果集,按照顺序存放
const resArr = [];
let i = 0;
// 处理结果
const result = (res, index, resolve) => {
// index 记录传入数组中 promise 对象的位置
resArr[index] = res;
i++;
if (i === arr.length) return resolve(resArr);
};
return new Promise((resolve, reject) => {
if (!Array.isArray(arr)) return reject('参数必须是数组');
arr.forEach((item, index) => {
item.then(
(res) => {
// 拿到的只是结果,要等结果全部出现,才能 resolve
// resArr.push(res);
// if (resArr.length === arr.length) return resolve(resArr);
// console.log(res)
// resArr[index] = res;
// console.log(resArr, index);
// if (resArr.length === arr.length) return resolve(resArr);
result(res, index, resolve);
},
(err) => {
reject(err);
}
);
});
});
};
Promise.race 方法
// 实现 Promise.race() 方法
// Promise.race() 方法会发起并行的 Promise 异步操作,只要任何一个异步操作完成,就会立即执行下一步的 .then 操作(赛跑机制)
const myRace = (arr) => {
return new Promise((resolve, reject) => {
if (!Array.isArray(arr)) return reject('参数必须是数组');
// 遍历arr, 看谁先满足条件, 谁先满足条件, 就先让外层的promise resolve
// promise的状态只能被修改一次, 只要第一个改了, 就成功, 后续再改, 也无效了
arr.forEach((item) => {
item.then(
(res) => {
resolve(res);
},
(err) => {
reject(err);
}
);
});
});
};
语法上:
导出值类型:
值的拷贝
,ES6 模块输出的是值的引用
加载时机:
运行时
加载,ES6 模块是编译时
加载模块化是指解决一个复杂问题时自顶向下逐层把系统划分成若干模块的过程,有多种属性,分别反映其内部特性。
模块化的好处:
WebPack
是一个模块打包工具,你可以使用WebPack
管理你的模块依赖,并编绎输出模块们所需的静态文件。它能够很好地管理、打包Web开发中所用到的HTML、JavaScript、CSS
以及各种静态文件(图片、字体等),让开发过程更加高效。对于不同类型的资源,webpack
有对应的模块加载器。webpack
模块打包器会分析模块间的依赖关系,最后 生成了优化且合并后的静态资源。
Babel: Babel是一个工具链,主要用于将ECMAScript 2015+版本的代码转换为向后兼容的JavaScript代码,使之可以运行在各种环境中
loader: loader可以让webpack能够处理那些非js文件(webpack自身只理解js、json,现webpack5可以处理图片资源了~)
plugin: 插件plugins可以用于执行范围更广的任务。插件的范围包括:从打包优化和压缩、一直到重新定义环境中的变量 【