Экспорт массива JavaScript в CSV на стороне клиента
Узнайте, как экспортировать массивы JavaScript в CSV прямо в браузере без серверной обработки. Поддержка Dojo 1.8, RFC 4180 и рекомендации по библиотекам.
Как экспортировать массив JavaScript в CSV‑формат на стороне клиента?
Мне нужно экспортировать данные массива JavaScript в CSV, используя только клиентский JavaScript. Я работаю с Dojo 1.8, а мои данные структурированы как вложенный массив, например:
[["name1", "city_name1", ...], ["name2", "city_name2", ...]]
Какой лучший способ преобразовать эту структуру массива в скачиваемый CSV‑файл прямо в браузере без серверной обработки?
Для экспорта массива JavaScript в CSV‑формат на стороне клиента можно использовать несколько подходов, которые работают напрямую в браузере без серверной обработки. Для вашей вложенной структуры массива с Dojo 1.8 ниже приведены самые эффективные методы:
Содержание
- Базовое преобразование массива в CSV
- Решение, совместимое с Dojo 1.8
- Реализация, соответствующая RFC 4180
- Использование внешних библиотек
- Обработка сложных сценариев данных
- Совместимость с браузерами
Базовое преобразование массива в CSV
Самый простой способ использует встроенные методы JavaScript для преобразования вложенного массива в CSV‑строку и запуска скачивания:
function exportArrayToCSV(data, filename = 'data.csv') {
// Преобразуем 2D массив в CSV‑строку
const csvContent = "data:text/csv;charset=utf-8," +
data.map(row => row.map(cell =>
typeof cell === 'string' ? `"${cell.replace(/"/g, '""')}"` : cell
).join(',')).join('\n');
// Создаём ссылку для скачивания
const encodedUri = encodeURI(csvContent);
const link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", filename);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
// Использование с вашей вложенной структурой массива
const data = [["name1", "city_name1", ...], ["name2", "city_name2", ...]];
exportArrayToCSV(data, "export.csv");
Этот подход работает во всех современных браузерах и эффективно обрабатывает вашу вложенную структуру массива.
Решение, совместимое с Dojo 1.8
Для совместимости с Dojo 1.8 приведён более надёжный вариант, учитывающий требования фреймворка:
define([
"dojo/_base/array",
"dojo/dom-construct"
], function(array, domConstruct) {
function exportToCSV(data, filename) {
// Обрабатываем пустые данные
if (!data || !data.length) {
console.warn("No data to export");
return;
}
// Создаём CSV‑контент с правильной экранизацией
var csvContent = "data:text/csv;charset=utf-8,";
// Обрабатываем каждую строку
array.forEach(data, function(row) {
if (array.isArray(row)) {
var escapedRow = array.map(row, function(cell) {
// Обрабатываем null/undefined
if (cell === null || cell === undefined) {
return '';
}
// Преобразуем в строку и экранируем кавычки
var cellStr = cell.toString();
if (cellStr.indexOf(',') >= 0 || cellStr.indexOf('"') >= 0 ||
cellStr.indexOf('\n') >= 0) {
return '"' + cellStr.replace(/"/g, '""') + '"';
}
return cellStr;
});
csvContent += escapedRow.join(',') + '\r\n';
}
});
// Создаём механизм скачивания
var encodedUri = encodeURI(csvContent);
var link = domConstruct.create("a", {
href: encodedUri,
download: filename || "export.csv"
}, document.body);
// Запускаем скачивание
link.click();
// Очищаем
domConstruct.destroy(link);
}
return {
exportToCSV: exportToCSV
};
});
Это решение использует утилиты массива и методы создания DOM‑элементов из Dojo.
Реализация, соответствующая RFC 4180
Для корректного форматирования CSV, соответствующего стандарту RFC 4180, используйте более полный вариант:
function exportRFC4180CSV(data, filename = 'data.csv') {
var finalVal = '';
for (var i = 0; i < data.length; i++) {
var value = data[i];
if (Array.isArray(value)) {
var innerValue = '';
for (var j = 0; j < value.length; j++) {
var cellValue = value[j];
if (cellValue === null || cellValue === undefined) {
cellValue = '';
} else {
cellValue = cellValue.toString();
}
// Экранируем кавычки и оборачиваем в кавычки при необходимости
var result = cellValue.replace(/"/g, '""');
if (result.indexOf(',') >= 0 || result.indexOf('\n') >= 0 ||
result.indexOf('"') >= 0) {
result = '"' + result + '"';
}
if (j > 0) {
innerValue += ',';
}
innerValue += result;
}
finalVal += innerValue + '\r\n';
}
}
// Создаём скачивание
var blob = new Blob([finalVal], { type: 'text/csv;charset=utf-8;' });
if (navigator.msSaveBlob) { // IE 10+
navigator.msSaveBlob(blob, filename);
} else {
var link = document.createElement("a");
if (link.download !== undefined) { // проверка поддержки
var url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
}
// Использование
const myData = [["name1", "city_name1", "some info"], ["name2", "city_name2", "more,info"]];
exportRFC4180CSV(myData, "export.csv");
Использование внешних библиотек
Для более сложных сценариев рассмотрите специализированные библиотеки:
PapaParse (рекомендовано для работы с CSV)
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.3.2/papaparse.min.js"></script>
<script>
function exportWithPapaParse(data, filename) {
Papa.unparse(data, {
header: false,
quotes: true,
escapeFormulae: true,
encoding: "utf-8"
}, function(csv) {
var blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
var link = document.createElement("a");
var url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
});
}
// Использование
exportWithPapaParse([["name1", "city_name1"], ["name2", "city_name2"]], "data.csv");
</script>
json2csv
<script src="https://cdnjs.cloudflare.com/ajax/libs/json2csv/5.0.6/json2csv.umd.min.js"></script>
<script>
function exportJson2csv(data, filename) {
const { Parser } = window.json2csv;
const parser = new Parser({});
const csv = parser.parse(data);
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
const link = document.createElement("a");
const url = URL.createObjectURL(blob);
link.setAttribute("href", url);
link.setAttribute("download", filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
</script>
Обработка сложных сценариев данных
Для вложенной структуры массива есть несколько продвинутых аспектов:
Заголовки и разделение данных
function exportWithHeaders(data, headers, filename) {
// Добавляем строку заголовков
var csvContent = "data:text/csv;charset=utf-8," +
headers.map(h => `"${h.replace(/"/g, '""')}"`).join(',') + '\n';
// Добавляем строки данных
csvContent += data.map(row =>
row.map(cell =>
typeof cell === 'string' ? `"${cell.replace(/"/g, '""')}"` : cell
).join(',')
).join('\n');
// Запускаем скачивание
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
// Использование
const headers = ["Name", "City", "Additional Info"];
const data = [["John", "New York", "Some details"], ["Jane", "San Francisco", "More, details with commas"]];
exportWithHeaders(data, headers, "with_headers.csv");
Обработка больших наборов данных
function exportLargeDataset(data, filename, chunkSize = 1000) {
var csvContent = "data:text/csv;charset=utf-8,";
var processed = 0;
function processChunk() {
var end = Math.min(processed + chunkSize, data.length);
var chunk = data.slice(processed, end);
var chunkCsv = chunk.map(row =>
row.map(cell =>
typeof cell === 'string' ? `"${cell.replace(/"/g, '""')}"` : cell
).join(',')
).join('\n');
csvContent += chunkCsv;
processed = end;
if (processed < data.length) {
// Обрабатываем следующий блок
setTimeout(processChunk, 0);
} else {
// Финальное скачивание
triggerDownload(csvContent, filename);
}
}
function triggerDownload(content, downloadFilename) {
var encodedUri = encodeURI(content);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", downloadFilename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
processChunk();
}
Совместимость с браузерами
Для максимальной совместимости, особенно с более старыми браузерами, поддерживаемыми Dojo 1.8:
function crossBrowserExport(data, filename) {
var csvContent = "";
// Формируем CSV‑контент
for (var i = 0; i < data.length; i++) {
var row = data[i];
if (Array.isArray(row)) {
var escapedRow = [];
for (var j = 0; j < row.length; j++) {
var cell = row[j];
if (cell === null || cell === undefined) {
escapedRow.push('');
} else {
var cellStr = cell.toString();
if (cellStr.indexOf(',') >= 0 || cellStr.indexOf('"') >= 0 ||
cellStr.indexOf('\n') >= 0) {
escapedRow.push('"' + cellStr.replace(/"/g, '""') + '"');
} else {
escapedRow.push(cellStr);
}
}
}
csvContent += escapedRow.join(',') + '\r\n';
}
}
// Специфические методы скачивания для браузеров
if (window.navigator.msSaveOrOpenBlob) {
// Поддержка IE 10+
var blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
navigator.msSaveOrOpenBlob(blob, filename);
} else {
// Стандартные браузеры
var encodedUri = encodeURI("data:text/csv;charset=utf-8," + csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", filename);
if (link.style) {
link.style.visibility = 'hidden';
}
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
Заключение
Преобразование массивов JavaScript в CSV на стороне клиента простое и доступно несколькими способами:
- Базовый метод: простые
join()и data‑URI для быстрой экспорта - Совместимость с Dojo 1.8: использование утилит Dojo и методов DOM‑конструкции
- Соответствие RFC 4180: надёжное экранирование и форматирование
- Библиотечные решения: PapaParse для надёжной работы с CSV без лишнего кода
Для вашей вложенной структуры [['name1', 'city_name1', ...], ['name2', 'city_name2', ...]] решение, совместимое с Dojo 1.8, обеспечивает лучший баланс совместимости и функциональности. Всегда тестируйте с вашими конкретными данными, чтобы убедиться в корректной обработке специальных символов, запятых и переводов строк.
Не забывайте:
- Правильно обрабатывать специальные символы и кавычки
- Учитывать требования совместимости браузеров
- Тестировать с пустыми значениями и большими наборами данных
- Предоставлять пользователю обратную связь во время операции экспорта
Источники
- Stack Overflow – Как экспортировать массив JavaScript в CSV (на стороне клиента)
- Stack Overflow – JavaScript array to CSV
- LambdaTest Community – Как экспортировать массив JavaScript в CSV напрямую на стороне клиента?
- The Web Dev – Как позволить пользователям скачивать данные массива JavaScript как CSV на стороне клиента
- SQLPey – JavaScript: Создание и скачивание CSV из массива на стороне клиента
- npm export‑to‑csv Package
- Delft Stack – Как экспортировать массив в CSV в JavaScript