傳送門
先放一些我認(rèn)為非常優(yōu)秀的參考文檔,作為傳送門集合侦副,方便大家查看吧:
【1】Node.js中如何利用xlsx設(shè)置導(dǎo)出表格的樣式侦锯?
這個(gè)問題告訴了你,你用xlsx設(shè)置樣式不行秦驯,但是用xlsx-style導(dǎo)出樣式就ok
【2】純前端利用 js-xlsx 實(shí)現(xiàn) Excel 文件導(dǎo)入導(dǎo)出功能示例
這算是全網(wǎng)尺碰,注意是全網(wǎng)講解js-xlsx比較全面系統(tǒng)的文章了,可以好好了解一下译隘。
本系統(tǒng)使用node+express 作為后臺亲桥,導(dǎo)出excel使用的是xlsx-style。在開始之前固耘,先簡單介紹一下node常用的一些導(dǎo)出excel的工具题篷,因?yàn)檫@對我們后面的工作十分重要。
預(yù)備
(1)js-xlsx和xlsx厅目。xlsx和js-xlsx可以理解為基本庫番枚,API十分復(fù)雜法严,上手難度高,但是你想要的功能葫笼,基本上都有深啤。但是文檔不好,看起來十分費(fèi)力路星。不信你去點(diǎn)點(diǎn)下面的鏈接看看溯街,嚇?biāo)滥恪?/p>
js-xlsx文檔:https://www.npmjs.com/package/js-xlsx
xlsx文檔:https://www.npmjs.com/package/xlsx
(2)node-xlsx⊙筘ぃ基于基本庫的封裝呈昔,底層的庫是用的xlsx。
node-xlsx npm文檔:https://www.npmjs.com/package/node-xlsx
十分操蛋的文檔垫挨,反正我是看完之后不知道怎么用韩肝,寫了跟沒寫一樣,關(guān)鍵的樣式都沒說九榔。
(3)xlsx-style 基于xlsx封裝的樣式庫哀峻,可以在xlsx的基礎(chǔ)上設(shè)置樣式。
正文
一般在使用node的時(shí)候我們是直接使用node-xlsx庫的哲泊,關(guān)鍵的導(dǎo)出代碼如下:
const xlsx = require('node-xlsx').default;
const options = {
'!cols': [
{wpx: 300},//1-變更名稱
{wpx: 100},//2-變更描述
{wpx: 140},//3-計(jì)劃上線測試時(shí)間
{wpx: 140}, //4-計(jì)劃上線時(shí)間
{wpx: 250}, //5-子系統(tǒng)剩蟀、模塊名稱
{wpx: 120}, //6-依賴模塊
{wpx: 195},//7-功能點(diǎn)
{wpx: 195}, //8-詳細(xì)描述
{wpx: 195}, //9-測試要點(diǎn)
{wpx: 205}, //10-對應(yīng)需求
{wpx: 150}, //11-是否
{wpx: 150}, //12-開發(fā)A
{wpx: 150}, //13-開發(fā)B
{wpx: 110}, //14-關(guān)聯(lián)版本
{wpx: 110}, //15-代碼走查
],
'!rows': [
{hpx: 40,},
{hpx: 60},
{hpx: 80},
{hpx: 100},
],
'!margins': {left: 0.7, right: 0.7, top: 0.75, bottom: 0.75, header: 0.3, footer: 0.3},
}
const range = {s: {c: 0, r: 0}, e: {c: 0, r: 2}}; // A1:A4
options['!merges'] = [range]
const xlsxData = xlsx.build([form], options)
options是導(dǎo)出表格的一些樣式,!cows和切威!rows分別設(shè)置的是列寬和行高育特,可以成功設(shè)置,但是樣式不能成功設(shè)置先朦,也就是說
s標(biāo)簽里的東西通通無效缰冤。
在網(wǎng)上查詢了一些辦法后,發(fā)現(xiàn)主需要吧node-xlsx里對xlsx的引入改為xlsx-style就能夠成功設(shè)置樣式喳魏。
然后就發(fā)現(xiàn)了樣式成功設(shè)置棉浸,行高卻無效了……(我tm!@#¥%)
問題分析
我對比了xlsx-style和xlsx的源碼刺彩,發(fā)現(xiàn)兩個(gè)庫很多的方法和代碼都是一樣的迷郑,xlsx-style之所以能夠設(shè)置樣式,是因?yàn)樗嗔艘粋€(gè)styleBuilder
而xlsx-style不能夠設(shè)置行高创倔,是因?yàn)樵趙rite_ws_xml-data里沒有對rows進(jìn)行處理嗡害,而在xlsx庫里可以清楚的看到它對!rows的處理
所以解決方法就必須去改庫(我認(rèn)為),思路也有2中:
(1)在xlsx-style加xlsx里設(shè)置行高的代碼
(2)在xlsx里加入xlsx-style里設(shè)置樣式的代碼
用腳想也應(yīng)該知道(1)的工作量最小畦攘,所以解決辦法就是在xlsx-style里加入行高設(shè)置的代碼霸妹。
解決方法:
先修改node-xlsx lib目錄下的hepler.js
var buildSheetFromMatrix = function buildSheetFromMatrix(data) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var workSheet = {};
var range = {s: {c: 1e7, r: 1e7}, e: {c: 0, r: 0}};
if (!Array.isArray(data)) throw new Error('sheet data is not array');
for (var R = 0; R !== data.length; R += 1) {
for (var C = 0; C !== data[R].length; C += 1) {
if (!Array.isArray(data[R])) throw new Error(R + 'th row data is not array');
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;
if (data[R][C] === null) {
continue; // eslint-disable-line
}
var cell = isCellDescriptor(data[R][C]) ? data[R][C] : {v: data[R][C]};
var cellRef = _xlsx2.default.utils.encode_cell({c: C, r: R});
if (isNumber(cell.v)) {
cell.t = 'n';
} else if (isBoolean(cell.v)) {
cell.t = 'b';
} else if (cell.v instanceof Date) {
cell.t = 'n';
cell.v = buildExcelDate(cell.v);
cell.z = cell.z || _xlsx2.default.SSF._table[14]; // eslint-disable-line no-underscore-dangle
} else {
cell.t = 's';
}
if (isNumber(cell.z)) cell.z = _xlsx2.default.SSF._table[cell.z]; // eslint-disable-line no-underscore-dangle
workSheet[cellRef] = cell;
}
}
if (range.s.c < 1e7) {
workSheet['!ref'] = _xlsx2.default.utils.encode_range(range);
}
if (options['!cols']) {
workSheet['!cols'] = options['!cols'];
}
if (options['!rows']) {
workSheet['!rows'] = options['!rows'];
}
if (options['!merges']) {
workSheet['!merges'] = options['!merges'];
}
return workSheet;
};
讓opts里的rows能夠被添加至workSheet當(dāng)中
然后再修改在xlsx-style里的xlsx.js write_ws_xml_data 方法,添加設(shè)置行高的代碼念搬。
function write_ws_xml_data(ws, opts, idx, wb) {
var o = [], r = [], range = safe_decode_range(ws['!ref']), cell, ref, rr = "", cols = [], R, C,rows = ws['!rows'];
for(C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
for(R = range.s.r; R <= range.e.r; ++R) {
r = [];
rr = encode_row(R);
for(C = range.s.c; C <= range.e.c; ++C) {
ref = cols[C] + rr;
if(ws[ref] === undefined) continue;
if((cell = write_ws_xml_cell(ws[ref], ref, ws, opts, idx, wb)) != null) r.push(cell);
}
if(r.length > 0){
params = ({r:rr});
if(rows && rows[R]) {
row = rows[R];
if(row.hidden) params.hidden = 1;
height = -1;
if (row.hpx) height = px2pt(row.hpx);
else if (row.hpt) height = row.hpt;
if (height > -1) { params.ht = height; params.customHeight = 1; }
if (row.level) { params.outlineLevel = row.level; }
}
o[o.length] = (writextag('row', r.join(""), params));
}
}
if(rows) for(; R < rows.length; ++R) {
if(rows && rows[R]) {
params = ({r:R+1});
row = rows[R];
if(row.hidden) params.hidden = 1;
height = -1;
if (row.hpx) height = px2pt(row.hpx);
else if (row.hpt) height = row.hpt;
if (height > -1) { params.ht = height; params.customHeight = 1; }
if (row.level) { params.outlineLevel = row.level; }
o[o.length] = (writextag('row', "", params));
}
}
return o.join("");
}
結(jié)語
如果還有什么問題歡迎評論交流抑堡,最近一段時(shí)間都會折騰excel摆出,所以會經(jīng)常關(guān)注的。
詳細(xì)的樣式和完整的設(shè)置代碼過段時(shí)間再補(bǔ)上~
先附上導(dǎo)出表格的效果圖:
問題回復(fù)
【1】
這里再解釋一下node-xlsx和xlsx的關(guān)系首妖。首先node-xlsx是對xlsx的封裝偎漫,簡化了一些操作(這是我們在node項(xiàng)目里使用它比較重要的原因)
但是由于xlsx庫沒有對樣式做處理,所以有人又在xlsx的基礎(chǔ)上封裝了樣式有缆,也就是xlsx-style庫象踊。
所以我們進(jìn)行了從A到B的步驟,為的就是能夠使用樣式
在回到問題本身棚壁,只用xlsx-style的話肯定可以杯矩,修改的方法和上述一樣。因?yàn)檫@種方法的核心就是去修改xlsx-style里的xlsx文件
只不過袖外,如果只使用xlsx-style的話史隆,那你需要一些額外的步驟去調(diào)用build方法,可以參看node-xlsx的處理(因?yàn)閚ode-xlsx就是對xlsx的封裝)
這里再多說一句曼验,其實(shí)xlsx庫和xlsx-style庫很多很多地方都非常相似泌射,而后者主要增加了對樣式的處理。
以上鬓照。(如果還有不明白的歡迎繼續(xù)留言~)
--------------------------------------4月5日更新--------------------------------------------------
增加github的demo供大家參考~
https://github.com/huyifan/NodeExcelStyleDemo
歡飲大家討論~