我需要使用excel-builder.js导出带有样式的excel文件(标题背景颜色蓝色,冻结顶行,列过滤),但是包含所有文档的网站已经无法访问,我什至联系了作者但没有回复。
如果有人可以帮助创建一个包含所有这些格式的小示例,我将非常感激!
我知道以下代码将构建一个 Excel 文件:
var jsonData = [
['sample', 'data', 'for'],
['generating', 'excel', 'in'],
['java', 'script', ' ']
];
require(['excel-builder.js/excel-builder', 'download'], function (EB, downloader) {
var JSworkBook = EB.createWorkbook();
var JSworkSheet = JSworkBook.createWorksheet({name: 'Sheet'});
JSworkSheet.setData(jsonData);
JSworkBook.addWorksheet(JSworkSheet);
var data = EB.createFile(JSworkBook);
downloader('Artist WB.xlsx', data);
});
2024 年 9 月 20 日更新:
项目现在维护在这里:https://github.com/ghiscoding/excel-builder-vanilla
感谢@ghiscoding 的出色工作,也对其进行了升级。
原答案如下:
我添加这个只是因为该项目现已被宣布死亡(https://github.com/stephenliberty/excel-builder.js),并且网站文档已离线(http://excelbuilderjs.com/ )。因此,我们能做的最好的事情就是找到愿意用分叉来控制它的人,或者分享我们的代码。
服务器端脚本..
<cfscript>
path="/app/uploads/temp/";
full_path=ExpandPath(path) & FORM.filename;
if (!DirectoryExists(ExpandPath(path))) DirectoryCreate(ExpandPath(path));
FileWrite(full_path,(BinaryDecode(FORM.contents,"Base64")));
json=StructNew();
json.file=path & FORM.filename;
WriteJSON(json);
</cfscript>
你可以使用 PHP..
<?php
header("Content-type: ".$_POST['contentType']);
header("Content-disposition: attachment; filename=\"{$_POST['fileName']}\"");
echo base64_decode($_POST['contents']);
?>
或asp..
[Authorize]
[System.Web.Mvc.SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
public class SystemController : ApiController {
private ILog log = LogManager.GetLogger(typeof(SystemController));
public class ExcelResponse {
public String FILE = "";
}
public class ExcelRequest {
public String filename;
public String contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
public String contents;
}
[HttpPost]
public ExcelResponse Excel(ExcelRequest request) {
ExcelResponse response = new ExcelResponse();
String the_path = "/_assets/temp/";
String path=System.Web.HttpContext.Current.Server.MapPath("~"+the_path);
log.Info("Generating excel file from data: "+path+request.filename);
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
byte[] file_data=(Convert.FromBase64String(request.contents));
File.WriteAllBytes(path + request.filename, file_data);
response.FILE = the_path+request.filename;
return response;
}
}
还有包含脚本...
require.config({
baseUrl: '/app/assets/',
paths: {
underscore: '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min',
JSZip: './excel-builder/jszip',
EB: './excel-builder.dist.min',
spin: '//cdnjs.cloudflare.com/ajax/libs/spin.js/1.2.7/spin.min',
image: '/3rdparty/requirejs/image',
text: '/3rdparty/requirejs/text',
util: '/excel-builder/Excel/util'
},
shim: {
'underscore': {
exports: '_'
},
'JSZip': {
exports: 'JSZip'
},
'swfobject': {
exports: 'swfObject'
}
}
});
进入./excel-builder/download.js
define(function () {
return function (fileName, content) {
var form = $("<form id='download'>").attr({
target: '_BLANK',
action: '/app/assets/excel-builder/excel.cfm',
method: 'post'
}).css({display: 'none'});
form.append($("<input>").attr({name: 'fileName', value: fileName}));
form.append($("<input>").attr({name: 'contentType', value: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}));
var ta=$("<textarea>").attr({name: 'contents', value: content});
ta.val(content);
form.append(ta);
form.appendTo($("body"));
form.submit();
window.setTimeout(function () {form.remove();}, 30000);
}
});
引导程序(用于表格排序器)...
$(document).ready(function() {
$("table.sort").on("filterEnd",ts_onTableFiltered);
});
它的肉...
function ts_onTableFiltered(event,tblsorter) {
$(tblsorter.table).data('ts_sorter',tblsorter);/*legacy :: */ window.ts_currentSorter=tblsorter;
console.log(event.type);
$(tblsorter.table).data('ts_isFiltered',false); /*legacy. remove me after verification :: */ window.ts_isFiltered=false;
for (var i=0;i<tblsorter.lastSearch.length;i++) {
var currentItemFilter=((tblsorter.lastSearch[i]!="")?true:false);
if (currentItemFilter) {
$(tblsorter.table).data('ts_isFiltered',true);/* legacy:: */ts_isFiltered=true;
break;
}
}
var rows=[];
if ($.isEmptyObject( tblsorter.cache )) {
rows=tblsorter.$tbodies.eq( 0 ).children( 'tr' );
} else {
for(i=0;i<tblsorter.cache[0].normalized.length;i++) {
var row=tblsorter.cache[0].normalized[i][tblsorter.columns].$row[0];
if (!ts_isFiltered) {rows.push($(row));continue;}
var result=tblsorter.pager.regexRows.test(row.className);
if (!result) { // skip 'filtered' className
rows.push($(row));
}
}
}
$(tblsorter.table).data('ts_currentRowsInTable',rows); /*legacy :: */window.ts_currentRowsInTable=rows;
console.log(rows.length);
}
function downloadExcelFromTable(tableObj,filename,props) {
var button=$('a:contains("Excel")');
if (button.length > 1) {
var temp=0;
button.each(function() {
if ($(this).attr('onclick').indexOf(tableObj.attr('id'))>=0) {
temp=$(this);
}
});
//button=temp;
}
console.log("Generating document...");
var orig_data = [];
var headers=[];
var headers_text_len_max=0;
var excel_wait_html='<i class="fa fa-spinner fa-pulse"></i> Please wait...';
button.data('orig-html',button.html());button.html(excel_wait_html);
if (tableObj.data('ts_currentRowsInTable').length<1 || (tableObj.data('ts_currentRowsInTable').length==1 && tableObj.find('tr:contains("No known")').length>0)) {
return BootstrapMessage("Cannot download Excel document","Sorry but there aren't any result rows to populate an excel document. Please refine your report/resultant listing.",function() {
button.html(button.data('orig-html'));
});
}
var doSetupProperties=false;
if (typeof(props)==='undefined') {props={};}
if (typeof(props.column_widths)==='undefined') {
doSetupProperties=true;
props.column_widths=[];
props.column_widths_auto=[];
props.maxWidthPerRow=[];
}
var filterChosen=false;
if (tableObj.hasClass("selectable")) filterChosen=true;
var ignoreCols=[];
var i=0;
tableObj.find('th').each(function() {
if ($(this).text().length<1) ignoreCols.push(i);
else {
headers.push($(this).text());
props.maxWidthPerRow.push(0);
headers_text_len_max+=$(this).text().length;
}
i++;
});
orig_data.push(headers);
console.log("Headers done.");
var handleRow=function(row,ignoreCols) {
var col_i=0;
row.find('td').each(function() {
if ($.inArray(col_i,ignoreCols)<0) {
var text=$(this).text().split('\n').join('').trim();
if ($(this).hasClass('sorter-select')) {
text=$(this).find('select:first').val();
}
var contents=text;
if (tableObj.hasClass('attachTotalsRow')) {
if ((''+tableObj.data('totals_columns')).indexOf(col_i+1)!=-1) {
text=(text.replace('$',''));
contents=parseFloat(text);
}
//row_data.push({value: text,metadata: {style: }});
//row_data.push(parseFloat(text));
}
row_data.push(contents);
var href=$(this).find('a');
if (href.length>0) {
var url=href.attr('href');
row_data[row_data.length-1]={value: 'HYPERLINK("'+url+'","'+text+'")', metadata: { type: 'formula' }};
}
if (text.length > props.maxWidthPerRow[col_i]) props.maxWidthPerRow[col_i]=text.length;
}
col_i++;
});
return (row_data);
}
if (tableObj.hasClass('tablesorter')) {
/*its tablesorter, so we need to obtain all of the hidden filtered data too. */
var rows=tableObj.data('ts_currentRowsInTable');
for (i=0;i<rows.length;i++) {
var row_data=[];
var row = $(rows[i]);
/*if (filterChosen && !isNaN(tableObj.data('chosen'))) {
var target=row.find('td:nth-child('+tableObj.data('chosen')+' input[type=checkbox]');
if (target.length==1) {
if (!target.prop('checked')) continue;
}
}*/
orig_data.push(handleRow(row,ignoreCols));
}
} else {
tableObj.find('tbody tr').each(function() {
var row_data=[];
var row=$(this);
orig_data.push(handleRow(row,ignoreCols));
});
}
if (tableObj.hasClass('attachTotalsRow')) {
var list_cols=tableObj.data('totals_columns');
if (isNaN(list_cols)) {
var av_cols=list_cols.split(',');
} else {
var av_cols=[list_cols];
}
av_cols=av_cols.sort();
var max=orig_data.length;
var min=2; // skip header row
var new_totals_row=[];
for (var ii=0;ii<headers.length;ii++) {
new_totals_row[ii]="";
}
for (var i=0;i<av_cols.length;i++) {
var colIdent=String.fromCharCode(64+av_cols[i]);
new_totals_row[0]="Totals:"
new_totals_row[av_cols[i]-1]={value: 'SUM('+((colIdent+min)+':'+(colIdent+max))+')',metadata: {type: 'formula'}};
}
orig_data.push(new_totals_row);
}
// adjust column widths to fit their text.
if (doSetupProperties) {
var maxDigitWidth=8;
var padding=22;
var fn_truncate=function(num) {return Math.round(num*100)/100;};
var fn_calcWidth=function(numchars,maxdigit,pad) {return fn_truncate(((numchars * maxdigit + pad)/maxdigit*256)/256 );};
var fn_calcPixels=function(p_width,maxdigit){return fn_truncate(((256 * p_width + fn_truncate(128/maxdigit))/256)*maxdigit);};
for (var i=0;i<headers.length;i++) {
var perc_size_of_whole=(100/headers_text_len_max)*headers[i].length;
//props.column_widths.push({width: perc_size_of_whole*1.5});
//props.column_widths_auto.push({bestFit: true,width: maxWidthPerRow[i]});
props.column_widths.push({width: (fn_calcWidth(props.maxWidthPerRow[i],maxDigitWidth,padding)) });
}
}
console.log(props);
console.log("Row data done.");
require(['excel-builder/excel-builder', 'excel-builder/Excel/Table','excel-builder/download'], function (EB, Table, downloader) {
console.log("Beginning excel creation.");
var workbook = EB.createWorkbook();
var worksheet = workbook.createWorksheet({name: filename});
var stylesheet = workbook.getStyleSheet();
var currency = stylesheet.createFormat({
format: '$#,##0.00'
});
var boldDXF = stylesheet.createDifferentialStyle({
font: {
italic: true,
size: 12
}
});
var sheetStyle=stylesheet.createTableStyle({
name: 'SlightlyOffColorBlue',
wholeTable: boldDXF.id,
headerRow: stylesheet.createDifferentialStyle({
alignment: {horizontal: 'center'},
font: {
size: 13,
bold: true
}
}).id
});
console.log("Styles applied.");
var table = new Table();
table.styleInfo.themeStyle = "SlightlyOffColorBlue"; //"TableStyleDark2"; //This is a predefined table style
table.setReferenceRange([1, 1], [headers.length, orig_data.length]); //X/Y position where the table starts and stops.
//Table columns are required, even if headerRowCount is zero. The name of the column also must match the
//data in the column cell that is the header - keep this in mind for localization
table.setTableColumns(headers);
console.log("headers configured.");
worksheet.setData(orig_data);
worksheet.setColumns(props.column_widths)
//worksheet.setColumnFormats(props.column_widths_auto);
workbook.addWorksheet(worksheet);
worksheet.addTable(table);
workbook.addTable(table);
console.log("tables configured.");
var dt=new Date();
var file= replaceAll(filename," ","_") +"_"+ (dt.getFullYear()+"-"+dt.getMonth()+"-"+dt.getDate()+"_"+dt.getMilliseconds())+'.xlsx';
file=replaceAll(file,"/","_"); file=replaceAll(file,"\\","_");
var data = EB.createFile(workbook);
console.log("workbook generated. File generation commensing: ");
//downloader(file, data); // this uses the downloader.js file. Disabled as I am customizing the ajax call completely... as follows..
/*legacy attempt.. var contents=''+
'<form method="POST" action="/app/assets/excel-builder/excel.cfm" enctype="application/x-www-form-urlencoded">'+
'<input type="hidden" name="filename" value="'+file+'" />'+
'<input type="hidden" name="contentType" value="'+('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')+'" />'+
'<input type="hidden" name="contents" value="'+data+'" />'+
'<input type="submit" value="Download Now" class="button print" />'+
'</form>';*/
var dat={
filename: file,
contentType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
contents: data
};
$.ajax({
url: '/app/assets/excel-builder/excel2.cfm',
type: "POST",
data: dat,
success: function(result) {
result=$.parseJSON(result);
console.log("Response received. File is located here: "+result.FILE);
if (typeof(onExcelDocGenerated)==='function') onExcelDocGenerated(); // optional callback (global)
contents='<a style="color: lightgreen;" href="'+result.FILE+'" class="button print" >Download Now</a>';
$.notice("Confirm Excel Download",contents,"Cancel",function() {
button.html(button.data('orig-html'));
if (typeof(excel_download_done)==='function') {
excel_download_done(); // optional callback (global)
}
},function() {
button.html(button.data('orig-html'));
if (typeof(excel_download_done)==='function') {
excel_download_done();
}
});
},
error: function(e) {
console.log("Fatal networking error: "+e);
}
});
});
}
以及页面上的实现..
<a href="#" id="exceldownload" onclick="try {downloadExcelFromTable($('table'),'My Report');}catch(e){alert('failed due to error: '+e);};return false;" class="button print table-excel">
<i class="fa fa-file-excel-o"></i> Excel
</a>
这是一个表格排序器的完整实现,支持插入 Excel 工作表中的链接,甚至通过简单地将类(.attachTotalsRow)添加到表类 attr 来求和(总计)行。 甚至支持过滤,因此它只抓取由 Excel 表排序器过滤的行,并根据文本宽度自动调整列大小。 您可以看到有几个部分正在开发中,并且有大量稀疏的注释和控制台日志,但它确实有效。 上面是为 ajax 调用设计的,它在 JSON 响应中提供了文件的路径。这样您就可以使用所有设备都支持的浏览器本机点击。通过 javascript 打开新窗口是不安全的,因此这就是采用该方法的原因。因此,顶部的 php 脚本需要更新以模仿 Coldfusion 脚本。
您想要的部分位于 ajax 调用之前的底部。 祝你好运!
您可以通过 网络存档 访问文档的缓存版本。 但请记住,您需要使用缓存 url 语法在文档页面之间导航,而不是仅仅单击链接。
var workbook = ExcelBuilder.Builder.createWorkbook();
var stylesheet = workbook.getStyleSheet();
var sheet1 = workbook.createWorksheet({
name: 'Data1'
});
var headings = stylesheet.createFormat({
"fill": {
"type": 'pattern',
"patternType": 'solid',
"fgColor": '4BACC6'
}
});
var jsonData = [
[{value:'sample', metadata: {style: headings.id}}, {value:'data', metadata: {style: headings.id}}, {value:'for', metadata: {style: headings.id}}],
['generating', 'excel', 'in'],
['java', 'script', ' ']
];
sheet1.setData(jsonData);
workbook.addWorksheet(sheet1);
ExcelBuilder.Builder.createFile(workbook, {
type: "blob"
}).then(function(data) {
saveAs(new Blob([data], {
type: "base64"
}), "Demo.xlsx");
});