主頁 > 企業開發 > 記錄--前端如何優雅匯出多表頭xlsx

記錄--前端如何優雅匯出多表頭xlsx

2023-06-16 08:23:51 企業開發

這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

前言

xlsx匯出是比較前后端開發程序中都比較常見的一個功能,但傳統的二維表格可能很難能滿足我們對業務的需求,因為當資料的維度和層次比較多時,二維表格很難以清晰和壓縮的方式展現所有的資訊,所以我們也就經常能碰到多級表頭開發了,

demo

每當我們新使用一個插件的時候,我們都可以看著官方檔案去新建立一個demo,然后去嘗試一下效果,這有助于我們分析錯誤,

npm i xlsx -S
function exportFile() {
  const ws = utils.json_to_sheet([])
  const wb = utils.book_new()
  utils.sheet_add_aoa(ws, [
    [1, 2, 3, 4, 5, 6, 7, 8, 9], 
    ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
  ], { origin: 'A1' })
  utils.book_append_sheet(wb, ws, 'Data')
  writeFileXLSX(wb, 'SheetJSVueAoO.xlsx')
}
exportFile()

demo已經成功了,xlsx已經下載下來了,

需求分析

  1. 新建一個表格
  2. 根據表頭將表格進行合并
  3. 對合并后的表頭進行內容填充
  4. 填入資料內容

效果如上圖(時間原因就先不寫xlsx的樣式了),

需求實作

  1. 合并單元格: 需要指定開始的行和列以及結束的行和列,如{ 's': { 'r': 0, 'c': 0 }, 'e': { 'r': 3, 'c': 0 } },計算好需要合并的單元格后統一賦值給!merges屬性,
  2. 合并單元格后填充內容:由多個合并后的單元格填入內容時,應該也按照多個單元格填入,只是第一個有內容,其他按空填入即可,
  3. 表頭結束后我們可以指定在某一行繼續填入內容,即可繼續填入資料內容,
function exportFile() {
  const ws = utils.json_to_sheet([])
  ws['!merges'] = [
    { 's': { 'r': 0, 'c': 0 }, 'e': { 'r': 3, 'c': 0 } },
    { 's': { 'r': 0, 'c': 1 }, 'e': { 'r': 3, 'c': 1 } },
    { 's': { 'r': 0, 'c': 2 }, 'e': { 'r': 3, 'c': 2 } },
    { 's': { 'r': 0, 'c': 3 }, 'e': { 'r': 0, 'c': 8 } },
    { 's': { 'r': 1, 'c': 3 }, 'e': { 'r': 3, 'c': 3 } },
    { 's': { 'r': 1, 'c': 4 }, 'e': { 'r': 1, 'c': 7 } },
    { 's': { 'r': 2, 'c': 4 }, 'e': { 'r': 3, 'c': 4 } },
    { 's': { 'r': 2, 'c': 5 }, 'e': { 'r': 3, 'c': 5 } },
    { 's': { 'r': 2, 'c': 6 }, 'e': { 'r': 2, 'c': 7 } },
    { 's': { 'r': 1, 'c': 8 }, 'e': { 'r': 3, 'c': 8 } },
    { 's': { 'r': 0, 'c': 9 }, 'e': { 'r': 3, 'c': 9 } }
  ] // 合并單元格內容
  const wb = utils.book_new()
  utils.book_append_sheet(wb, ws, 'Data')
  utils.sheet_add_aoa(ws, [
    ['序號', '姓名', '性別', '公司概況', '', '', '', '', '', '備注'],
    ['', '', '', '職位', '專案', '', '', '', '公司名稱'],
    ['', '', '', '', '專案時長', '專案描述', '金額', ''],
    ['', '', '', '', '', '', '總金額', '利潤']
  ], { origin: 'A1' }) // 表頭內容
  utils.sheet_add_aoa(ws, [
    [0, '張三', '男', '區域經理', '3天', '暫無描述', 998, 9.98, '阿里巴巴', '暫無'],
    [1, '李四', '女', 'CEO', '30天', '穩了', 998, 9.98, '中石油', '暫無']
  ], { origin: 'A5' }) // 資料內容
  writeFileXLSX(wb, `${+new Date()}.xlsx`)
}
好的,大功告成,今天就先到這里?

這東西也太丑了吧,我是一個開發,我不是來這里數格子的,看看上面的代碼,我都不好意思說是我自己寫的,要不到同事電腦上提交一下吧?

資料分析

[
    { 's': { 'r': 0, 'c': 0 }, 'e': { 'r': 3, 'c': 0 } },
    { 's': { 'r': 0, 'c': 1 }, 'e': { 'r': 3, 'c': 1 } },
    { 's': { 'r': 0, 'c': 2 }, 'e': { 'r': 3, 'c': 2 } },
    { 's': { 'r': 0, 'c': 3 }, 'e': { 'r': 0, 'c': 8 } },
    { 's': { 'r': 1, 'c': 3 }, 'e': { 'r': 3, 'c': 3 } },
    { 's': { 'r': 1, 'c': 4 }, 'e': { 'r': 1, 'c': 7 } },
    { 's': { 'r': 2, 'c': 4 }, 'e': { 'r': 3, 'c': 4 } },
    { 's': { 'r': 2, 'c': 5 }, 'e': { 'r': 3, 'c': 5 } },
    { 's': { 'r': 2, 'c': 6 }, 'e': { 'r': 2, 'c': 7 } },
    { 's': { 'r': 1, 'c': 8 }, 'e': { 'r': 3, 'c': 8 } },
    { 's': { 'r': 0, 'c': 9 }, 'e': { 'r': 3, 'c': 9 } }
]

我想要轉成上面的資料結構,r從0開始,最大值就是它的深度,c從0開始,最大值就是它的廣度,因為這是一個多級表頭,每一級都會出現比上一級相等或更多子級的情況,我好像已經把答案說到嘴邊了,對,就是用樹形結構將其轉換處理,

我們結合上面已轉換好的串列結構和下面準備轉換的樹形結構,比如現在要合并第一個單元格序號,我們應該先找到起始位置,也就是0,0,這個很好確定;我們單單從當前節點并不能判斷真正的結束位置,我們應該找到同級節點的最大深度,也就是公司概況->專案->金額->總金額,深度為3,所以它的結束位置應該為3,0

當我們要合并橫向單元格的時候,比如公司概況,它下邊有三個子節點分別是職位,專案,公司名稱,而子節點下方仍有不同的子節點,此時我們就應該去獲取它們的每個子節點的每層子節點的總長度 - 1,為什么要 - 1,因為當前節點和第一個子節點占用的是同一個col,因此可以需要減一,也就是說,如果公司概況的起始點為0,3,那么它的終止位置由此可推:職位+專案+公司名稱-1+專案時長+專案描述+金額-1+總金額+利潤-1 = 5,所以終點位置為0,3+5 => 0,8

const mergedCells = [ 
    { name: '序號', prop: 'id' },
    { name: '姓名', prop: 'name' },
    { name: '性別', prop: 'sex' },
    { 
        name: '公司概況', 
        children: [ 
            { name: '職位', prop: 'jobTitle' },
            { 
                name: '專案', children: [
                    { name: '專案時長', prop: 'projectTime' },
                    { name: '專案描述', prop: 'projectDesc' },
                    { 
                        name: '金額', 
                        children: [
                            { name: '總金額', prop: 'total' },
                            { name: '利潤', prop: 'profit' }
                        ] 
                    } 
                ] 
            }, 
            { name: '公司名稱', prop: 'companyName' }
        ] 
    },
    { name: '備注', prop: 'remark' } 
]

思路分析

  1. 找到當前節點的深度和廣度
  2. 根據當前節點深度和廣度,生成當前節點單元格開始與結束位置
  3. 根據當前節點深度和廣度,生成表頭資料結構
  4. 根據最大深度位置,生成表單串列資料

代碼實作

tips: 如果你對樹結構的遍歷還不太熟悉,可以看看【前端不求人】樹形結構和一維陣列,一笑泯恩仇

獲取當前節點最大廣度和最大深度

  1. 遞回發現當前已無子節點時,就回傳0,然后每回傳一層就遞增1,每次回傳時都獲取當前節點的最大值,這樣就能獲得最深層數,
  2. 遞回記錄每層每個子節點的長度 - 1,這樣就能獲取當前串列的最大寬度,
  3. 我們使用map做記錄,下次獲取就不需要重新計算了,
const map = new Map()
const getCellsSize = list => {
    if (map.has(list)) { return map.get(list) }
    if (list?.length) {
        let rows = -1, cols = list.length - 1
        list.forEach(item => {
            if (item.children) {
                const size = getCellsSize(item.children)
                rows = Math.max(size[0], rows)
                cols += size[1]
            }
        })
        map.set(list, [rows + 1, cols])
        return [rows + 1, cols]
    }
}

合并單元格開始和結束位置

  1. 獲取當前節點的開始和結束位置
  2. 當前節點無子節點,單元格寬為1,高為整個根節點的最大深度
  3. 當前節點有子節點,單元格高為1,寬為當前節點的寬,即最大廣度
const size = getCellsSize(headers)
const headerMerge = []
const mergeHeadersCell = (headers, row, col) => {
    for (let i = 0, len = headers.length;i < len;i++) {
        const cell = headers[i]
        if (!cell.children?.length) {
            if (row === size[0]) { continue }
            headerMerge.push({ s: { r: row, c: col + i }, e: { r: size[0], c: col + i } })
        } else {
            const size = map.get(cell.children)
            headerMerge.push({ s: { r: row, c: col + i }, e: { r: row, c: col + size[1] + i }})
            mergeHeadersCell(cell.children, row + 1, col + i)
            col += size[1]
        }
    }
}

多表頭值填充

  1. 我們宣告一個headerValue的空陣列來記錄表頭內容
  2. headerValue應該是一個二維陣列,headerValue[i][j]代表第i行第j列的內容
  3. 當發現當前節點有children,直接獲取當前節點的寬度,該寬度就是合并后空白單元格的個數,
  4. 當發現當前節點并沒有headerValue,表示前面的節點被縱向合并了,因此應該直接加上這些空白單元格的節點
  const headerValue = https://www.cnblogs.com/smileZAZ/archive/2023/06/15/[]
  const getHeadersValue = (headers, row, col) => {
    if (!headerValue[row]) {
      headerValue[row] = new Array(col).fill('')
    }
    for (let i = 0, len = headers.length; i < len; i++) {
      const cell = headers[i]
      headerValue[row].push(cell.name)
      if (cell.children?.length) {
        const len = getCellsSize(cell.children)[1]
        const emptyNameList = new Array(len).fill('')
        headerValue[row].push(...emptyNameList)
        getHeadersValue(cell.children, row + 1, col + i)
      }
    }
  }

獲取串列prop

  1. 繼續遞回mergedCells
  2. 收集無葉子節點的prop值
  3. 將prop值依次放進一個陣列中以備后續使用
const bodyMapList = []
const getBodyMapList = list => {
    if (list?.length) {
        list.forEach(item => {
            !item.children ? bodyMapList.push(item.prop) : getBodyMapList(item.children)
        })
    }
}

list.map(item => bodyMapList.map(key => item[key]))

以上就是核心代碼展示啦,如果想看完整代碼,可以到github觀看,歡迎star,

總結

我們通過計算當前樹節點的大小,就可以獲取該節點的廣度和深度,通過廣度和深度又可以讓我們進一步去演算當前節點是否需要去合并其他單元格,是否需要生成空白單元格的資料內容,生成表格內容則只需要將最子層節點的prop收集,然后對應取值即可,

本文轉載于:

https://juejin.cn/post/7243435843145678907

如果對您有所幫助,歡迎您點個關注,我會定時更新技術檔案,大家一起討論學習,一起進步,

 

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/555293.html

標籤:其他

上一篇:利用jQuery制作簡易的table上下無縫輪播

下一篇:返回列表

標籤雲
其他(161081) Python(38230) JavaScript(25498) Java(18240) C(15237) 區塊鏈(8271) C#(7972) AI(7469) 爪哇(7425) MySQL(7253) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4594) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2435) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) 功能(1967) HtmlCss(1967) Web開發(1951) C++(1940) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 記錄--前端如何優雅匯出多表頭xlsx

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言 xlsx匯出是比較前后端開發程序中都比較常見的一個功能。但傳統的二維表格可能很難能滿足我們對業務的需求,因為當資料的維度和層次比較多時,二維表格很難以清晰和壓縮的方式展現所有的資訊,所以我們也就經常能碰到多級表頭開發了。 demo ......

    uj5u.com 2023-06-16 08:23:51 more
  • 利用jQuery制作簡易的table上下無縫輪播

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="wi ......

    uj5u.com 2023-06-16 08:23:36 more
  • 使用vue ui創建vue專案

    vue ui是什么? 簡單來說,vue ui是一個可視化圖形界面,方便你去創建、更新和管理vue專案,包括下載router,vuex,axios,elementui等插件,配置好一些屬性以及依賴關系,方便我們使用,我個人第一次接觸它就感覺非常非常非常智能和強大 配置步驟 1、安裝Vue CLI,因為 ......

    uj5u.com 2023-06-16 08:23:14 more
  • 解決:js 根據圖片鏈接(image url)下載,有的打開預覽,有的下載

    1、問題描述 https://*****/drugTestReport/20230515/202305151106111386737.png https://*****/drugTestReport/20230605/202306051540314553141.jpg 同樣結構的兩個圖片鏈接,使用w ......

    uj5u.com 2023-06-16 08:22:59 more
  • 基于Spark的大規模日志分析

    摘要:本篇文章將從一個實際專案出發,分享如何使用 Spark 進行大規模日志分析,并通過代碼演示加深讀者的理解。 本文分享自華為云社區《【實戰經驗分享】基于Spark的大規模日志分析【上進小菜豬大資料系列】》,作者:上進小菜豬。 隨著互聯網的普及和應用范圍的擴大,越來越多的應用場景需要對海量資料進行 ......

    uj5u.com 2023-06-16 08:22:55 more
  • 什么是微格式

    微格式是一種用于在HTML檔案中嵌入語意化資訊的簡單而輕量級的標記語言。它們通過使用已有的HTML標簽和類名來表示結構化資料,以便機器能夠更容易地理解和處理這些資料。 微格式的目標是為了讓資訊更易于被自動化工具(如搜索引擎、資料聚合器、日歷應用程式等)提取和決議。通過添加特定的類名和屬性值,可以標記 ......

    uj5u.com 2023-06-16 08:22:50 more
  • 前端vue仿京東天貓簡單好用的瀑布流瀑布流式布局串列組件waterfa

    前端vue仿京東天貓簡單好用的瀑布流瀑布流式布局串列組件waterfall, 下載完整代碼請訪問uni-app插件市場址:https://ext.dcloud.net.cn/plugin?id=13046 效果圖如下: ![image](https://img2023.cnblogs.com/blo ......

    uj5u.com 2023-06-16 08:22:41 more
  • 解決:js 根據圖片鏈接(image url)下載,有的打開預覽,有的下載

    1、問題描述 https://*****/drugTestReport/20230515/202305151106111386737.png https://*****/drugTestReport/20230605/202306051540314553141.jpg 同樣結構的兩個圖片鏈接,使用w ......

    uj5u.com 2023-06-16 08:22:26 more
  • 基于Spark的大規模日志分析

    摘要:本篇文章將從一個實際專案出發,分享如何使用 Spark 進行大規模日志分析,并通過代碼演示加深讀者的理解。 本文分享自華為云社區《【實戰經驗分享】基于Spark的大規模日志分析【上進小菜豬大資料系列】》,作者:上進小菜豬。 隨著互聯網的普及和應用范圍的擴大,越來越多的應用場景需要對海量資料進行 ......

    uj5u.com 2023-06-16 08:22:22 more
  • 利用jQuery制作簡易的table上下無縫輪播

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="wi ......

    uj5u.com 2023-06-16 08:22:03 more