工作笔记

401 阅读6分钟

1、截取url地址栏指定参数

获取地址栏参数,可能会有多个参数,取第一个不一定对,所以需要截取指定参数的值

      // 获取地址栏参数
      function GetRequest() {
        var url = location.search; //获取url中"?"符后的字串 http://y.qq.com?projectId=29&userType=3
        var theRequest = new Object();
        if (url.indexOf("?") != -1) {
              var str = url.substr(1);
              strs = str.split("?");
              console.log(strs)//["projectId=29"]
              for (var i = 0; i < strs.length; i++) {
                  theRequest[strs[i].split("=")[0]] = decodeURIComponent(strs[i].split("=")[1]);
              }
          }
          return theRequest;
      }
      
   //调用
  var a=GetRequest();
  var projectId = a['projectId'];
  console.log(projectId,'projectId')//29
  
  
  function transformParams() {                   
    var params = location.search.substring(1); 
    return params.split('&').map(item => {      
        var index = item.indexOf('=')          
        if (index == -1) {                     
            return {                           
                [item]: null                   
            }                                  
        }                                      
        var key = item.slice(0, index);    
        val = item.slice(index + 1)        
        return {                               
            [key]: val                     
        }                                      
    })                                     
} 

function getQueryString(name) {
  let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
  let r = window.location.search.substr(1).match(reg);
  if (r != null) {
  return unescape(r[2]);
  };
  return null;
}
getQueryString('token') // token串

transformParams()
// http://localhost:3000/nx-temp13-k8s/app?code=8b7bf92b-4911-4b69-9ca4-ba9929a72876#/InvAcctgJournalCheckExceptionView/list
[
    {
        "code": "8b7bf92b-4911-4b69-9ca4-ba9929a72876"
    }
]

2、处理字符串,截取某个字符前后值

   function getCaption(str) {
      let index = str.lastIndexOf('\,');
      let strFront = str.substring(index + 1, str.length);
      let strAfter = str.substring(0, index);
      this.after = strAfter;//hello
      this.front = strFront;//word
    }
  let str = 'hello,word';
  getCaption(str)

3、使用moment 第三方插件格式化日期

安装:npm install moment --save
引用:import moment from 'moment';
使用:
    getTimeFn() {
      const end = new Date();
      const start = new Date();
      start.setTime(start.getTime() - 3600 * 1000 * 24 * 89);//默认返现3个月日期
      this.ruleForm.startDate = moment(start).format('YYYY-MM-DD');
      this.ruleForm.endDate = moment(end).format('YYYY-MM-DD');
    }

4、千分符

  function qffformat(num) {
    var reg = /\d{1,3}(?=(\d{3})+$)/g;
    return (num + "").replace(reg, "$&,");
  }
  qffformat('123456789')//"123,456,789"

5、vue全局注册,全局按需引入

  • 初始化插件对象需要通过Vue.use(),插件对象中必须有install方法
  • 每一个vue组件都是Vue的实例,所以组件内this可以拿到Vue.prototype上添加的属性和方法。
// 下拉树 tree
import Treeselect from '@riophae/vue-treeselect';
import '@riophae/vue-treeselect/dist/vue-treeselect.css';
// 全局注册树
Vue.component('treeselect', Treeselect);

// 按需引入 Element
import './libs/js/elementUi';
import 'element-ui/lib/theme-chalk/index.css';

//挂在全局使用
Vue.prototype.$axios = axios;
Vue.prototype.$loading = loading;
Vue.prototype.$api = api;
this.$axios.post(this.$api.info)
this.$loading.open();

6、自动补全2位小数,一位补0

function returnSmallNumber(valueParam) {
  let value = Math.round(parseFloat(valueParam) * 100) / 100;
  let xsd = value.toString().split('.');
  if (xsd.length == 1) {
    value = value.toString() + '.00';
    return value;
  }
  if (xsd.length > 1) {
    if (xsd[1].length < 2) {
      value = value.toString() + '0';
    }
    return value;
  }
}
returnSmallNumber(1.2)//1.20  (1 -> 1.00)

7、el-input 输入框限制最大值、保留小数点2位

 <el-input
  v-model="ruleForm.gdsylzcStart"
  type="number"
></el-input>
 watch: {
    'ruleForm.gdsylzcStart': function (newVal, oldVal) {
      // 解决数字键盘可以输入输入多个小数点问题
      if (newVal === '' && oldVal.toString().indexOf('.') > 0) {
        this.ruleForm.gdsylzcStart = oldVal;
        return;
      }
      // 保留两位小数
      if (newVal) {
        newVal = newVal.toString();
        let pointIndex = newVal.indexOf('.');
        if (pointIndex > 0 && newVal.length - pointIndex > 3) {
          this.ruleForm.gdsylzcStart = oldVal;
          return;
        }
      }
      // 最大值
      if (newVal > 100) {
        this.ruleForm.gdsylzcStart = oldVal;
        return;
      }
    }
  }

8、el-input 输入框根据参数(n)保留小数点n位

/**
 * @author m
 * @description 自动补全n位小数
 * @param  (value) 值 (num) 位数
 */
function formatNumber(value, num) {
  if (value && !isNaN(value)) {
    let a, b, c, i;
    a = value.toString();
    b = a.indexOf('.');
    c = a.length;
    if (num == 0) {
      if (b != -1) {
        a = a.substring(0, b);
      }
    } else {
      //如果没有小数点
      if (b == -1) {
        a = a + '.';
        for (i = 1; i <= num; i++) {
          a = a + '0';
        }
      } else {
        //有小数点,超出位数自动截取,否则补0
        a = a.substring(0, b + num + 1);
        for (i = c; i <= b + num; i++) {
          a = a + '0';
        }
      }
    }
    return a;
  } else {
    return '';
  }
}
formatNumber(3.256, 4) // 3.2560

9、el-input 行内校验

<!-- 只允许输入数字和一位小数点和小数点后两位 并且首位不能为小数点 -->
<el-input type="text" onkeyup="value= value.match(/\d+(\.\d{0,2})?/) ? this.value.match(/\d+(\.\d{0,2})?/)[0] : ''" >
 
<!-- 只能输入英文 -->
<el-input type="text" onkeyup="value=value.replace(/[^a-zA-Z]/g,'')">  
 
<!-- 只能输入字母和数字 -->
<el-input oninput="value=value.replace(/[^\w\.\/]/ig,'')">
 
<!--只能输入数字-->
<el-input type='text' onkeyup="this.value=this.value.replace(/[^0-9-]+/,'');" />
 
<!--只能输入数字和小数点-->
<el-input  type="text"   onkeyup="this.value=this.value.replace(/[^0-9.]/g,'')" />
 
<!--只能输入正数,小数点后保留两位-->
<el-input  type="text"   onkeyup="this.value= this.value.match(/\d+(\.\d{0,2})?/) ? this.value.match(/\d+(\.\d{0,2})?/)[0] : ''" />
 
<!--只能输入字母和汉字 禁止特殊字符-->
<el-input  type="text"  onkeyup="value=value.replace(/[^\a-zA-Z\u4E00-\u9FA5]/g,'')" onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\a-zA-Z\u4E00-\u9FA5]/g,''))"/>

<!--有时候输入框是对象的方式渲染的,想要控制各个对象的输入校验(不能小于?, 不能大于?),可以通过@input.native根据event处理-->
<el-input
  v-model="scope.row.ratio"
  type="Number"
  :min="0"
  :max="100"
  @input.native="validateInput($event, scope.row)"
/>
// 校验方法
validateInput(e, row) {
  // 验证是否是纯数字
  // let isNumber = /^\d*$/.test(e.target.value);
  // 过滤非数字
  e.target.value = e.target.value.replace(/\D/g, "");
  if (e.target.value <= 0) {
    e.target.value = 1;
  }
  if ( e.target.value > row.orderNum) {
    e.target.value = row.orderNum;
  }
},

10、首字母大小、下划线转驼峰、是否是数字

// 首字母大小
function titleCase(str) {
  return str.replace(/( |^)[a-z]/g, L => L.toUpperCase())
}
titleCase(str="abcd")  //"Abcd"

// 下划转驼峰
function camelCase(str) {
  return str.replace(/-[a-z]/g, str1 => str1.substr(-1).toUpperCase())
}
camelCase(str="my-test") //"myTest"

function isNumberStr(num){
  return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(num)
}
isNumberStr(num="2")//true num="a" false

11、截取今天前30天按月

function createBeginDate(month = 1) {
  let date = new Date();
  date.setMonth(date.getMonth() - month);
  date.toLocaleDateString();
  let y = date.getFullYear();
  let m = date.getMonth() + 1;
  m = m < 10 ? '0' + m : m;
  let d = date.getDate();
  d = d < 10 ? '0' + d : d;
  const time = y + '-' + m + '-' + d;
  return time;
}
createBeginDate(1)//2021-03-26 传0是今天,传n是n月

12、截取今天前30天按日

function createBeginDateDay(agoDay,nowDay) {
  let date1 = new Date();
  let date2 = new Date(date1);
  let getDate1 = date1.getDate() < 10 ? `0${date1.getDate()}` : date1.getDate();
  let getDate2 = date2.getDate() < 10 ? `0${date2.getDate()}` : date2.getDate();

  //-30为30天前,+30可以获得30天后的日期
  date2.setDate(date1.getDate() - agoDay);

  //30天前(月份判断是否小于10,小于10的前面+0)
  agoDay = `${date2.getFullYear()}-${
    date2.getMonth() + 1 < 10
      ? `0${date2.getMonth() + 1}`
      : date2.getMonth() + 1
  }-${getDate2}`;

  //当前日期
  nowDay = `${date1.getFullYear()}-${
    date1.getMonth() + 1 < 10
      ? `0${date1.getMonth() + 1}`
      : date1.getMonth() + 1
  }-${getDate1}`;

  return [agoDay, nowDay];
}
// 第一个参数是n天前的日期,第二个参数是当天的日期(今天的日期不用传,只取时候用)
createBeginDateDay(30)  //2021-03-27至2021-04-26

13、截取今天之前 n天的日期

默认1个月 30天,半年180天,一年365天

/**
 * @param  manyDayBeforeNowDay(agoDay = n天,nowDay不用传) 第一个参数[0]获取当前n天的日期,
 * 第二个参数[1]不用传(默认获取今天的日期)
 */
function manyDayBeforeNowDay(agoDay, nowDay) {
  if (agoDay * 1) {
    return [
      timeStampToFormdate(new Date().getTime() - agoDay * 60 * 60 * 24 * 1000),
      (nowDay = toDay()),
    ];
  } else {
    return [];
  }
}

function toDay() {
  let date = new Date();
  let year = date.getFullYear();
  let month = date.getMonth() + 1;
  month = month < 10 ? '0' + month : month;
  let day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
  return `${year}-${month}-${day}`;
}

function timeStampToFormdate(timestamp) {
  if (!timestamp) {
    return '';
  }
  var date =
    timestamp.toString().length == '13'
      ? new Date(timestamp)
      : new Date(timestamp * 1000); //时间戳为10位需*1000,时间戳为13位的话不需乘1000
  var Y = date.getFullYear() + '-';
  var M =
    (date.getMonth() + 1 < 10
      ? '0' + (date.getMonth() + 1)
      : date.getMonth() + 1) + '-';
  var D = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
  var h =
    date.getHours() < 10 ? '0' + date.getHours() + ':' : date.getHours() + ':';
  var m =
    date.getMinutes() < 10
      ? '0' + date.getMinutes() + ':'
      : date.getMinutes() + ':';
  var s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds();
  return Y + M + D;
  // return Y + M + D + ' ' + h + m + s;
}
manyDayBeforeNowDay(30) //["2021-05-25", "2021-06-24"]

14、获取当前时间,自动轮询计算下一秒时间

   function timeRun(time) {
      let timeJoin = time.split(':');
      let hour = timeJoin[0];
      let minute = timeJoin[1];
      let second = timeJoin[2];
      let ymd;
      this.timeRunSetInterval = setInterval(() => {
        if (second == 59) {
          second = '00';
          if (minute == 59) {
            minute = '00';
            if (hour == 23) {
              hour = '00';
            } else {
              hour++;
              if (hour <= 9) {
                hour = '0' + hour;
              }
            }
          } else {
            minute++;
            if (minute <= 9) {
              minute = '0' + minute;
            }
          }
        } else {
          second++;
          if (second <= 9) {
            second = '0' + second;
          }
        }
        ymd = hour + ':' + minute + ':' + second;
        console.log(ymd)//17:20:15 17:20:16 17:20:17 ...
      }, 1000);
    }
    timeRun('17:20:14')

15、获取今天的日期

直接调用方法获取今天日期 toDay() "2021-06-04"

//  let dddd = 'Fri Dec 10 2021 00:00:00 GMT+0800 (中国标准时间)'
//  let date = new Date(dddd); //处理自定义的日期编码
function toDay() {
  let date = new Date();
  let year = date.getFullYear();
  let month = date.getMonth() + 1;
  month = month < 10 ? '0' + month : month;
  let day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
  return `${year}-${month}-${day}`
}
toDay() // "2021-06-04"

16、table 表格分页计算

/**
 * @description 添加序号索引
 * @param  pageNum 页数
 */
function createIndex(pageNum, i, size) {
  i = parseInt(i);
  size = parseInt(size);
  return (pageNum - 1) * size + i + 1;
}
data.rows.map((item, i) => {
    //id: table表格序号
    let id = createIndex(this.searchForm['pageNum'],i,this.searchForm['pageSize']);
}

17、取数组的最大值|最小值

function getMin(arr) {
  let ary = [];
  if (arr.length >= 1) {
    for (let i = 0; i < arr.length; i++) {
      if (arr[i] !== '' && arr[i] !== null && arr[i] !== undefined) {
        ary.push(arr[i]);
      }
    }
    return Math.min(...ary);
  } else {
    return 0;
  }
}
function getMax(arr) {
  let ary = [];
  if (arr.length >= 1) {
    for (let i = 0; i < arr.length; i++) {
      if (arr[i] != '' && arr[i] !== null && arr[i] !== undefined) {
        ary.push(arr[i]);
      }
    }
    return Math.max(...ary);
  } else {
    return 0;
  }
}
getMin([0.254,1.25,5,4,0.9885,3.5,5.5,9.8])//0.254
getMax([0.254,1.25,5,4,0.9885,3.5,5.5,9.8])//9.8

18、数字转化大写金额

调用 changeNum(1000)方法 参数传金额

function changeNum(money) {
    var cnNums = new Array("零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"); //汉字的数字
    var cnIntRadice = new Array("", "拾", "佰", "仟"); //基本单位
    var cnIntUnits = new Array("", "万", "亿", "兆"); //对应整数部分扩展单位
    var cnDecUnits = new Array("角", "分", "毫", "厘"); //对应小数部分单位
    var cnInteger = "整"; //整数金额时后面跟的字符
    var cnIntLast = "元"; //整型完以后的单位
    var maxNum = 999999999999999.9999; //最大处理的数字
    var IntegerNum; //金额整数部分
    var DecimalNum; //金额小数部分
    var ChineseStr = ""; //输出的中文金额字符串
    var parts; //分离金额后用的数组,预定义
    var Symbol = ""; //正负值标记
    if (money == "") {
      return "";
    }

    money = parseFloat(money);
    if (money >= maxNum) {
      alert('超出最大处理数字');
      return "";
    }
    if (money == 0) {
      ChineseStr = cnNums[0] + cnIntLast + cnInteger;
      return ChineseStr;
    }
    if (money < 0) {
      money = -money;
      Symbol = "负 ";
    }
    money = money.toString(); //转换为字符串
    if (money.indexOf(".") == -1) {
      IntegerNum = money;
      DecimalNum = '';
    } else {
      parts = money.split(".");
      IntegerNum = parts[0];
      DecimalNum = parts[1].substr(0, 4);
    }
    if (parseInt(IntegerNum, 10) > 0) { //获取整型部分转换
      var zeroCount = 0;
      var IntLen = IntegerNum.length;
      for (var i = 0; i < IntLen; i++) {
        var n = IntegerNum.substr(i, 1);
        var p = IntLen - i - 1;
        var q = p / 4;
        var m = p % 4;
        if (n == "0") {
          zeroCount++;
        } else {
          if (zeroCount > 0) {
            ChineseStr += cnNums[0];
          }
          zeroCount = 0; //归零
          ChineseStr += cnNums[parseInt(n)] + cnIntRadice[m];
        }
        if (m == 0 && zeroCount < 4) {
          ChineseStr += cnIntUnits[q];
        }
      }
      ChineseStr += cnIntLast;
      //整型部分处理完毕
    }
    if (DecimalNum != '') { //小数部分
      var decLen = DecimalNum.length;
      for (var i = 0; i < decLen; i++) {
        var n = DecimalNum.substr(i, 1);
        if (n != '0') {
          ChineseStr += cnNums[Number(n)] + cnDecUnits[i];
        }
      }
    }
    if (ChineseStr == '') {
      ChineseStr += cnNums[0] + cnIntLast + cnInteger;
    } else if (DecimalNum == '') {
      ChineseStr += cnInteger;
    }
    ChineseStr = Symbol + ChineseStr;
    return ChineseStr;
  }
  //changeNum(12345) "壹万贰仟叁佰肆拾伍元整"

19、递归处理树结构

image.png

const data = [{
    id: 1,
    title: "课程 1",
    children: [
            {
                id: 4,
                title: "课程 1-1"
            },
            {
                id: 5,
                title: "课程 1-2",
                children: [{
                    id: 6,
                    title: "课程 1-2-1"
                },
                {
                    id: 7,
                    title: "课程 1-2-2"
                },
                ],
            },
        ],
    },
    {
        id: 2,
        title: "课程 2"
    },
    {
        id: 3,
        title: "课程 3"
    },
];

const formatData = (data) => {
        const newArr = [];
        const callFn = (root, newArr) => {
                let currentArr;
                if (Array.isArray(root)) {
                        currentArr = root;
                } else {
                        newArr.push(root);
                        currentArr = root.children;
                }
                if (!currentArr || !currentArr.length) return;
                for (let i = 0; i < currentArr.length; ++i) {
                        callFn(currentArr[i], newArr);
                }
        };
        callFn(data, newArr);
        newArr.forEach(item => {
                if (item.children) delete item.children
        })
        return newArr;
};
console.log(formatData(data))


// 创建一个辅助函数用于递归构建带有折叠功能的DOM节点
<div id="courses-tree"></div>
function createTreeNodes(course, level = 0) {
  const li = document.createElement('li');
  li.dataset.id = course.id;

  const titleSpan = document.createElement('span');
  titleSpan.textContent = `${'  '.repeat(level)}${course.title}`;
  li.appendChild(titleSpan);

  // 折叠按钮
  const toggleBtn = document.createElement('button');
  toggleBtn.textContent = '[-]';
  toggleBtn.addEventListener('click', () => {
    const childrenUL = li.querySelector('ul');
    if (childrenUL) {
      childrenUL.style.display = childrenUL.style.display === 'none' ? 'block' : 'none';
    }
    toggleBtn.textContent = toggleBtn.textContent === '[+]' ? '[-]' : '[+]';
  });
  li.appendChild(toggleBtn);

  if (course.children && course.children.length > 0) {
    const childrenUL = document.createElement('ul');
    course.children.forEach(child => {
      childrenUL && childrenUL.appendChild(createTreeNodes(child, level + 1));
    });
    li.appendChild(childrenUL);
    if (childrenUL) {
      childrenUL.style.display = 'none'; // 初始时子项隐藏
    }
  }

  return li;
}
// 将课程列表转换为DOM元素并插入到页面中某个容器内
const treeContainer = document.getElementById('courses-tree');
options.forEach(course => {
  treeContainer.appendChild(createTreeNodes(course));
});

treeContainer image.png

20、日期编码格式转为标准日期,日期大小比较

let bigDate = 'Fri Dec 12 2021 00:00:00 GMT+0800 (中国标准时间)';
let bigDate2 = "Fri Dec 12 2021 00:00:00 GMT+0800 (中国标准时间)";

function toDay(dates) {
  // let date = new Date(dates);

  let dddd = 'Fri Dec 10 2021 00:00:00 GMT+0800 (中国标准时间)'
  let date = new Date(dddd);//自定义的格式

  let year = date.getFullYear();
  let month = date.getMonth() + 1;
  month = month < 10 ? '0' + month : month;
  let day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
  return `${year}-${month}-${day} 00:00:00`
}

let t1 = toDay(bigDate)
let t2 = toDay(bigDate2)

function tab(date1,date2){
    var oDate1 = new Date(date1);
    var oDate2 = new Date(date2);
        if(oDate1.getTime() == oDate2.getTime()){
                console.log('相等')
        }else if(oDate1.getTime() !== oDate2.getTime()) {
                console.log('不想等')
        }

    if(oDate1.getTime() > oDate2.getTime()){
        console.log('第一个大');
    } else if(oDate1.getTime() < oDate2.getTime()){
        console.log('第二个大');
    }else {}
}
tab(t1,t2);

21、巧用数组方法判断日期是否相等

let viewItemsReturnDate = ['Thu Dec 16 2021 00:00:00 GMT+0800 (中国标准时间)',
'Thu Dec 17 2021 00:00:00 GMT+0800 (中国标准时间)','Thu Dec 18 2021 00:00:00 GMT+0800 (中国标准时间)'];
let t1 = 'Thu Dec 16 2021 00:00:00 GMT+0800 (中国标准时间)';
let t2 = 'Thu Dec 18 2021 00:00:00 GMT+0800 (中国标准时间)';

let allEqual = false;

//调用toDay 方法转位日期,去比对大小
if (viewItemsReturnDate.length > 0) {
      viewItemsReturnDate.map(item => {
        let t1 = this.toDay(viewItemsReturnDate[0]);
        let t2 = this.toDay(item);
        allEqual = t1 == t2 ? true : false;
      })
  } 
  if(!allEqual){
      // 不相等
  }else {
      //相等
  }

22、判断数组中的每一项是否相等

function isAllEqual(array) {
    if (array.length > 0) {
        return !array.some(function(value, index) {
            return value !== array[0];
        });
    } else {
        return true;
    }
}
isAllEqual([1,1,2]) // false

23、数组对象里 item 里有重复的,那么保留ary初始化的,去掉 item 里新增的

let ary = [
    {
        name:"ha",
        key: 'StockTransfer',
    },
    {
        name:"he",
        key: 'MiscIssue',
    },
];
let item = [];
item.push(
    {
        name:"hi",
        key: 'MiscReceipt',
    },
    {
        name:"ha",
        key: 'StockTransfer',
    }
)
let hash = {};
const newAry = item.reduce((cur, next) => {
  hash[next.key] ? "" : hash[next.key] = true && cur.push(next);
  return cur;
}, [])

24、数组中的值是否相等

let ary = [
    "2022-04-20T16:00:00.000Z",
    "2022-04-20T16:00:00.000Z",
    "2022-04-20T16:00:00.000Z"
]

// 判断是否相等
function isAllEqual(array) {
    if (array.length > 0) {
        return !array.some((value, index) => {
            return value !== array[0];
        });
    } else {
        return true;
    }
}

isAllEqual(ary) // true

let allEqualtakeT;
if (ary.length > 0) {
takeT = ary.join(",") + ",";
}
for(let i = 0;i < ary.length; i++){
allEqual = takeT.replace(ary[i] + ",", "").indexOf(ary[i] + ",") > -1
}
console.log(allEqual)// true

25、把obj对象里的值覆盖到newobj里面

有两个对象,需要用某个对象覆盖另一个对象的,根据属性来覆盖

let obj = {
    a:"1",
    b:"2"
}
let newobj = {
    a:"10",
    b:"20"
}
function deepCopy(newobj, obj) {
    if (typeof obj != 'object') {
            return obj
    }
    for (var attr in obj) {
            var a = {}
            if (newobj[attr]) {
                    a = newobj[attr]
            }
            newobj[attr] = deepCopy(a, obj[attr])
    }
    return newobj
}

deepCopy(newobj,obj)
// {a: '1', b: '2'}

26、不足位数前面补0 & 后缀补0

不足位数前面补0&后缀补0,length是值的总位数

function PrefixInteger(num, length) {
    return (Array(length).join('0') + num).slice(-length)
}

function SuffixInteger(num, length) {
    return (num + Array(length).join('0')).slice(-length)
}

PrefixInteger(4,9) // '000000004'
SuffixInteger(4,9) //'400000000'

27、防抖与节流

防抖 (Debouncing) 的含义是指在一定时间内,多次触发同一个事件,只执行最后一次操作。例如,当我们在搜索框中输入关键词时,输入框会不断触发 oninput 事件,如果每次输入都去请求服务器获取数据,会造成不必要的请求浪费。此时就可以使用防抖技术,将一定时间内的多次触发合并为一次操作,只请求一次服务器数据,减少了请求次数和服务器负载。

节流 (Throttling) 的含义是指在一定时间内,多次触发同一个事件,只执行第一次操作。例如,当我们拖动网页上的滚动条时,会不断触发 onscroll 事件,如果每次触发都去计算滚动距离,会造成浏览器性能下降。此时就可以使用节流技术,将一定时间内的多次触发限制为一次操作,只计算一次滚动距离,提高了浏览器性能和用户体验。

/* 防抖函数 */
export const debounce = (fn, wait) => {
  let timer = null;

  return function () {
    let context = this,
      args = arguments;

    if (timer) {
      clearTimeout(timer);
      timer = null;
    }

    timer = setTimeout(() => {
      fn.apply(context, args);
    }, wait);
  };
};

/* 节流函数 */
export const throttle = (fn, delay) => {
  let curTime = Date.now();

  return function () {
    let context = this,
      args = arguments,
      nowTime = Date.now();

    if (nowTime - curTime >= delay) {
      curTime = Date.now();
      return fn.apply(context, args);
    }
  };
};

28、深拷贝与浅拷贝

对象属于引用类型的值,会在浏览器的栈内存中存一个十六进制的地址,指向对象的堆内存。

浅拷贝就是创建一个新对象,这个对象有着原始属性值的一份精准拷贝。

如果属性是基本类型,拷贝的就是基本类型的值;如果是引用类型,拷贝的就是内存地址。

修改同一份内存地址中的值,就会影响到另一个对象的原有值。

let schemaObj = {
  code: 1,
  templateId: "12345678",
  rangeWork: "view",
  function: () => {}
}

// 浅拷贝
let schemaObj1 = schemaObj;
schemaObj1.rangeWork = "add";
console.log(schemaObj.rangeWork) // add
console.log(schemaObj1.rangeWork)// add

// 深拷贝
let schemaObj2 = {...schemaObj}; // 等同于 Object.assign({}, schemaObj);
schemaObj2.rangeWork = "add";
console.log(schemaObj.rangeWork) // view
console.log(schemaObj2.rangeWork)// add

// 这种方法虽然可以实现数组或对象深拷贝,但不能处理函数和正则,因为这两者基于JSON.stringify和JSON.parse处理后,得到的正则就不再是正则(变为空对象),得到的函数就不再是函数(变为null)了。
let schemaObj3 = JSON.parse(JSON.stringify(schemaObj)); 
schemaObj3.rangeWork = "add";
console.log(schemaObj.rangeWork) // view
console.log(schemaObj3.rangeWork)// add

// 调用封装的 deepClone
let schemaObj4 = deepClone(schemaObj);
schemaObj4.rangeWork = "add";
console.log(schemaObj.rangeWork) // view
console.log(schemaObj4.rangeWork)// add

// 封装递归方法
function deepClone(obj, hash = new WeakMap()) {
  if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  // 可能是对象或者普通的值  如果是函数的话是不需要深拷贝
  if (typeof obj !== "object") return obj;
  // 是对象的话就要进行深拷贝
  if (hash.get(obj)) return hash.get(obj);
  let cloneObj = new obj.constructor();
  // 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身
  hash.set(obj, cloneObj);
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      // 实现一个递归拷贝
      cloneObj[key] = deepClone(obj[key], hash);
    }
  }
  return cloneObj;
}
/**
 * 【对象】
 * 扩展 jQuery.extend()方法 -> $.extend(true, {}, schemaObj)//第一个参数为true,就是深拷贝
 * 函数库lodash的_.cloneDeep方法  ->  _.cloneDeep(schemaObj)
 * 
/ 

29、根据url地址转换为file文件

音频地址(audio.mp3),转换为file文件 image.png

// url地址转file文件,设置文件名称
function handerUrlToFile(fileUrl) {
  if (!fileUrl) return;

  fetch(fileUrl)
    .then(response => {
      if (!response.ok) {
        throw new Error('Network response was not ok');
      }
      return response.blob();
    })
    .then(blob => {
      const speakerName = fileUrl.split('/').pop();
      const urlSuffix = fileName.split('.').pop();
      const audioOrgFile = new File([blob], `${fileName}`, {
        type: `audio/${urlSuffix}`,
      });
      console.log(audioOrgFile, 'audioOrgFile');
      console.log(speakerName, 'speakerName');

      this.audioOrgFile = audioOrgFile;
      this.speakerName = speakerName;
    })
    .catch(error => {
      console.error('There has been a problem with your fetch operation:', error);
    });
}

let formdata = new FormData();
formdata.append('file', this.audioOrgFile);
formdata.append('speakerName', this.speakerName);

30、使用 Promise 实现防止重复请求

const preventReqMore = (fn, p = null) => {
  return (...argv) => {
    p = p ? p : fn(...argv).finally(() => {
        p = null 
    })
    return p
  }
}
// 可以简写成一行
// const preventReqMore = (fn, p = null) => (...argv) => p ? p : (p = fn(...argv).finally(() => (p = null)))

let fetchReq = () => {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log('Request completed');
      resolve();
    }, 1000);
  });
};
let fetchReqPrevented = preventReqMore(fetchReq);
fetchReqPrevented();  
fetchReqPrevented();  // 会被阻止,不会发起请求

31、生成 uuid 的方法

const uuid = (a) => a ? (a ^ ((Math.random() * 16) >> (a / 4))).toString(16) : ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, uuid);

console.log(uuid()) // bf6fb22e-4162-48ca-9d93-1c2566e63152

32、检查是否是空对象的方法

方法一:
function isEmptyObject(obj){
    //排除null或undefined
    if(obj == null) return false;
    if(typeof obj !== "object") return false;
    //是一个对象,纯对象或特殊对象都可以
    var keys = Object.keys(obj);
    //如果兼容再去拼接
    if(Object.prototype.hasOwnProperty.call(Object,"getOwnPropertySymbols")){
        keys.concat(Object.getOwnPropertySymbols(obj));
    }
    return keys.length === 0;
}

isEmptyObject({}) // true


方法二:
const isEmptyObject = obj => Reflect.ownKeys(obj).length === 0 && obj.constructor === Object; 
isEmptyObject({}) // true 
isEmptyObj({a:"not empty"}) //false

33、video播放器切换tab键去掉默认被选中


  /* 移除 video 元素本身的焦点边框 */
  video:focus {
    outline: none;
  }
  video::-moz-focus-inner {
    border: none;
  }
  // /* 移除 video 内部控件(播放按钮、进度条等)的焦点边框 */
  video::-webkit-media-controls-enclosure:focus,
  video::-webkit-media-controls-panel:focus,
  video::-webkit-media-controls-current-time-display:focus,
  video::-webkit-media-controls-time-remaining-display:focus,
  video::-webkit-media-controls-timeline:focus,
  video::-webkit-media-controls-mute-button:focus,
  video::-webkit-media-controls-volume-slider:focus,
  video::-webkit-media-controls-fullscreen-button:focus,
  video::-webkit-media-controls-play-button:focus,
  video::-webkit-media-controls-overflow-button:focus {
    outline: none;
    box-shadow: none;
  }