paint-brush
Importando e exportando Excel XLSX usando Vue: um guiapor@mesciusinc
Novo histórico

Importando e exportando Excel XLSX usando Vue: um guia

por MESCIUS inc.17m2024/06/26
Read on Terminal Reader

Muito longo; Para ler

Aprenda como importar e exportar arquivos Excel XLSX em um aplicativo Vue.
featured image - Importando e exportando Excel XLSX usando Vue: um guia
MESCIUS inc. HackerNoon profile picture

“Parece ótimo, mas você poderia simplesmente adicionar a importação do Excel?”


Se você desenvolve software há muito tempo, provavelmente já ouviu essa pergunta de um gestor mais de uma vez. Para um público não técnico, pedir importação/exportação de Excel não parece grande coisa. Quão difícil poderia ser, certo?


Mas muitas vezes esta questão causa medo nos corações dos desenvolvedores. Na maioria das plataformas, trabalhar com arquivos Excel exige muito trabalho. Historicamente, isso tem sido duplamente verdadeiro na web. Trabalhar com dados do Excel em um aplicativo da web parece um pouco com esta história em quadrinhos do xkcd : "Pode ser difícil explicar a diferença entre o fácil e o virtualmente impossível." Construir sua própria planilha no navegador com importação e exportação do Excel parece um problema que levará cinco anos e uma equipe de pesquisa para ser resolvido.


Isso está mudando. Agora temos bibliotecas prontas para uso que permitem inserir uma planilha totalmente funcional em seu aplicativo da web. SpreadJS é um deles. Veremos como pegar um aplicativo Vue existente – um aplicativo do mundo real usando uma loja Vuex – e aprimorá-lo usando SpreadJS.


O restante do artigo pressupõe que você já entenda HTML, CSS e JavaScript. Também pressupõe que você tenha um conhecimento prático da estrutura JavaScript progressiva Vue.js para criar UI da web. Ajudará se você tiver usado o Vuex para gerenciamento de estado, mas não se preocupe se ainda não o fez. É intuitivo e fácil de entender, e você poderá descobrir o que está acontecendo apenas lendo o código, caso tenha usado o Vue.


Neste blog, abordaremos como adicionar importação e exportação do Excel ao seu aplicativo Vue seguindo estas etapas:


  1. Estrutura do aplicativo Vue
  2. Adicione SpreadJS ao seu aplicativo Vue
  3. Adicionar exportação do Excel
  4. Adicionar importação do Excel
  5. Teste seu aplicativo Vue

O aplicativo Vue

O aplicativo Vue no qual trabalharemos é um painel de vendas simples com alguns painéis de resumo e uma tabela de dados. É o tipo de aplicativo que se enquadra na categoria “nada mal”:


Painel de vendas Vue


Embora seja apenas uma demonstração, é exatamente o tipo de aplicativo que os desenvolvedores web corporativos precisam criar. Também é exatamente o tipo de aplicativo ao qual normalmente somos solicitados a adicionar funcionalidades do Excel, portanto, será um exemplo perfeito para o restante deste artigo.


O código desta aplicação pode ser encontrado aqui .


Se você quiser ver como criar um aplicativo Vue do zero, confira este guia de início rápido .


Para preparar o cenário, o painel é um aplicativo de página única feito com Vue. Ele usa as melhores e mais recentes práticas recomendadas do Vue : componentes de arquivo único e um armazenamento de dados Vuex. Também está usando Bootstrap para seus componentes CSS e sistema de grade.


Bootstrap não é tão popular como costumava ser, mas na realidade, Bootstrap ainda está em toda parte – especialmente em aplicativos web corporativos onde o suporte do Excel geralmente é necessário. Apostamos que muitos novos aplicativos web corporativos ainda usarão o Bootstrap em 2030.


Se você preferir usar Bulma ou Tachyons em seus aplicativos habilitados para planilhas, vá em frente! SpreadJS funcionará bem com qualquer um deles.

Estrutura do aplicativo Vue

Vamos dar uma olhada em como o código está estruturado. Nossa loja Vuex e aplicativo Vue são definidos em main.js . Temos vários componentes Vue de arquivo único, todos localizados na pasta de componentes.


Se você olhar nossa loja Vuex, verá o seguinte:


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


O estado inicial da nossa loja é definido como o valor de recentSales, um conjunto de dados fictícios que importamos. Também temos uma função que atualiza as vendas recentes quando elas são alteradas.


Espere um minuto. Se tivermos apenas um conjunto de dados, como geraremos três gráficos e uma tabela? Para ver o que está acontecendo, abra o componente Dashboard.vue . Nele, você verá várias propriedades computadas sendo geradas com base nos dados da loja 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>


Agora faz mais sentido! O conjunto de dados único contém tudo que precisamos para gerar todos os números e tabelas para nosso painel. Como os dados estão em um armazenamento Vuex reativo, se os dados forem atualizados, todos os painéis do painel serão atualizados automaticamente.


Essa reatividade será útil na próxima seção, quando substituirmos nossa velha e chata tabela estática por uma planilha editável.

Adicionando SpreadJS ao seu aplicativo Vue

É aqui que a diversão começa! Temos nosso painel, mas queremos eliminar aquela velha tabela HTML desajeitada. Então, teremos que mudar um pouco as coisas. Temos um ótimo ponto de partida, mas precisamos executar nosso aplicativo localmente para usar o SpreadJS em modo de desenvolvimento sem licença.


Você pode baixar o código finalizado para ver o resultado final.


Comece abrindo o projeto original sem SpreadJS. Abra um terminal, navegue até o diretório onde você clonou o repositório e execute ‘npm install’. Isso instala as dependências necessárias para executar o aplicativo. Quando a instalação da dependência terminar, execute 'npm serve' para ver o aplicativo atualizado em ação. Se quiser importar especificamente as bibliotecas usadas, você pode usar este comando:


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


Vamos examinar as mudanças que teremos que fazer para atualizar nosso aplicativo antigo para sua versão nova e aprimorada. Como substituiremos nossa tabela de vendas por uma planilha, colocaremos a planilha em nosso componente SalesTable.vue existente, mas primeiro teremos que nos livrar de nossa tabela antiga. Depois que ele acabar, nosso modelo SalesTable ficará assim:


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


Depois de eliminar a tabela, estamos com nosso painel de mesa pronto e aguardando uma planilha, então vamos adicionar uma! Depois de adicionar uma planilha SpreadJS, nosso modelo ficará assim:


 <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>


Isso é muito para entender, então vamos examinar isso para entender o que está acontecendo.


Primeiro, criamos uma planilha usando o elemento gc-spread-sheets e vinculando-a a duas propriedades do nosso componente: hostClass e workbookInit.


Dentro da planilha, criamos uma nova planilha com o elemento gc-worksheet e a vinculamos às propriedades tableData e autoGenerateColumns do nosso componente. Observe que tableData é exatamente o mesmo tableData que usamos para gerar nossa tabela HTML simples. Podemos colocar nossos dados no SpreadJS como estão, sem necessidade de alterações!


Por fim, dentro da planilha, definimos colunas que informam ao SpreadJS como exibir nossos dados. A propriedade dataField nos informa qual propriedade do conjunto de dados subjacente esta coluna deve exibir, e headerText fornece ao SpreadJS um nome de coluna bem formatado para usar. O restante das ligações para cada coluna é simples. A documentação do SpreadJS tem uma lista completa de tudo que você pode passar para uma coluna gc.


Então, com nosso modelo implementado, quanto código será necessário para fazer tudo funcionar? Felizmente, não muito! Aqui está o novo código de script do nosso componente 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); }); } } };


Devido à simplicidade do Vue, é necessário muito pouco código para fazer isso funcionar. Se houver algo aqui com o qual você não esteja familiarizado, a seção 'Componentes detalhados' da documentação do Vue explica os componentes do Vue em detalhes. As únicas coisas que mudaram foram algumas importações, algumas propriedades de dados e alguns métodos. As propriedades dos dados devem parecer familiares; nós os vimos há pouco no modelo. São opções de configuração que vinculamos aos componentes de nossa planilha SpreadJS.


O método workbookInit é um retorno de chamada que SpreadJS chama quando a planilha é inicializada. Neste método, salvamos nosso objeto de planilha SheetJS como uma variável de instância em nosso componente para que possamos interagir diretamente com ele, se necessário. Também adicionamos uma função de ligação para o evento ValueChanged para atualizar automaticamente os dados sempre que os valores forem alterados na instância SpreadJS.


Uma última mudança: damos ao nosso componente um estilo de escopo para ajudar o próprio estilo da planilha. Vimos isso anteriormente quando passamos o hostClass para o elemento gc-spread-sheets. Como hostClass está definido como 'planilha', criaremos uma classe CSS chamada planilha:


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


Neste ponto, se não fizermos outras alterações e carregarmos nosso Dashboard, ele ficará assim:


Novo painel Vue


Mas espere, tem mais!


Lembra como passamos os dados da nossa tabela para a planilha sem fazer nenhuma alteração no conjunto de dados? Agora que nossos dados estão em uma planilha, podemos editá-los.


O que acontecerá se alterarmos o valor da venda nº 6 de US$ 35.000 para US$ 3.500? Se entrarmos na planilha e editarmos o valor, obteremos um painel parecido com este:


Painel Vue editado


Uau! O que aconteceu?


Atualizamos a planilha SpreadJS e ela atualizou automaticamente nossa loja Vuex.


Também parece que Angela passou de um mês de vendas espetacular para um mês medíocre. Desculpe por isso, Ângela!


Agora temos um painel aprimorado com o qual um gerente ficaria satisfeito. Eles podem modificar os dados e observar a atualização do painel diante de seus olhos, mas podemos fazer ainda melhor adicionando a capacidade de importar e exportar arquivos Excel. A seguir, aprenderemos como fazer isso.

Adicionando exportação do Excel

Adicionar exportação do Excel à nossa planilha é fácil. Primeiro, vamos adicionar um botão de exportação ao nosso painel. Vamos colocá-lo na parte inferior do painel da tabela no arquivo SalesTable.vue , logo após a tag de fechamento gc-spread-sheets:


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


Como você pode ver, nosso botão espera um manipulador de cliques chamado exportSheet. Iremos adicioná-lo em um momento, mas primeiro importaremos uma função de um pacote NPM chamado file-saver:


 import { saveAs } from 'file-saver';


A seguir, vamos adicionar exportSheet ao objeto de métodos do nosso componente:


 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) }); }


Aqui está o que o código está fazendo: primeiro, obtemos uma referência à nossa Folha de Dados de Vendas. Como é a única planilha em nossa planilha, ela fica no índice 0 e podemos acessá-la chamando getSheet. Isso pode ser usado em outras partes da função caso precisemos interagir diretamente com a planilha.


Em seguida, instanciamos a biblioteca ExcelIO do SpreadJS, convertemos nossa planilha para JSON e pedimos ao SpreadJS para salvá-la. Voilá! Exportamos um arquivo Excel de nosso aplicativo Vue habilitado para planilha!


Observe que estamos passando duas opções de serialização para a chamada toJSON da planilha: includeBindingSource e columnHeadersAsFrozenRows. Juntas, essas opções garantem que os dados vinculados à planilha sejam exportados corretamente e que a planilha contenha os cabeçalhos das colunas. Assim, olhar o arquivo Excel exportado entenderá cada coluna.

Adicionando importação do Excel

Em seguida, é hora de adicionar a capacidade de importar arquivos do Excel.


Logo abaixo do nosso botão de exportação, adicionaremos a seguinte marcação:


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


Como você pode ver, usaremos um seletor de arquivo HTML padrão e acionaremos um método de componente chamado fileChange quando um arquivo for selecionado.


Agora que adicionamos o modelo, vamos adicionar o manipulador de alterações ao objeto de métodos do nosso componente:


 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) }); } }


Importar um arquivo Excel é praticamente o mesmo que exportá-lo, exceto o contrário. Após a escolha de um arquivo, pedimos ao ExcelIO para importá-lo. Quando terminar, ele passa as informações da planilha para uma função de retorno de chamada como um objeto JavaScript. Em seguida, passamos os dados importados por meio de uma função personalizada para extrair deles os dados necessários e, em seguida, enviá-los de volta para a loja Vuex.


Normalmente, importar um arquivo é tão simples quanto chamar o método aberto do ExcelIO, mas usando o método “fromJSON” da pasta de trabalho. Neste caso, queremos apenas analisar os dados do arquivo importado e atualizar a loja, que então atualizará o SpreadJS.


Em nossa função extractSheetData, que você encontrará no arquivo src/util.util.js, você verá que extraímos dados do objeto JavaScript retornado pelo ExcelIO e os reestruturamos para corresponder ao formato dos dados em nosso Vuex loja.


Nossa função de importação pressupõe que os dados na planilha importada terão as mesmas colunas do nosso conjunto de dados original. Se alguém fizer upload de uma planilha que não atenda a esse requisito, nosso aplicativo não conseguirá lidar com isso. Esta é uma limitação aceitável na maioria dos aplicativos de linha de negócios. Como nosso painel foi projetado para exibir um tipo de dados específico, é razoável pedir aos usuários que forneçam dados no formato esperado pelo aplicativo.


Quando a extração dos dados for concluída, chamamos commit na loja Vuex e enviamos os dados atualizados da transação de vendas. A planilha SpreadJS e os painéis do painel são atualizados para refletir os novos dados. Na verdade, podemos usar uma função de mutação diferente para importar versus um valor sendo alterado para que possamos adicioná-lo ao arquivo main.js como “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; } } });

Testando seu aplicativo Vue

Agora que você viu o código, vamos testar a importação e exportação do Excel em nosso aplicativo Vue.


Comece clicando no botão 'Exportar para Excel'. Seu navegador fará o download de uma planilha Excel contendo todos os dados que vimos na planilha do nosso painel.


Abra a planilha no Excel e adicione algumas linhas de dados. Não há problema se você usar novos países ou novos vendedores; todos os nossos componentes do painel podem lidar com isso. Apenas tome cuidado para não alterar a ordem ou os nomes das colunas. Quando terminar, clique no botão “Escolher arquivo” na parte inferior do painel Vendas recentes. Selecione o arquivo Excel que você acabou de editar.


Ao selecionar o arquivo, você verá os componentes atualizados do painel.

Conclusão

Foram realizadas! Pegamos um aplicativo de painel Vue comum e adicionamos uma planilha dinâmica a ele. Agora podemos editar os dados na planilha e observar todo o nosso painel se atualizar. Nosso painel aprimorado também é capaz de importar e exportar arquivos Excel.


Vue, Vuex e SpreadJS se complementam bem. Com a fácil modelagem e vinculação de dados do Vue, o armazenamento de dados reativos do Vuex e as planilhas interativas do SpreadJS, aplicativos JavaScript corporativos complexos podem ser criados em horas.


Por melhor que isso possa parecer, mal arranhamos a superfície do que o SpreadJS pode fazer. Para entender melhor o que o SpreadJS pode fazer por você, consulte as Demonstrações do SpreadJS , que incluem demonstrações completas dos diferentes recursos do SpreadJS, explicações e código ao vivo apresentando esses recursos. Se você deseja se aprofundar no uso do SpreadJS em seus próprios aplicativos, a documentação do SpreadJS tem as informações que você precisa.


Saiba mais sobre este componente de planilha JavaScript: