1.取消前后空格
str.replace(/(^\s*)|(\s*$)/g, "");
2.事件封装方法
addEvent(elem,type,handle){
if(elem.addEventListener){
  elem.addEventListener(type,handle,false);
}else if(elem.attachEvent){
  elem.attachEvent("on" + type,function(){
  handle.call(elem);
})
}else{
  elem["on" + type] = handle;
}
},
3.获取浏览器可视区域的高度
clientHeight(){
if(window.innerHeight !== undefined){
return window.innerHeight
}else if(document.compatMode === "CSS1Compat"){
return document.documentElement.clientHeight
}else{
return document.body.clientWidth
}
},
4.获取滚动条滚动的高度
let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
5.回到顶部
backTop() {
window.scrollTo(0,0)
},
6.回到顶部按钮显示隐藏函数
btnShow() {
let _this = this;
let btn = _this.$refs.topBtn;
this.addEvent(window,'scroll',()=> {
let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
let clientHeight = _this.clientHeight();
if(scrollTop > clientHeight){
btn.style.display = 'block';
}else{
btn.style.display = 'none';
}
})
}
7.vue路由监听
watch: {
$route(to,from){
this.getCurrentRoute();
}
},
methods: {
getCurrentRoute(){
let current = this.$route.path;
}
}
8.获取base64图片的大小
// 获取base64图片的大小
getImgByteSize(data) {
const equalIndex = data.indexOf('='); // 获取=号下标
let strLength, fileLength;
if (equalIndex > 0) {
const str = data.substring(0, equalIndex); // 去除=号
strLength = str.length;
fileLength = strLength - (strLength / 8) * 2; // 真实的图片byte大小
} else {
strLength = data.length;
fileLength = strLength - (strLength / 8) * 2;
}
console.log(fileLength)
return Math.floor(fileLength); // 向下取整
},
9.压缩base64图片
// 压缩图片
compressImg(base64, callback){
let imgSize = this.getImgByteSize(base64);
let maxSize = 1024 * 1024 * 8 // 图片最大为8M
let compressSize = 1024 * 300 // 压缩目标为300kb
// 如果图片小于300kb则返回,否则压缩图片
if(imgSize > maxSize){
alert('图片最大为8M,请重新上传')
return;
}
if(imgSize < compressSize){
callback(base64)
return ;
}
let newImage = new Image();
let quality = 0.65; //压缩系数0-1之间
let that = this;
newImage.src = base64;
newImage.setAttribute("crossOrigin", 'Anonymous'); //url为外域时需要
var imgWidth, imgHeight;
this.addEvent(newImage, 'load', function() {
imgWidth = this.width;
imgHeight = this.height;
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = imgWidth;
canvas.height = imgHeight
ctx.clearRect(0, 0, imgWidth, imgHeight);
ctx.drawImage(this, 0, 0, imgWidth, imgHeight);
var base64 = canvas.toDataURL("image/jpeg", quality); //压缩语句
// 如想确保图片压缩到自己想要的尺寸,如要求在小于300kb之间,请加以下语句,quality初始值根据情况自定
imgSize = that.getImgByteSize(base64);
// 500kb以内,压缩质量0.01为单位递减。
let nearSize = 500 *1024
while (imgSize > compressSize) {
if(imgSize > nearSize){
quality -= 0.1
}else{
quality -= 0.01;
}
base64 = canvas.toDataURL("image/jpeg", quality);
imgSize = that.getImgByteSize(base64);
}
callback(base64);//必须通过回调函数返回,否则无法及时拿到该值
})
},
10.js判断数据为空的方法
//js判断数据为空的方法
function isBlank(str){
if (Object.prototype.toString.call(str) ==='[object Undefined]'){//空
return true
} else if (
Object.prototype.toString.call(str) === '[object String]' ||
Object.prototype.toString.call(str) === '[object Array]') { //字条串或数组
return str.length==0?true:false
} else if (Object.prototype.toString.call(str) === '[object Object]') {
return JSON.stringify(str)=='{}'?true:false
}else{
return true
}
}
11.判断数据类型
isString (o) { //是否字符串
return Object.prototype.toString.call(o).slice(8, -1) === 'String'
}
isNumber (o) { //是否数字
return Object.prototype.toString.call(o).slice(8, -1) === 'Number'
}
isBoolean (o) { //是否boolean
return Object.prototype.toString.call(o).slice(8, -1) === 'Boolean'
}
isFunction (o) { //是否函数
return Object.prototype.toString.call(o).slice(8, -1) === 'Function'
}
isNull (o) { //是否为null
return Object.prototype.toString.call(o).slice(8, -1) === 'Null'
}
isUndefined (o) { //是否undefined
return Object.prototype.toString.call(o).slice(8, -1) === 'Undefined'
}
isObj (o) { //是否对象
return Object.prototype.toString.call(o).slice(8, -1) === 'Object'
}
isArray (o) { //是否数组
return Object.prototype.toString.call(o).slice(8, -1) === 'Array'
}
isDate (o) { //是否时间
return Object.prototype.toString.call(o).slice(8, -1) === 'Date'
}
isRegExp (o) { //是否正则
return Object.prototype.toString.call(o).slice(8, -1) === 'RegExp'
}
isError (o) { //是否错误对象
return Object.prototype.toString.call(o).slice(8, -1) === 'Error'
}
isSymbol (o) { //是否Symbol函数
return Object.prototype.toString.call(o).slice(8, -1) === 'Symbol'
}
isPromise (o) { //是否Promise对象
return Object.prototype.toString.call(o).slice(8, -1) === 'Promise'
}
isSet (o) { //是否Set对象
return Object.prototype.toString.call(o).slice(8, -1) === 'Set'
}
isBlob (o) { //是否Blob对象
return Object.prototype.toString.call(o).slice(8, -1) === 'Blob'
}
12.判断浏览器类型
browserType(){
var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
var isOpera = userAgent.indexOf("Opera") > -1; //判断是否Opera浏览器
var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1 && !isOpera; //判断是否IE浏览器
var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf("rv:11.0") > -1;
var isEdge = userAgent.indexOf("Edge") > -1 && !isIE; //判断是否IE的Edge浏览器
var isFF = userAgent.indexOf("Firefox") > -1; //判断是否Firefox浏览器
var isSafari = userAgent.indexOf("Safari") > -1 && userAgent.indexOf("Chrome") == -1; //判断是否Safari浏览器
var isChrome = userAgent.indexOf("Chrome") > -1 && userAgent.indexOf("Safari") > -1; //判断Chrome浏览器
if (isIE) {
var reIE = new RegExp("MSIE (\\d+\\.\\d+);");
reIE.test(userAgent);
var fIEVersion = parseFloat(RegExp["$1"]);
if(fIEVersion == 7) return "IE7"
else if(fIEVersion == 8) return "IE8";
else if(fIEVersion == 9) return "IE9";
else if(fIEVersion == 10) return "IE10";
else return "IE7以下"//IE版本过低
}
if (isIE11) return 'IE11';
if (isEdge) return "Edge";
if (isFF) return "FF";
if (isOpera) return "Opera";
if (isSafari) return "Safari";
if (isChrome) return "Chrome";
}
13.表单常用校验信息
/^1[3|4|5|6|7|8][0-9]{9}$/.test(str); //校验手机号
`/(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(str); //校验身份证号`
14.数组相关
const uniqueArray = arr => [...new Set(arr)]; //数组去重
const randomArray = arr => arr.sort(() => Math.random() - 0.5); //随机打乱数组顺序
15.驼峰和连字符相互转化
// 连字符转驼峰
const camelizeRE = /-(\w)/g;
camelize = str => {
return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
}
// 驼峰转连字符
const hyphenateRE = /\B([A-Z])/g;
export const hyphenate = str => {
return str.replace(hyphenateRE, '-$1').toLowerCase()
}
replace里面回调函数详解

16.axios全局拦截封装
主要包括,开发和生产环境请求地址,全局loading设置,请求头中增加token,避免同一个请求触发多次,以及添加路由跳转取消当前所有请求,以及对响应信息统一判断等功能。
import axios from 'axios';
import Toast from 'show-toast';
import store from '@/store';
import { dataType } from '@/util'
const { isBlob } = dataType;
let myFlag = '';
let baseURL = '/api';
if(process.env.NODE_ENV == 'production') {
baseURL = 'http://www.abc.com';
}
let generateKey = function (url, method, data) {
let strData = JSON.stringify(data);
return (`${url || ''}${method || ''}${strData || ''}`);
};
const instance = axios.create({
baseURL,
timeout: 9000,
withCredentials: true,
});
// 请求拦截
instance.interceptors.request.use(function (config) {
let requestKey = generateKey(config.url, config.method, config.data);
if (myFlag == requestKey) {
return Promise.reject({
code: 'CANCEL'
});
}
store.commit('showLoading',true); //显示加载中
config.cancelToken = new axios.CancelToken(function (cancel) {
store.commit('pushToken', {cancelToken: cancel})
})
myFlag = requestKey;
// 请求头添加token
config.headers.token = store.state.userToken;
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
/* 拦截返回预处理---获取数据 */
instance.interceptors.response.use(function (response) {
myFlag = '';
store.commit('showLoading',false); // 关闭loading
// if (response.status !== 200) {
const data = response.data;
// 判断返回的数据是否是二进制对象,因为如果是二进制则只会返回文件流,没有状态码的,所以需要单独判断。
if(isBlob(data)) {
if(data.type=="application/vnd.ms-excel"){
data.success = true;
}else{
Toast('下载失败!')
}
return response
}else {
if(data.ret == 0){
data.success = true;
}else if(data.ret == 1053){
Toast('登录失效,请重新登录');
store.dispatch('clearUserInfo').then(()=> location.href = "#/login");
}else{
data && Toast(data.msg || '请求数据失败!!!');
}
return data;
}
}, function (error) {
myFlag = '';
store.commit('showLoading',false); // 关闭loading
// 如果是连续发起的请求。
if (error.code === 'CANCEL') {
return Promise.reject(error);
}
if(error.message.indexOf('Network') > -1) {
Toast('暂无网络!!!')
return Promise.reject(error);
}
if(error.message.indexOf('timeout') > -1){
Toast('请求超时!!!')
return Promise.reject(error);
}
// Toast('服务器故障!!!');
return Promise.reject(error);
});
export default instance;
17.vuex基本配置。
主要配置有:登录,退出等接口,以及全局loading,由于路由跳转取消请求的数组,用户基本信息,以及路由相关函数等。
此处还增加了权限等配置,如果是管理员则展示所有路由,如果不是管理员,则需要根据具体权限permission来动态生成路由。
import Vue from 'vue'
import Vuex from 'vuex'
import { login, logout } from '@/service/api/user';
import { getUserInfo } from '@/util'
import { publicRoutes, asyncRoutes, redirectRoutes, addRedirect, generateRoutes} from '@/router/permission';
import { Loading } from 'element-ui';
Vue.use(Vuex)
let userInfo = getUserInfo();
export default new Vuex.Store({
state: {
loading: false, // 是否展示loading
loadingCount: 0, // 当发起多个请求的时候,会有用
cancelTokenArr: [], //取消请求token数组
username: userInfo('email') || '', // 用户名
loginStatus: !!userInfo('email'), // 是否登录标志
userToken: userInfo('token') || '', // token
permission: userInfo('permission') || [], // 权限列表
admin: userInfo('privilegeLevel') == 0 ? true : false,// 是否是管理员 0:管理员,1:普通领导
// admin: true,// 是否是管理员 0:管理员,1:普通领导
routes: publicRoutes,
hasUpdateRoutes: false,
},
mutations: {
showLoading(state,newValue) {
// isChangeRoute 表示是否是路由跳转
if(newValue) {
state.loadingCount ++;
state.loading = newValue;
}else{
state.loadingCount --;
if(state.loadingCount <= 0) {
state.loading = newValue;
state.loadingCount = 0;
}
}
// state.loading = newValue;
},
pushToken (state, payload) {
state.cancelTokenArr.push(payload.cancelToken)
},
clearToken ({ cancelTokenArr }) {
cancelTokenArr.forEach(item => {
item('路由跳转取消请求')
})
cancelTokenArr = []
},
updateUsername(state, newValue) {
state.username = newValue;
},
updateLoginStatus(state, newValue) {
state.loginStatus = newValue
},
updateUserToken(state, newValue) {
state.userToken = newValue
},
updatePermission(state, newValue) {
state.permission = newValue
},
updateAdmin(state, newValue) {
state.admin = newValue == 0 ? true : false;
},
updateRoutes(state, newValue) {
state.routes = newValue;
},
updateRoutesFlag(state, newValue){
state.hasUpdateRoutes = newValue;
}
},
actions: {
doLogin({ commit }, data){
return new Promise((resolve, reject) => {
login(data).then(res => {
if(res.success) {
let userInfo = res.datas;
localStorage.setItem("userInfo", JSON.stringify(userInfo));
commit('updateUsername', userInfo.email)
commit('updateLoginStatus', true)
commit('updateUserToken', userInfo.token)
commit('updatePermission', userInfo.permission)
commit('updateAdmin', userInfo.privilegeLevel)
commit('updateRoutesFlag', false)
commit('updateRoutes', publicRoutes)
resolve(res);
}else {
reject(res)
}
}).catch(err => reject(err))
})
},
clearUserInfo({commit}) {
return new Promise(resolve => {
localStorage.removeItem("userInfo");
commit('updateUsername', '')
commit('updateLoginStatus', false)
commit('updateUserToken', '')
commit('updatePermission', [])
commit('updateAdmin', '')
commit('updateRoutesFlag', false)
commit('updateRoutes', publicRoutes)
resolve()
})
},
doLogout({ dispatch }) {
return logout()
},
perfectRoutes({ dispatch, commit, state}) {
return new Promise(resolve => {
let arr = [];
arr = state.admin ? arr.concat(asyncRoutes) : arr.concat(generateRoutes(asyncRoutes, state.permission));
arr = addRedirect(arr)
arr.push(redirectRoutes);
let all = publicRoutes.concat(arr)
commit('updateRoutes', all)
commit('updateRoutesFlag', true)
resolve(all)
})
}
},
})
18.权限配置(permission.js)
主要内容有公共路由,动态路由,重定向路由。
import { _import } from '@/util'
// 创建公共路由
export const publicRoutes = [
{
path: '/login',
name: 'login',
component: _import('login'),
meta: {title: '登录'}
},
{
path: '/404',
name: '404',
component: _import('404'),
meta: {title: '404'}
},
]
// 注意因为要把这句放在最后,才不会影响其他的路由,所以单独拿出来了
export const redirectRoutes = {
path: '*',
redirect: '/404'
}
export const asyncRoutes = [
{
path: '/',
component: _import('layout'),
meta: {title: '首页', auth: 3},
children: [
{
path: 'saleManager',
component: _import('saleManager'),
meta: {title: '销售管理', auth: 3},
icon: 'el-icon-menu',
children: [
// {
// path: '/',
// redirect: 'businessGroup',
// meta: {title: '事业群排名', auth: 3},
// },
{
path: 'businessGroup',
name: 'businessGroup',
component: _import('saleManager/businessGroup'),
meta: {title: '事业群排名', auth: 1},
},
{
path: 'division',
name: 'division',
component: _import('saleManager/division'),
meta: {title: '分部排名', auth: 2},
},
{
path: 'team',
name: 'team',
component: _import('saleManager/team'),
meta: {title: '团队排名', auth: 3},
},
{
path: 'advisor',
name: 'advisor',
component: _import('saleManager/advisor'),
meta: {title: '投顾排名', auth: 3},
},
]
},
{
path: 'newCustomerManager',
name: 'newCustomerManager',
component: _import('newCustomerManager'),
meta: {title: '拉新目标管理'},
icon: 'el-icon-s-custom',
},
{
path: 'dateMarkManager',
name: 'dateMarkManager',
component: _import('dateMarkManager'),
meta: {title: '日期标记管理'},
icon: 'el-icon-s-claim',
},
// {
// path: '/',
// redirect: 'saleManager'
// },
]
},
]
export const addRedirect = function(routes) {
routes.forEach(item => {
if(item.children && item.children.length > 0) {
let obj = {};
obj.path = '/',
obj.redirect = item.children[0].path;
item.children.push(obj);
addRedirect(item.children)
}
})
return routes;
}
export const generateRoutes = function(routes, permission) {
let res = []
routes.forEach(route => {
let cur = {};
let auth = route.meta && route.meta.auth;
if(permission && permission.includes(auth)) {
Object.keys(route).forEach(key => {
if(key=="children" && route[key].length > 0) {
cur[key] = generateRoutes(route[key], permission)
}else {
cur[key] = route[key]
}
})
res.push(cur)
}
});
return res;
}
19.全局导航(router.js)
主要内容有自定义$addRoutes方法,进度条,登录拦截,路由跳转取消请求得调用,以及动态生成路由函数。
import Vue from 'vue'
import VueRouter from 'vue-router'
import store from '../store'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
Vue.use(VueRouter)
const router = new VueRouter({
routes: store.state.routes
})
// 自定义$addRoutes方法,如果直接使用router.addRoutes定义的话,仅仅只是添加路由,原有路由还不会变。
// 所以会出现“Duplicate named routes definition:”的错误提示
router.$addRoutes = (params) => {
router.matcher = new VueRouter().matcher;
router.addRoutes(params)
}
router.beforeEach((to, from, next) => {
NProgress.start()
if (to.meta.title) {
document.title = `${to.meta.title} - 恒大财富战报管理系统`;
}
store.commit('clearToken'); // 取消请求
store.commit('showLoading', false);
if(to.path != '/login' && !store.state.loginStatus) {
let redirect = to.fullPath;
// 注意在这里面加入NProgress.done();原因是,当点击退出按钮的时候,通过手动在地址栏输入路由时,进度条不会消失的状况。
NProgress.done();
return next({
path: '/login',
query: {
redirect
}
})
}else if(store.state.loginStatus && !store.state.hasUpdateRoutes) {
store.dispatch('perfectRoutes').then((res) => {
// 注意虽然将routes存入vuex中,登录以后,vuex里面的路由会改变,但是router.options.routes里的路由还是原来的路由
// 因此,我们需要手动赋值给router.options。
router.options.routes = res;
// 注意如果不加入下面这句,页面会出现空白,虽然url有路由,但是却显示空。
// 但是如果只加入这句不加上面那句,虽然页面会显示,但是router.options.routes的内容并不会改变
// 重写方法也是为了,当第二个用户登录的时候,防止权限交叉。
router.$addRoutes(res);
// 替代之前的路由,防止留下历史记录。
NProgress.done();
return next({...to, replace: true});
})
}
next()
})
router.afterEach(() => {
NProgress.done();
})
export default router
})
20.获取用户信息
// 获取当前用户的所有信息
export const user = function() {
return JSON.parse(localStorage.getItem('userInfo'));
}
// 获取当前用户的指定信息 注意此函数为了避免多次执行user函数
export const getUserInfo = function() {
let userInfo = user();
return info => userInfo == null ? null : userInfo[info]
}
21.base64转为二进制
export const base64_to_blob = function(data) {
let bstr = window.atob(data),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return u8arr;
}
22.下载文件
export const blob_to_url = function(data, name, type) {
if(!dataType.isBlob(data)) {
return;
}
let blob = new Blob([data], {type});
let objectUrl = window.URL.createObjectURL(blob); //生成一个url
let downloadElement = document.createElement('a');
downloadElement.href = objectUrl;
downloadElement.download = name;
document.body.appendChild(downloadElement);
downloadElement.click(); //点击下载
document.body.removeChild(downloadElement); //下载完成移除元素
window.URL.revokeObjectURL(objectUrl); //释放blob对象
}
23.将小数转为固定位数的百分数。
// 将小数变成百分比,n是代表保留几位小数
export const toPercent = function(num, n) {
if(num === 0) {
return num+'%';
}
let str = (num * 100) + '',
index = str.indexOf('.'),
res = (index > -1) ? str.substring(0, index+n+1) : str;
// console.log(num, str , res)
return res + '%'
}
24.路由懒加载
// 注意"[request]"是传入的变量名
let _import = file => () => import(/* webpackChunkName: "[request]" */ `@/views/${file}.vue`)
{
path: '/about',
name: 'about',
component: _import('about')
}

需要注意的是: 如上图,如果想要打包的文件不含有“About-vue”中的vue字样,则直接可以把上面的${file}.vue中的“.vue”去掉即可。
25.五星评级
变量rate是1到5的值,然后执行上面代码
★★★★★☆☆☆☆☆".slice(5 - rate, 10 - rate);
26.浮点类型取整
var a = ~~2.33
var b= 2.33 | 0
var c= 2.33 >> 0
27.数字变为金钱格式化
1234567890 --> 1,234,567,890
let reg = /(?=(\B)(\d{3})+$)/g || /\B(?=(\d{3})+$)/g
let res = '12345678'.replace(reg,',');
28.两个变量交换的方法
var a = 11, b = 22;
// 第一种方法
a ^= b;
b ^= a;
a ^= b;
// 第二种方法
a = a + b;
b = a - b;
a = a - b;
29.一行代码实现深拷贝
let res = JSON.parse(JSON.stringify({})
30.数组去重
let arr = [1,2,3,2,1,3,4,1];
// 第一种
let res1 = [...new Set(arr)]
// 第二种
let res2 = Array.from(new Set(arr))
31.取数组中的最大值和最小值
Math.max(...arr1); Math.min(...arr2)
32.防抖和节流
- 防抖:最后一次为准。
function debounce (callback, time) {
var timer;
return function() {
if(timer) {
clearTimeout(timer)
}else{
timer = setTimeout(()=> {
callback();
},time)
}
}
}
window.addEventListener('scroll', debounce(()=> {
console.log('防抖')
},200) ,false)
- 节流
function throttle(callback, time) {
var timer;
return function() {
if(!timer){
timer = setTimeout(()=> {
callback();
clearTimeout(timer);
timer = null;
},time)
}
}
}
window.addEventListener('scroll', throttle(()=> {
console.log('节流')
},200) ,false)
33.将数据转为树形(tree)结构
function buildTree(list) {
let res = [],
temp = {};
list.forEach(item => {
temp[item.menuId] = item
})
for(let i in temp){
let itm = temp[i]
if(itm.parentId > 100) {
let parentId = itm.parentId;
if(!temp[parentId].child) {
temp[parentId].child = []
}
temp[parentId].child.push(itm)
}else {
res.push(itm)
}
}
return res
}