0%

小技巧

记录一些前端小技巧。

浏览器

大部分使用技巧,基于chrome浏览器。

强制刷新

强制刷新清除本地缓存。

Windows:

  • Ctrl + F5,Chrome

Macos:

  • Command + Shift + R,Chrome

  • Command + Option + R,Safari

开发者工具

F12ctrl + shift + i打开开发者工具

调试

在代码中添加debugger;,可在开发者工具中进行代码调试。

样式

在“元素”面板,通过按钮“创建样式规则”来添加样式,会自动在“源代码”面板中相对所修改页面的路径下创建一个inspector-stylesheet文件保存修改。

在调试完样式后直接拷走其中的内容即可。

移动app

localStorage API,保存

sessionStorage API,保存的数据在app被杀掉后台之后将不存在。不希望自动登录可将登录状态保存在这

使用HTML技术开发移动app时,可添加如下meta标签:

1
2
<!-- 可视宽度为device-width;首次显示缩放级别为1,即按设备尺寸显示无缩放;最大缩放级别为1,即禁止用户放大页面;是否可缩放设置为否 -->
<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">

calc函数:菜鸟教程

1
2
3
4
5
使用 calc() 函数计算 <div> 元素的宽度:

在移动端开发的过程中,常常会遇到布局中有顶部/底部导航栏的情况,在设定内容部分的绝对高度时可使用calc()函数辅助。
例如:已知导航栏高度为50px,可通过这样设定内容部分的高度:
height: calc(100% - 50px);

正则表达式

笔记摘自:菜鸟教程

案例一

去除url指定参数。

案例二

获取url中的参数值。

^,有限定开头、(否)取反的意思。一般在中括号”[]”中使用表示否定(取反)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//案例见后边的笔记,这里对正则表达式进行分析:

//函数getUrlParam,用于获取地址栏参数值。
// http://www.baidu.com?word=china&a=1
// 从上边的url地址中获取china或者1
var getUrlParam = function(name){
var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
// var r = window.location.search.substr(1).match(reg);//地址栏 参数部分
var r = 'key=value&key2=value2&key3=value3'.match(reg);//模拟地址栏参数
console.log(JSON.stringify(r));//["&key2=value2&","&","value2","&"]
if(r!=null)return decodeURI(r[2]); return '';
}

// (^|&)
//^这里表示任意字符,&就是&字符
//匹配任意字符或者&字符

// ([^&]*)
//^这里表示取反(有[]与没[]的区别)。[^&]表示匹配不包含&的其他字符, *表示可以重复0或N次
//匹配非&字符0或N次

// (&|$)
//匹配&字符或$字符

//RegExp对象
//若要全局匹配,可添加第二个参数 'g'
//符合匹配规则 "(^|&)"+ name +"=([^&]*)(&|$)" 的作为匹配结果返回
//()部分也作为匹配结果返回
//所以,上边的例子中若有匹配到会返回四个匹配结果,一个包含四个元素的数组(没有匹配到会返回null)。
//["整个匹配结果","第一个()部分的匹配结果","第二个()部分的匹配结果","第三个()部分的匹配结果"]


//为了解释匹配规则中()的作用,对getUrlParam函数做如下修改:
//可以看到:匹配规则中没有()时,只返回一个匹配结果
var getUrlParam = function(name){
var reg1 = new RegExp(name +"=[^&]*");
var r = 'key=value&key2=value2&key3=value3'.match(reg1);//模拟地址栏参数
console.log(JSON.stringify(r));//["key2=value2"]
var reg2 = new RegExp("=[^]*");
r = r[0].match(reg2);
console.log(JSON.stringify(r));//["=value2"]
if(r!=null)return decodeURI(r[0].substr(1,r[0].length-1)); return '';//value2
}

案例三

匹配“[]”,其中字符(为数据库字段名)可有可无

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//使用 RegExp对象
var reg = new RegExp("\\[\\w*\\]",'g');
var r = '123[4_5]67[8]90[]456[777]6766'.match(reg);
console.log(JSON.stringify(r));

//不使用 RegExp对象
var reg2 = /\[\w*\]/g;
var r2 = '123[4_5]67[8]90[]456[777]6766'.match(reg2);
console.log(JSON.stringify(r2));


//运行结果如下:
["[4_5]","[8]","[]","[777]"]
["[4_5]","[8]","[]","[777]"]

说明:

  • \w,查找数字、字母及下划线。
  • *,匹配任何包含零个或多个 n 的字符串。
  • “\”,为转义符。使用RegExp对象,需特别注意转义,请仔细阅读代码。
  • g,全局匹配

案例四

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//不使用正则:

/**
* 将 [dept_id] 转换为 ${item.dept_id}
* @param {Object} str 原字符串
* @return {string} 处理后的字符串
*/
var handelParam = function(str) {
var leftIndex = str.indexOf('[');
var rightIndex = str.indexOf(']');
if (leftIndex != -1 && rightIndex != -1) {
//包含 []
if (rightIndex - leftIndex > 1) {
str = str.substr(0, leftIndex) + "${item." + str.substring(leftIndex + 1, rightIndex) + "}" + str
.substr(rightIndex + 1);
} else {
// [] 中间没有参数。去掉[]即可
str = str.substr(0, leftIndex) + str.substr(rightIndex + 1);
}
return handelParam(str);
} else {
//不包含 [] 直接返回
return str;
}
}

//使用正则:

/**
* 作用同上
*/
var changeStr = function(str) {
str.match(/\[\w*\]/g).forEach(s => {
var tempStr = s.replaceAll('[', '{').replaceAll(']', '}')
if (tempStr !== '{}') tempStr = '$' + `{item.${tempStr.split('{')[1]}`
str = str.replaceAll(s, tempStr == '{}' ? '' : tempStr)
})
return str
}

地址栏相关

获取url中的参数值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//获取地址栏中的参数(?key=value)
getUrlParam(name){
var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if(r!=null)return decodeURI(r[2]); return '';
}

//window.location
//window的location对象

//search
//得到的是url中?后边部分(包括?)

//substr()
//返回一个从指定位置开始的指定长度的子字符串
//这里设置一个参数1,代表从索引为1的地方开始截取到最后,是为了把url中的?号去掉

//decodeURI,uri解码,有一些参数值会经过uri编码的,所以保险起见应该进行解码(因为value值中不能包括&,若包括&则需要进行uri编码)

//关于RegExp对象的介绍,见上边的“正则表达式”笔记。

//扩展:
var getUrlParam2 = function(name){
// var url = window.location.search.substr(1).match(reg);
var url = 'key=value&key2=value2&key3=value3';
var allVal = url.split('&');//分割,得到键值对数组
var str = allVal.filter(item => item.includes(name)).toString();//遍历,返回包含name的键值对
return decodeURI(str.split('=')[1]);//分割,返回value(key=value)
}

console.log(getUrlParam2('key2'));

去除url指定参数

1
2
3
4
5
6
7
8
9
10
11
var removeURLParam = function(url,name){
var e = eval('/'+name+'=[^&]*&?/g');//参数,例如:“age=18&”,&可有可无,/g表示匹配全局而不是匹配的第一个。
return url.replace(e, '');
}

//正则表达式分析:
// [^&]* --除&之外的其他字符,出现零次或多次
// &? --字符&,出现零次或一次
// g --匹配全局而不是匹配的第一个
// 匹配规则,用两个斜杆//包裹
// 若匹配规则要使用变量拼装,需要使用eval()函数处理后再放到replace()函数中作为匹配规则

HTML相关

单位

PX

px像素(Pixel)。相对长度单位。像素px是相对于显示器屏幕分辨率而言的。

REM

rem是CSS3新增的一个相对单位(root em,根em),使用rem为元素设定字体大小时,仍然是相对大小,但相对的只是HTML根元素。这个单位可谓集相对大小和绝对大小的优点于一身,通过它既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反应。目前,除了IE8及更早版本外,所有浏览器均已支持rem。对于不支持它的浏览器,应对方法也很简单,就是多写一个绝对单位的声明。这些浏览器会忽略用rem设定的字体大小。下面就是一个例子:

1
p {font-size:14px; font-size:.875rem;}

注意: 选择使用什么字体单位主要由你的项目来决定,如果你的用户群都使用最新版的浏览器,那推荐使用rem,如果要考虑兼容性,那就使用px,或者两者同时使用。

px 与 rem 的选择?

对于只需要适配少部分手机设备,且分辨率对页面影响不大的,使用px即可 。

对于需要适配各种移动设备,使用rem,例如只需要适配iPhone和iPad等分辨率差别比较挺大的设备。

摘自菜鸟教程

input

1
2
3
4
5
6
7
8
//设置 默认值
document.querySelector('input').value = item.sp_outstore_det__out_num; //输入框默认值
//设置 键盘类型
document.querySelector('input').type = 'number'; //数字键盘
document.querySelector('input').pattern = '\d*'; //数字 九宫格键盘
//设置 焦点
document.querySelector('input').focus(); //获取焦点
document.querySelector('input').blur();//失去焦点(隐藏键盘)

innerHTML和innerText

document对象中有innerHTML、innerText这两个属性,都是获取document对象文本内容,但使用起来还是有区别的;

1) innerHTML设置或获取标签所包含的HTML+文本信息(从标签起始位置到终止位置全部内容,包括HTML标签,但不包括自身)

2) outerHTML设置或获取标签自身及其所包含的HTML+文本信息(包括自身)

3) innerText设置或获取标签所包含的文本信息(从标签起始位置到终止位置的内容,去除HTML标签,但不包括自身)

4) outerText设置或获取标签自身及其所包含的文本信息(包括自身)

样式相关

占位符

1
2
中文占位符:
&#12288

打印时的样式

style标签上添加属性media="print"

1
2
3
4
5
6
7
<style media="print">
body{
margin: 0;/*打印的时候,去掉顶部外边距*/
}
</style>

page-break-before: always;/*在元素前插入分页符。想让某个元素显示到下一页*/

隐藏滚动条

3种方法实现CSS隐藏滚动条并可以滚动内容

1
2
3
4
/* 隐藏滚动条。element,应用在要隐藏滚动条的元素上 */
.element::-webkit-scrollbar { width: 0 !important }
.element { -ms-overflow-style: none; }
.element { overflow: -moz-scrollbars-none; }

布局

居中

方法一:弹性盒模型。body这样设置,内部嵌套的div会水平、垂直方向居中

1
2
3
4
5
6
7
8
9
10
body {
height: 100vh;
/*居中,父元素要设置宽高*/
display: flex;
align-items: center;/*垂直居中*/
justify-content: center;/*水平居中*/
}

//子元素没有居中,可以尝试将定位更改为绝对
position: absolute;

方法二:

1
2
3
4
5
6
7
8
9
父元素
position: relative;
text-align: center;/*水平居中*/

/*垂直居中*/
子元素
position: absolute;
top: 50%;
transform: translateY(-50%);

靠到两边

上边的弹性盒模型,除了可以让元素水平、垂直居中,还可以设置靠到两边(元素内,有两个元素)。可用在header布局中。

1
2
3
4
5
display: flex;
/*靠到两边*/
justify-content: space-between;
/*垂直居中*/
align-items: center;

平分宽度

1
2
3
4
5
6
#父元素,设置弹性布局,水平方向
display: flex;
flex-direction:row;

#子元素,给定flex占比为1,则平分空间
flex: 1;

占满剩余空间

上边的“平分宽度”中。一个子元素设置“flex: 1”一个不设置。则设置了的,将占满剩余空间。

渐变

1
2
/*径向渐变*/
background: radial-gradient(#000000, rgb(31, 77, 20));

弹出数字键盘

1
2
document.querySelector('input').type = 'number'; //数字键盘
document.querySelector('input').pattern = '\d*'; //数字 九宫格键盘

图标

标签页图标

网页标签页中的图标

使用link rel=”shortcut icon”为网页标题加图标

1
<link rel="shortcut icon" href="../../../images/markdown_img/2020/20210617175633.png" type="image/x-icon">

图片无法显示

笔记摘自:知乎

保存在gitee的图片不能正常访问,被重定向(302,防盗链)。解决方法:

1
2
3
4
<!-- html文件的head中添加以下meta标签-->
<meta name="referrer" content="no-referrer" />
<!-- 或者img标签中添加以下referrer属性-->
<img referrer="no-referrer|origin|unsafe-url" src="{item.src}"/>

第三方API

必应壁纸API

1
https://www.yangshangzhen.com/bing/wallpaper

使用:

1
2
3
4
5
6
background: url(https://www.yangshangzhen.com/bing/wallpaper) center no-repeat;
/*url;位置,两个方向都居中;不平铺,只显示一次;*/
background-size: cover;/*缩放至图片能够铺满整个容器,可能会有部分图片区域被裁剪*/

/*还可以再添加一个fixed属性,使图片固定在屏幕上*/
background: url(https://www.yangshangzhen.com/bing/wallpaper) center no-repeat fixed;

数据相关

小数点

1
2
3
4
5
// 如果去零时需要保留位数: (比如 19.520100 --> 19.52)
parseFloat(Number(19.520100).toFixed(2))

// 如果只想去除小数点后多余的0 (比如 18.2300 --> 18.23)
parseFloat(arg)

过滤

使用filter()函数,过滤数组中的元素。

案例:

1
2
3
4
5
6
7
8
9
10
11
12
//this.table_data数组 中保存原始数据
//search_val、item 过滤条件(可以是table_data数组中取出的一个元素,也可以是任意数据)

//返回 mat_name中包含search_val中的数据(应用场景:搜索)
this.table_data = this.table_data.filter(data =>
data.mat_name.toLowerCase().includes(search_val.toLowerCase())
);

//返回 mat_id中不包含item.mat_id中的数据(应用场景:删除某条数据)
this.table_data = this.table_data.filter(data =>
!(data.mat_id+"").toLowerCase().includes((item.mat_id+"").toLowerCase())
);

其他应用,见VUE中的搜索框案例

存储

详细介绍、案例,见这篇博客

JS文件

把一些常用数据(json对象、字符串等)保存在js文件中,通过script标签引入使用。

Storage API

包括sessionStorage、localStorage。

前端数据库

前端数据库——WebSQLIndexedDB

转换

字符串生成文本

将字符串保存到文件中,并通过浏览器下载

1
2
3
4
5
6
7
8
function download(filename, text) {//文件名(例如:用户数据.txt)、文本内容(即待保存的字符串)
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
element.setAttribute('download', filename);
element.click();
}

download('hello.txt','hello,我是txt文件的内容。');

文本转换为字符串

使用到elementUI的upload组件,有图片的选择示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<el-upload :on-change="fileChange" :show-file-list="false" :auto-upload="false" action="#"
style="display: inline-block;">
<el-button type="primary"
style="border:0;font-size: 3.25rem!important;width: 100vw;height: 100%;padding: 1.625rem 4.25rem;">
选择文件
</el-button>
</el-upload>


fileChange(file) {
var _vue = this;
var reader = new FileReader();
reader.onload = function() {
console.log(this.result);//文件内容在this.result中
}
reader.readAsText(file.raw);//将文件转换为字符串
}

将excel转换为json

使用SheetJs将excel转换为json对象(数据保存在数组中),笔记在这篇博客

base64

1
2
3
4
window.btoa('china is so nb') // 编码
"Y2hpbmEgaXMgc28gbmI="
window.atob("Y2hpbmEgaXMgc28gbmI=") // 解码
"china is so nb"

JSON

获取json对象的属性值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var student = {
name: "pete",
age: 18
}

//获取student对象的属性,有两种方式:
console.log(student.age)
console.log(student['age'])


//拓展:
for (var key in this.form) {
this.form[key] = ""; //清空form表单的数据
}
//扩展:动态获取/设置vue中定义的变量值(field_name,函数传递过来的变量名)
this.$data[field_name] = '';

获取json对象的属性

1
2
3
4
5
6
7
 //方法一:使用上边的方法,遍历一遍
for (var key in this.form) {
console.log(key);
}

//方法二:使用函数Object.getOwnPropertyNames()
console.log(Object.getOwnPropertyNames(Math))

getOwnPropertyNames方法可以获得对象的所有属性名,并储存于一个数组当中。

keys方法只能获取可遍历的属性名并储存于数组。

删除属性

1
2
3
4
5
6
7
8
9
10
11
12
//有一个json对象如下:
let form = {
name:'xiaohei',
age:'18'
}
//要删掉age属性。使用delete实现:
delete form.age

//删掉age属性后,json对象结构如下:
//form = {
// name:'xiaohei'
//}

判断两个对象是否相同

https://www.cnblogs.com/wangweizhang/p/11113890.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 对比两个对象的值是否完全相等 返回值 true/false
isObjectValueEqual (a, b) {
//取对象a和b的属性名
var aProps = Object.getOwnPropertyNames(a);
var bProps = Object.getOwnPropertyNames(b);
//判断属性名的length是否一致
if (aProps.length != bProps.length) {
return false;
}
//循环取出属性名,再判断属性值是否一致
for (var i = 0; i < aProps.length; i++) {
var propName = aProps[i];
if (a[propName] !== b[propName]) {
return false;
}
}
return true;
}

类型判断

判断是不是数字

1
2
3
4
// true:数值型的,false:非数值型
function myIsNaN(value) {
return typeof value === 'number' && !isNaN(value);
}

object、number、string等

判断是不是数组

1
2
3
if(value instanceof Array){//value,要判断的数据
...
}

判空

判断一个对象是否存在

1
2
3
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}

问题

若json对象,无法通过json对象.属性名来获取属性值:

  • 检查json对象是否被引号包裹({}前后有引号),可将json对象转换为字符串,去掉前后引号后再转换为json对象。
  • 尝试将内部的单引号'转换为双引号"
1
2
3
4
5
6
7
8
9
10
11
12
//例子:
{'sys_user__user_name':'Alger','sys_user__user_code':'Alger','sys_user__duty':'','sys_dept__dept_name':'财核算报告中心会计一科','sys_user__is_leader':'0','sys_user__phone_code':'','sys_user__mob_code':'','sys_user__sex':'','sys_user__email':'','sys_user__is_novalid':'0','sys_user__auditing':'1','sys_user__wx_openid':'','sys_user__memo':'','sys_user__user_photo':'','sys_user__is_sync':'0','sys_user__wxqy_userid':'','sys_user__dept_id':'100200190002','sys_user__user_photo_v':'','sys_user__im_user_code':'RgduGc4frFt0hfbtpuo1','sys_user__user_id':'jxstar-434-1444'}


//示例:
var userdata = "{'sys_user__use。。。__user_id':'jxstar-434-1444'}";
userdata = (JSON.stringify(userdata)).replace(/'/g,'"');
userdata = userdata.substr(1,userdata.length-2);
userdata = JSON.parse(userdata);
console.log(userdata);
console.log("用户名 = "+userdata.sys_user__user_name);
console.log("用户名 = "+userdata['sys_user__user_name']);

时间相关

时钟

周期定时器,实现时钟

1
2
3
4
5
6
7
8
9
10
var myInterval = setInterval(() => {
var nowtime = new Date();
var hour = nowtime.getHours();
var min = nowtime.getMinutes();
var sec = nowtime.getSeconds();
var mill = nowtime.getMilliseconds();
console.log((hour>=10?hour:'0'+hour) + ":" + (min>=10?min:'0'+min) + ":" + (sec>=10?sec:'0'+sec)+":"+mill);//三目运算符,实现显示两位数
}, 1);

clearInterval(myInterval);//关闭周期定时器

时间格式化

自定义函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//准备:

//为Date原型添加format方法,可用于格式化时间,例如yyyy-MM-dd hh:mm:ss 或者 yyyy-MM-dd
//https://www.cnblogs.com/tugenhua0707/p/3776808.html
Date.prototype.format = function(fmt) {
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
"S": this.getMilliseconds() //毫秒
};
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
}
for (var k in o) {
if (new RegExp("(" + k + ")").test(fmt)) {
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
}
}
return fmt;
}

//使用:
item.mytime = new Date(item.mytime).format("yyyy-MM-dd");

第三方库

使用Day.js进行时间格式化。

1
2
3
4
5
6
7
8
9
10
11
12
<!-- cdn引入dayjs -->
<script src="https://unpkg.com/dayjs@1.8.21/dayjs.min.js"></script>

var date_val = '2022-1-11 17:56:34';
//使用前边的自定义format函数进行时间格式化
var mydate = new Date(date_val).format("yyyy-MM-dd");
console.log(mydate);//2022-01-11
//扩展:使用Day.js进行时间格式化
var mydate2 = dayjs(date_val).format('YYYY-MM-DD');
console.log(mydate2);//2022-01-11
var mydate3 = dayjs(date_val).format('[今天是]YYYY[年]MM[月]DD[日]');
console.log(mydate3);//今天是2022年01月11日

24小时制

1
new Date().toLocaleString('chinese', {hour12: false})

时间戳

第一种方法:(这种方法只精确到秒)

var timestamp = Date.parse(new Date());
结果:1545816450000

第二种方法:

var timestamp=new Date().getTime();
结果:1545816456780

第三种方法:

var timestamp=new Date().getTime();(和二重复了)
var timestamp = (new Date()).valueOf() //1572173440709
结果:1572173440709

链接:https://www.jianshu.com/p/96bc61012b90

获取月份

1
2
3
4
5
6
7
8
9
10
var getMonths = function(startTime) {
var startDate = new Date(startTime);
var endDate = new Date();
var number = 0;
var yearToMonth = (endDate.getFullYear() - startDate.getFullYear()) * 12;
number += yearToMonth;
var monthToMonth = endDate.getMonth() - startDate.getMonth();
number += monthToMonth;
return number;
}

JS语法

事件监听

addEventListener,添加事件监听器。

removeEventListener,移除监听器。

1
2
3
4
5
6
7
8
9
10
11
12
13
//添加事件监听器,监听自定义事件mycustom
var mycustom = window.addEventListener('click', myClickHandler);
//移除事件监听器
//window.removeEventListener('click',myClickHandler);

//参数一致,均为:
//第一个参数是事件的类型 (如 "click" 或 "mousedown").
//第二个参数是事件触发后调用的函数。
//第三个参数是个布尔值用于描述事件是冒泡还是捕获。该参数是可选的。

function myClickHandler(e) {
。。。
}

自定义事件

1
event = new CustomEvent(typeArg, customEventInit);

CustomEvent的参数:

  • typeArg

    • 指定事件类型,传递一个字符串。
  • customEventInit可选

    • 一个字典类型参数(json对象),有如下字段:
    • "detail", 可选的默认值是 null 的任意类型数据,是一个与 event 相关的值
    • bubbles,一个布尔值,表示该事件能否冒泡。 来自 EventInit。注意:测试chrome默认为不冒泡。
    • cancelable, 一个布尔值,表示该事件是否可以取消。 来自 EventInit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//添加事件监听器,监听自定义事件mycustom
var mycustom = window.addEventListener('mycustom', customHandler);

function customHandler(e) {
// 打印事件对象 在5秒后 出现打印,可以看到我们自定义的参数
console.log('e = ')
console.log(e)
console.log('data = ' + e.detail.data)
var token = e && e.detail.token;
console.log('token = ' + token)
}


// 创建事件对象
let event = new CustomEvent('mycustom', {
//可直接传入 自定义事件的参数
detail: {
data: 'data',
token: 'ikde532lwe4'
}
})
// 同样 也可以直接在事件对象上绑定 参数
event.name = '自定义事件'
// 抛出/发出 事件(自定义事件)
window.dispatchEvent(event);


//可简写为:
window.dispatchEvent(new CustomEvent('mycustom', {
detail: {
data: 'data',
token: 'ikde532lwe4'
}
}));

笔记摘自:自定义事件 Event 与 CustomEvent

模板字符串

模板字符串里面${var}是变量的占位符,在字符串里面可以使用js语法和js表达式。

1
2
3
4
5
6
7
8
9
10
11
//`string` 是模板字符串,ES2015新增的符号。
//案例:
console.log(`随机数: ${Math.random()}`)

var x = 'a', y = 'b';
var z = `${x,y}`; //'b'
console.log(`z = ${z}`);

//结果:
随机数: 0.07094254431903635
z = b

更多模板字符串使用方法,看官方文档

匿名函数

(function(){})();

第一个部分(function(){})定义一个匿名函数,第二个部分();在匿名函数定义完成后马上调用它;

避免产生全局变量,影响整体页面环境,增加代码的兼容性。

扩展:

函数声明:使用function声明函数,并指定函数名。

1
function setFn() {   // coding  }

注释

函数注释:

1
2
3
4
5
6
7
8
9
10
/**
* 执行sql
* @param {string} sql sql语句,字符串类型
* @param {string[]} params ?占位符对应的数据,字符串数组
* @param {requestCallback} hdcall sql执行成功后的回调
*
* @param {Object} json对象
* @param {Object[]} 数组
* @param {*} 任意类型
*/

常用函数

汉字转拼音

GItee地址:Bopomofo

下载bopomofo.js、bopomofo.min.js(字库文件,较大)文件,使用script标签引入项目。

1
2
3
4
5
6
7
8
9
10
11
<!-- Bopomofo汉字转拼音 -->
<script src="./bopomofo.js"></script>
<script src="./bopomofo.min.js"></script>

//汉字转拼音(用法见bopomofo.js中 函数pinyin 的注释
//带音调
console.log(pinyin('你好啊,很高兴认识你!'));//nǐ hǎo ā, hěn gāo xìng rèn shí nǐ!
//不带音调
console.log(pinyin('你好啊,很高兴认识你!',2));//ni hao a, hen gao xing ren shi ni!
//去掉分隔符(默认空格)
console.log(pinyin('你好啊,很高兴认识你!',2,false,false,''));//nihaoa,hengaoxingrenshini!

长度计算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//长度计算(针对数据库长度限制,避免超长度报错)
function getStrLeng(str){
var realLength = 0;
var len = str.length;
var charCode = -1;
for(var i= 0;i < len; i++){
charCode = str.charCodeAt(i);
if (charCode >= 0 && charCode <= 128){
realLength += 1;
}else{
// 如果是中文则长度加2
realLength += 2;
}
}
return realLength;
}

截取字符串

上边“长度计算”的拓展。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//截取指定长度(针对数据库长度限制)的字符串
//英文 - 1位
//中文 - 2位
getStrByLen(str, length) { //字符串,长度
var realLength = 0;
var len = str.length;
var charCode = -1;
for (var i = 0; i < len; i++) {
charCode = str.charCodeAt(i);
if (charCode >= 0 && charCode <= 128) {
realLength += 1;
} else {
// 如果是中文则长度加2
realLength += 2;
}
if (length && realLength >= length) {
return str.substring(0, i);
}
}
return str;
}

程序暂停

类似Java中的休眠Thread.sleep(毫秒数);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function sleep(millisecond) {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, millisecond)
})
}

async function test() {
const start = new Date().getTime();
console.log("执行开始",start);
await sleep(3000);//暂停3秒
console.log("执行结束",new Date().getTime() - start)
}

test();

异步操作并行

把多个异步操作,并行执行。然后按照顺序(调用顺序,即下边案例中构造iterationFunArr时添加的顺序)返回执行结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Math.ceil() 向上取整。 2.3 -》 3
// Array(3),创建一个长度为3的数组,只有length,没有元素的空数组
// array.keys(),返回一个数组迭代器,元素为旧数组的索引
// “...”展开运算符,把数组迭代器中的元素展开,重新创建一个数组(迭代器没有map方法)
// map返回的数组,元素为promise对象
const iterationFunArr = [...Array(num).keys()].map(i => {
//异步操作,返回promise对象
fetch(this.request.url, {
method: 'POST',
headers: this.myrequest.headers,
body: `data=xxx&limit=XXX&start=XXX`
}).then((resp) => {
return resp.text()
}).then((data) => {
//...
})
})
//Promise.all 里面参数为一个数组,数组的每一项是一个返回promise的函数调用
Promise.all(iterationFunArr).then(...).catch(...)

第三方工具库

xe-utils,文档:Gitee仓库官方文档

封装了一些常用js函数。

拼接sql

特殊字符处理:使用运算符||拼接或使用转义字符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//转义 字符 '
//待处理的字段值,作为value传到函数handelChar中。
handelChar(value) {
if (typeof value != 'string') {
return value;
}
var index = value.indexOf("'");
if (index != -1) {
//包含 '
var one = value.substring(0, index);
var two = value.substring(index + 1, value.length);
two = this.handelChar(two);
return `${one}'||''''||'${two}`;//英文单引号'有点特殊
} else {
return value;
}
}


//转义 字符 --
//思路:将-,转换为 ||'-'||
//var index = value.indexOf("-");
//return `${one}'||'-'||'${two}`;


//转义 字符 ;
//思路:将英文;转换为中文;,或者使用运算符||拼接
//var index = value.indexOf(";");
//return `${one};${two}`;

获取随机数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//获取随机数。参数n为随机数的长度。
getRandomNumber(n) {
var arr = new Array(n); //用于存放随机数
var randomNumber = ''; //存放随机数
for (var i = 0; i < arr.length; i++)
arr[i] = parseInt(Math.random() * 10);
var flag = 0;
for (var i = 0; i < arr.length - 1; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (arr[i] == arr[j]) {
flag = 1;
break;
}
}
if (flag) break;
}
for (var i = 0; i < arr.length; i++) {
randomNumber += arr[i];
}
return randomNumber;
}

除前/后字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 去除字符串 前/后 指定字符。默认去除前后空格。
* @param {Object} str 待处理的字符串。只有此一个参数时,与trim函数作用相同。
* @param {Object} char 需要去除的字符
* @param {Object} type 去除头部还是尾部的字符, left(头部),right(尾部),不带此参数则去除字符串前后
*/
mytrim(str, char, type) {
if (char) {
if (type == 'left') {
return str.replace(new RegExp('^\\' + char + '+', 'g'), '').trim();
} else if (type == 'right') {
return str.replace(new RegExp('\\' + char + '+$', 'g'), '').trim();
}
return str.replace(new RegExp('^\\' + char + '+|\\' + char + '+$', 'g'), '').trim();
} else {
return str.trim();
}
}

扩展:

1
2
3
var datas = JSON.parse(this.textarea2);
this.text2 = this.text2.replace(/ +/g, ' ').trim(); //将多个空格替换成一个空格,去除前后多余空格
var text2Arr = this.text2.split(' '); //以空格为标志分割字符串返回数组

判断设备

扩展:

阮一峰博客:JavaScript 侦测手机浏览器的五种方法

js判断

JavaScript判断打开html的设备是手机还是电脑,以便分别设置不同的参数。

1
2
3
4
5
6
7
var ua = navigator.userAgent.toLowerCase();
if (/AppleWebKit.*Mobile/i.test(navigator.userAgent) || ( /MIDP|SymbianOS|NOKIA|SAMSUNG|LG|NEC|TCL|Alcatel|BIRD|DBTEL|Dopod|PHILIPS|HAIER|LENOVO|MOT-|Nokia|SonyEricsson|SIE-|Amoi|Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|ZTE/
.test(navigator.userAgent)) || ua.match(/MicroMessenger/i) == "micromessenger") {
//手机
} else {
//pc
}

CSS判断

使用@media 查询来判断。@media 规则允许在相同样式表为不同媒体设置不同的样式。(更详细介绍,见菜鸟教程。案例1:传送门

1
2
3
4
5
6
7
8
/*如果文档宽度小于 500 像素则修改背景颜色(background-color);500是一个经验值,用于设置手机端样式*/
<style>
@media(max-width: 500px) {
body{
background-color:lightblue;
}
}
</style>

也可以针对不同的媒体使用不同 stylesheets :

1
<link rel="stylesheet" media="*mediatype* and|not|only (*media feature*)" href="*mystylesheet.css*">

使用@media 查询来设置手机端显示的样式,在头部最好添加下边的<meta>标签。意思是根据手机屏幕1:1显示的页面。

1
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">

ajax

使用fetch,发起ajax请求。

fetch是web提供的一个可以获取异步资源的api,目前还没有被所有浏览器支持,它提供的api返回的是Promise对象。

1
2
3
4
5
6
7
8
9
10
fetch(this.request.url, {
method: 'POST',
headers: {...},
body: `data=xxx&limit=xxx&start=xxx`
}).then((resp) => {
return resp.text()
}).then((data) => {
data = JSON.parse(data);
//...
})

剪贴板

execCommand

使用命令execCommand实现复制、粘贴。

特点:

  • 需要使用到输入组件,只能将输入组件中选中的内容拷贝至剪贴板。
  • 只能读取/写入文本(剪贴板)。
  • 涉及到用户隐私,在chrome浏览器中不支持执行Paste命令。使用Clipboard API解决。

复制:

1
2
3
4
5
6
7
8
9
10
//复制
copyBtn(input_id) {//input组件的id
var copyText = document.querySelector(`#${input_id}`); //获取对象
copyText.select(); //选择(选中内容。全选)
document.execCommand("Copy"); //执行复制命令
this.$message({
message: '复制成功!',
type: 'success'
});
}

粘贴:

1
2
3
4
5
6
7
8
9
10
//粘贴(chrome浏览器不支持执行Paste命令)
pasteBtn(inputbox_id) {//input组件的id
var inputBox = document.querySelector(`#${inputbox_id}`); //获取对象
inputBox.focus(); //获取焦点
document.execCommand("Paste"); //执行复制
this.$message({
message: '粘贴成功!',
type: 'success'
});
}

扩展:第三方库clipboarddocument.execCommand()命令进行封装,简化使用方法和提高兼容性。

Clipboard API

使用Clipboard API实现复制、粘贴。

特点:

  • 不需要使用到输入组件
  • 可将任意数据写入剪贴板、可从剪贴板读取任意数据(文本、图片、二进制数据等)
  • 只支持 https 协议或开发环境localhost。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//查看权限
navigator.permissions.query({
name: 'clipboard-read'
}).then(permissionStatus => {
// permissionStatus.state 的值是 'granted'、'denied'、'prompt':
//granted 有权限
//denied 无权限
//prompt 提示状态(等待用户给予权限)
console.log(permissionStatus.state);
});


// 读取剪切板内容:
(async () => {
const text = await navigator.clipboard.readText();//无权限会弹窗提示,需用户授予权限
console.log(text);
})();
//chrome控制台窗口使用setTimeout执行
setTimeout(async () => {
// 读取剪切板内容
const text = await navigator.clipboard.readText();//read()读取其他类型数据
console.log(text);
}, 5000);


// 往剪切板写入内容:
document.body.addEventListener(
'click',
async (e) => {
await navigator.clipboard.writeText('Yo');//write()写入其他类型数据
}
)

笔记摘自这篇博客阮一峰博客

扩展:chrome浏览器,可在chrome://settings/content/clipboard中授予剪贴板权限。

数组

判断是不是数组

1
2
3
if(value instanceof Array){//value,要判断的数据
...
}

元素操作

往数组中添加/删除元素:

  • push()
    • 往数组尾部添加元素,返回新数组长度
    • 使用...arr.push(...arr2)合并数组
  • unshift()
    • 往数组头部添加元素,返回新数组长度
  • shift()
    • 从数组头部开始删除(1个)元素,返回所删除的数组元素
    • 一次删除一个元素,不接收参数
  • pop()
    • 从数组尾部开始删除(1个)元素,返回所删除的数组元素
  • splice()
  • 注意:以上操作均会改变原数组。删除元素时,空数组不报错,但返回undefined
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
var arr = ['1', '2'];
var arr2 = ['a', 'b'];

//push,往数组尾部添加元素,返回新数组长度,会改变原数组
//案例:
//添加一个元素
console.log(arr.push('hello')) //打印:3
//将数组arr2中的元素全部添加到数组arr的尾部
console.log(arr.push(...arr2)) //打印:5
console.log(JSON.stringify(arr)) //打印:["1","2","hello","a","b"]


//unshift,往数组头部添加元素,返回新数组长度,会改变原数组
//案例:
//添加一个元素
console.log(arr.unshift('hello')) //打印:6
//将数组arr2中的元素全部添加到数组arr的头部
console.log(arr.unshift(...arr2)) //打印:8
console.log(JSON.stringify(arr)) //打印:["a","b","hello","1","2","hello","a","b"]


//shift,从数组头部开始删除(1个)元素,返回所删除的数组元素,会改变原数组
//案例:
//删除1个元素
console.log(arr.shift()) //打印:a
//删除1个元素
console.log(arr.shift()) //打印:b
console.log(JSON.stringify(arr)) //打印:[hello","1","2","hello","a","b"]


//pop,从数组尾部开始删除(1个)元素,返回所删除的数组元素,会改变原数组
//案例:
//删除1个元素
console.log(arr.pop()) //打印:b
//删除1个元素
console.log(arr.pop()) //打印:a
console.log(JSON.stringify(arr)) //打印:["hello","1","2","hello"]
for (var i = 1; i <= 4; i++) {
arr.pop();
}
console.log(arr.pop()) //打印:undefined
console.log(JSON.stringify(arr)) //打印:[]

//注意:空数组调用pop、shift不报错,但返回undefined

截取/拷贝

  • splice()

    • splice() 方法可以添加元素、删除元素,也可以截取数组片段。删除元素时,将返回被删除的数组片段,因此可以使用 splice() 方法截取数组片段。

    • array.splice(index, howmany, item1, ....., itemX)

    • index 必需。整数,指定在什么位置添加/删除项目,使用负值指定从数组末尾开始的位置。
      howmany 可选。要删除的项目数。如果设置为 0,则不会删除任何项目。
      item1, …, itemX 可选。要添加到数组中的新项目。
  • slice()

    • slice() 方法与 splice() 方法功能相近,但是它仅能够截取数组中指定区段的元素,并返回这个子数组。该方法包含两个参数,分别指定截取子数组的起始和结束位置的下标。

案例

数组拷贝

slice,从数组中返回指定下标内的新数组,下标包括前不包括后。

1
this.showTableData = this.tableData.slice((this.currentPage - 1) * this.pageSize, this.currentPage * this

扩展

  • 浅拷贝。引用数据类型的赋值操作,是地址的拷贝。缺点:会污染源数据。

  • 深拷贝。对数值的拷贝。深拷贝可以使用JSON的stringify、parse方法实现。

    1
    2
    3
    4
    //1.使用stringify方法,将JSON对象转换成字符串
    JSON.stringify()
    //2.使用parse方法,将字符串转换成JSON对象,再进行赋值操作
    JSON.parse()

数组拆分

1
2
3
4
//案例:把一个数组拆分成两个
//data为一个数组,在索引为800的位置将数组拆分成两个数组
var data1 = data.slice(0,800);//包括前,不包括后
var data2 = data.slice(800);//从索引800截取到最后

数组去重

1
2
3
4
5
6
7
8
9
10
11
12
13
//数组去重
function dedupe(array){
return Array.from(new Set(array));
}


var depts = ['1','3','1','4'];
console.log(depts.length);//4

var depts_new = dedupe(depts);//去重

console.log(depts_new.length)//3
console.log(JSON.stringify(depts_new))//["1","3","4"]

循环遍历

笔记摘自:map和forEach的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//map和forEach的区别:在于返回值
var a = arr.forEach(function(item,index,arr){ 
return 123
});
var b = arr.map(function(item,index,arr){
return 123
}); 
console.log(a); //undefined。没有返回值
console.log(b); //[123,123,123,123]。返回一个数组,由return的结果组成


//可以利用map的这个特性做哪些事情呢,比如:
var b = arr.map(function(item,index,arr){
return item+'a';
}); 
console.log(b); //["aa", "ba", "ca", "da"]



// 在ES6我们还可以这样任性
// 循环下标或者key(for-in)
for (var index in myArray) { // don't actually do this
console.log(myArray[index]);
}

// 循环value(for-of)
for (var value of myArray) {
console.log(value);
}

// 甚至直接循环key和value,no problem
for (var [key, value] of phoneBookMap) {
console.log(key + "'s phone number is: " + value);
}

// 或者更者我们这样“优雅”的循环对象(貌似和ES6没有关系)
for (var key of Object.keys(someObject)) {
console.log(key + ": " + someObject[key]);
}

npm命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//下载到项目的node_modules,但不会添加到package.json文件中
npm install xxx

//下载到安装npm时所设置的目录(不是当前项目的node_modules中)
npm install -g xxx

//下载到项目的node_modules,同时添加到package.json文件中(正式、测试环境)
npm install -save xxx

//下载到项目的node_modules,同时添加到package.json文件中(测试环境)
npm install -save-dev xxx


//只有添加到package.json文件中,在使用npm install命令时才会下载相关依赖

草稿

自动点击登录按钮

1
2
3
4
5
6
7
8
9
10
setInterval(() => {
//页面没有显示加载中遮罩层、有账号输入框的时候
if (document.querySelector('.processbar').style[0] == 'display' && document.querySelector('#usr')) {
//填充账号与密码
document.querySelector('#usr').value = 'caiyoxxedsf';
document.querySelector('#pwd').value = 'pxxxx34';
//点击登录按钮
document.querySelector('.subbtn').click();
}
}, 100);

(js)markdown插件:

https://github.com/jonschlinkert/remarkable

https://github.com/miaolz123/vue-markdown

优雅的代码

键值映射

0 - 未提交

1 - 已提交

2 - 审批中

3 - 已审批

要将数据0、1、2、3转换为对应的显示值。

1
2
3
4
5
6
7
8
9
10
//将 键值对 定义为json对象的属性,传递进来的数据要转换为显示值,将其作为json对象的key,从json对象中取出值返回即可( json对象['属性名'] ,返回对应属性值 )
var getData = function(text) {
return ({
1: "已提交",
0: "未提交",
2: "审批中",
3: "已审批"
} [text])
}
console.log(getData(0))
若图片不能正常显示,请在浏览器中打开

欢迎关注我的其它发布渠道