vue項目使用xlsx-style導出自定義格式excel

一.遇到問題

1.給自定義格式的excel中的合併單元格加邊框的時候,出現邊框不完整的情況.

解決:將該合併單元格拆分成最小單位的單元格,設置其邊框屬性. 直接賦值的話不可行,因爲子單元格並沒有邊框屬性,只有合併單元格纔有, 這裏使用的方法是:記錄合併單元格的屬性信息, 然後循環對子單元格賦值.
代碼:

function addRangeBorder(range,ws){
	let arr = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
    
	range.forEach(item=>{
		let startColNumber = Number(item.s.r), endColNumber = Number(item.e.r);
		let startRowNumber = Number(item.s.c), endRowNumber = Number(item.e.c);
		const test = ws[arr[startRowNumber] + (startColNumber + 1)];
		for(let col = startColNumber ; col <= endColNumber ; col++)
		{
			for(let row = startRowNumber; row <= endRowNumber ; row++)
			{
				//const test = ws[arr[j] + i];
				//console.log(arr[row] + (col + 1));
				ws[arr[row] + (col + 1)] = test;
				//{s:{border:{top:{style:'thin'}, left:{style:'thin'},bottom:{style:'thin'},right:{style:'thin'}}}};
			}
		}
	})
	return ws;
}

二.DEMO

一個完整的例子:

import FileSaver from 'file-saver'
import XLSX from 'xlsx-style'
 
 // 設置表格中cell默認的字體,居中,顏色等

var defaultCellStyle = {
 			font: {
 				name: "宋體", sz: 11, color: { auto: 1 } ,
 			},
 			border: {
 				color: { auto: 1 },
				top: { style: 'thin' },
				bottom: { style: 'thin'},
				left: { style: 'thin' },
				right: { style: 'thin' }
 			},
 			alignment: {
 				/// 自動換行
 				wrapText: 1,
 					// 居中
 				horizontal: "center",
 				vertical: "center",
 				indent: 0
 			}
 		};
// 從json轉化爲sheet,xslx中沒有aoaToSheet的方法,該方法摘自官方test
function sheet_from_array_of_arrays(data) {
  const ws = {};
  const range = {s: {c:10000000, r:10000000}, e: {c:0, r:0 }};
    for(let R = 0; R !== data.length; ++R) {
    for(let C = 0; C !== data[R].length; ++C) {
      if(range.s.r > R) range.s.r = R;
      if(range.s.c > C) range.s.c = C;
      if(range.e.r < R) range.e.r = R;
      if(range.e.c < C) range.e.c = C;
      /// 這裏生成cell的時候,使用上面定義的默認樣式
      const cell = {v: data[R][C], s: defaultCellStyle};
      if(cell.v == null) continue;
      const cell_ref = XLSX.utils.encode_cell({c:C,r:R});

      /* TEST: proper cell types and value handling */
      if(typeof cell.v === 'number') cell.t = 'n';
      else if(typeof cell.v === 'boolean') cell.t = 'b';
      else if(cell.v instanceof Date) {
      cell.t = 'n'; cell.z = XLSX.SSF._table[14];
      cell.v = this.dateNum(cell.v);
      }
      else cell.t = 's';
      ws[cell_ref] = cell;
    }
  }

  /* TEST: proper range */
  if(range.s.c < 10000000) ws['!ref'] = XLSX.utils.encode_range(range);
  return ws;
}


// 將一個sheet轉成最終的excel文件的blob對象,然後利用URL.createObjectURL下載
function sheet2blob(sheet, sheetName) {
  sheetName = sheetName || 'sheet1';
  const workbook = {
    SheetNames: [sheetName],
    Sheets: {}
  };
  workbook.Sheets[sheetName] = sheet

  window.console.log(workbook)
  // 生成excel的配置項
  const wopts = {
    bookType: 'xlsx', // 要生成的文件類型
    bookSST: false, // 是否生成Shared String Table,官方解釋是,如果開啓生成速度會下降,但在低版本IOS設備上有更好的兼容性
    type: 'binary'
  };

  const wbout = XLSX.write(workbook, wopts, { defaultCellStyle: defaultCellStyle });
  const blob = new Blob([s2ab(wbout)], {type: "application/octet-stream"});
  // 字符串轉ArrayBuffer
  function s2ab(s) {
    const buf = new ArrayBuffer(s.length);
    const view = new Uint8Array(buf);
    for (let i=0; i!==s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
    return buf;
  }
  return blob;
}


function addRangeBorder(range,ws){
	let arr = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
    
	range.forEach(item=>{
		let startColNumber = Number(item.s.r), endColNumber = Number(item.e.r);
		let startRowNumber = Number(item.s.c), endRowNumber = Number(item.e.c);
		const test = ws[arr[startRowNumber] + (startColNumber + 1)];
		for(let col = startColNumber ; col <= endColNumber ; col++)
		{
			for(let row = startRowNumber; row <= endRowNumber ; row++)
			{
				//const test = ws[arr[j] + i];
				//console.log(arr[row] + (col + 1));
				ws[arr[row] + (col + 1)] = test;
				//{s:{border:{top:{style:'thin'}, left:{style:'thin'},bottom:{style:'thin'},right:{style:'thin'}}}};
			}
		}
	})
	return ws;
}

function funtransformF() {
	 
      // 表頭信息 要合併的字段用null代替
	  let aoa = [
        ['江蘇省多式聯運示範工程項目2019年第二季度動態監測信息表'],
        ['序號', '市別', '示範工程項目名稱', '示範工程項目運行情況'],
        [null, null, null, '聯運組織',null, null, null, null, null, null, '企業總貨物運輸量(萬噸/萬標箱)', null, '樞紐場站建設投資額(萬元)', '裝備配備建設投資額(萬元)', '信息化建設投資額(萬元)', '其他'],
        [null, null, null, '聯運線路(條)','聯運線路運營情況', null, null, null, null, null],
        [null, null, null, null, '線路', '聯運路線', '聯運模式', '聯運量', null, '聯運週轉量(萬噸公里)', null, null, null, null, null, null],
        [null, null, null, null, null, null, null, '萬噸', '萬標箱', null, '萬噸', '萬標箱', null, null, null]
      ]
      
      // json => sheet
      const sheet = sheet_from_array_of_arrays(aoa);
      
      // 表頭合併: r: row 行;c:column 列
      const mergeTitle = [
        // 江蘇省多式聯運示範工程項目2019年第二季度動態監測信息表
        {
          s: {r: 0, c: 0},
          e: {r: 0, c: 15}
        },
        // 序號
        {
          s: {r: 1, c: 0},
          e: {r: 5, c: 0}
        },
        // 市別
        {
          s: {r: 1, c: 1},
          e: {r: 5, c: 1}
        },
        // 示範工程名稱
        {
          s: {r: 1, c: 2},
          e: {r: 5, c: 2}
        },
        // 示範工程項目運行情況
        {
          s: {r: 1, c: 3},
          e: {r: 1, c: 15}
        },
        // 聯運組織
        {
          s: {r: 2, c: 3},
          e: {r: 2, c: 9}
        },
        // 聯運線路(條)
        {
          s: {r: 3, c: 3},
          e: {r: 5, c: 3}
        },
        // 聯運線路運營情況
        {
          s: {r: 3, c: 4},
          e: {r: 3, c: 9}
        },
        // 線路
        {
          s: {r: 4, c: 4},
          e: {r: 5, c: 4}
        },
        // 聯運路線
        {
          s: {r: 4, c: 5},
          e: {r: 5, c: 5}
        },
        // 聯運模式
        {
          s: {r: 4, c: 6},
          e: {r: 5, c: 6}
        },
        // 聯運量
        {
          s: {r: 4, c: 7},
          e: {r: 4, c: 8}
        },
        // 聯運週轉量(萬噸公里)
        {
          s: {r: 4, c: 9},
          e: {r: 5, c: 9}
        },

        // 企業總貨物運輸量(萬噸/萬標箱)
        {
          s: {r: 2, c: 10},
          e: {r: 4, c: 11}
        },
        // 樞紐場站建設投資額(萬元)
        {
          s: {r: 2, c: 12},
          e: {r: 5, c: 12}
        },
        //裝備配備建設投資額(萬元)
        {
          s: {r: 2, c: 13},
          e: {r: 5, c: 13}
        },
        // 信息化建設投資額(萬元)
        {
          s: {r: 2, c: 14},
          e: {r: 5, c: 14}
        },
        // 其他
        {
          s: {r: 2, c: 15},
          e: {r: 5, c: 15}
        },
				]
				
      //sheet['!merges'] = mergeTitle.concat(mergeContent);
      sheet['!merges'] = mergeTitle;
      // 凍結前6行和第一列,右下可以滑動
      sheet["!freeze"] = {
        xSplit: "1",
        ySplit: "6",
        topLeftCell: "B7",
        activePane: "bottomRight",
        state: "frozen",
      }
      sheet["!margins"] = { left: 1.0, right: 1.0, top: 1.0, bottom: 1.0, header: 0.5, footer: 0.5 }
      // 列寬 使用的不是像素值
      const sheetCols = [
        { wch: 8} , // 序號
        { wch: 10 }, // 市別
        { wch: 20 }, // 示範工程項目名稱
        { wch: 9 }, // 聯運線路(條)
        { wch: 8 }, // 線路
        { wch: 18 }, // 聯運路線
        { wch: 15 }, // 聯運模式
        { wch: 9 }, // 聯運量-萬噸
        { wch: 9 }, // 聯運量-萬標箱
        { wch: 12 }, // 聯運週轉量
        { wch: 9 }, // 企業萬噸
        { wch: 9 }, // 企業 萬標箱
        { wch: 10 }, // 樞紐站
        { wch: 10 }, // 裝備
        { wch: 10 }, // 信息化
        { wch: 27 }, // 備註
      ];
      sheet['!cols'] = sheetCols;
			
			addRangeBorder(mergeTitle, sheet);
			
      const wbBlob = sheet2blob(sheet, '1')
      // 保存下載
      FileSaver.saveAs(wbBlob, 'd.xlsx')
    }
	
	export {
		funtransformF
	}

效果圖:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章