前端常用的工具類函式, 持續更新中

我在長安長安發表於2019-02-16

在開發專案的時候,有一些場景用到次數頻繁的函式,就封裝在了自己的工具類裡,在這裡和大家分享一下

1. 通過value獲取到資料列表中對應顯示的欄位

經常做平臺類的專案,容易碰到這樣的場景,增刪改查頁面,新增完之後,表格要顯示某個型別,但是介面返回資料是型別ID,就可以通過這個方法得到對應要顯示的欄位了。

 用法示例:let list = [{id: 1, name: `深圳`}, {id: 2, name: `廣州`}]
          getDataName({dataList: arr, value: `id`, label: `name`, data: 1}) // 深圳
          getDataName({dataList: arr, value: `id`, label: `name`, data: 2}) // 廣州

 /**
   * 通過value找到在列表中對應的名字
   * @param {Object} obj
   *  @param obj.dataList 資料列表
   *  @param obj.value    資料的值對應的欄位名稱   例如 `value`
   *  @param obj.label    資料的說明對應的欄位名稱 例如 `label`
   *  @param obj.data     當前傳入的資料值
   * @return name        返回當前傳入值在陣列中對應的名字
   */
  getDataName: (obj) => {
    let name = obj.data
    if (Array.isArray(obj.dataList) && obj.dataList.length > 0) {
      for (let i = 0; i < obj.dataList.length; i++) {
        if (obj.dataList[i][obj.value] == obj.data) {
          name = obj.dataList[i][obj.label]
        }
      }
    }
    return name
  }

2. 對請求失敗的HTTP狀態碼做處理

說多了都是淚,之前公司介面返回資料,一開始沒有做異常處理,然後在使用的時候一旦出現什麼問題頁面上就是一大堆的英文,很長很長一串,或者是出現問題了不返回錯誤原因,然後說影響使用者體驗,但是後端又不做異常處理,於是就寫了一個關於http狀態碼的處理。根據返回的狀態碼頁面上顯示對應的提示內容,不過感覺稍微正常的流程都用不上這個,哈哈

/**
   * 對請求失敗的HTTP狀態嗎做處理
   * @param {Number} code     HTTP狀態碼
   * @param {String} message  錯誤提示
   * @return message 返回處理過的提示資訊
   */
  requestError: (code, message) => {
    let statusCode = (code + ``).replace(/[^0-9]+/g, ``) - 0

    switch (statusCode) {
      case 400:
        return `Bad Request (錯誤的請求)`
      case 401:
        return `Unauthorized (請求要求身份驗證)`
      case 403:
        return `Forbidden (伺服器拒絕請求)`
      case 404:
        return `NOT Found (伺服器找不到請求的資源)`
      case 405:
        return `Bad Request (禁用請求中指定的方法)`
      case 406:
        return `Not Acceptable (無法使用請求的內容特性響應請求的網頁)`
      case 407:
        return `Proxy Authentication Required (需要代理授權)`
      case 408:
        return `Request Timed-Out (伺服器等候請求時發生超時)`
      case 409:
        return `Conflict (伺服器在完成請求時發生衝突。伺服器必須在響應中包含有關衝突的資訊)`
      case 410:
        return `Gone (請求的資源已被永久刪除)`
      case 411:
        return `Length Required (伺服器不接受不含有效內容長度標頭欄位的請求)`
      case 412:
        return `Precondition Failed (未滿足前提條件)`
      case 413:
        return `Request Entity Too Large (請求實體過大)`
      case 414:
        return `Request, URI Too Large (請求的 URI 過長)`
      case 415:
        return `Unsupported Media Type (不支援的媒體型別)`
      case 429:
        return `您的操作過於頻繁,請稍後重試`
      case 500:
        return `Internal Server Error (伺服器內部錯誤)`
      case 501:
        return `Not Implemented (尚未實施)`
      case 502:
        return `Bad Gateway (錯誤閘道器)`
      case 503:
        return `Server Unavailable (服務不可用)`
      case 504:
        return `Gateway Timed-Out (閘道器超時)`
      case 505:
        return `HTTP Version not supported (HTTP 版本不受支援)`
      default:
        return message
    }
  },

3. 傳入時間戳,轉換指定的時間格式

這個是本人用的非常多的一個函式,平時經常需要對時間處理,就只需要傳入時間戳或者時間格式的字串,然後指定要轉換的時間格式,就可以了,很方便

 用法示例:switchTime(new Date()) // 傳入當前時間,預設返回當時時間,格式為 YYYY-MM-DD hh:mm:ss
          switchTime(`2018-11-10`, `YYYY.MM.DD`) // 2018.11.10

 /**
   * 傳入時間戳(或者時間格式的資料),轉換指定的時間格式
   * @param {Number} val      時間戳(或者時間格式的資料)
   * @param {String} dateType 要得到的時間格式 例如 YYYY-MM-DD hh:mm:ss
   * @return dataStr 例如 YYYY-MM-DD hh:mm:ss
   */
  switchTime: (val = +new Date(), dateType = `YYYY-MM-DD hh:mm:ss`) => {
    // 將字串轉換成數字
    let timeStamp, dateStr, str
    timeStamp = +new Date(val)

    // 如果轉換成數字出錯
    if (!timeStamp) {
      return val
    }

    // 得到時間字串
    dateStr = new Date(timeStamp)
    str = dateType.replace(`YYYY`, dateStr.getFullYear())
    str = str.replace(`MM`, (dateStr.getMonth() + 1 < 10 ? `0` : ``) + (dateStr.getMonth() + 1))
    str = str.replace(`DD`, (dateStr.getDate() < 10 ? `0` : ``) + dateStr.getDate())
    str = str.replace(`hh`, (dateStr.getHours() < 10 ? `0` : ``) + dateStr.getHours())
    str = str.replace(`mm`, (dateStr.getMinutes() < 10 ? `0` : ``) + dateStr.getMinutes())
    str = str.replace(`ss`, (dateStr.getSeconds() < 10 ? `0` : ``) + dateStr.getSeconds())

    return str
  }

4. 瀏覽器開啟新視窗

在平時開發中,一定會有這樣的需求,開啟新視窗。但是用window.open的方式往往會碰到被瀏覽器攔截的問題,所以可以用a標籤通過超連結的方式開啟新視窗。
往往在下載檔案的時候也會用到這個方法。不過下載檔案分為幾種情況,一種是直接訪問一個地址,瀏覽器會自動解析並且下載,還有一種情況就是後端返回的是一個檔案,這個時候需要先在響應型別中加上blob處理之後,再去處理。這種情況下訪問解析後的地址,往往是開啟一個新視窗並訪問,並不會自動下載,而需要下載的話需要給a標籤再加上一個download屬性。

  用法示例:openWindow(`https://www.baidu.com`) // 預設開啟方式為新視窗, id為open

  /**
   * a模擬window.open,不會被瀏覽器攔截
   * @param {String} url        a標籤開啟的地址
   * @param {String} id         a標籤的ID
   * @param {String} targetType a標籤點選開啟的方式(當前頁面開啟還是新視窗開啟)
   */
  openWindow: (url, targetType = `_blank`, id = `open`) => {
    // 如果存在則刪除
    if (document.getElementById(id)) {
      document.body.removeChild(document.getElementById(id))
    }
    let a = document.createElement(`a`)
    a.setAttribute(`href`, url)
    a.setAttribute(`download`, url)
    a.setAttribute(`target`, targetType)
    a.setAttribute(`id`, id)
    document.body.appendChild(a)
    a.click()
  },

5. 將有層級關係的列表轉換成樹狀資料

不知道大家碰到樹狀結構的情況,但是本人開發的時候,因為開發的平臺類的專案較多,所以經常碰到樹狀的資料結構。
以前都是叫後端直接返回樹狀資料的,但是後端好像也不喜歡處理這樣的資料,就自己寫了一個方法。
傳入有層級關係的列表資料,然後根據定義的引數,處理成樹狀的資料結構。

  用法示例:let arr = [{id: 1, pid: 0, name: `一級`}, {id: 2, pid: 1, name: `二級`}],
               arr1 = getTreeArr({key: `id`, pKey: `pid`, rootPValue: 0, data: arr})
  得到的資料為:
           arr1 = [
               {id: 1, pid: 0, name: `一級`, children: [{id: 2, pid: 1, name: `二級`, children: []}]
               }
           ]

  /**
   * 將一級的資料結構處理成樹狀資料結構
   * @param {Object} obj {key, pKey, data}
   *  @param obj.key  欄位名稱 比如id
   *  @param obj.pKey 父欄位名稱 比如 pid
   *  @param obj.rootPValue 根節點的父欄位的值
   *  @param obj.data 需要處理的資料
   * @return {Array} arr
   */
  getTreeArr: (obj) => {
    if (!Array.isArray(obj.data)) {
      console.log(`getTreeArr=>請傳入陣列`)
      return []
    }
    let arr, arr1
    arr = obj.data
    arr1 = []
    // 資料處理
    arr.forEach(item => {
      item.children = []
      arr.forEach(item1 => {
        if (item[obj.key] === item1[obj.pKey]) {
          item.children.push(item1)
        }
      })
      // 沒有傳入根節點的父ID時,預設設為0
      obj.rootPValue = obj.rootPValue || 0
      if (item[obj.pKey] === obj.rootPValue) {
        arr1.push(item)
      }
    })
    return arr1
  },

6. 佔位顯示

寫vue元件的時候,總是習慣用物件去做引數,因為覺得把引數變成物件的形式維護起來會非常方便,每次增加引數的時候只需要在物件中加上屬性,接受的地方對屬性做處理就好了。
但是vue元件的話,Object是不能設定預設值的,沒有預設值的話,讀取物件的屬性便是一個錯誤的語法,所以就寫了一個佔位顯示的方法,比如

  用法示例:showData(obj, `name`, `名字`) // 當obj未傳入的時候顯示 ‘名字’, 傳入後顯示為 obj.name

  /**
 * 用來判斷物件不存在是,顯示的欄位資料
 * @param {Object} obj 物件
 * @param {String} key 要顯示的屬性
 * @param {String} staticName 屬性不存在時顯示的值
   */
  showData (obj, key, staticName) {
    if (!obj) {
      obj = {}
    }
    if (obj && obj[key]) {
      return obj[key]
    } else {
      return staticName
    }
  }

7. 陣列(物件陣列去重)

  • 使用和引數說明
用法示例:handleRepeatArr({data: [1 , 1 ,1]}) // [1]
         handleRepeatArr({data: [{name: 1}, {name: 1}], key: `name`}) // [{name: 1}]
    
  /**
 - 陣列去重
 - @param {Array} data 要去重的陣列
 - @param {String} key 作為去重依據的欄位 (處理物件陣列時需要傳入)
 - @return arr 返回處理後的資料
   */
  • 1.遞迴去重(資料無法保持之前的排序)

  handleRepeatArr ({data, key}) {
    if (!Array.isArray(data)) {
      console.log(`請傳入陣列`)
      return
    }
    // 先對資料做排序處理
    data = data.sort((item, item1) => {
      if (key) {
        return item[key] - item1[key]
      }
      return item - item1
    })
    // 遞迴去重
    function getData (index) {
      if (index >= 1) {
        // 判斷當前資料和下一條資料是否相等
        let result = key ? data[index][key] === data[index - 1][key] : data[index] === data[index - 1]
        if (result) {
          data.splice(index, 1)
        }
        getData(index - 1)
      }
    }
    getData(data.length - 1)
    return data
  }
  • 2.根據物件的屬性不同去重 (推薦使用)

  handleRepeatArr ({data, key}) {
    if (!Array.isArray(data)) {
      console.log(`請傳入陣列`)
      return
    }
    let arr = [], obj = {}
    data.forEach((item, index) => {
      let attr = key ? item[key] : item
      if (!obj[attr]) {
        obj[attr] = index + 1
        arr.push(item)
      }
    })
    return arr
  }
  • 3.利用indexOf以及forEach (適合處理陣列,不適合處理物件陣列)

  handleRepeatArr ({data, key}) {
    if (!Array.isArray(data)) {
      console.log(`請傳入陣列`)
      return
    }
    let arr = []
    data.forEach((item, index) => {
      // 如果當前元素在之後沒有出現過(後面出現的資料會保留)
      // let result = data.indexOf(item, index + 1)
      // 如果當前元素在之前沒有出現過(前面出現的資料會保留)
      let result = index === 0 ? -1 : data.lastIndexOf(item, index - 1)
      if (result === -1) {
        arr.push(item)
      }
    })
    return arr
 }
  • 4.雙層迴圈去重 (佔用記憶體高)

  handleRepeatArr ({data, key}) {
    if (!Array.isArray(data)) {
      console.log(`請傳入陣列`)
      return
    }
    for (let i = 0, len = data.length; i < len; i++) {
      for (let j = i + 1; j < len; j++) {
        let result = key ? data[i][key] === data[j][key] : data[i] === data[j]
        if (result) {
          data.splice(j, 1)
          len--
          j--
        }
      }
    }
    return data
 }

相關文章