前端常用的JS(代码片段)小工具方法总结
# 1、密码验证
只能由英文、数字、下划线组成
export const isPassword = (s) => {
return /^\w+$/.test(s)
}
2
3
只能由英文、数字组成
export const isPassword = (s) => {
return (/^[a-z0-9]+$/i).test(s)
}
2
3
# 2、邮箱验证
//方法一
export const isEmail = (s) => {
return /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/.test(s);
}
//方法二
export const isEmail = (s) => {
return /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(s);
}
2
3
4
5
6
7
8
# 3、手机号验证
export const isMobile = (s) => {
return /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/.test(s)
}
2
3
# 4、简单的身份证校验
export const isCardId = (s) => {
return /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/.test(s)
}
2
3
# 5、严格的身份证校验
export const isCardID = (sId) => {
if (!/(^\d{15}$)|(^\d{17}(\d|X|x)$)/.test(sId)) {
console.log('你输入的身份证长度或格式错误')
return false
}
//身份证城市
var aCity = { 11: "北京", 12: "天津", 13: "河北", 14: "山西", 15: "内蒙古", 21: "辽宁", 22: "吉林", 23: "黑龙江", 31: "上海", 32: "江苏", 33: "浙江", 34: "安徽", 35: "福建", 36: "江西", 37: "山东", 41: "河南", 42: "湖北", 43: "湖南", 44: "广东", 45: "广西", 46: "海南", 50: "重庆", 51: "四川", 52: "贵州", 53: "云南", 54: "西藏", 61: "陕西", 62: "甘肃", 63: "青海", 64: "宁夏", 65: "新疆", 71: "台湾", 81: "香港", 82: "澳门", 91: "国外" };
if (!aCity[parseInt(sId.substr(0, 2))]) {
console.log('你的身份证地区非法')
return false
}
// 出生日期验证
var sBirthday = (sId.substr(6, 4) + "-" + Number(sId.substr(10, 2)) + "-" + Number(sId.substr(12, 2))).replace(/-/g, "/"),
d = new Date(sBirthday)
if (sBirthday != (d.getFullYear() + "/" + (d.getMonth() + 1) + "/" + d.getDate())) {
console.log('身份证上的出生日期非法')
return false
}
// 身份证号码校验
var sum = 0,
weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2],
codes = "10X98765432"
for (var i = 0; i < sId.length - 1; i++) {
sum += sId[i] * weights[i];
}
var last = codes[sum % 11]; //计算出来的最后一位身份证号码
if (sId[sId.length - 1] != last) {
console.log('你输入的身份证号非法')
return false
}
return true
}
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
# 6、去除空格
// type: 1-所有空格 2-前后空格 3-前空格 4-后空格
export const trim = (str, type) => {
type = type || 1
switch (type) {
case 1:
return str.replace(/\s+/g, "");
case 2:
return str.replace(/(^\s*)|(\s*$)/g, "");
case 3:
return str.replace(/(^\s*)/g, "");
case 4:
return str.replace(/(\s*$)/g, "");
default:
return str;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 7、字符转换
//type: 1:首字母大写 2:首字母小写 3:大小写转换 4:全部大写 5:全部小写
export const changeCase = (str, type) => {
type = type || 4
switch (type) {
case 1:
return str.replace(/\b\w+\b/g, function (word) {
return word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase();
});
case 2:
return str.replace(/\b\w+\b/g, function (word) {
return word.substring(0, 1).toLowerCase() + word.substring(1).toUpperCase();
});
case 3:
return str.split('').map(function (word) {
if (/[a-z]/.test(word)) {
return word.toUpperCase();
} else {
return word.toLowerCase()
}
}).join('')
case 4:
return str.toUpperCase();
case 5:
return str.toLowerCase();
default:
return str;
}
}
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
# 8、是否是URL地址
export const isURL = (s) => {
return /^http[s]?:\/\/.*/.test(s)
}
2
3
# 9、随机数范围
export const random = (min, max) => {
if (arguments.length === 2) {
return Math.floor(min + Math.random() * ((max + 1) - min))
} else {
return null;
}
}
2
3
4
5
6
7
参考资料:JS - 生成随机数的方法汇总(不同范围、类型的随机数) (opens new window)
# 10、获取当前时间
// 获取当前时间
export const dateTime = () => {
let date = new Date();
let seperator1 = "-";
let seperator2 = ":";
let month = date.getMonth() + 1;
let strDate = date.getDate();
if (month >= 1 && month <= 9) {
month = "0" + month;
};
if (strDate >= 0 && strDate <= 9) {
strDate = "0" + strDate;
};
let hours = date.getHours();
if (hours >= 0 && hours <= 9) {
hours = "0" + hours;
};
let minutes = date.getMinutes();
if (minutes >= 0 && minutes <= 9) {
minutes = "0" + minutes;
};
let seconds = date.getSeconds();
if (seconds >= 0 && seconds <= 9) {
seconds = "0" + seconds;
};
let currentdate = date.getFullYear() + seperator1 + month + seperator1 + strDate
+ " " + hours + seperator2 + minutes
+ seperator2 + seconds;
return currentdate;
}
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
# 11、生成随机ID
//生成随机ID
export const getUid = () => {
function S4() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
};
return (S4() + S4() + S4() + S4() + S4() + S4() + S4() + S4()).slice(0, 30);
};
2
3
4
5
6
7
# 12、将阿拉伯数字翻译成中文的大写数字
export const numberToChinese = (num) => {
var AA = new Array("零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十");
var BB = new Array("", "十", "百", "仟", "萬", "億", "点", "");
var a = ("" + num).replace(/(^0*)/g, "").split("."),
k = 0,
re = "";
for (var i = a[0].length - 1; i >= 0; i--) {
switch (k) {
case 0:
re = BB[7] + re;
break;
case 4:
if (!new RegExp("0{4}//d{" + (a[0].length - i - 1) + "}$")
.test(a[0]))
re = BB[4] + re;
break;
case 8:
re = BB[5] + re;
BB[7] = BB[5];
k = 0;
break;
}
if (k % 4 == 2 && a[0].charAt(i + 2) != 0 && a[0].charAt(i + 1) == 0)
re = AA[0] + re;
if (a[0].charAt(i) != 0)
re = AA[a[0].charAt(i)] + BB[k % 4] + re;
k++;
}
if (a.length > 1) // 加上小数部分(如果有小数部分)
{
re += BB[6];
for (var i = 0; i < a[1].length; i++)
re += AA[a[1].charAt(i)];
}
if (re == '一十')
re = "十";
if (re.match(/^一/) && re.length == 3)
re = re.replace("一", "");
return re;
}
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
# 13、下载一个excel文档
同时适用于word,ppt等浏览器不会默认执行预览的文档,也可以用于下载后端接口返回的流数据
//下载一个链接
function download(link, name) {
if(!name){
name=link.slice(link.lastIndexOf('/') + 1)
}
let eleLink = document.createElement('a')
eleLink.download = name
eleLink.style.display = 'none'
eleLink.href = link
document.body.appendChild(eleLink)
eleLink.click()
document.body.removeChild(eleLink)
}
//下载excel
download('http://111.229.14.189/file/1.xlsx')
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 14、在浏览器中自定义下载一些内容
场景:我想下载一些DOM内容,我想下载一个JSON文件
/**
* 浏览器下载静态文件
* @param {String} name 文件名
* @param {String} content 文件内容
*/
function downloadFile(name, content) {
if (typeof name == 'undefined') {
throw new Error('The first parameter name is a must')
}
if (typeof content == 'undefined') {
throw new Error('The second parameter content is a must')
}
if (!(content instanceof Blob)) {
content = new Blob([content])
}
const link = URL.createObjectURL(content)
download(link, name)
}
//下载一个链接
function download(link, name) {
if (!name) {//如果没有提供名字,从给的Link中截取最后一坨
name = link.slice(link.lastIndexOf('/') + 1)
}
let eleLink = document.createElement('a')
eleLink.download = name
eleLink.style.display = 'none'
eleLink.href = link
document.body.appendChild(eleLink)
eleLink.click()
document.body.removeChild(eleLink)
}
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
使用方式:
downloadFile('1.txt','lalalallalalla')
downloadFile('1.json',JSON.stringify({name:'hahahha'}))
2
# 15、下载后端返回的流
数据是后端以接口的形式返回的,调用1中的download方法进行下载
download('http://111.229.14.189/gk-api/util/download?file=1.jpg')
download('http://111.229.14.189/gk-api/util/download?file=1.mp4')
2
# 16、提供一个图片链接,点击下载
图片、pdf等文件,浏览器会默认执行预览,不能调用download方法进行下载,需要先把图片、pdf等文件转成blob,再调用download方法进行下载,转换的方式是使用axios请求对应的链接
//可以用来下载浏览器会默认预览的文件类型,例如mp4,jpg等
import axios from 'axios'
//提供一个link,完成文件下载,link可以是 http://xxx.com/xxx.xls
function downloadByLink(link,fileName){
axios.request({
url: link,
responseType: 'blob' //关键代码,让axios把响应改成blob
}).then(res => {
const link=URL.createObjectURL(res.data)
download(link, fileName)
})
}
2
3
4
5
6
7
8
9
10
11
12
13
注意
注意:会有同源策略的限制,需要配置转发
# 17、防抖
在一定时间间隔内,多次调用一个方法,只会执行一次.
/**
*
* @param {*} func 要进行debouce的函数
* @param {*} wait 等待时间,默认500ms
* @param {*} immediate 是否立即执行
*/
export function debounce(func, wait=500, immediate=false) {
var timeout
return function() {
var context = this
var args = arguments
if (timeout) clearTimeout(timeout)
if (immediate) {
// 如果已经执行过,不再执行
var callNow = !timeout
timeout = setTimeout(function() {
timeout = null
}, wait)
if (callNow) func.apply(context, args)
} else {
timeout = setTimeout(function() {
func.apply(context, args)
}, wait)
}
}
}
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
使用方式:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<input id="input" />
<script>
function onInput() {
console.log('1111')
}
const debounceOnInput = debounce(onInput)
document
.getElementById('input')
.addEventListener('input', debounceOnInput) //在Input中输入,多次调用只会在调用结束之后,等待500ms触发一次
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
如果第三个参数immediate传true,则会立即执行一次调用,后续的调用不会在执行,可以自己在代码中试一下
# 18、节流
多次调用方法,按照一定的时间间隔执行
/**
* 节流,多次触发,间隔时间段执行
* @param {Function} func
* @param {Int} wait
* @param {Object} options
*/
export function throttle(func, wait=500, options) {
//container.onmousemove = throttle(getUserAction, 1000);
var timeout, context, args
var previous = 0
if (!options) options = {leading:false,trailing:true}
var later = function() {
previous = options.leading === false ? 0 : new Date().getTime()
timeout = null
func.apply(context, args)
if (!timeout) context = args = null
}
var throttled = function() {
var now = new Date().getTime()
if (!previous && options.leading === false) previous = now
var remaining = wait - (now - previous)
context = this
args = arguments
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout)
timeout = null
}
previous = now
func.apply(context, args)
if (!timeout) context = args = null
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining)
}
}
return throttled
}
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
第三个参数还有点复杂,options
- leading,函数在每个等待时延的开始被调用,默认值为false
- trailing,函数在每个等待时延的结束被调用,默认值是true
可以根据不同的值来设置不同的效果:
- leading-false,trailing-true:默认情况,即在延时结束后才会调用函数
- leading-true,trailing-true:在延时开始时就调用,延时结束后也会调用
- leading-true, trailing-false:只在延时开始时调用 例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<input id="input" />
<script>
function onInput() {
console.log('1111')
}
const throttleOnInput = throttle(onInput)
document
.getElementById('input')
.addEventListener('input', throttleOnInput) //在Input中输入,每隔500ms执行一次代码
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 19、cleanObject
去除对象中value为空(null,undefined,'')的属性,举个栗子:
let res=cleanObject({
name:'',
pageSize:10,
page:1
})
console.log("res", res) //输入{page:1,pageSize:10} name为空字符串,属性删掉
2
3
4
5
6
使用场景是:后端列表查询接口,某个字段前端不传,后端就不根据那个字段筛选,例如name不传的话,就只根据page和pageSize筛选,但是前端查询参数的时候(vue或者react)中,往往会这样定义
export default{
data(){
return {
query:{
name:'',
pageSize:10,
page:1
}
}
}
}
const [query,setQuery]=useState({name:'',page:1,pageSize:10})
2
3
4
5
6
7
8
9
10
11
12
13
14
给后端发送数据的时候,要判断某个属性是不是空字符串,然后给后端拼参数,这块逻辑抽离出来就是cleanObject,代码实现如下
export const isFalsy = (value) => (value === 0 ? false : !value);
export const isVoid = (value) =>
value === undefined || value === null || value === "";
export const cleanObject = (object) => {
// Object.assign({}, object)
if (!object) {
return {};
}
const result = { ...object };
Object.keys(result).forEach((key) => {
const value = result[key];
if (isVoid(value)) {
delete result[key];
}
});
return result;
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let res=cleanObject({
name:'',
pageSize:10,
page:1
})
console.log("res", res) //输入{page:1,pageSize:10}
2
3
4
5
6
# 20、获取文件后缀名
使用场景:上传文件判断后缀名
/**
* 获取文件后缀名
* @param {String} filename
*/
export function getExt(filename) {
if (typeof filename == 'string') {
return filename
.split('.')
.pop()
.toLowerCase()
} else {
throw new Error('filename must be a string type')
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
使用方式
getExt("1.mp4") //->mp4
# 21、复制内容到剪贴板
export function copyToBoard(value) {
const element = document.createElement('textarea')
document.body.appendChild(element)
element.value = value
element.select()
if (document.execCommand('copy')) {
document.execCommand('copy')
document.body.removeChild(element)
return true
}
document.body.removeChild(element)
return false
}
2
3
4
5
6
7
8
9
10
11
12
13
使用方式:
//如果复制成功返回true
copyToBoard('lalallala')
2
原理: ::: info 1、创建一个textare元素并调用select()方法选中
2、document.execCommand('copy')方法,拷贝当前选中内容到剪贴板。 :::
# 22、生成随机字符串
使用场景:用于前端生成随机的ID,毕竟现在的Vue和React都需要绑定key
/**
* 生成随机id
* @param {*} length
* @param {*} chars
*/
export function uuid(length, chars) {
chars =
chars ||
'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
length = length || 8
var result = ''
for (var i = length; i > 0; --i)
result += chars[Math.floor(Math.random() * chars.length)]
return result
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
使用方式
//第一个参数指定位数,第二个字符串指定字符,都是可选参数,如果都不传,默认生成8位
uuid()
2
# 23、简单的深拷贝
/**
*深拷贝
* @export
* @param {*} obj
* @returns
*/
export function deepCopy(obj) {
if (typeof obj != 'object') {
return obj
}
if (obj == null) {
return obj
}
return JSON.parse(JSON.stringify(obj))
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
缺陷:只拷贝对象、数组以及对象数组,对于大部分场景已经足够
const person={name:'xiaoming',child:{name:'Jack'}}
deepCopy(person) //new person
2
# 24、数组去重
/**
* 数组去重
* @param {*} arr
*/
export function uniqueArray(arr) {
if (!Array.isArray(arr)) {
throw new Error('The first parameter must be an array')
}
if (arr.length == 1) {
return arr
}
return [...new Set(arr)]
}
2
3
4
5
6
7
8
9
10
11
12
13
原理是利用Set中不能出现重复元素的特性
uniqueArray([1,1,1,1,1])//[1]
# 25、对象转化为FormData对象
使用场景:上传文件时我们要新建一个FormData对象,然后有多少个参数就append多少次,使用该函数可以简化逻辑
/**
* 对象转化为formdata
* @param {Object} object
*/
export function getFormData(object) {
const formData = new FormData()
Object.keys(object).forEach(key => {
const value = object[key]
if (Array.isArray(value)) {
value.forEach((subValue, i) =>
formData.append(key + `[${i}]`, subValue)
)
} else {
formData.append(key, object[key])
}
})
return formData
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
使用方式:
let req={
file:xxx,
userId:1,
phone:'15198763636',
//...
}
fetch(getFormData(req))
2
3
4
5
6
7
# 26、保留到小数点以后n位
使用场景:JS的浮点数超长,有时候页面显示时需要保留2位小数
// 保留小数点以后几位,默认2位
export function cutNumber(number, no = 2) {
if (typeof number != 'number') {
number = Number(number)
}
return Number(number.toFixed(no))
}
2
3
4
5
6
7
# 27、将数字转换为大写金额
export const changeToChinese = (Num) => {
//判断如果传递进来的不是字符的话转换为字符
if (typeof Num == "number") {
Num = new String(Num);
};
Num = Num.replace(/,/g, "") //替换tomoney()中的“,”
Num = Num.replace(/ /g, "") //替换tomoney()中的空格
Num = Num.replace(/¥/g, "") //替换掉可能出现的¥字符
if (isNaN(Num)) { //验证输入的字符是否为数字
//alert("请检查小写金额是否正确");
return "";
};
//字符处理完毕后开始转换,采用前后两部分分别转换
var part = String(Num).split(".");
var newchar = "";
//小数点前进行转化
for (var i = part[0].length - 1; i >= 0; i--) {
if (part[0].length > 10) {
return "";
//若数量超过拾亿单位,提示
}
var tmpnewchar = ""
var perchar = part[0].charAt(i);
switch (perchar) {
case "0":
tmpnewchar = "零" + tmpnewchar;
break;
case "1":
tmpnewchar = "壹" + tmpnewchar;
break;
case "2":
tmpnewchar = "贰" + tmpnewchar;
break;
case "3":
tmpnewchar = "叁" + tmpnewchar;
break;
case "4":
tmpnewchar = "肆" + tmpnewchar;
break;
case "5":
tmpnewchar = "伍" + tmpnewchar;
break;
case "6":
tmpnewchar = "陆" + tmpnewchar;
break;
case "7":
tmpnewchar = "柒" + tmpnewchar;
break;
case "8":
tmpnewchar = "捌" + tmpnewchar;
break;
case "9":
tmpnewchar = "玖" + tmpnewchar;
break;
}
switch (part[0].length - i - 1) {
case 0:
tmpnewchar = tmpnewchar + "元";
break;
case 1:
if (perchar != 0) tmpnewchar = tmpnewchar + "拾";
break;
case 2:
if (perchar != 0) tmpnewchar = tmpnewchar + "佰";
break;
case 3:
if (perchar != 0) tmpnewchar = tmpnewchar + "仟";
break;
case 4:
tmpnewchar = tmpnewchar + "万";
break;
case 5:
if (perchar != 0) tmpnewchar = tmpnewchar + "拾";
break;
case 6:
if (perchar != 0) tmpnewchar = tmpnewchar + "佰";
break;
case 7:
if (perchar != 0) tmpnewchar = tmpnewchar + "仟";
break;
case 8:
tmpnewchar = tmpnewchar + "亿";
break;
case 9:
tmpnewchar = tmpnewchar + "拾";
break;
}
var newchar = tmpnewchar + newchar;
}
//小数点之后进行转化
if (Num.indexOf(".") != -1) {
if (part[1].length > 2) {
// alert("小数点之后只能保留两位,系统将自动截断");
part[1] = part[1].substr(0, 2)
}
for (i = 0; i < part[1].length; i++) {
tmpnewchar = ""
perchar = part[1].charAt(i)
switch (perchar) {
case "0":
tmpnewchar = "零" + tmpnewchar;
break;
case "1":
tmpnewchar = "壹" + tmpnewchar;
break;
case "2":
tmpnewchar = "贰" + tmpnewchar;
break;
case "3":
tmpnewchar = "叁" + tmpnewchar;
break;
case "4":
tmpnewchar = "肆" + tmpnewchar;
break;
case "5":
tmpnewchar = "伍" + tmpnewchar;
break;
case "6":
tmpnewchar = "陆" + tmpnewchar;
break;
case "7":
tmpnewchar = "柒" + tmpnewchar;
break;
case "8":
tmpnewchar = "捌" + tmpnewchar;
break;
case "9":
tmpnewchar = "玖" + tmpnewchar;
break;
}
if (i == 0) tmpnewchar = tmpnewchar + "角";
if (i == 1) tmpnewchar = tmpnewchar + "分";
newchar = newchar + tmpnewchar;
}
}
//替换所有无用汉字
while (newchar.search("零零") != -1)
newchar = newchar.replace("零零", "零");
newchar = newchar.replace("零亿", "亿");
newchar = newchar.replace("亿万", "亿");
newchar = newchar.replace("零万", "万");
newchar = newchar.replace("零元", "元");
newchar = newchar.replace("零角", "");
newchar = newchar.replace("零分", "");
if (newchar.charAt(newchar.length - 1) == "元") {
newchar = newchar + "整"
}
return newchar;
}
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
- 02
- Node与GLIBC_2.27不兼容解决方案08-19
- 03
- Git清空本地文件跟踪缓存08-13