Axios
axios 中,默认把请求头和响应头设置为
application/json;charset=UTF-8
所以这个时候在 node 中使用 bodyParser 的 req.body 获取的时候会得不到请求的数据。
两种解决方式:
前端解决方法: 使用 URLSearchParams 对象
注意:IE 浏览器不支持
getPage() {
let param = new URLSearchParams()
//把post的数据添加到param对象中
param.append('pageIndex',1)
param.append('pageSize',5)
// param是一个对象,直接把它传给服务器
axios.post('http://127.0.0.1:8888/getNewArticle',param)
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
})
}
URLSearchParams 对象会把请求头设置为相应的格式application/x-www-form-urlencoded;charset=UTF-8
后端解决方法: 使用 bodyParse.json()方法
// 使用中间件
app.use(
bodyParser.urlencoded({
extended: false,
})
);
app.use(bodyParser.json());
既然请求头是 json 格式,那就按 json 格式解析咯
Yapi模拟数据>axios 的 post 请求传递参数
这个情况说的是在Yapi模拟数据的时候
正常来说直接写对象就行
使用querystring
的stringify
将对象转为字符串,或者直接手动传字符串"id=1&name=gauhar"
import axios from "axios";
import qs from "querystring";
let data = {
id: "1",
name: "123456",
};
axios
.post("http://yapi.demo.qunar.com/mock/65699/path", qs.stringify(data))
.then((res) => {
console.log(res.data);
})
.catch((err) => {
console.log(err);
});
axios 的 delete 请求传参
如果是 body 传参,则需要使用可选的 config,设置 data 对象传参。
axios.delete(URL, {
data: { foo: "bar" },
});
// 注意并不是像put,post,patch那样直接用data属性
axios({
method: "delete",
data: {
foo: "bar",
},
}); // 错误
npm 清空缓存
npm cache clean --force
webpack 使用 webpack-dev-server
这个必须得全局安装,否则执行命令会出错
下载:
npm i webpack-dev-server -g
// 建议使用这个配置,新版本建议这样配置,默认会生成main.js
devServer: {
// 设置对外公开路径,后期这个目录中的文件可以被外界访问
publicPath: "/dist";
}
运行:
webpack-dev-server --open
icomoon 字体图标
两个重要文件:demo.css ; IcoMoon-Free.ttf
注意点:css 文件中引入 ttf 的路径
html 中使用:
<link rel="stylesheet" href="./demo.css" />
必须加icon类名
<p class="icon icon-image">12</p>
<p class="icon icon-paint-format">12</p>
<!-- glyph的字体大小为32 -->
<div class="glyph">
<p class=" icon icon-music">12</p>
</div>
Element-ui
在使用自定义验证函数的时候,注意调用 callback 函数。
data(){
// 验证非空公共函数
let notnull = (rule, value, callback) => {
if (value.trim().length <= 0) {
callback(new Error("不能为空哦"));
} else {
// !!!!!!!!!!!!!!!!!!
//--------------------------------------
// 一定要调用callback回调函数,不然进来这个notnull函数之后程序不会继续往下执行
callback();
}
};
// 手机号,姓名,验证码不能为空
let validateUsername = notnull; // 调用上面的notnull函数
return{
rules: {
username: [
{ required: true, message: "请输入用户名或手机", trigger: "blur" },
// 验证自定义验证函数
{ validator: validateUsername, trigger: "blur" }
],
}
}
}
两个字符串在进行比较大小的时候,会隐式转换为 Unicode 编码,再进行比较。此时默认调用字符串的 charCodeAt()方法转换
截取数组的时候,可以通过设置数组的 length 长度,强行截取
let arr = [1, 2, 3, 4, 5, 6];
arr.length = 3;
console.log(arr); // [1,2,3]
在使用vue
的props
传值的时候注意,这个传值的过程是需要时间的,如果在内容渲染上面用到,在props
传值这个过程中,他是undefind
这里的data.scores.environment就是父组件props过来的数据,解决方法就是三元表达式判断,如果是undefined就返回0
<el-progress
type="circle"
:percentage="data.scores.environment ? data.scores.environment *10 : 0"
>
</el-progress>
filter
filter 的 callback 函数需要返回布尔值 true 或 false. 如果为 true 则表示通过啦!如果为 false 则失败。
空字符串''
是false
空对象{}
和空数组[]
是true
CSS
calc、vh、vw、vmin、vmax
css 计算属性
vw
相对于视窗(可视化区域)的宽度:视窗宽度是100vw
vh
相对于视窗的高度:视窗高度是100vh
vmin
视窗(可视化区域)的宽度和视窗的高度,两个值之间最小的一个。如:width:500,height: 1000,则 100vmin = 500
vmax
视窗(可视化区域)的宽度和视窗的高度,两个值之间最大的一个。
注意:运算符的两边要加空格
width:calc(50% - 10px)
css 行内块元素之间的间距
1.将所有的行内块元素直接设置浮动,个人认为最直接的方法,当然是在适当的场景中,因为过度的浮动会产生需要清除浮动的
必要
2.在产生边距的行内块的父元素设置属性:font-size:0px;
3.在父元素上设置,word-spacing(词边距)的值设为合适的负值即可
4.在html中将行内块元素在同一行显示,不要进行美观缩进或者换行
5.开启flex布局
less
原样输出代码,加上
~''
height: ~"calc(100vh-90rpx)";
css 清除浮动
.clearfix::after,
.clearfix::before {
content: "";
display: table;
}
.clearfix::after {
clear: both;
}
css3 选择器连接符~
相当于选择兄弟元素
这种波浪线~ 分割两个 Css 选择器,第二部分选择器仅匹配那些不是第一个选择器 且不是第一个选择器的后代的元素(不是第一个选择器 且 不是他的后代元素)
这里表示输入框验证正确的时候,他的兄弟元素button的伪类的内容为验证通过😄
input:valid
~ button::ayanfter {
content: "验证通过😄";
}
css 验证输入框
pattern
接收一个正则
required
不能为空,如果为空,input
是invalid
的状态
valid
验证通过
invalid
验证不通过
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<style>
.box {
width: 400px;
height: 400px;
margin: 0 auto;
}
input:valid {
color: aquamarine;
}
input:valid ~ button::after {
content: "验证通过😄";
}
input:invalid {
color: red;
}
input:invalid ~ button::after {
content: "验证失败😞";
}
</style>
</head>
<body>
<div class="box">
<input type="text" required pattern="\d{0,5}" /> 输入0到5个数字才是正确的
<button></button>
</div>
</body>
</html>
cookie、session、localStorage
区别
- cookie 数据始终在同源的 http 请求中携带(即使不需要),数据不能超过 4k
- sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie 只在设置的 cookie 过期时间之前一直有效,即使窗口或浏览器关闭。
- 作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localStorage 在所有同源窗口中都是共享的;cookie 也是在所有同源窗口中都是共享的。
- session 存储在服务端
网页标题左侧 icon
href
填写 icon 文件路径
<link rel="shortcut icon" href="图标地址" type="image/x-icon" />
给行内元素的父元素设置为伸缩盒子,行内元素就可以设置宽高了
数组的 every 方法
every 需要所有的循环项都为 true 时才返回 true,否则返回 false。相当于全选状态
数组的 some 方法
some 只要有一个为 true 那么就会返回 true。
对象转换为数组
Object.values(对象);
focus 和 focusin 的区别
blur 和 focusout 同理
当元素即将接收 focus
事件时,focusin
事件被触发。 这个事件和 focus 事件的主要区别在于后者不会冒泡。
js 计算当前时间点所在的周一和周日的时间戳
精髓在于利用
相差的天数
*一天的时间戳计算
let date = new Date();
let today = date.getTime(); // 获取今天的时间戳
let todayWeek = date.getDay(); //获取今天是星期几
let oneDayTime = 24 * 60 * 60 * 1000; //一天的时间戳
let mon = today - (todayWeek - 1) * oneDayTime; // 今天的时间戳 - 相差天数的时间戳
let sun = today + (7 - todayWeek) * oneDayTime; // 今天的时间戳 + 相差天数的时间戳
// 获取年月日再转时间戳
let monDate = new Date(mon);
let monDateDay = monDate.getDate();
let monDateMonth = monDate.getMonth() + 1;
let monDateYear = monDate.getFullYear();
let start = monDateYear + "/" + monDateMonth + "/" + monDateDay;
console.log(Date.parse(start)); //周一的时间戳
let sunDate = new Date(sun);
let sunDateDay = sunDate.getDate();
let sunDateMonth = sunDate.getMonth() + 1;
let sunDateYear = sunDate.getFullYear();
let end = sunDateYear + "/" + sunDateMonth + "/" + sunDateDay;
console.log(Date.parse(end)); //周日的时间戳
最简单的深拷贝
不能拷贝函数
JSON.parse(JSON.stringify(变量));
Json.stringify()不能把函数转换 !!
let fun = function () {
console.log(111);
};
console.log(JSON.stringify(fun)); //undefined
node 的辅助工具
- nvm 可以切换 node 版本
- nrm 切换镜像源
nrm ls
nrm use yarn
右键 git Bash here 命令行
复制快捷键:ctrl + insert
粘贴快捷键:shift + insert
js 执行顺序
macrotask
宏任务队列
microtask
微任务队列
- macrotask:主代码块、setTimeout、setInterval 等(可以看到,事件队列中的每一个事件都是一个 macrotask,现在称之为宏任务队列)
- microtask:Promise、process.nextTick 等
- 在某一个宏任务队列执行完后,在重新渲染与开始下一个宏任务之前,就会将在它执行期间产生的所有
微任务
都执行完毕(在渲染前)。
promise 的 resolve 和 reject 是才是异步的回调。
创建了一个 promise 实例对象的时候,钻进去回调函数中,执行输出2
,for 循环,调用 resolve 函数(异步,微任务),执行输出3
,代码往下面走,执行输出5
,在渲染宏任务之前,完成微任务输出4
,最后输出1
setTimeout(() => {
console.log(1);
}, 0);
new Promise((resolve) => {
console.log(2);
for (let i = 0; i < 10000; i++) {
i == 9999 && resolve();
}
console.log(3);
}).then(() => {
console.log(4);
});
console.log(5);
// 2 3 5 4 1
跨域
cors
服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。该属性表示哪些域名可以访问资源,如果设置通配符*
则表示所有网站都可以访问资源。
请求头设置Content-Type 的值仅限于下列三者之一:
text/plain
multipart/form-data
application/x-www-form-urlencoded
jsonp
浏览器通过 src 请求接口,url 携带函数名,服务器通过传递的函数名,返回一个
json
格式的字符串数据给浏览器
- 声明一个回调函数,其函数名(如 show)当做参数值,要传递给跨域请求数据的服务器,函数形参为要获取目标数据(服务器返回的 data)。
- 创建一个
<script>
标签,把那个跨域的 API 数据接口地址,赋值给 script 的 src,还要在这个地址中向服务器传递该函数名(可以通过问号传参:?callback=show)。 - 服务器接收到请求后,需要进行特殊的处理:把传递进来的函数名和它需要给你的数据拼接成一个字符串,例如:传递进去的函数名是 show,它准备好的数据是
show('我不爱你')
。 - 最后服务器把准备的数据通过 HTTP 协议返回给客户端,客户端再调用执行之前声明的回调函数(show),对返回的数据进行操作。
代理服务器。。
js 定义变量时使用 var 关键字与不使用的区别
在全局作用域下,两者都是定义为全局变量。for 循环的使用 var 定义的变量也是全局的,在局部作用域下(function,class...),
如果不使用关键字定义,则变量时全局变量。使用关键字定义,就是局部变量。
特别注意的是:函数身上有一个 name 属性,是函数名
function Foo() {
// 由于这个函数里面没有用关键字定义变量,所以当Foo函数被调用的时候,里面的变量变成了全局变量
// 这个函数是变量
getName = function () {
this.say = "hello";
console.log(1);
};
name = "123";
a = "dd";
return this; // 谁调用Foo函数,this就指向谁
}
// 函数也是对象,这里是给Foo函数对象定义了getName属性
Foo.getName = function () {
console.log(2);
};
function bar() {}
bar.rrr = "123"; // 函数也是对象,这里是给bar函数定义了getName属性
// 这里是给Foo函数对象的原型身上绑定了一个getName属性,它是一个函数
Foo.prototype.getName = function () {
console.log(3);
};
/**
下面这两个函数都是全局作用域下的,都会变量提升
区别在于,function关键字定义的,提升的优先级较高,而var在后
所以var定义的函数会覆盖function定义的函数
*/
var getName = function () {
console.log(4);
};
function getName() {
console.log(5);
}
console.dir(Foo); //可以查看Foo函数对象,特别注意的是:函数身上有一个name属性,是函数名
console.log(window.a); //undefined 因为这个时候Foo函数还没有被调用
Foo.getName();
2; // 调用了Foo函数对象的getName方法
getName();
4; // 全局作用域下的函数,var最后覆盖
Foo().getName();
1; // 首先这里调用Foo函数之前,代码已经跑完,
// 所以Foo()执行之后,里面的getName方法覆盖了全局的var定义的getName方法
getName();
1; // 上面的一句代码改变了全局作用域下的变量
new Foo.getName();
2; //调用了Foo函数对象的getName方法,执行了方法,然后实例化了对象。所以这里是Foo.getName对象
new Foo().getName();
3; // new关键字创建了一个实例对象,然后调用了原型身上的getName方法
new new Foo().getName();
3; //new关键字创建了一个实例对象,然后调用了console.log(tt.say);
// 然后在通过new关键字,实例化了Foo原型身上的getName方法
// 所以这里是Foo.getName对象
window.getName();
1; // 和上面的getName()一样; 1 // 上面的一句代码改变了全局作用域下的变量
console.log(Foo.name); // Foo 函数身上有一个name属性,是函数名
console.dir(bar); // 查看bar函数对象
console.log(window.name); // 上面的代码调用了Foo函数,里面的变量变成了全局变量
console.log(window.a);
audio 标签
load 方法,重新加载 audio 标签
因为用户体验的问题,部分环境(浏览器,苹果)必须要用户操作过,才能播放音频。js 动态赋值 src 属性,调用 play 方法也是不行的。
所以最好的解决方法是,首先在 html 中就写好 src 地址,然后用户点击某个地方时,调用 play 方法
js dom 变量
在标签名,id 名相同时,在 js 中直接通过相同的变量名获取 dom 节点,而无需声明
<canvas id="canvas"></canvas>
console.log(canvas); // ID为canvas的canvas dom 节点
vue
v-if
不要和v-for
一起使用,v-for
的优先级较高,应该分层写
<div v-if="flag">
<div v-for="(item,index) in list" :key="index">
{{item}}
</div>
</div>
版本号错误
我在使用全局@vue/cli 脚手架创建项目的时候,出现了以下错误,一开始也是很懵,但静下心来看报错还是看出了问题。
解决方法:全局安装最新版的vue
: yarn global add vue
更新到2.6.11
版本
重写打印
vue 的打印输出很不友好,默认不展开,为... 我们要一个一个点开
在main.js
加入以下代码,使用时:this.$print('打印的东西')
// 重写打印方法
Vue.prototype.$print = (obj, type) => {
type = type || "log";
const log = JSON.parse(JSON.stringify(obj));
console[type](log);
};