1. 事件
onclick //左键点击
oncontextmenu //右键点击
onmouseover //鼠标移入 (冒泡,每次悬停触发一次)
onmousemove //鼠标移动 (每次移动都触发)
onmouseout //鼠标移出
onmousedown //鼠标在元素上按下
onmouseup //鼠标在元素上弹起
onmouseenter //鼠标移入 (不冒泡)
onmouseleave //鼠标移出 (不冒泡)
ondbclick //鼠标双击
onchange //内容改变
onfocus //获取焦点
onblur //失去焦点
ontimeupdate //媒体元素播放时间改变
2. 变量
var num = 10;
typeof: //判断变量的数据类型
Number //数值型
String //字符型
Boolean //布尔值
Array //数组
Object //对象
null //空值
undefined //未定义
//js 内置变量
top
parent
3. 数据类型转换
//转成 number
Number(str) //string -> number
Number(true) //boolean -> number (true:1 false:0)
parseInt(str) //string -> number (不保留小数)
parseFloat(str) //string -> number (保留小数)
//转成 string
String(val) // -> string (包含null和undefined)
.toString() //number -> string (null和undefined时报错)
String.charCodeAt(ascii) //ascii -> string
JSON.stringify //json -> string
JSON.parent(str) //string -> json (必须符合json格式)
//转成 bool
Boolean(val) // 0/NaN/null/undefined -> false
4. 获取节点
document.getElementById('app') //通过id获取
document.getElementsByClassName('box') //通过类名获取
document.getElementsByTagName('div') //通过标签名获取
document.querySelector('.box') //获取符合条件的第一个
document.querySelectorAll('.box') //获取所有符合条件的
5. 设置节点内容
var app = document.getElementById('app');
app.innerHTML //获取节点html格式文本
app.innerText //获取节点纯文本
app.innerHTML = '<h2>hello</h2>' //设置节点html格式文本
app.innerText = '<h2>hello</h2>' //设置节点纯文本 (不解析标签,原样输出)
//获取 设置样式
app.style.width //获取宽
app.style.fontSize //获取字体大小 (驼峰式写法)
input[0].getAttribute('type') //获取属性值 (获取类型)
input[0].className //获取类名
input[0].className = 'box' //设置类名
var input = document.getElementsByTagName('input');
input[0].value //获取表单节点输入内容
input[0].value = 'admin' //设置表单输入框内容
input[0]["type"] //获取属性
input[0]["type"] = 'checkbox' //设置属性
节点滚动
// 父节点滚动到指定位置
[pdom].scrollTo({
left: 100,
behavior: 'smooth'
});
// 使指定子节点显示在可视区域内容
[cdom].scrollIntoView({ behavior: 'smooth' });
6. 方法
1. Array 数组
arr.concat(arr2) //合并数组,返回新数组
arr.length //获取数组长度,返回长度
arr.push(val1) //数组尾部追加内容
arr.unshift(val1) //数组头部添加内容
arr.pop() //删除数组最后一个元素,返回删除的元素
arr.reverse() //数组反序输出
arr.toString() //将数组拼接成一个字符串
arr.splice(start, num, val1) //数组操作 (1:开始位置 2:数量 3:值)
arr.slice(start, num) //数组截取 (1:开始位置 2:数量)
arr.indexOf(str) //查找数组指定元素,返回索引
arr.lastIndexOf(str) //反向查找数组指定元素,返回索引
arr.includes(str) //在数组中查找元素,返回true/false
arr.join("-") // 将数组的元素合并成一个字符串,用指定字符分割
arr.find((val, index, arr) => { // 查找第一个符合条件的元素,返回
return val > 10;
})
arr.findIndex((val, index, arr) => { // 与find()类似,返回下标
return val > 10;
})
arr.falt(Infinity) // 返回一维数组 [1,2,3,4],参数为 Infinity,表示无论几层,都转成一维数组
// 不兼容所有浏览器
arr.fill(val, statrt, end) // 填充一个数组(覆盖一个数组)(1.填充的值 2.开始填充的位置 3.结束填充的位置)
arr.toString().split(',') // 数组扁平化 返回的元素是String
Array.of(10,20,30) // 转成数组,创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型
// (有几个参数就有几个数组元素)
Array.from() // 转成数组,从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例
// (尽量还原数组,浅拷贝)
sort 排序
let arr = [
{ id: 15, name: "a" },
{ id: 12, name: "b" },
{ id: 13, name: "c" },
{ id: 2, name: "d" },
{ id: 5, name: "e" }
]
// 普通用法
arr.sort()
// 升级用法
let result = arr.sort((a, b) => {
return a.id - b.id
})
2. Object 对象
delete obj["key"]; // 删除对象属性
Object.keys(obj).length // 获取对象长度
Object.is(obj1, obj2) // 比较两个对象是否相等
Object.assign(obj, obj1, obj2) // 合并对象,返回第一个对象
Object.prototype.toString.call(123) // 判断数据类型 例:[object Number]
obj.hasOwnProperty("a") // 判断对象上是否有指定属性
extend 合并对象
// 1.是否深拷贝 2.参数1 3.参数2...
function extend(){
let deep = false
let newObj = {}
let i = 1
if(typeof arguments[0] === 'boolean'){
i++
deep = arguments[0]
}
newObj = arguments[i - 1]
for(; i<arguments.length; i++){
for(let key in arguments[i]){
let copy = arguments[i][key]
if(deep && newObj[key] && typeof copy === 'object'){
newObj[key] = extend(newObj[key], copy)
} else {
newObj[key] = copy
}
}
}
return newObj
}
let result = extend(false, obj1, obj2, obj3, obj4)
2. Date 日期/时间
// 获取时间戳
var date = new Date();
date.getTime() //时间戳
date.valueOf() //时间戳
Number(date) //时间戳
+date //时间戳
Date.parse(date) //时间戳
var date = new Date();
date.getFullYear() //年份 (2020)
date.getMonth() //月份 (5+1 -- 比实际月份少1)
date.getDate() //日 (14)
date.getHours() //时
date.getMinutes() //分
date.getSeconds() //秒
date.getMilliseconds() //毫秒
* date.toLocaleString() //格式化字符串 (2020-6-14 21:13:15)
date.toString() //时间转成字符串 (Sun Jun 14 2020 21:12:21 GMT+0800 (GMT+08:00))
date.toLocaleDateString() //日期部分 (2020-6-14)
date.toLocaleTimeString() //时间部分 (21:15:11)
3. Math 数学 -> es6
Math.abs(-10) //绝对值 (10)
Math.pow(2, 31) //取幂值 (次方2^31)
Math.ceil(1.1) //向上取整 (2)
Math.floor(1.9) //向下取整 (1)
Math.max(1,2,3) //取最大值 (3)
Math.min(1,2,3) //取最小值 (1)
Math.random() //取随机数 (0~1的小数)
Math.floor(Math.random()*10) //随机数 (0-9的整数)
Math.floor(Math.random()*(max-min+1)+min) //随机数 (最大值到最小值的整数)
Math.round(1.5) //四舍五入M
Math.cbrt(1) //立方根
[num].toFixed(n) //小数点后保留 n 位
Number.isNaN("15") //检查值是否为数字
Number.isIntEger() //判断一个数是否为整数,返回true/false(如果精度要求,不适用)
Math.trunc(5.5) //去除小数,保留整数 => 5
Math.sign(5) //判断数值类型 正数:+1 负数:-1 0:0 -0:-0 其他值:NaN
[number] | 0 //按位或取整,数字取整(类型可以是int或string) (201.56 | 0 => 201)
4. String 字符串
str.charAt(n) //取第 n 个字符
str.charCodeAt(n) //取第 n 个字符的ascii码
str.concat("789") //连接字符串
str.length //字符串长度
str.split(" ") //分割字符串,返回数组
str.replace("a","0") //替换字符串 (用 0 替换str中的所有 a)
str.toLocaleLowerCase() //字符串全部转小写
str.toLocaleUpperCase() //字符串全部转大写
str.toLowerCase() //字符串全部转小写
str.toUpperCase() //字符串全部转大写
// 查找字符串
str.slice(start, end) //查找字符串 [开始下标,结束下标] (不包含结束下标)
str.lastIndexOf('l') //反向查找,返回正向下标
str.substring(start, end) //同 slice
str.substr(start, lenth) //查找字符串 [开始下标,长度]
//
str.includes("o", [查找位置]) //查找字符串是否存在,返回ture/false
str.startWith("he", [查找位置]) //查找字符串是否在原字符串的头部,返回true/false
str.endsWith("world", [查找位置]) //与 startWith 相似,判断是否在尾部,返回true/false
str.indexOf("a") //查找指定字符或字符串,返回字符下标
str.search("a") //类似于indexOf,但可以使用 正则
str.repeat(5) //将原字符串重复5次,形成新字符串(参数是小数,向下取整; 参数是负数,报错)
str.padStart(5,"0") //字符串长度不足时,用“0”在前面补全
str.padEnd(5,"0") //字符串长度不足时,用“0”在后面补全
str.trimStart() //清除字符串头部空格
str.trimEnd() //清除字符串尾部空格
5. RegExp 正则
var pattern = /[0-9]/; //正则表达式
var str = "1a2s3d4f5g" //字符串
var reg = new RegExp(pattern,"g") //正则对象 (g -> 全局匹配)
var s = str.match(reg) //匹配文本
console.log(s); //返回数字
// 正则表达式
[\u4E00-\u9FA5]+ // 汉字
1(5|8|3)(\d){9} // 手机号
(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8} // 手机号
\d.+\d.+\d.+\d // ip地址
6. JSON
JSON.parse(jsonarr) //string 转 json
JSON.stringify(jsonobj) //json 转 string
7. 编码
encodeURI() //编码
decodeURI() //解码
8. document
document.execCommand("copy") // 浏览器的复制功能
7. 循环
//for 循环
var arr = [10,20,30,40,50]
for (var i=0; i<arr.length; i++) {
console.log(arr[i]);
}
//ES6:for...of 遍历数组
var arr = [10,20,30,40,50]
for (var item of arr) {
console.log(item);
}
// result: 10 20 30 40 50 (item就是每一个元素)
// keys() 遍历数组 键
for (var index of arr.key() {
console.log(index);
}
// values() 遍历数组 值
for (var value of arr.key() {
console.log(value);
}
// entries() 遍历数组 键值对
for (var [index, value] of arr.entries) {
console.log(index value);
}
//while 循环
var arr = [1,2,3,4,5]
var i=0;
while(i<arr.length) {
console.log(arr[i]);
i++;
}
//do...while 循环
var arr = [1,2,3,4,5]
var i=0;
do{
console.log(arr[i]);
i++;
}while(i<arr.length)
8. 操作节点
var el = document.createElement('p') //创建一个标签节点
var text = document.createTextNode('string') //创建一个文本节点
el.appendChild(text) //在标签节点中插入文本节点
el.className = "box" //设置节点的属性
parentEl.appendChild(el) //在已有元素中插入节点
var el = document.createElement('p') //创建一个节点
el.innerHTML = "<mark>hello</mark>" //在节点中插入内容
el.className = "box" //设置节点的属性
parentEl.appendChild(el) //插入到父元素
1. 创建节点
document.createElement('p') //创建 标签节点
document.createTextNode('string') //创建 文本节点
2. 插入
父元素.appendChild("节点") //将新建节点追加到父元素尾部
父元素.insertBefore("节点", "位置") //将新建节点插入到父元素指定位置
3. 删除
父元素.removeChild("节点") //删除指定节点
4. 获取
父元素.childNodes //获取父元素的所有节点,返回节点数组
父元素.childNodes[n].nodeType //获取第 n 个节点的类型,返回 1:标签节点 3:文本节点
父元素.firstChild //获取第一个任意元素
父元素.lastChild //获取最后一个任意元素
父元素.firstElementChild //获取第一个子节点元素
父元素.lastElementChild //获取最后一个子节点元素
节点.nextElementSibling //同级元素的下一个节点
节点.previousElementSibling //同级元素的上一个节点
9. Ajax 数据请求
function ajax(){
if (window.XMLHttpRequest) {
var ajax = new XMLHttpRequest(); //chrome
} else {
var ajax = new ActiveXObject("Microsoft.XMLHTTP"); //IE
}
// 连接服务器
ajax.open('GET', url, true); //true:异步 false:同步
// 发送请求
ajax.send();
// 接收响应信息
ajax.onreadystatechange = function(){
if (ajax.readyState===4 && ajax.status===200) {
console.log("请求成功");
} else {
console.log("请求失败");
}
}
}
10. 数组迭代 遍历
1. forEach
遍历数组
var arr = [1,2,3,4,5]
arr.forEach((val,index)=>{
console.log(index,val);
})
2. map
遍历数组,返回新数组
var arr = [1,2,3,4,5]
var newArr = arr.map((val,index)=>{
return val*10
})
console.log(newArr);
3. filter
过滤数组,返回符合条件的数组
var arr = [1,2,3,4,5]
var newArr = arr.filter((val,index)=>{
return val<=3
})
console.log(newArr);
4. reduce
遍历数组,相邻元素进行计算 (可以相加,可以相乘。。。)
var arr = [1,2,3,4,5]
var newArr = arr.reduce((val1,val2)=>{
return val1*val2
})
console.log(newArr);
5. every
遍历数组,检查数组每一项是否都符合条件,返回true / false
var arr = [1,2,3,4,5]
var bool = arr.every((val,index)=>{
return val!==0
})
console.log(bool);
6. some
遍历数组,检查是否有符合条件的,有就返回 true
var arr = [1,2,3,4,5]
var bool = arr.some((val,index)=>{
return val===0
})
console.log(bool);
11. 获取表格节点
表格节点.tHead //获取表头
表格节点.tBodies //获取所有表格主体
表格节点.tFoot //获取表格尾部
表格节点.rows //获取所有行 (tr)
表格节点.cells //获取所有单元格 (td)
12. 获取盒模型
1. client (客户区 / 可视区)
app.clientWidth //宽 (宽 + 内边距)
app.clientHeight //高 (高 + 内边距)
app.clientLeft //左边边框的宽度 (border-left-width)
app.clientTop //上边边框的宽度 (border-top-width)
2. scroll (滚动条 / 卷曲)
app.scrollWidth //全部宽度 (包括内边距和外边距)
app.scrollHeight //全部高度 (包括内边距和外边距)
app.scrollLeft //距离左边的位置
app.scrollTop //距离上边的位置
3. offset (文档 / 元素本身)
app.offsetWidth //宽度 (没有外边距)
app.offsetHeight //高度 (没有外边距)
app.offsetLeft //带有定位的 距离左边的长度
app.offsetTop //带有定位的 距离上边的长度
app.offsetParent //距离定位父元素的 长度
4. 距离屏幕的位置
app.getBoundingClientRect().left //距离屏幕左边的长度 (定位和外边距)
app.getBoundingClientRect().right //距离屏幕右边的长度
app.getBoundingClientRect().top //距离屏幕上边的长度
app.getBoundingClientRect().bottom //距离屏幕下边的长度
5. 屏幕分辨率
window.screen.width
window.screen.height
13. 懒加载
页面加载时,先加载可视区的图片
<img _src="./img/bg/jpg" alt="" >
var oImg = document.getElementByTagName('img')[0];
var url = oImg.getAttribute('_src');
setTimeout(function(){
oImg.src = url;
}, 200)
14. Event
// 获取事件类型
function func(){
var type = ev.type;
console.log(type);
}
// 点击事件属性
ev.clientX //在可视区的点击位置
ev.clientY
ev.pageX //在body的点击位置
ev.pageY
ev.screenX //在显示器的点击位置
ev.screenY
15. 绑定事件
0级绑定事件:带on的
btn.onClick = function(){
console.log("click 事件");
}
btn.onmouseover = function(){
console.log("mouseover 事件");
}
......
2级绑定事件
// 事件绑定: 1.事件类型 2.事件函数 3.是否在捕获或冒泡阶段执行(true-捕获,false-冒泡)
btn.addEventListener('click', function(){
console.log("addEventListener 绑定事件");
}, true)
16. 默认事件 / 事件冒泡
1. 默认事件:浏览器右键点击出现菜单。。。
// 方法一:ev.preventDefault();
document.oncontextmenu = function(ev){
ev.preventDefault();
console.log("ev");
}
// 方法二:return false;
document.oncontextmenu = function(){
console.log("ev");
return false;
}
2. 事件冒泡:里层元素事件作用到外层元素上
<!-- ev.stopPropagation()阻止事件冒泡 -->
<body>
<div id="app"> </div>
<script>
var el = document.getElementById('app');
el.onclick = function(ev){
ev.stopPropagation();
console.log('app');
}
document.onclick = function(){
console.log("body");
}
</script>
</body>
3. 键盘事件
window.onkeydown = function(ev){
console.log(ev.key); //ev.key:按下得键盘 按键
console.log(ev.keyCode); //ev.keyCode:按下得键盘码
console.log("ctrl:",ev.ctrlKey); //ctrl, alt, sgift 是否按下
console.log("alt:",ev.altKey); // 按下为true,未按下为false
console.log("shift:",ev.shiftKey);
}
4. 滚轮事件
// 获取滚轮值:上滚返回120,下滚返回-120
window.onmousewheel = function(ev){
console.log(ev.wheelDelta);
}
17. 面向对象
1. 封装
封装函数,方法。把函数封装成函数使用,在任意地方使用
2. 继承
- 基类也叫父类,子类也叫派生类,子类中可以使用父类得某些属性和方法,子类是父类功能得扩展
- 如果继承关系复杂时,比如多个类之间都存在继承关系,那么当使用某一个类时,要把这几个联系在一起的类一同使用
3. 多态
重载。同一个接口,不同类型调用,实现不同的功能
4. typeof
判断基本数据类型
5. instanceof
判断实例或对象
18. 改变 this 指向
**this:**使用function
时指向的是触发事件本身,使用 箭头函数 时指向的是上一层,如果没有,指向的是window
// 改变this指向
element.call(obj, [参数1], [参数2])
element.apply(obj, [参数1], [参数2])
element.bind(obj, [参数1], [参数2])
19. 原型
- prototype:类的属相,原型
- constructor:js内置属性,指向本身
__proto__
:指向当前实例的原型
20. ES6: set()
const s = new Set(); //s.add(1).add(2).add(3) => 链式操作
s.add(1); //添加
s.delete(1); //删除
s.has(1); //是否存在 true/false
21. ES6: map()
const m = new Map();
m.set("key","value"); //添加,添加时注意key和value,都要写
m.get("key"); //获取
m.has("key"); //是否存在 true/false
m.delete("key"); //删除
m.clear(); //清空
遍历map
for(let [key,value] of m){
console.log(key,value);
}
22. 页面禁用回退按钮
消除 后退的所有动作。包括 键盘、鼠标手势等产生的后退动作
// 禁用回退按钮 (vue登录页 例)
mounted() {
// 登录页 : 禁用回退按钮
if(this.$route.name === "login"){
history.pushState(null, null, document.URL);
window.addEventListener("popstate", function () {
history.pushState(null, null, document.URL);
});
}
}
23. 失去焦点,页面回到顶部
// 输入框失去焦点,页面滑动到顶部
inpurBlur(){
setTimeout(function (){
document.body.scrollTop = 0;
},200);
},
inputOnFocus(e) {
setTimeout(function (){
e.target.scrollIntoView(true); // 让当前的元素滚动到浏览器窗口的可视区域内
},200); // 延时 == 键盘弹起需要时间
}
24. 数组长度报错
Cannot read property ‘length’ of undefined
后台在返回数据时是需要时间的 不管多快 都是需要时间的 但是在初始化时,并没有给一个空的数组 注意 是数组形式 所以当调用 .length 方法时 这时后台数据还没有返回回来 此时它不是数组 就会报错
方法:
同时判断数组的布尔值 和 数组的长度
25. 获取电脑用户唯一标识
<script src="https://cdn.staticfile.org/fingerprintjs2/2.1.0/fingerprint2.min.js"></script>
var pcid = "";
Fingerprint2.get(function (components) {
// 参数
const values = components.map(function (component) {
return component.value
});
// 指纹
pcid = Fingerprint2.x64hash128(values.join(''), 31);
_YS.userConfig = {
author: pcid
};
});
26. 表格导出到Excel
npm install --save file-saver xlsx
npm install --save script-loader
blob.js
(function (view) {
"use strict";
view.URL = view.URL || view.webkitURL;
if (view.Blob && view.URL) {
try {
new Blob;
return;
// eslint-disable-next-line no-empty
} catch (e) {}
}
let BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function (view) {
let get_class = function (object) {
return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
}
, FakeBlobBuilder = function BlobBuilder() {
this.data = [];
}
, FakeBlob = function Blob(data, type, encoding) {
this.data = data;
this.size = data.length;
this.type = type;
this.encoding = encoding;
}
, FBB_proto = FakeBlobBuilder.prototype
, FB_proto = FakeBlob.prototype
, FileReaderSync = view.FileReaderSync
, FileException = function (type) {
this.code = this[this.name = type];
}
, file_ex_codes = (
"NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
+ "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
).split(" ")
, file_ex_code = file_ex_codes.length
, real_URL = view.URL || view.webkitURL || view
, real_create_object_URL = real_URL.createObjectURL
, real_revoke_object_URL = real_URL.revokeObjectURL
, URL = real_URL
, btoa = view.btoa
, atob = view.atob
, ArrayBuffer = view.ArrayBuffer
, Uint8Array = view.Uint8Array
;
FakeBlob.fake = FB_proto.fake = true;
while (file_ex_code--) {
FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
}
if (!real_URL.createObjectURL) {
URL = view.URL = {};
}
URL.createObjectURL = function (blob) {
var
type = blob.type
, data_URI_header
;
if (type === null) {
type = "application/octet-stream";
}
if (blob instanceof FakeBlob) {
data_URI_header = "data:" + type;
if (blob.encoding === "base64") {
return data_URI_header + ";base64," + blob.data;
} else if (blob.encoding === "URI") {
return data_URI_header + "," + decodeURIComponent(blob.data);
} if (btoa) {
return data_URI_header + ";base64," + btoa(blob.data);
} else {
return data_URI_header + "," + encodeURIComponent(blob.data);
}
} else if (real_create_object_URL) {
return real_create_object_URL.call(real_URL, blob);
}
};
URL.revokeObjectURL = function (object_URL) {
if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
real_revoke_object_URL.call(real_URL, object_URL);
}
};
FBB_proto.append = function (data/*, endings*/) {
let bb = this.data;
// decode data to a binary string
if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
let str = ""
, buf = new Uint8Array(data)
, i = 0
, buf_len = buf.length
;
for (; i < buf_len; i++) {
str += String.fromCharCode(buf[i]);
}
bb.push(str);
} else if (get_class(data) === "Blob" || get_class(data) === "File") {
if (FileReaderSync) {
let fr = new FileReaderSync;
bb.push(fr.readAsBinaryString(data));
} else {
// async FileReader won't work as BlobBuilder is sync
throw new FileException("NOT_READABLE_ERR");
}
} else if (data instanceof FakeBlob) {
if (data.encoding === "base64" && atob) {
bb.push(atob(data.data));
} else if (data.encoding === "URI") {
bb.push(decodeURIComponent(data.data));
} else if (data.encoding === "raw") {
bb.push(data.data);
}
} else {
if (typeof data !== "string") {
data += ""; // convert unsupported types to strings
}
// decode UTF-16 to binary string
bb.push(unescape(encodeURIComponent(data)));
}
};
FBB_proto.getBlob = function (type) {
if (!arguments.length) {
type = null;
}
return new FakeBlob(this.data.join(""), type, "raw");
};
FBB_proto.toString = function () {
return "[object BlobBuilder]";
};
FB_proto.slice = function (start, end, type) {
var args = arguments.length;
if (args < 3) {
type = null;
}
return new FakeBlob(
this.data.slice(start, args > 1 ? end : this.data.length)
, type
, this.encoding
);
};
FB_proto.toString = function () {
return "[object Blob]";
};
FB_proto.close = function () {
this.size = this.data.length = 0;
};
return FakeBlobBuilder;
}(view));
view.Blob = function Blob(blobParts, options) {
var type = options ? (options.type || "") : "";
var builder = new BlobBuilder();
if (blobParts) {
for (let i = 0, len = blobParts.length; i < len; i++) {
builder.append(blobParts[i]);
}
}
return builder.getBlob(type);
};
}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this));
Export2Excel.js
/* eslint-disable */
require('script-loader!file-saver');
require('./blob');
require('script-loader!xlsx/dist/xlsx.core.min');
function generateArray(table) {
var out = [];
var rows = table.querySelectorAll('tr');
var ranges = [];
for (var R = 0; R < rows.length; ++R) {
var outRow = [];
var row = rows[R];
var columns = row.querySelectorAll('td');
for (var C = 0; C < columns.length; ++C) {
var cell = columns[C];
var colspan = cell.getAttribute('colspan');
var rowspan = cell.getAttribute('rowspan');
var cellValue = cell.innerText;
if (cellValue !== "" && cellValue == +cellValue) cellValue = +cellValue;
//Skip ranges
ranges.forEach(function (range) {
if (R >= range.s.r && R <= range.e.r && outRow.length >= range.s.c && outRow.length <= range.e.c) {
for (var i = 0; i <= range.e.c - range.s.c; ++i) outRow.push(null);
}
});
//Handle Row Span
if (rowspan || colspan) {
rowspan = rowspan || 1;
colspan = colspan || 1;
ranges.push({s: {r: R, c: outRow.length}, e: {r: R + rowspan - 1, c: outRow.length + colspan - 1}});
}
;
//Handle Value
outRow.push(cellValue !== "" ? cellValue : null);
//Handle Colspan
if (colspan) for (var k = 0; k < colspan - 1; ++k) outRow.push(null);
}
out.push(outRow);
}
return [out, ranges];
};
function datenum(v, date1904) {
if (date1904) v += 1462;
var epoch = Date.parse(v);
return (epoch - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
}
function sheet_from_array_of_arrays(data, opts) {
var ws = {};
var range = {s: {c: 10000000, r: 10000000}, e: {c: 0, r: 0}};
for (var R = 0; R != data.length; ++R) {
for (var C = 0; C != data[R].length; ++C) {
if (range.s.r > R) range.s.r = R;
if (range.s.c > C) range.s.c = C;
if (range.e.r < R) range.e.r = R;
if (range.e.c < C) range.e.c = C;
var cell = {v: data[R][C]};
if (cell.v == null) continue;
var cell_ref = XLSX.utils.encode_cell({c: C, r: R});
if (typeof cell.v === 'number') cell.t = 'n';
else if (typeof cell.v === 'boolean') cell.t = 'b';
else if (cell.v instanceof Date) {
cell.t = 'n';
cell.z = XLSX.SSF._table[14];
cell.v = datenum(cell.v);
}
else cell.t = 's';
ws[cell_ref] = cell;
}
}
if (range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range);
return ws;
}
function Workbook() {
if (!(this instanceof Workbook)) return new Workbook();
this.SheetNames = [];
this.Sheets = {};
}
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
return buf;
}
export function export_table_to_excel(id) {
var theTable = document.getElementById(id);
console.log('a')
var oo = generateArray(theTable);
var ranges = oo[1];
/* original data */
var data = oo[0];
var ws_name = "SheetJS";
console.log(data);
var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
/* add ranges to worksheet */
// ws['!cols'] = ['apple', 'banan'];
ws['!merges'] = ranges;
/* add worksheet to workbook */
wb.SheetNames.push(ws_name);
wb.Sheets[ws_name] = ws;
var wbout = XLSX.write(wb, {bookType: 'xlsx', bookSST: false, type: 'binary'});
saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), "test.xlsx")
}
function formatJson(jsonData) {
console.log(jsonData)
}
export function export_json_to_excel(th, jsonData, defaultTitle) {
/* original data */
var data = jsonData;
data.unshift(th);
var ws_name = "SheetJS";
var wb = new Workbook(), ws = sheet_from_array_of_arrays(data);
/* add worksheet to workbook */
wb.SheetNames.push(ws_name);
wb.Sheets[ws_name] = ws;
var wbout = XLSX.write(wb, {bookType: 'xlsx', bookSST: false, type: 'binary'});
var title = defaultTitle || '列表'
saveAs(new Blob([s2ab(wbout)], {type: "application/octet-stream"}), title + ".xlsx")
}
util / index.js
export const export2Excel = (columns, list, name) => {
require.ensure([], () => {
const { export_json_to_excel } = require('./excel/Export2Excel');
let tHeader = [];
let filterVal = [];
columns.forEach(item => {
tHeader.push(item); // 表头值
});
for (let key in list[0]) {
filterVal.push(key); // 表头键
}
const data = list.map(v => filterVal.map(j => v[j]));
export_json_to_excel(tHeader, data, name); // excel表名称
});
};
26.1 导入Excel数据
npm install vue-xlsx-table --save
import vueXlsxTable from 'vue-xlsx-table';
Vue.use(vueXlsxTable, {rABS: false});
<template>
<div id="app">
<vue-xlsx-table @on-select-file="handleSelectedFile"></vue-xlsx-table>
</div>
</template>
<script>
export default {
name: 'app',
methods: {
handleSelectedFile (convertedData) {
console.log(convertedData)
}
}
}
</script>
27. 导出生成pdf
npm install --save html2canvas
npm install jspdf --save
创建 htmlToPdf.js
import html2Canvas from 'html2canvas';
import JsPDF from 'jspdf';
const htmlToPdf = (Vue) => {
Vue.prototype.$getPdf = function () {
var title = this.htmlTitle;
html2Canvas(document.querySelector('#pdfDom'), {
allowTaint: true
}).then(function (canvas) {
let contentWidth = canvas.width;
let contentHeight = canvas.height;
let pageHeight = contentWidth / 592.28 * 841.89;
let leftHeight = contentHeight;
let position = 0;
let imgWidth = 595.28;
let imgHeight = 592.28 / contentWidth * contentHeight;
let pageData = canvas.toDataURL('image/jpeg', 1.0);
let PDF = new JsPDF('', 'pt', 'a4');
if (leftHeight < pageHeight) {
PDF.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);
} else {
while (leftHeight > 0) {
PDF.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight);
leftHeight -= pageHeight;
position -= 841.89;
if (leftHeight > 0) {
PDF.addPage();
}
}
}
PDF.save(title + '.pdf');
});
};
};
export default {
htmlToPdf
};
在 main.js 中引入注册
import htmlToPdf from 'htmlToPdf.js';
Vue.use(htmlToPdf);
创建 index.vue 使用生成pdf的方法
<template>
<div class="content" @contextmenu.prevent>
<!-- 模板 -->
<div id="pdfDom">
<h1 class="title">hello world</h1>
</div>
<!-- 下载 -->
<button class="button" @click="download">download</button>
</div>
</template>
<script>
export default {
props: {},
data() {
return {
htmlTitle: "个人信息", // 生成的pdf文件名
};
},
methods: {
download(){
// 生成pdf的方法
this.$getPdf();
},
},
};
</script>
28. 字符串加密
// 字符串加密
const compile: (code) => {
var c = String.fromCharCode(code.charCodeAt(0) + code.length);
for(let i = 1; i < code.length; i++){
c += String.fromCharCode(code.charCodeAt(i) + code.charCodeAt(i - 1));
}
return escape(c);
};
29. 字符串解密
// 字符串解密
const uncompile: (code) => {
code = unescape(code);
let c = String.fromCharCode(code.charCodeAt(0) - code.length);
for(let i = 1; i < code.length; i++){
c += String.fromCharCode(code.charCodeAt(i) - c.charCodeAt(i - 1));
}
return c;
};
30. 特殊功能
<input type=button value=导入收藏夹 onclick="window.external.ImportExportFavorites(true,'http://localhost');">
<input type=button value=导出收藏夹 onclick="window.external.ImportExportFavorites(false,'http://localhost');">
<input type=button value=整理收藏夹 onclick="window.external.ShowBrowserUI('OrganizeFavorites', null)">
<input type=button value=语言设置 onclick="window.external.ShowBrowserUI('LanguageDialog', null)">
<input type=button value=加入收藏夹 onclick="window.external.AddFavorite('http://www.google.com/', 'google')">
<input type=button value=加入到频道 onclick="window.external.addChannel('http://www.google.com/')">
<input type=button value=加入到频道 onclick="window.external.showBrowserUI('PrivacySettings',null)">
31. <meta>功能
不缓存
<META HTTP-EQUIV="pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<META HTTP-EQUIV="expires" CONTENT="0">
页面进入特效
进入页面 <meta http-equiv="Page-Enter" content="revealTrans(duration=x, transition=y)">
推出页面 <meta http-equiv="Page-Exit" content="revealTrans(duration=x, transition=y)">
这个是页面被载入和调出时的一些特效。duration表示特效的持续时间,以秒为单位。transition表示使
用哪种特效,取值为1-23:
0 矩形缩小
1 矩形扩大
2 圆形缩小
3 圆形扩大
4 下到上刷新
5 上到下刷新
6 左到右刷新
7 右到左刷新
8 竖百叶窗
9 横百叶窗
10 错位横百叶窗
11 错位竖百叶窗
12 点扩散
13 左右到中间刷新
14 中间到左右刷新
15 中间到上下
16 上下到中间
17 右下到左上
18 右上到左下
19 左上到右下
20 左下到右上
21 横条
22 竖条
网页是否被检索
//网页是否被检索 <meta name="ROBOTS" content="属性值">
其中属性值有以下一些:
属性值为"all": 文件将被检索,且页上链接可被查询;
属性值为"none": 文件不被检索,而且不查询页上的链接;
属性值为"index": 文件将被检索;
属性值为"follow": 查询页上的链接;
属性值为"noindex": 文件不检索,但可被查询链接;
属性值为"nofollow":
页面自动刷新
<meta http-equiv="Refresh" content="30" />
<meta http-equiv="Refresh" content="5; url=子任-专注网站前端开发技术和UEO实战技能" />
34. 下载文件
function DownURL(strRemoteURL,strLocalURL)
{
try
{
var xmlHTTP=new ActiveXObject("Microsoft.XMLHTTP");
xmlHTTP.open("Get",strRemoteURL,false);
xmlHTTP.send();
var adodbStream=new ActiveXObject("ADODB.Stream");
adodbStream.Type=1;//1=adTypeBinary
adodbStream.Open();
adodbStream.write(xmlHTTP.responseBody);
adodbStream.SaveToFile(strLocalURL,2);
adodbStream.Close();
adodbStream=null;
xmlHTTP=null;
}
catch(e)
{
window.confirm("下载URL出错!");
}
//window.confirm("下载完成.");
}
//检验连接是否有效
function getXML(URL)
{
var xmlhttp = new ActiveXObject("microsoft.xmlhttp");
xmlhttp.Open("GET",URL, false);
try
{
xmlhttp.Send();
}
catch(e){}
finally
{
var result = xmlhttp.responseText;
if(result)
{
if(xmlhttp.Status==200)
{
return(true);
}
else
{
return(false);
}
}
else
{
return(false);
}
}
}
35. 打印页面
window.print()
36. 获取浏览器信息
navigator.appVersion // 浏览器的版本号
navigator.appName // 浏览器的名称
navigator.language // 浏览器使用的语言
navigator.platform // 浏览器使用的平台
navigator.userAgent // 浏览器的user-agent信息
37. 运行环境
// process.env.NODE_ENV
if(process.env.NODE_ENV === 'development'){
console.log("开发环境");
} else if(process.env.NODE_ENV === 'production'){
console.log("线上环境");
}
38. 滑动触底更新
const onScroll = () => {
// 总高度
let innerHeight = document.querySelector('#app').clientHeight;
// 客户区高度
let clientHeight = document.documentElement.clientHeight || document.body.clientHeight;
// 滚动高度
let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
// 客户区高度 + 滚动高度 >= 总高度
if (clientHeight + scrollTop >= innerHeight) {
console.log("到底了");
}
};
39. 单层数据整理成树形结构
let data = [
{ roleId: 1, name: "A", parentId: 0 },
{ roleId: 2, name: "B", parentId: 1 },
{ roleId: 3, name: "C", parentId: 1 },
{ roleId: 4, name: "D", parentId: 3 },
{ roleId: 5, name: "E", parentId: 4 },
]
console.log(setTreeData(data))
function setTreeData(arr) {
let map = {}; //构建map
arr.forEach(i => {
map[i.roleId] = i; //构建以id为键 当前数据为值
});
let treeData = [];
arr.forEach(item => {
const mapItem = map[item.parentId]; //判断当前数据的parentId是否存在map中,返回存在的数据
console.log(mapItem);
if (mapItem) {
//存在则表示当前数据不是最顶层的数据
//注意: 这里的map中的数据是引用了arr的它的指向还是arr,当mapItem改变时arr也会改变,踩坑点
(mapItem.children || (mapItem.children = [])).push(item); //这里判断mapItem中是否存在child
} else {
//不存在则是顶层数据
treeData.push(item);
}
});
return treeData;
}
40. 检测身份证号
isCardNo(num) {
num = num.toUpperCase();
//身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X。
if (!(/(^\d{15}$)|(^\d{17}([0-9]|X)$)/.test(num))) {
return false;
}
//校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
//下面分别分析出生日期和校验位
var len, re;
len = num.length;
if (len == 15) {
re = new RegExp(/^(\d{6})(\d{2})(\d{2})(\d{2})(\d{3})$/);
var arrSplit = num.match(re);
//检查生日日期是否正确
var dtmBirth = new Date('19' + arrSplit[2] + '/' + arrSplit[3] + '/' + arrSplit[4]);
var bCorrectDay;
bCorrectDay = (dtmBirth.getYear() == Number(arrSplit[2])) && ((dtmBirth.getMonth() + 1) == Number(arrSplit[3])) &&
(
dtmBirth.getDate() == Number(arrSplit[4]));
if (!bCorrectDay) {
return false;
} else {
//将15位身份证转成18位
//校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
var arrInt = new Array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
var arrCh = new Array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
var nTemp = 0,
i;
num = num.substr(0, 6) + '19' + num.substr(6, num.length - 6);
for (i = 0; i < 17; i++) {
nTemp += num.substr(i, 1) * arrInt[i];
}
num += arrCh[nTemp % 11];
return true;
}
}
if (len == 18) {
re = new RegExp(/^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/);
var arrSplit = num.match(re);
//检查生日日期是否正确
var dtmBirth = new Date(arrSplit[2] + "/" + arrSplit[3] + "/" + arrSplit[4]);
var bCorrectDay;
bCorrectDay = (dtmBirth.getFullYear() == Number(arrSplit[2])) && ((dtmBirth.getMonth() + 1) == Number(arrSplit[3])) &&
(dtmBirth.getDate() == Number(arrSplit[4]));
if (!bCorrectDay) {
return false;
} else {
//检验18位身份证的校验码是否正确。
//校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
var valnum;
var arrInt = new Array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
var arrCh = new Array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
var nTemp = 0,
i;
for (i = 0; i < 17; i++) {
nTemp += num.substr(i, 1) * arrInt[i];
}
valnum = arrCh[nTemp % 11];
if (valnum != num.substr(17, 1)) {
return false;
}
return true;
}
}
return false;
}
41. 复制文本内容
let oInput = document.createElement('input');
oInput.value = "123456";
document.body.appendChild(oInput);
oInput.select();
document.execCommand("Copy");
oInput.className = 'oInput';
oInput.style.display = 'none';
42. 上传多张图片
*** 上传时参数不能序列化**
// state.imgList = [file, file, file];
let formData = new FormData();
if (state.imgList.length > 0) {
for (let i = 0; i < state.imgList.length; i++) {
formData.append('files', state.imgList[i].file)
}
}
formData.append("id", route.query.id);
formData.append("organizeId", userInfo.organizeId);
formData.append("schoolId", route.query.schoolId);
formData.append("remarks", state.submit.remarks);
43. 人脸拍照
<template>
<div>
<!--图片展示-->
<div class="video">
<video ref="video" width="100%" height="100%" autoplay></video>
</div>
<!--canvas截取流-->
<div class="video">
<canvas ref="canvas" width="200%" height="200%"></canvas>
<!-- <canvas ref="canvas" width="800%" height="800%"></canvas> -->
</div>
<!--确认-->
<el-button size="mini" type="primary" @click="callCamera">开启摄像头</el-button>
<el-button size="mini" type="primary" @click="closeCamera">关闭摄像头</el-button>
<el-button size="mini" type="primary" @click="photograph">拍照</el-button>
</div>
</template>
// 调用摄像头
callCamera() {
// H5调用电脑摄像头API
navigator.mediaDevices.getUserMedia({
video: true
}).then(success => {
// 摄像头开启成功
this.$refs['video'].srcObject = success
// 实时拍照效果
this.$refs['video'].play()
}).catch(error => {
console.error('摄像头开启失败,请检查摄像头是否可用!')
})
},
// 关闭摄像头
closeCamera() {
if (!this.$refs['video'].srcObject) return
let stream = this.$refs['video'].srcObject
let tracks = stream.getTracks()
tracks.forEach(track => {
track.stop()
})
this.$refs['video'].srcObject = null
},
// 拍照
photograph() {
let ctx = this.$refs['canvas'].getContext('2d')
// 把当前视频帧内容渲染到canvas上
ctx.drawImage(this.$refs['video'], 0, 0, 320, 400)
// ctx.drawImage(this.$refs['video'], 0, 0, 160, 200)
// 转base64格式、图片格式转换、图片质量压缩
let imgBase64 = this.$refs['canvas'].toDataURL('image/jpeg', 1)
// 由字节转换为KB 判断大小
let str = imgBase64.replace('data:image/jpeg;base64,', '')
let strLength = str.length
let fileLength = parseInt(strLength - (strLength / 8) * 2)
// 图片尺寸 用于判断
let size = (fileLength / 1024).toFixed(2)
console.log(size)
// 上传拍照信息 调用接口上传图片 .........
console.log("Base64", imgBase64);
// base64 转 文件流(file) *方法见 44
// let file = this.dataURLtoFile(imgBase64, "123.jpeg")
// console.log("file", file);
},
44. 图片格式转换
// canvas转dataURL:canvas对象、转换格式、图像品质
function canvasToDataURL(canvas, format, quality) {
return canvas.toDataURL(format||'image/jpeg', quality||1.0);
}
// DataURL转canvas
function dataURLToCanvas(dataurl, cb){
var canvas = document.createElement('CANVAS');
var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = function(){
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
cb(canvas);
};
img.src = dataurl;
}
// image转canvas:图片地址
function imageToCanvas(src, cb){
var canvas = document.createElement('CANVAS');
var ctx = canvas.getContext('2d');
var img = new Image();
img.src = src;
img.onload = function (){
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
cb(canvas);
};
}
// canvas转image
function canvasToImage(canvas){
var img = new Image();
img.src = canvas.toDataURL('image/jpeg', 1.0);
return img;
}
// File/Blob对象转DataURL
function fileOrBlobToDataURL(obj, cb){
var a = new FileReader();
a.readAsDataURL(obj);
a.onload = function (e){
cb(e.target.result);
};
}
// DataURL转Blob对象
function dataURLToBlob(dataurl){
var arr = dataurl.split(',');
var mime = arr[0].match(/:(.*?);/)[1];
var bstr = atob(arr[1]);
var n = bstr.length;
var u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {type:mime});
}
// Blob转image
function blobToImage(blob, cb){
fileOrBlobToDataURL(blob, function (dataurl){
var img = new Image();
img.src = dataurl;
cb(img);
});
}
// image转Blob
function imageToBlob(src, cb){
imageToCanvas(src, function (canvas){
cb(dataURLToBlob(canvasToDataURL(canvas)));
});
}
// Blob转canvas
function BlobToCanvas(blob, cb){
fileOrBlobToDataURL(blob, function (dataurl){
dataURLToCanvas(dataurl, cb);
});
}
// canvas转Blob
function canvasToBlob(canvas, cb){
cb(dataURLToBlob(canvasToDataURL(canvas)));
}
// image转dataURL
function imageToDataURL(src, cb){
imageToCanvas(src, function (canvas){
cb(canvasToDataURL(canvas));
});
}
// dataURL转image,这个不需要转,直接给了src就能用
function dataURLToImage(dataurl){
var img = new Image();
img.src = d;
return img;
}
// DataUrl转为File
/**
* DataUrl转为File
* @param {String} dataUrl - dataUrl地址
* @param {String} fileName - file文件名
*/
dataURLtoFile(dataUrl, fileName){
var arr = dataUrl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], fileName, {type:mime});
}
// url转base64
/**
* url转base64
* @param {String} url - url地址
*/
urlToBase64(url) {
return new Promise ((resolve,reject) => {
let image = new Image();
image.onload = function() {
let canvas = document.createElement('canvas');
canvas.width = this.naturalWidth;
canvas.height = this.naturalHeight;
// 将图片插入画布并开始绘制
canvas.getContext('2d').drawImage(image, 0, 0);
// result
let result = canvas.toDataURL('image/png')
resolve(result);
};
// CORS 策略,会存在跨域问题https://stackoverflow.com/questions/20424279/canvas-todataurl-securityerror
image.setAttribute("crossOrigin",'Anonymous');
// 加时间戳解决跨域问题
image.src = url + '?time=' + String(new Date().getTime());
// 图片加载失败的错误处理
image.onerror = () => {
reject(new Error('转换失败'));
};
});
}
//使用例子
this.urlToBase64(this.Url).then(res=>{
console.log(res);
})
45. 获取当前页面的滚动位置
const getScrollPosition = (el = window) => ({
x: el.pageXOffset !== undefined ? el.pageXOffset : el.scrollLeft,
y: el.pageYOffset !== undefined ? el.pageYOffset : el.scrollTop
})
getScrollPosition(); // {x: 0, y: 200}
46. 平滑滚动到页面顶部
const scrollToTop = () => {
const c = document.documentElement.scrollTop || document.body.scrollTop
if (c > 0) {
window.requestAnimationFrame(scrollToTop) window.scrollTo(0, c - c / 8)
}
}
scrollToTop()
47. 确定设备是移动设备还是台式机/笔记本电脑
const detectDeviceType = () =>
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i
.test(navigator.userAgent) ?
'Mobile' : 'Desktop'
detectDeviceType() // "Mobile" or "Desktop"
48. 带图带事件的桌面通知
function doNotify(title, options = {}, events = {}) {
const notification = new Notification(title, options)
for (let event in events) {
notification[event] = events[event]
}
}
function notify(title, options = {}, events = {}) {
if (!('Notification' in window)) {
return console.error('This browser does not support desktop notification')
} else if (Notification.permission === 'granted') {
doNotify(title, options, events)
} else if (Notification.permission !== 'denied') {
Notification.requestPermission().then(function (permission) {
if (permission === 'granted') {
doNotify(title, options, events)
}
})
}
}
notify(
'中奖提示',
{
icon: 'https://sf1-ttcdn-tos.pstatp.com/img/user-avatar/f1a9f122e925aeef5e4534ff7f706729~300x300.image',
body: '恭喜你,掘金签到一等奖',
tag: 'prize'
},
{
onclick(ev) {
console.log(ev)
ev.target.close()
window.focus()
}
}
)
49. 数组转树
function treeDataTranslate(data, id = 'id', pid = 'pId') {
let res = []
let temp = {}
for (let i = 0; i < data.length; i++) {
temp[data[i][id]] = data[i]
}
for (let k = 0; k < data.length; k++) {
if (temp[data[k][pid]] && data[k][id] !== data[k][pid]) {
if (!temp[data[k][pid]]['children']) {
temp[data[k][pid]]['children'] = []
}
temp[data[k][pid]]['children'].push(data[k])
} else {
res.push(data[k])
}
}
return res
}
50. 禁用在浏览器打开控制台
setInterval(function () {
check()
}, 4000)
var check = function () {
function doCheck(a) {
if (('' + a / a)['length'] !== 1 || a % 20 === 0) {
;(function () {}['constructor']('debugger')())
} else {
;(function () {}['constructor']('debugger')())
}
doCheck(++a)
}
try {
doCheck(0)
} catch (err) {}
}
check()
禁止使用F12打开控制台
window.onkeydown = window.onkeyup = window.onkeypress = function (event) {
if (event.keyCode == 123) {
event.preventDefault(); // 阻止默认事件行为
window.event.returnValue = false;
}
};
51. toFullScreen:全屏
function toFullScreen() {
let elem = document.body
elem.webkitRequestFullScreen
? elem.webkitRequestFullScreen()
: elem.mozRequestFullScreen
? elem.mozRequestFullScreen()
: elem.msRequestFullscreen
? elem.msRequestFullscreen()
: elem.requestFullScreen
? elem.requestFullScreen()
: alert('浏览器不支持全屏')
}
52. exitFullscreen:退出全屏
function exitFullscreen() {
let elem = parent.document
elem.webkitCancelFullScreen
? elem.webkitCancelFullScreen()
: elem.mozCancelFullScreen
? elem.mozCancelFullScreen()
: elem.cancelFullScreen
? elem.cancelFullScreen()
: elem.msExitFullscreen
? elem.msExitFullscreen()
: elem.exitFullscreen
? elem.exitFullscreen()
: alert('切换失败,可尝试Esc退出')
}
53. 首字母大写
let firstUpperCase = ([first, ...rest]) => first?.toUpperCase() + rest.join('')
54. 数据类型验证
// 1
function typeOf(obj) {
const toString = Object.prototype.toString
const map = {
'[object Boolean]': 'boolean',
'[object Number]': 'number',
'[object String]': 'string',
'[object Function]': 'function',
'[object Array]': 'array',
'[object Date]': 'date',
'[object RegExp]': 'regExp',
'[object Undefined]': 'undefined',
'[object Null]': 'null',
'[object Object]': 'object',
'[object FormData]': 'formData'
}
return map[toString.call(obj)]
}
// 2
function typeOf(obj){
Object.prototype.toString.call(obj).slice(8, -1).toLowerCase()
}
55. 页面关闭时发送请求
window.navigator.sendBeacon
window.addEventListener("beforeunload", (e) => {
const data = {name: "编程三昧"};
window.navigator.sendBeacon("http://127.0.0.1:1991/loginout", JSON.stringify(data));
});
56. 后台返回文件流 前端下载
// 从请求中拿到后台返回的文件名
let contentDisposition = res.headers['content-disposition'];
let patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*');
let result = patt.exec(contentDisposition)[1];
const url = window.URL.createObjectURL(new Blob([res.data]));
const link = document.createElement('a');
link.style.display = 'none';
link.href = url;
link.setAttribute('download', result);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);