Vue.js 3中对象数组转CSV文件失败,求修复方案
修复对象数组转CSV并下载的问题
核心问题分析
- 原
arrayToCsv函数是为二维数组设计的,但你传入的是对象数组,导致每个对象被直接转为[object Object],输出完全不符合预期。 - 嵌套对象
pick未做特殊处理,直接转字符串会丢失内部数据。 - 下载文件名里的
./属于无效前缀,浏览器下载时会自动忽略。
修复方案
方案1:保留嵌套对象(转为JSON字符串)
适合需要保留原数据结构的场景,嵌套对象会以JSON格式存入CSV列中:
<template> <div @click="saveLogs()">save csv</div> </template> <script> export default { name: "App", components: {}, methods: { arrayToCsv(data) { if (!data.length) return ''; // 提取对象键作为CSV表头 const headers = Object.keys(data[0]); // 处理每行数据:转义引号、包裹字段、处理嵌套对象 const rows = data.map(row => { return headers.map(key => { let value = row[key]; // 嵌套对象转为JSON字符串 if (typeof value === 'object' && value !== null) { value = JSON.stringify(value); } // 转义双引号并包裹字段 value = String(value).replaceAll('"', '""'); return `"${value}"`; }).join(','); }); // 拼接表头和行数据 return [headers.join(','), ...rows].join('\r\n'); }, downloadBlob(content, filename, contentType) { const blob = new Blob([content], { type: contentType }); const url = URL.createObjectURL(blob); const pom = document.createElement("a"); pom.href = url; pom.setAttribute("download", filename); // 兼容部分浏览器,需临时添加到DOM document.body.appendChild(pom); pom.click(); document.body.removeChild(pom); URL.revokeObjectURL(url); // 释放URL资源,避免内存泄漏 }, saveLogs() { const logData = [ { act_id: 44, actor: "robot_arm", color: "yellow", lego: "yb1", pick: {x: 1, y: 2, z:5} }, { act_id: 44, actor: "robot_arm", color: "yellow", lego: "yb2", pick: {x: 1, y: 2, z:5} }, ]; const myLogs = this.arrayToCsv(logData); this.downloadBlob(myLogs, "gui_logs.csv", "text/csv;charset=utf-8;"); console.log("Logs has been saved"); }, }, }; </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
方案2:展开嵌套对象(拆分为独立列)
适合需要在表格工具中直接查看嵌套字段的场景,嵌套对象的键会被展开为pick_x、pick_y这类表头:
<template> <div @click="saveLogs()">save csv</div> </template> <script> export default { name: "App", components: {}, methods: { // 递归展开嵌套对象 flattenObject(obj, parentKey = '') { let result = {}; for (const key in obj) { if (obj.hasOwnProperty(key)) { const newKey = parentKey ? `${parentKey}_${key}` : key; if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) { Object.assign(result, this.flattenObject(obj[key], newKey)); } else { result[newKey] = obj[key]; } } } return result; }, arrayToCsv(data) { if (!data.length) return ''; // 先展开所有嵌套对象 const flattenedData = data.map(item => this.flattenObject(item)); // 提取展开后的表头 const headers = Object.keys(flattenedData[0]); // 处理每行数据 const rows = flattenedData.map(row => { return headers.map(key => { let value = row[key]; value = String(value).replaceAll('"', '""'); return `"${value}"`; }).join(','); }); return [headers.join(','), ...rows].join('\r\n'); }, downloadBlob(content, filename, contentType) { const blob = new Blob([content], { type: contentType }); const url = URL.createObjectURL(blob); const pom = document.createElement("a"); pom.href = url; pom.setAttribute("download", filename); document.body.appendChild(pom); pom.click(); document.body.removeChild(pom); URL.revokeObjectURL(url); }, saveLogs() { const logData = [ { act_id: 44, actor: "robot_arm", color: "yellow", lego: "yb1", pick: {x: 1, y: 2, z:5} }, { act_id: 44, actor: "robot_arm", color: "yellow", lego: "yb2", pick: {x: 1, y: 2, z:5} }, ]; const myLogs = this.arrayToCsv(logData); this.downloadBlob(myLogs, "gui_logs.csv", "text/csv;charset=utf-8;"); console.log("Logs has been saved"); }, }, }; </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
内容的提问来源于stack exchange,提问作者Bilal
相关产品推荐
相关产品推荐

