Javascript学习笔记

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. 继承
  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. 原型

  1. prototype:类的属相,原型
  2. constructor:js内置属性,指向本身
  3. __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);
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值