前端开发中常用的工具函数

前言

记录自己日常开发中,常用到的一些工具函数,如果有问题欢迎大家指正,谢谢~


1. 根据传入的对象构造url

/**
* 可以根据传递的对象构造url 常用在get请求或者链接跳转
* 例如 user/userList  {id:"123",name:"小王"}
* 返回 user/userList?id=123&name=小王
*/
export function createSearch(url, params) {
    const query = Object.keys(params).reduce((acc, cur) => {
        debugger
        if (params[cur]) {
            if (!acc) return `?${acc}=${params[cur]}`;
            return `${acc}&${cur}=${params[cur]}`
        }
        return acc
    }, '')
    return `${url}${query}`
}

2. JSON格式容错判断

/**
* JSON在 JSON.parse 的时候,在参数为 undefined、null 或者不合规时,会报错
* 所以在 JSON.parse 时候应该进行容错处理 可以简单封装成一个函数,放在项目中特定的文件中进行维护
* 对异常进行捕获 
*/

export const parse = <T = any> (text: string,func?: (test: T) => any ) => {
    let parsedString: strng | T = "";
    try {
        parsedString = JSON.parse(text);
    } catch (error) {
        parsedString = text;
    }
    if(typeof func === "function") return func(parsedString as T);
    return parsedString;
}


3. 一维数组去重

/**
* 一维数组或者一维对象数组去重
* @params arr 要去重的数据
* @params key 去重字段
*/
export const removeDuplicates = function (arr: any[], key?: string): any[]  {
    if (key) {
        const map = new Map();
        return arr.filter((item) => !map.has(item[key]) && map.set(item[key], 1))
    } else {
        return [... new Set(arr)]
    }
}


// [{name:"123"},{name:"456"},{name:"123"}]  => [{name:"123"},{name:"456"}]

4. 解析url中的参数

/**
* 解析url参数
* @params url 要解析的参数
*/
export const getSearcParamsUtil = function (url: string): Record<string, any>  {
    const result = {}

    // 取url中的参数部分
    const str = url.substr(url.indexOf('?') + 1)
    // 将参数部分按照 & 分割为数组
    const paramsArr = str.split('&')
    
    paramsArr.forEach(item => {
        const params = item.split('=');
        result[params[0]] = params[1];
    });
    return result
}

5. 解析带有HTML实体的字符串

/**
* 在某些情况下,后端在入库存储时可能会将HTML实体,例如:换行、引号等进行转义
* 但是在读库的时候又没有进行反转义,这时候在回填的时候可能会出现文本问题
*
* @params str 
*/
export const decodeHtmlEntities = (str?: string)  {
    if(!str) return "";
    else{
        let result = "";
        const span = document.createElement("span");
        span.innerHTML = str;
        span.childNodes?.forEach((v)=>result += v?.nodeValue);
        return result;
    }
}

6. 使用 a 标签下载文件

HTML <a> 元素可以创建一个到其他网页、文件、同一页面内的位置、电子邮件地址或任何其他URL的超链接。

<a>元素的 href download 是我们下载文件所需要的两个属性。

download 可以实现对下载文件的重命名,但目前存在很大的兼容性问题,只有Chrome和Opear才有效,并且如果说下载文件不是在子集的服务器或域名中(),这些浏览器会忽视download属性,文件名不变。简而言之,跨域会导致download属性无效。另外再说一下 target 属性

target _blank打开新页面  _self在本身页面中打开

 // GET 下载文件   
 const download = (path:sring, target?: "_blank" | "_self") => {
        const a = document.createElement("a");
        a.download = "";
        a.target = target ?? "_self";
        a.href = path;
        a.style.display = "none";

        // 向body的子节点末尾添加上面的 a 标签
        document.body.appendChild(a);
        a.click();
        // 触发下载之后,移除 a 标签
        document.body.removeChild(a);
 }






    /***
     * GET POST 使用Blob(二进制流)下载文件
     * 
     * 正常情况下 axaios 或者request 不会处理二进制数据,即:会去接收但是不会去处理,需要在请求的时候设置  responseType: "blob" 
     * 拿到文件流之后,这时候文件流就会被保存在内存里。需要我们生成一个 URL 来实现下载,,而生成的URL 就是文件流在内存中的地址(这个地址为临时的,浏览器在 document 卸载时,会自动释放它们)
     * 我们可以通过 URL.createObjectURL() 方法生成一个链接
     * 
     * 这里用了Blob对象,该方法的意思是用从服务器接收到的文件流创建了一个blob对象,
     * 并使用该blob创建一个指向类型数组的URL,将该url作为a标签的链接目标,然后去触发a标签的点击事件从而实现下载功能。
     * 
     * @ requestFn 文件导出的异步请求 
     * @ fileName 文件名称
    */
    const downloadBlod = async (requestFn, fileName) => {
        const { data, response } = await requestFn();
        const contentType = response.headers.get("Content-type")?.split(";")?.[0]; //获取请求的类型
        let reFileName = window.decodeURI(response.headers.get("Content-Disposition")?.split("=")?.[0]);  //获取请求文件名称

        if (["undefined", "null"].includes(reFileName)) reFileName = fileName;
        if (contentType === "application/json") return false; // 接口未正常导出文件时
        // 接口正常导出文件时 处理二进制文件流
        if (contentType === "application/octet-stream") { // 非IE下载
            const blob = new Blob([data], { type })
            if ("download" in document.createElement("a")) {
                const url = window.URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.style.display = 'none';
                a.href = url;
                a.setAttribute('download', reFileName);// a标签的 download 属性可以指定文件的名称

                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a); //移除 a 标签 
                URL.revokeObjectURL(url); //释放URL对象
            } else window.navigator.msSaveBlob(blob, reFileName);  //IE下载
            return true;
        }
        return false;

    }

    // 使用
    document.getElementById('down').onclick = async () => {
        downloadBlod(
            () => { exportRequest({ responseType: "blob", getResponse: true }) }, // 导出的异步请求
            "文件导出.xls"
        )
    }

7. 递归获取对象的key,如果对象不存在某个属性或属性值未获取到则返回默认的值

const user = {
  info: {
    name: "张三",
    address: { home: "Shaanxi", company: "Xian" },
  },
};


// obj是获取属性的对象,path是路径,fallback是默认值
function get(obj, path, fallback) {
  const parts = path.split(".");
  const key = parts.shift();
  if (typeof obj[key] !== "undefined") {
    return parts.length > 0 ?
      get(obj[key], parts.join("."), fallback) :
      obj[key];
  }
  // 如果没有找到key返回fallback
  return fallback;
}

console.log(get(user, "info.name")); // 张三
console.log(get(user, "info.address.home")); // Shaanxi
console.log(get(user, "info.address.company")); // Xian
console.log(get(user, "info.address.abc", "fallback")); // fallback



另外一种方法
function get(obj: any, path: string, fallback: any) {
let parts = path.split('.');
return parts.reduce((a, b) => a && a[b], obj) || fallback
}
但是由于reduce会有循环,即使已经undefined,方法还是会继续循环下去,不会及时停止,增加不必要的执行次数

おすすめ

転載: blog.csdn.net/fsfsdgsdg/article/details/127060737