1.字符串.replace(正则, function(v,i,str){ return 'xxx' }) //xxx为替换掉匹配到的内容
//v为匹配到的值,i是下标,str是'myTestJob'这个字符串
'myTestJob'.replace(/[A-Z]/g, (v,i,str) => `_${v.toLowerCase()}`)
输出结果为 'my_test_job'
2.如何用异步post请求 文件流数据,并触发浏览器的下载功能
//以下例子是在vue中的写法
downloadFile(url, params, fileName) { //下载文件
this.$http.post(url, params, {'responseType': 'blob'}).then(res => {
const blob = new Blob([res.data], {type: res.headers['content-type']});
const a = document.createElement('a');
if ('download' in a) { // 非IE下载
a.style.display = 'none';
a.download = fileName;
a.href = URL.createObjectURL(blob);
document.body.appendChild(a);
a.click();
URL.revokeObjectURL(a.href); //不释放的话会一直占用资源
document.body.removeChild(a);
}else{ // IE10+下载
navigator.msSaveBlob(blob, fileName);
}
})
}
注意:html5中a标签新增了download属性,用于重命名下载文件,不指定则使用默认文件名;
但当a标签用于下载文件流的时候,必须指定download,否则无法触发浏览器的下载模块。
3.canvas内容实现水平翻转(垂直翻转同理)
1) 先ctx.scale(width缩放倍数,height缩放倍数)进行水平翻转
ctx.scale(-1, 1)
2) 再ctx.translate(x坐标移动距离, y坐标移动距离)把翻转后的结果移回画布
ctx.translate(100, 0) //假设画布宽为100px
4.前端计算文件md5最快最准的插件使用(其他插件在计算大文件会算错)
//该插件是在js-spark-md5插件的基础上进行封装的
import BMF from 'browser-md5-file';
const el = document.getElementById('upload');
const bmf = new BMF();
el.addEventListener('change', handle, false);
function handle(e) {
const file = e.target.files[0];
bmf.md5(file, (err, md5) => {
console.log('md5 string:', md5);
}, progress => { // 计算的进度值
console.log('progress number:', progress);
bmf.abort(); // 中止md5计算
});
}
5.--save-dev 和 --save的区别
--save会写入package.json的dependencies下; //指定 生产环境 下需要安装的依赖
当npm install --production 或 当NODE_ENV变量值 为production时,会将dependencies的依赖下载到node_modules中
--save-dev会写入package.json的devDependencies下; //指定 非生产环境 下需要安装的依赖
当npm install 或 当NODE_ENV变量值 不为production时,会将devDependencies的依赖下载到node_modules中
6.替代eval的方法
function myEvil(str) { //str指表达式字符串
var Fn = Function; //一个变量指向Function,防止有些前端编译工具报错
return new Fn('return ' + str)();
}
注意:str中如果涉及外部变量,会变成undefined
7.字符串插入值,比如千分位
'12312312'.replace(/\d{1,3}(?=(\d{3})+$)/g, "$&,")
输出结果为"12,312,312"
注意:$&表示匹配到的部分
8.正则匹配括号:/[(]/
9.初始化数组的值
方法1:
new Array(num).fill(val, startIdx, endIdx); //含头不含尾
例子:
new Array(5).fill(10); //结果为[10, 10, 10, 10, 10]
new Array(5).fill(10, 0, 2); //结果为[10, 10, undefined, undefined, undefined]
方法2:
[...str.repeat(num)]; //str必须是字符串
例子:
[...'1'.repeat(5)]; //结果为['1', '1', '1', '1', '1']
[...'10'.repeat(2)]; //结果为['1', '0', '1', '0']
注意:扩展运算符 打散字符串时,是以 1个字符为单位 进行打散的
10.将某个html内容块转为图片 - 插件 html2canvas
1234
html2canvas(document.getElementById('result')).then(function (canvas) {
var newImg = new Image();
newImg.width = window.innerWidth;
newImg.height = window.innerHeight;
//生成的jpeg图片为base64数据(比png小很多)
newImg.src = canvas.toDataURL("image/jpeg");
newImg.onload = function(){
document.getElementById('resultImg').appendChild(newImg);
}
})
11.flex布局常用写法
display: flex;
/* flex-direction 决定主轴的方向 row(默认)|row-reverse|column|column-reverse*/
/* flex-direction: row; */
/* flex-wrap决定当排列不下时是否换行以及换行的方式,nowrap(默认)|wrap|wrap-reverse */
/* flex-wrap:wrap; */
/* flex-flow是lex-direction和flex-wrap的简写形式,如:row wrap|column wrap-reverse等。默认值为row nowrap,即横向排列 不换行 */
flex-flow:row wrap;
/* !当主轴沿水平方向时!justify-content,决定item在主轴上的对齐方式,可能的值有flex-start(默认),flex-end,center,space-between,space-around */
justify-content:center;
/* !主轴水平时!决定了item在交叉轴上的对齐方式,可能的值有flex-start|flex-end|center|baseline|stretch */
align-items:center;
12.input上传文件反应很慢 问题解决
问题描述:
input标签上传文件,当选中文件后,会卡顿2-3秒才触发onchange事件(vue里会,原生的写法不会),同时上传的文件越多,卡顿越久,且无法监听到在选中文件之后触发loading
解决办法:
1) 在input标签上监听click事件,当点击"浏览"时弹出loading
2) 在loading标签上监听mousemove事件,触发时隐藏loading,用于点击"取消"选择文件
3) 在input标签上监听change事件,触发时隐藏loading
13.数组的every()和some()
用法:
arr.every((v) => { return 布尔值 }); //每一个元素经回调方法处理后都返回true该方法才返回true,否则返回false
arr.some((v) => { return 布尔值 }); //只要有一个元素经回调方法处理返回true该方法就返回true,否则返回false
14.H5获取经纬度方法(参考文章)
if(navigator.geolocation){
navigator.geolocation.getCurrentPosition(success, error, option);
}
success为成功的回调:
success(res){ console.log(res.coords.latitude, res.coords.longitude) }
error为失败的回调:
error(err){ console.log(err) }
option为配置对象:
{
enableHighAccuracy: true, //是否使用高精度
timeout: 3000, //设置超时时间,单位ms
}
15.谷歌地图vue插件vue2-google-maps
谷歌官方api文档
1) 在main.js引入:
import * as VueGoogleMaps from 'vue2-google-maps';
Vue.use(VueGoogleMaps, {
load: {
key: 'AIzaSyAd1qk6XSs2u-Ea5Muc1hCf-ibL2mXOZKw', //需要一个结算账户才可正常使用
libraries: 'places',
language: 'cn', //语言码根据国际标准即可
}
});
2) vue页面中:
html部分:
js部分:
import { gmapApi } from 'vue2-google-maps';
computed: {
google: gmapApi
},
mounted: {
this.$refs.gMap.$mapPromise.then((map) => {
this.gMap = map; //渲染完获取地图对象
this.geocoder = new this.google.maps.Geocoder(); //实例化Geocoder对象,用于定位功能
})
},
methods: {
reset(){
this.gMap.setCenter({lat: xx, lng: xx}); //动态设置中心点
this.gMap.setZoom(12); //动态设置地图缩放倍数
},
search(){
this.geocoder.geocode({address: 'xxx'}, (results, status) => { //搜地址返回经纬度
if (status === 'OK') {
this.centerInfo = {
lng: results[results.length - 1].geometry.location.lng(),
lat: results[results.length - 1].geometry.location.lat()
}
}
});
this.geocoder.geocode({location: {lat: x, lng: x}}, (results, status) => { //根据经纬度返回地址
if (status === 'OK') {
this.searchAddr = results[results.length - 1].formatted_address;
}
});
}
}
16.ios的兼容问题
onkeyup事件在有些ios手机上不生效,一般要用oninput事件(支持ie8以上)或 onpropertychange事件(支持ie8及以下)来实时监听用户输入
17.计算某元素到页面顶部的距离
function getToTop(){
const elem = document.getElementById('elem');
let top = 0;
while(elem = elem.offsetParent){
top += elem.offsetTop;
}
return top;
}
18.二维码生成插件qrcodejs2 (直接用npm安装)
import QRCode from 'qrcodejs2';
components: { QRCode },
makeCode() {
document.getElementById('twoCode').innerHTML = ''; //清除上一次的二维码
new QRCode('twoCode', {
width: 180, // 二维码宽度
height: 180, // 二维码高度
text: codeUrl, //转二维码的url
});
}
19.堆排序(原理)
const target = [6,30,1,9,2,8,5,7,4,10,20,5,14,13,88,-1];
function stackSort(arr, n){ //大根堆(结果为升序)
if(arr.length && n < arr.length - 1){ //数组中至少有2个数才需做排序
let stackNum = arr.length - n; //每次组成堆的所有节点数
let last = parseInt(stackNum/2 - 1); //从最后一个节点(除叶子节点)开始往根方向做对比,把本次堆的最大值冒出到根节点
for(let i=last; i>=0; i--){
let parentIdx = Math.floor((i-1)/2);
let leftIdx = 2*i + 1;
let rightIdx = 2*i + 2;
if(leftIdx < stackNum && arr[i] < arr[leftIdx]){ //(1)跟左子节点比较
arr[leftIdx] = [arr[i], arr[i] = arr[leftIdx]][0];
}
if(rightIdx < stackNum && arr[i] < arr[rightIdx]){ //(2)跟右子节点比较
arr[rightIdx] = [arr[i], arr[i] = arr[rightIdx]][0];
}
if(parentIdx >= 0 && arr[parentIdx] < arr[i]){ //(3)跟父节点比较
arr[parentIdx] = [arr[i], arr[i] = arr[parentIdx]][0];
}
}
arr[0] = [arr[stackNum - 1], arr[stackNum - 1] = arr[0]][0];
stackSort(arr, n+1);
}
}
stackSort(target, 0); //结果为[-1, 1, 2, 4, 5, 5, 6, 7, 8, 9, 10, 13, 14, 20, 30, 88]
注意:小根堆 则把(1)(2)(3)中第2个条件的 "<" 改为 ">" 即可(结果为降序)
20.将字符串false转为布尔值false
JSON.parse('false') //false
21.css中隐藏的几种方式和区别
display: none; //脱落文档流,不占位置
visibility: hidden; //隐藏,占位置(元素自身的事件不可触发,如:input框中的内容 不可选中)
opacity: 0; //隐藏,占位置(元素自身的事件可触发,如:input框中的内容 可选中,$('#input').select())
22.类型对比
1)实例化结果对比的是值、或者内存地址,且有些值的对比会进行隐式转换;
例如:let a = new Array(); let b = new Array(); a === b; // false
2)实例化结果的constructor指向其构造函数
例如:let a = new Array(); a.constructor === Array; // true
3)构造函数的对比其实就是2个构造函数的内存地址对比
例如:Array === Object; // false
4)任何构造函数本身的constructor都是指向Function这个构造函数
例如:Array.constructor === Function; // true
Object.constructor === Function; // true
Function.constructor === Function; //true
23.数组的sort方法
sort() 默认排序是按 字符串 做 升序排序(冒泡)
[4,1,23,0,5].sort() //[0,1,23,4,5]
sort(fn)中回调函数返回值的作用:
返回-1,则会将2个入参的排序顺序对调;
返回0或1,则按原来的顺序;
[4,1,23,0,5].sort(()=> 0) //[4,1,23,0,5] 不变
[4,1,23,0,5].sort(()=> 1) //[4,1,23,0,5] 不变
[4,1,23,0,5].sort(()=> -1) //[5,0,23,1,4] 全反
[4,1,23,0,5].sort((next,prev)=>next - prev) //[0,1,4,5,23] 按数字升序
[4,1,23,0,5].sort((next,prev)=>prev - next) //[23,5,4,1,0] 按数字降序
24.回流和重绘
解析html+解析css -> 生成render tree -> layout(回流)-> painting(重绘)-> 展示
参考1:你真的了解回流和重绘吗 - SegmentFault 思否
参考2:重绘和回流----降低回流减少性能影响_weixin_30416871的博客-CSDN博客
注意1:浮动会脱离文档流,但不会脱离文本流(文字会围绕在其周围),absolute和fixed定位则二者都脱离
注意2:绝对定位的元素已经脱离文档流,可减少其父元素和后续兄弟元素多余的回流
表格渲染大数据卡死问题
表格如果是滚动加载数据的话,那么会不断回流重绘,因为在不断地添加dom;如果只是单纯滚动,那么只会重绘,因为dom没有发生变化,而重绘是让你看到滚动的效果。
表格加载大数据会卡死,通常是在渲染前卡死,因为操作的dom太多了,一般渲染成功后去滚动则不怎么卡,因为单纯的滚动没有引起dom的改变
25.从后往前截取字符串
‘12345’.slice(-2); // -2表示从后往前截取2位,即 '45'
26.hasOwnProperty报错问题
const obj = {a:1};
obj.hasOwnProperty('a') // true
在严格模式下会报错,可改为以下写法即可:
const obj = {a:1};
Object.hasOwnProperty.call(obj, 'a') //true
27..call(),.apply(),.bind()的区别
.call(obj, a, b, ...)
.apply(obj, [a,b,...])
.bind(obj, a, b, ...)()
详情可见:JavaScript 中 call()、apply()、bind() 的用法 | 菜鸟教程
28.tiansition冲突
假如某个组件本身样式有transition,你自己想再加另一个transition,两者就会冲突,只有里面那个生效。因为transition样式不可被继承。
解决:可以在该组件外层套一个
29.正则.exec()的使用
let reg = /[a-z]+-c\d+/g;
let str = 'asa/ddd-c123/p33asa/eee-c456/p44';
let arr = reg.exec(str); //返回['ddd-c123']
exec会返回一个数组arr,arr[0]就是匹配到的第一个结果,然后就停下了(所以g标识对exec而言是无效的,可以不写),内部的lastIndex指到第一个匹配结果的下一个字符串。如果想继续匹配下一个结果,那么就得再执行一次exec,一直到匹配不到为止,则返回null。所以用exec想匹配所有结果,必须自己写循环逻辑,如下:
while(arr){
arr = reg.exec(str);
}
假如只想从匹配到'ddd-c123'中的子片段,如ddd和123,那么可以用()在正则中包裹起来即可。结果仍然返回一个数组arr,arr[0]还是匹配到的第一个完整片段,后续的则都是正则中用()包裹起来的内容,如ddd和123,如果()包裹的内容匹配不到,则会返回一个空字符串,比如[完整片段,'','']。
let reg = /([a-z]+)-c(\d+)/;
let str = 'asa/ddd-c123/p33asa/eee-c456/p44';
let arr = reg.exec(str); //返回['ddd-c123','ddd','123']
30.JS的事件冒泡
This is a span.
点击子元素span,这个点击事件会冒泡给所有父元素,事件朝 子元素->父元素 这个方向传递,称为冒泡。点击完开始朝冒泡的方向依次执行各自的回调 onclick1 -> onclick2 -> onclick3。
在onclick(e)中使用e.stopPropagation()可阻止冒泡。
31.web worker介绍
参考文档:Web Worker 使用教程 - 阮一峰的网络日志
作用:为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。
注意:Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。
// 主线程
var myWorker = new Worker('worker.js', { name : 'subWorker' });
Worker.onerror:指定 error 事件的监听函数。
Worker.onmessage:指定 message 事件的监听函数,发送过来的数据在Event.data属性中。
Worker.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。
Worker.postMessage():向 Worker 线程发送消息。
Worker.terminate():立即终止 Worker 线程。
// subWorker 线程
self.name: Worker 的名字。该属性只读,由构造函数指定。
self.onmessage:指定message事件的监听函数。
self.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。
self.close():关闭 Worker 线程。
self.postMessage():向产生这个 Worker 线程发送消息。
self.importScripts():加载 JS 脚本。
32.两个||和两个??的区别
0 || 123 //输出123
0 ?? 123 //输出0
|| 前面的表达式只要能转为false,就会执行后面的
?? 前面的表达式为undefined或null的时候,才会执行后面的
33.前端实现页面水印
1)利用canvas画出单个水印,然后利用.toDataURL('image/png')转为base64数据
2)创建一个与根元素(比如
)平级的另一个div,并把上一步的数据放入background-image: url(...)中3)对该新的div做绝对定位,遮住整个页面
4)设置该新div的css为 pointer-events: none; (画重点,如果不设置的话,这个新div会挡住页面的所有其他事件,因为该div本身也有hover/click等等事件)
34.JSON.stringify()解析undefined
将对象转字符串时,会自动删掉 值为undefined的属性;
JSON.stringify({test: undefined}); 结果为 '{}'
将数组转字符串时,会把undefined自动转为null;
JSON.stringify([undefined]); 结果为 '[null]'