paint-brush
Vue를 사용하여 Excel XLSX 가져오기 및 내보내기: 가이드~에 의해@mesciusinc
새로운 역사

Vue를 사용하여 Excel XLSX 가져오기 및 내보내기: 가이드

~에 의해 MESCIUS inc.17m2024/06/26
Read on Terminal Reader

너무 오래; 읽다

Vue 애플리케이션에서 Excel XLSX 파일을 가져오고 내보내는 방법을 알아보세요.
featured image - Vue를 사용하여 Excel XLSX 가져오기 및 내보내기: 가이드
MESCIUS inc. HackerNoon profile picture

“멋져 보이는데 그냥 Excel 가져오기만 추가해 주실 수 있나요?”


오랫동안 소프트웨어를 개발해 왔다면 관리자로부터 이런 질문을 한 번쯤 들어본 적이 있을 것입니다. 기술적인 지식이 없는 사람들에게는 Excel 가져오기/내보내기를 요청하는 것이 큰 문제처럼 들리지 않습니다. 얼마나 힘들겠어요?


그러나 이 질문은 개발자의 마음에 두려움을 불러일으키는 경우가 너무 많습니다. 대부분의 플랫폼에서 Excel 파일을 사용하려면 많은 작업이 필요합니다. 역사적으로 이것은 웹에서 두 배로 사실이었습니다. 웹 앱에서 Excel 데이터로 작업하는 것은 다음 xkcd 만화 와 약간 비슷합니다. "쉬운 것과 사실상 불가능한 것의 차이를 설명하는 것은 어려울 수 있습니다." Excel 가져오기 및 Excel 내보내기를 사용하여 자신만의 브라우저 내 스프레드시트를 만드는 것은 5년이 걸리고 연구팀이 해결해야 하는 문제처럼 느껴집니다.


그것은 변화하고 있습니다. 이제 완벽하게 작동하는 스프레드시트를 웹 앱에 추가할 수 있는 턴키 라이브러리가 있습니다. SpreadJS도 그 중 하나입니다. Vuex 스토어를 사용하는 실제 앱인 기존 Vue 앱을 가져와 SpreadJS를 사용하여 향상시키는 방법을 살펴보겠습니다.


이 기사의 나머지 부분에서는 귀하가 이미 HTML, CSS 및 JavaScript를 이해하고 있다고 가정합니다. 또한 웹 UI 생성을 위한 Vue.js 프로그레시브 JavaScript 프레임워크에 대한 실무 지식이 있다고 가정합니다. 상태 관리를 위해 Vuex를 사용했다면 도움이 되지만, 사용하지 않았더라도 걱정하지 마세요. 직관적이고 이해하기 쉬우며, Vue를 사용해 본 적이 있다면 코드만 읽어도 무슨 일이 일어나고 있는지 파악할 수 있을 것입니다.


이 블로그에서는 다음 단계에 따라 Vue 앱에 Excel 가져오기 및 내보내기를 추가하는 방법을 다룹니다.


  1. Vue 애플리케이션 구조
  2. Vue 앱에 SpreadJS 추가
  3. Excel 내보내기 추가
  4. Excel 가져오기 추가
  5. Vue 앱 테스트

Vue 앱

우리가 작업할 Vue 앱은 몇 가지 요약 패널과 데이터 테이블이 포함된 간단한 판매 대시보드입니다. "나쁘지 않음" 카테고리에 속하는 앱입니다.


Vue 판매 대시보드


비록 데모에 불과하지만 정확히 기업 웹 개발자가 만들어야 하는 종류의 앱입니다. 또한 이는 일반적으로 Excel 기능을 추가하라는 요청을 받는 종류의 앱이므로 이 문서의 나머지 부분에 대한 완벽한 예가 될 것입니다.


이 애플리케이션의 코드는 여기에서 찾을 수 있습니다.


Vue 애플리케이션을 처음부터 만드는 방법을 보려면 이 빠른 시작 가이드를 확인하세요.


무대를 설정하기 위해 대시보드는 Vue로 만든 단일 페이지 애플리케이션입니다. 단일 파일 구성 요소 및 Vuex 데이터 저장소와 같은 최신 및 최고의 Vue 모범 사례를 사용합니다. 또한 CSS 구성 요소와 그리드 시스템에 Bootstrap을 사용하고 있습니다.


Bootstrap은 예전만큼 인기가 없지만 실제로 Bootstrap은 여전히 어디에나 있습니다. 특히 Excel 지원이 일반적으로 필요한 엔터프라이즈 웹 앱에서는 더욱 그렇습니다. 우리는 2030년에도 많은 새로운 기업용 웹 앱이 여전히 Bootstrap을 사용할 것이라고 확신합니다.


스프레드시트 지원 앱에서 Bulma 또는 Tachyons를 사용하고 싶다면 바로 사용하세요! SpreadJS는 둘 중 하나와 잘 작동합니다.

Vue 애플리케이션 구조

코드가 어떻게 구성되어 있는지 살펴보겠습니다. Vuex 스토어와 Vue 애플리케이션은 모두 main.js 에 정의되어 있습니다. 여러 개의 단일 파일 Vue 구성 요소가 구성 요소 폴더에 있습니다.


Vuex 스토어를 보면 다음과 같은 내용을 볼 수 있습니다.


 const store = new Vuex.Store({ state: { recentSales } mutations: { UPDATE_RECENT_SALES(state) { state.recentSales.push([]); state.recentSales.pop(); } } });


우리 매장의 초기 상태는 우리가 가져온 더미 데이터 세트인 RecentSales의 값으로 설정됩니다. 또한 최근 매출이 변경되면 업데이트를 처리하는 기능도 있습니다.


잠깐 기다려요. 데이터 세트가 하나만 있는 경우 차트 3개와 테이블 1개 어떻게 생성합니까? 무슨 일이 일어나고 있는지 보려면 Dashboard.vue 구성 요소를 엽니다. 여기서는 Vuex 저장소의 데이터를 기반으로 여러 계산된 속성이 생성되는 것을 볼 수 있습니다.


 <template> <div style="background-color: #ddd"> <NavBar title="Awesome Dashboard"/> <div class="container"> <div class="row"> <TotalSales :total="totalSales"/> <SalesByCountry :salesData="countrySales"/> <SalesByPerson :salesData="personSales"/> <SalesTable :tableData="salesTableData"/> </div> </div> </div> </template> <script> import NavBar from "./NavBar"; import TotalSales from "./TotalSales"; import SalesByCountry from "./SalesByCountry"; import SalesByPerson from "./SalesByPerson"; import SalesTable from "./SalesTable"; import { groupBySum } from "../util/util"; export default { components: { NavBar, SalesByCountry, SalesByPerson, SalesTable, TotalSales }, computed: { totalSales() { const items = this.$store.state.recentSales; const total = items.reduce((acc, sale) => (acc += sale.value), 0); return parseInt(total); }, chartData() { const items = this.$store.state.recentSales; const groups = groupBySum(items, "country", "value"); return groups; }, personSales() { const items = this.$store.state.recentSales; const groups = groupBySum(items, "soldBy", "value"); return groups; }, salesTableData() { return this.$store.state.recentSales; }, } }; </script>


이제 더 의미가 있습니다! 단일 데이터 세트에는 대시보드의 모든 숫자와 테이블을 생성하는 데 필요한 모든 것이 포함되어 있습니다. 데이터는 반응형 Vuex 저장소에 있으므로 데이터가 업데이트되면 모든 대시보드 패널이 자동으로 업데이트됩니다.


이 반응성은 지루하고 오래된 정적 테이블을 편집 가능한 스프레드시트로 교체할 때 다음 섹션에서 유용하게 사용될 것입니다.

Vue 앱에 SpreadJS 추가하기

여기서부터 재미가 시작됩니다! 대시보드가 있지만 투박하고 오래된 HTML 테이블을 제거하고 싶습니다. 그래서 우리는 상황을 조금 바꿔야 할 것입니다. 좋은 출발점이 있지만 라이선스 없이 개발 모드에서 SpreadJS를 사용하려면 앱을 로컬에서 실행해야 합니다.


완성된 코드를 다운로드하여 최종 결과를 확인할 수 있습니다.


SpreadJS 없이 원본 프로젝트를 여는 것부터 시작하세요. 터미널을 열고 저장소를 복제한 디렉터리로 이동한 후 'npm install'을 실행하세요. 그러면 애플리케이션을 실행하는 데 필요한 종속성이 설치됩니다. 종속성 설치가 완료되면 'npm Serve'를 실행하여 업데이트된 앱이 작동하는 모습을 확인하세요. 사용된 라이브러리를 구체적으로 가져오려면 다음 명령을 사용할 수 있습니다.


 npm install @mescius/spread-sheets @mescius/spread-sheets-vue @mescius/spread-excelio file-saver bootstrap


기존 앱을 새롭고 향상된 버전으로 업그레이드하기 위해 변경해야 할 사항을 살펴보겠습니다. 판매 테이블을 스프레드시트로 바꿀 예정이므로 시트를 기존 SalesTable.vue 구성 요소에 넣습니다. 하지만 먼저 이전 테이블을 제거해야 합니다. 사라지면 SalesTable 템플릿은 다음과 같습니다.


 <template> <TablePanel title="Recent Sales"> </TablePanel> </template>


테이블을 제거한 후 테이블 패널이 준비되었고 스프레드시트를 기다리고 있으므로 하나 추가해 보겠습니다. SpreadJS 시트를 추가한 후 템플릿은 다음과 같습니다.


 <template> <TablePanel title="Recent Sales"> <gc-spread-sheets :hostClass='hostClass' @workbookInitialized='workbookInit'> <gc-worksheet :dataSource='tableData' :autoGenerateColumns='autoGenerateColumns'> <gc-column :width='50' :dataField="'id'" :headerText="'ID'" :visible = 'visible' :resizable = 'resizable' > </gc-column> <gc-column :width='300' :dataField="'client'" :headerText="'Client'" :visible = 'visible' :resizable = 'resizable' > </gc-column> <gc-column :width="350" :headerText="'Description'" :dataField="'description'" :visible = 'visible' :resizable = 'resizable' > </gc-column> <gc-column :width="100" :dataField="'value'" :headerText="'Value'" :visible = 'visible' :formatter = 'priceFormatter' :resizable = 'resizable' > </gc-column> <gc-column :width="100" :dataField="'itemCount'" :headerText="'Quantity'" :visible = 'visible' :resizable = 'resizable' > </gc-column> <gc-column :width="100" :dataField="'soldBy'" :headerText="'Sold By'" :visible = 'visible' :resizable = 'resizable' ></gc-column> <gc-column :width="100" :dataField="'country'" :headerText="'Country'" :visible = 'visible' :resizable = 'resizable' ></gc-column> </gc-worksheet> </gc-spread-sheets> </TablePanel> </template>


고려해야 할 내용이 많기 때문에 무슨 일이 일어나고 있는지 이해하기 위해 살펴보겠습니다.


먼저, gc-spread-sheets 요소를 사용하고 이를 구성 요소의 두 가지 속성(hostClass 및 workbookInit)에 바인딩하여 스프레드시트를 만듭니다.


스프레드시트 내에서 gc-worksheet 요소를 사용하여 새 워크시트를 생성하고 이를 구성 요소의 tableData 및 autoGenerateColumns 속성에 바인딩합니다. tableData는 일반 HTML 테이블을 생성하는 데 사용한 tableData와 정확히 동일합니다. 변경할 필요 없이 데이터를 있는 그대로 SpreadJS에 넣을 수 있습니다!


마지막으로 워크시트 내에서 SpreadJS에 데이터 표시 방법을 알려주는 열을 정의합니다. dataField 속성은 이 열이 표시해야 하는 기본 데이터세트의 속성을 알려주고 headerText는 SpreadJS에 사용할 멋진 형식의 열 이름을 제공합니다. 각 열의 나머지 바인딩은 간단합니다. SpreadJS 문서에는 gc-column에 전달할 수 있는 모든 항목의 전체 목록이 있습니다.


그렇다면 템플릿을 적용한 상태에서 이 모든 것이 작동하려면 얼마나 많은 코드가 필요할까요? 다행히도 전혀 많지 않습니다! SalesTable.vue 구성 요소의 새 스크립트 코드는 다음과 같습니다.


 import "@mescius/spread-sheets/styles/gc.spread.sheets.excel2016colorful.css"; // SpreadJS imports import GC from "@mescius/spread-sheets"; import "@mescius/spread-sheets-vue"; import Excel from "@mescius/spread-excelio"; import TablePanel from "./TablePanel"; export default { components: { TablePanel }, props: ["tableData"], data(){ return { sheetName: 'Sales Data', hostClass:'spreadsheet', autoGenerateColumns:true, width:200, visible:true, resizable:true, priceFormatter:"$ #.00" } }, methods: { workbookInit: function(_spread_) { this._spread = spread; var self = this; spread.bind(GC.Spread.Sheets.Events.ValueChanged, function () { const store = self.$store; var sheet = self._spread.getSheetFromName("Sales Data"); var newSalesData = sheet.getDataSource(); store.commit('UPDATE_RECENT_SALES', newSalesData); }); } } };


Vue의 단순성으로 인해 이 작업을 수행하는 데는 코드가 거의 필요하지 않습니다. 여기에 익숙하지 않은 내용이 있으면 Vue 설명서의 '심층 구성 요소' 섹션에서 Vue 구성 요소에 대해 자세히 설명합니다. 변경된 유일한 사항은 몇 가지 가져오기, 일부 데이터 속성 및 몇 가지 메서드입니다. 데이터 속성은 익숙해 보여야 합니다. 우리는 조금 전에 템플릿에서 그것들을 보았습니다. 이는 SpreadJS 스프레드시트의 구성 요소에 바인딩하는 구성 옵션입니다.


workbookInit 메서드는 시트가 초기화될 때 SpreadJS가 호출하는 콜백입니다. 이 방법에서는 SheetJS 스프레드시트 개체를 구성 요소의 인스턴스 변수로 저장하므로 필요한 경우 직접 상호 작용할 수 있습니다. 또한 SpreadJS 인스턴스에서 값이 변경될 때마다 자동으로 데이터를 업데이트하기 위해 ValueChanged 이벤트에 대한 바인딩 기능을 추가했습니다.


마지막 변경 사항: 스프레드시트 스타일 자체를 돕기 위해 구성 요소에 범위가 지정된 스타일을 제공합니다. 앞서 gc-spread-sheets 요소에 호스트클래스를 전달할 때 이를 보았습니다. HostClass가 'spreadsheet'로 설정되었으므로 스프레드시트라는 CSS 클래스를 생성하겠습니다.


 <style scoped> .spreadsheet { width: 100%; height: 400px; border: 1px solid lightgray; } </style>


이 시점에서 다른 변경 사항을 적용하지 않고 대시보드를 로드하면 다음과 같이 표시됩니다.


새로운 Vue 대시보드


하지만 더 많은 것이 있습니다!


데이터 세트를 변경하지 않고 테이블 데이터를 스프레드시트에 어떻게 전달했는지 기억하시나요? 이제 데이터가 스프레드시트에 있으므로 편집할 수 있습니다.


판매 #6의 가치를 $35,000에서 $3500로 변경하면 어떻게 되나요? 시트로 이동하여 값을 편집하면 다음과 같은 대시보드가 표시됩니다.


편집된 Vue 대시보드


우와! 무슨 일이에요?


SpreadJS 시트를 업데이트했고 Vuex 스토어가 자동으로 업데이트되었습니다.


또한 Angela는 엄청난 판매 월을 보더니 평범한 월을 갖는 것으로 보입니다. 미안해요, 안젤라!


이제 관리자가 만족할 수 있는 향상된 대시보드가 생겼습니다. 데이터를 수정하고 대시보드 업데이트를 눈앞에서 볼 수 있지만 Excel 파일을 가져오고 내보내는 기능을 추가하면 훨씬 더 나은 작업을 수행할 수 있습니다. 다음으로 그 방법을 알아보겠습니다.

Excel 내보내기 추가

시트에 Excel 내보내기를 추가하는 것은 쉽습니다. 먼저 대시보드에 내보내기 버튼을 추가해 보겠습니다. SalesTable.vue 파일의 테이블 패널 하단, gc-spread-sheets 닫는 태그 바로 뒤에 배치하겠습니다.


 … </gc-spread-sheets> <div class="dashboardRow"> <button class="btn btn-primary dashboardButton" @click="exportSheet"> Export to Excel </button> </div> </TablePanel> </template>


보시다시피, 우리 버튼에는 내보내기 시트(exportSheet)라는 클릭 핸들러가 필요합니다. 잠시 후에 추가하겠지만 먼저 file-saver라는 NPM 패키지에서 함수를 가져옵니다.


 import { saveAs } from 'file-saver';


다음으로, 컴포넌트의 메소드 객체에 importSheet를 추가해 보겠습니다.


 exportSheet: function() { const spread = this._spread; const fileName = "SalesData.xlsx"; //const sheet = spread.getSheet(0); const excelIO = new IO(); const json = JSON.stringify(spread.toJSON({ includeBindingSource: true, columnHeadersAsFrozenRows: true, })); excelIO.save(json, (blob) => { saveAs(blob, fileName); }, function (e) { console.log(e) }); }


코드가 수행하는 작업은 다음과 같습니다. 먼저 판매 데이터시트에 대한 참조를 얻습니다. 스프레드시트의 유일한 시트이므로 인덱스 0에 있으며 getSheet를 호출하여 액세스합니다. 시트와 직접 상호 작용해야 하는 경우 함수의 다른 곳에서 사용할 수 있습니다.


그런 다음 SpreadJS의 ExcelIO 라이브러리를 인스턴스화하고 시트를 JSON으로 변환한 다음 SpreadJS에 저장하도록 요청합니다. 짜잔! 스프레드시트 지원 Vue 앱에서 Excel 파일을 내보냈습니다!


시트의 toJSON 호출에 두 가지 직렬화 옵션(includeBindingSource 및 columnHeadersAsFrozenRows)을 전달하고 있습니다. 이러한 옵션을 함께 사용하면 시트에 바인딩된 데이터가 올바르게 내보내지고 시트에 열 머리글이 포함됩니다. 그래서 내보낸 엑셀 파일을 보면 각 열을 이해하게 됩니다.

Excel 가져오기 추가

다음으로 Excel 파일을 가져오는 기능을 추가할 차례입니다.


내보내기 버튼 바로 아래에 다음 마크업을 추가하겠습니다.


 <div> <b>Import Excel File:</b> <div> <input type="file" class="fileSelect" @change='fileChange($event)' /> </div> </div>


보시다시피 표준 HTML 파일 선택기를 사용하고 파일이 선택되면 fileChange라는 구성 요소 메서드를 트리거합니다.


이제 템플릿을 추가했으므로 구성 요소의 메소드 객체에 변경 핸들러를 추가해 보겠습니다.


 fileChange: function (_e_) { if (this._spread) { const fileDom = e.target || e.srcElement; const excelIO = new Excel.IO(); const spread = this._spread; const store = this.$store; /*const deserializationOptions = { includeBindingSource: true, frozenRowsAsColumnHeaders: true };*/ excelIO.open(fileDom.files[0], (_data_) => { // Used for simply loading the JSON from a file //spread.fromJSON(data, deserializationOptions); var newSalesData = extractSheetData(data); store.commit('IMPORT_RECENT_SALES', newSalesData) }); } }


Excel 파일 가져오기는 반대의 경우를 제외하면 내보내기와 거의 동일합니다. 파일을 선택한 후 ExcelIO에 파일을 가져오도록 요청합니다. 완료되면 시트 정보를 JavaScript 개체로 콜백 함수에 전달합니다. 다음으로 가져온 데이터를 사용자 정의 함수를 통해 전달하여 필요한 데이터를 추출한 다음 Vuex 저장소에 다시 커밋합니다.


일반적으로 파일 가져오기는 ExcelIO 열기 메서드를 호출하고 통합 문서 "fromJSON" 메서드를 사용하는 것만큼 간단합니다. 이 경우 가져온 파일의 데이터를 구문 분석하고 저장소를 업데이트하면 SpreadJS가 업데이트됩니다.


src/util.util.js 파일에 있는 extractSheetData 함수에서는 ExcelIO가 반환한 JavaScript 개체에서 데이터를 가져와서 Vuex의 데이터 모양과 일치하도록 재구성하는 것을 볼 수 있습니다. 가게.


가져오기 기능은 가져온 시트의 데이터가 원래 데이터 세트와 동일한 열을 갖는다고 가정합니다. 누군가 이 요구 사항을 충족하지 않는 스프레드시트를 업로드하면 앱에서 이를 처리할 수 없습니다. 이는 대부분의 LOB(기간 업무) 앱에서 허용되는 제한 사항입니다. 대시보드는 특정 데이터 유형을 표시하도록 설계되었으므로 사용자에게 앱이 기대하는 형식으로 데이터를 제공하도록 요청하는 것이 합리적입니다.


데이터 추출이 완료되면 Vuex 스토어에서 커밋을 호출하고 업데이트된 판매 거래 데이터를 보냅니다. 그런 다음 SpreadJS 시트와 대시보드 패널이 자동으로 업데이트되어 새 데이터를 반영합니다. 실제로 main.js 파일에 "IMPORT_RECENT_SALES"로 추가할 수 있도록 가져오기와 변경되는 값에 대해 다른 돌연변이 함수를 사용할 수 있습니다.


 const store = new Vuex.Store({ state: { recentSales }, mutations: { UPDATE_RECENT_SALES(state) { state.recentSales.push([]); state.recentSales.pop(); }, IMPORT_RECENT_SALES(state, sales) { state.recentSales = sales; } } });

Vue 앱 테스트

이제 코드를 확인했으므로 Vue 앱에서 Excel 가져오기 및 내보내기를 테스트해 보겠습니다.


'Excel로 내보내기' 버튼을 클릭하여 시작하세요. 그러면 웹 브라우저는 대시보드 스프레드시트에서 본 모든 데이터가 포함된 Excel 스프레드시트를 다운로드합니다.


Excel에서 시트를 열고 몇 줄의 데이터를 추가합니다. 새로운 국가나 새로운 영업사원을 활용해도 괜찮습니다. 모든 대시보드 구성 요소가 이를 처리할 수 있습니다. 열 순서나 이름을 변경하지 않도록 주의하세요. 모두 마쳤으면 최근 판매 패널 하단에 있는 '파일 선택' 버튼을 클릭하세요. 방금 편집한 Excel 파일을 선택합니다.


파일을 선택하면 업데이트된 대시보드 구성 요소가 표시됩니다.

결론

이제 끝났습니다! 우리는 일반적인 Vue 대시보드 앱에 라이브 스프레드시트를 추가했습니다. 이제 시트의 데이터를 편집하고 전체 대시보드 업데이트를 직접 확인할 수 있습니다. 향상된 대시보드에서는 Excel 파일을 가져오고 내보낼 수도 있습니다.


Vue, Vuex 및 SpreadJS는 서로를 잘 보완합니다. Vue의 쉬운 템플릿 및 데이터 바인딩, Vuex의 반응형 데이터 저장소 및 SpreadJS의 대화형 스프레드시트를 사용하면 복잡한 엔터프라이즈 JavaScript 앱을 몇 시간 안에 만들 수 있습니다.


훌륭해 보일 수도 있지만 우리는 SpreadJS가 수행할 수 있는 작업의 표면만 살펴봤습니다. SpreadJS가 수행할 수 있는 작업을 더 잘 이해하려면 SpreadJS의 다양한 기능에 대한 전체 데모, 설명 및 해당 기능을 보여주는 라이브 코드가 포함된 SpreadJS 데모를 참조하세요. 자신의 앱에서 SpreadJS를 사용하는 방법을 더 자세히 알아보고 싶다면 SpreadJS 설명서에 필요한 정보가 있습니다.


이 JavaScript 스프레드시트 구성요소에 대해 자세히 알아보세요.