前端开发 小方法(记录和提升)

94 阅读4分钟

验证 undefined 和 null

if(a === null && a === undefined){
     doSomething();
 }
 // 如果 a 是只需 验证 为 null 和 undefined 时
 // 可以精简成
 a ?? doSomething();
// 空值运算符 (??) 是一个逻辑操作符,当左侧的操作数为 null 或者 undefined时, 返回其右边操作数,否则返回左侧操作数。

数组元素中的每一项转化为数字。

 const arr = ['1','2','3','-45','1.45'];
 arr.map(Number); // [ 1 , 2 , 3 , -45 , 1.45 ]

禁止浏览器回退

    //禁止回退
    window.location.hash = "no-back";
    window.location.hash = "Again-No-back-button";
    window.onhashchange = function () { window.location.hash = "no-back"; }

js 监听浏览器页面切换

document.addEventListener('visibilitychange',function(){  
    if (document.visibilityState=='hidden') {  
        //切离该页面时执行  
    } else if (document.visibilityState=='visible') {  
        //切换到该页面时执行  
    }  
});

比较两个对象是否是相等的

vue 源码中的算法 !!(没有考虑正则表达式)
  • js中对象是无法使用 == 来比较的, 因为比较的是内存地址 一定是 false
  • 我一般会定义如果对象的各个属性都相等,那么对象就是相等的对象,例如: {} 与 {} 相等

算法描述 (抽象一下 就是判断两个集合是否相等)

  1. 假定对象 a 和 b
  2. 遍历a中的成员,判断是否每一个 a 中的成员都在 b 中,并且 与 b 中的对应成员相等。
  3. 遍历b中的成员,判断是否每一个 b 中的成员都在 a 中,并且 与 a 中的对应成员相等。
  4. 如果成员是引用类型, 递归
export function looseEqual (a: any, b: any): boolean {
  if (a === b) return true
  const isObjectA = isObject(a)
  const isObjectB = isObject(b)
  if (isObjectA && isObjectB) {
    try {
      const isArrayA = Array.isArray(a)
      const isArrayB = Array.isArray(b)
      if (isArrayA && isArrayB) {
        return a.length === b.length && a.every((e, i) => {
          return looseEqual(e, b[i]) // 这里是在判断a 里面的成员是不是都在b里面
        })
      } else if (a instanceof Date && b instanceof Date) {
        return a.getTime() === b.getTime() // 单独处理了 Date 类型, 时间戳应该是一样的
      } else if (!isArrayA && !isArrayB) {
        const keysA = Object.keys(a)
        const keysB = Object.keys(b)
        // 先判断 key 长度, 再判断 a 包含 b
        return keysA.length === keysB.length && keysA.every(key => {
          return looseEqual(a[key], b[key])
        })
      } else {
        /* istanbul ignore next */
        return false
      }
    } catch (e) {
      /* istanbul ignore next */
      return false
    }
  } else if (!isObjectA && !isObjectB) {
    return String(a) === String(b)
  } else {
    return false
  }
}

// 判断是否为对象
export function isObject (obj: mixed): boolean %checks {
  return obj !== null && typeof obj === 'object'
}

base64转文件流

   var data = new FormData(); // 创建 FormData
    const file = base64ToFile("base64文件");
    data.append("file", file); // 将这个 文件流 加入
    //此时这个 data 就是文件流格式了就能当参数使用了
    
    function base64ToFile(dataurl:string, filename = "file") {
      //将base64转换为文件
          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});
      }
      

//封装的 post 请求
    const instance = axios()   
    interface Options {
    params?: unknown;
    headers?: unknown;
    }
    post(url: string, data?: unknown, headers?: unknown, params?: unknown):any {
        const optionsOptions = {}
        if (headers) {
            options.headers = headers
        }
        if (params) {
            options.params = params
        }
        return instance.post(url, data, options)
    },
//在vue中
接口(params?: unknown) {
        return axios.post(`${url}/app/qxjgl/saveCommentPicture`, params,{"Content-Type":"multipart/form-data"});
    },
// 请求头 一般使用 {"Content-Type":"multipart/form-data"}

!! 注意 千万 不要 给参数 序列化 config.data = qs.stringify(config.data)

三秒钟连续点击超过8下打开 隐藏元素

    let count = 0;
    let lastClickTime = 0;
    function showddd() {
      const nowTime = new Date().getTime();
      if (count === 0) {
        lastClickTime = nowTime;
        count++;
      } else if (nowTime - lastClickTime < 3000) {
        lastClickTime = nowTime;
        count++;
      } else {
        count = 0;
      }
      if (count >= 8) {
        const element = document.getElementById("DOM");
        element!.style.display = "block";
      }
    }

自定义指令 点击 元素内部外部

<div V-click-outside>
    <input type="text" :value="formatDate">
    <div class="panneu" v-if="isVisible">
        content 
    <button></button>
    /div>
</div>
directives:{
    clickOutside:[ // 指令的生命周期
        bind(el,bindings,vnode){ // context
    // 把事件绑定给document上 看一下点击的是否是当前这个元素内部let handler = (e)=>[
    if(el.contains(e.target)){
    // 判断一下是否当前面板已经显示出来了if(!vnode.context.isVisible){vnode.context.focus();
     }elsef
    if(vnode.context.isVisible){vnode.context.blur();
        el.handler = handler;
        document.addEventListener('click',handler)
    unbind(el){
        document.removeEventListener('click',el.handler)
    }
}

前端实现一个 sleep函数

const sleep = (duration) => new Promise((resolve) => setTimeout(resolve, duration));

使用 生成器 解决回调地狱问题

// 生成器其实就是一个特殊的函数
function * gen(){

    yield '111';

    yield '222';

    yield '333';

}

let iterator = gen(); //定义的生成器不能直接调用需要调用next方法

iterator.next();

//一个Generator函数与普通function的区别就是函数名前面多了一个星号 * 但是执行时有很大不同,与yield命令配合,可以实现暂停执行的功能

//生成器可以解决 回调地狱的问题

//示例:

function one(){

    setTimeout(()=>{

        console.log(111);

        iterator.next();

       },1000)

}

function two(){

    setTimeout(()=>{

        console.log(111);

        iterator.next();

    },2000)

}

function three(){

    setTimeout(()=>{

        console.log(111);

        iterator.next();

    },3000)

}

function * gen(){

    yield one();

    yield two();

    yield three();

}

let iterator = gen();

iterator.next();

vue .once 方法实现

export function once (fnFunction): Function {
  let called = false //是否调用过
  return function () {
    if (!called) {
      called = true
      fn.apply(thisarguments)
    }
  }
}

div 键盘事件失效

    <div @keyup="onRockingBar" tabindex="0" style="outline: 0">
  • tabindex="0" 加上这个属性即可。
  • 不希望出现白框 style="outline: 0"

后续还会持续更新 共勉 加油