Vuex与前端表格施展“组合拳”,实现大屏展示应用的交互增强
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
下图是一个产品开发中非常常见的大屏展示界面示例。
通过Vue提供的Vuex,上方三个仪表板以及下方的表格组件共享同一个数据源,已经实现了数据改变后同步响应更新。

“很棒的大屏展示功能,能支持Excel数据的导入导出吗,表格数据可以实时编辑更新吗?”
如果你已经开发软件很长时间,可能不止一次地从最终客户或者产品经理那里听到过这个灵魂拷问。对于非技术人群来说,觉得要求 Excel 导入/导出/展示是一个非常正常且容易实现的需求。
但实际上,这个问题常常让前端开发人员感到恐惧。处理 Excel 文件需要大量工作。
这个问题通过前端表格可以变得简单,将电子表格嵌入Web 应用程序。同时和其他的组件进行交互。 这篇博客将研究如何使用现有的这个大屏展示 Vue 应用作为基础,使用前端电子表格对其进行增强。
本文假定你已经了解 HTML、CSS 和 JavaScript。以及Vue的基础应用。如果你有使用过Vuex ,当然会更容易理解,如果还没有,也不用担心。VueX在这个项目中的应用很简单。
关于VueX,可以在Vue官网了解更多信息
本文将分为下面的几个部分
- Vuex的原始应用
- 给应用添加实时编辑功能
- 添加 Excel 数据导入功能
- 添加导出为Excel功能
包含Vuex的原始应用
如上图看到的,将要使用的 Vue 应用程序是一个简单的大屏展示界面,带有几个汇总信息仪表板和一个数据表。
可以通过下面的附件获取这个Vue应用项目代码,然后运行“npm install”以及 “npm run serve”即可启动应用 。
附件下载地址:
https://gcdn.grapecity.com.cn/forum.php?mod=attachment&aid=MjI1NzA1fDNkMDNjNjQ2fDE2NjAxMTUxMjF8NjI2NzZ8OTk3MTg%3D
原始的Vue 应用代码结构如下:
- Vuex 和 Vue 应用程序都定义在main.js中。
- 有几个单文件 Vue 组件,位于该components文件夹中。
Vuex store代码如下,初始状态只有一个设置为recentSales 的值,表示近期销售记录 :
const store = new Vuex.Store({
state: {
recentSales
}
});
通过recentSales这一个数据,如何生成三个统计表和一个表格?打开 Dashboard.vue 组件。在其中,可以看到基于 Vuex 存储中的数据生成了几个计算属性:
<template>
<div style="background-color: #ddd">
<NavBar title="销售仪表板"/>
<div class="container">
<div class="row">
<TotalSales :total="totalSales"/>
<SalesByCountry :salesData="countrySales"/>
<SalesByPerson :salesData="personSales"/>
<SalesTableBySpreadjs :tableData="salesTableData"/>
<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 SalesTableBySpreadjs from "./SalesTableBySpreadjs";
import { groupBySum } from "../util/util";
export default {
components: { NavBar, SalesByCountry, SalesByPerson, SalesTable, TotalSales ,SalesTableBySpreadjs},
computed: {
totalSales() {
const total = this.$store.state.recentSales.reduce(
(acc, sale) => (acc += sale.value),
0
);
return parseInt(total);
},
countrySales() {
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>
因此recentSales这个单个数据集目前能为这个大屏展示的几个仪表板和表格提供一致数据。由于数据位于Vuex store中,那么如果数据更新,所有仪表板面板都会自动更新。
当我们用可以编辑的电子表格替换现有的表格来进行编辑时,这种特性将派上用场。
将前端电子表格添加到您的 Vue 应用程序
我们要用前端电子表格替换这个html表格,在component文件夹新建一个vue文件,命名为SalesTableBySpreadjs.vue,然后在其中添加一个template:
<template>
<TablePanel title="近期销售额">
<gc-spread-sheets
:hostClass="hostClass"
@workbookInitialized="workbookInit"
style="height: 300px"
>
<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元素创建了一个电子表格并定义了如何显示数据列。gc-column 中的dataField 属性告诉该列应该显示底层数据集的哪个属性。
接下来是js部分:
import "@grapecity/spread-sheets/styles/gc.spread.sheets.excel2016colorful.css";
_// SpreadJS imports_
import "@grapecity/spread-sheets-vue";
import Excel from "@grapecity/spread-excelio";
import TablePanel from "./TablePanel";
export default {
components: { TablePanel },
props: ["tableData"],
data(){
return {
hostClass:'spreadsheet',
autoGenerateColumns:true,
width:200,
visible:true,
resizable:true,
priceFormatter:"$ #.00"
}
},
methods: {
workbookInit: function(_spread_) {
this._spread = spread;
}
}
};
只需很少的代码即可完成。其中的几个数据属性和方法,是绑定到纯前端电子表格组件的配置选项,workbookInit 方法是SpreadJS在初始化工作表时调用的回调。
回到Dashboard.vue文件,加入刚刚创建的SalesTableBySpreadjs组件。
然后重新运行,即可显示电子表格数据:
<template>
<div style="background-color: #ddd">
<NavBar title="销售仪表板"/>
<div class="container">
<div class="row">
<TotalSales :total="totalSales"/>
<SalesByCountry :salesData="countrySales"/>
<SalesByPerson :salesData="personSales"/>
<SalesTableBySpreadjs :tableData="salesTableData"/>
<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 SalesTableBySpreadjs from "./SalesTableBySpreadjs";
import { groupBySum } from "../util/util";
export default {
components: { NavBar, SalesByCountry, SalesByPerson, SalesTable, TotalSales ,SalesTableBySpreadjs},
computed: {
totalSales() {
const total = this.$store.state.recentSales.reduce(
(acc, sale) => (acc += sale.value),
0
);
return parseInt(total);
},
countrySales() {
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>

现在我们已经用一个完整的电子表格替换了原来的html table,接下来可以对电子表格中的金额列中显示的金额进行编辑。比如将第6行的金额从 35,000 美元更改为 3500 美元,可以看到上面三个仪表板显示的内容同时也进行了更新。
原因是SpreadJS被编辑后同步更新了它的数据源=>VUEX store中的recentSales。
到这里我们已经有了一个可以随着数据变化而实时更新的增强型仪表板。下一步我们可以通过导出导入 Excel 数据的功能来做进一步增强。
导出为Excel文件
将 Excel 导出功能添加到工作表很容易。首先,在仪表板中添加一个导出按钮。把它放在表格面板的底部,在 gc-spread-sheets 结束标记之后:
</gc-spread-sheets>
<div class="row my-3">
<div class="col-sm-4">
<button class="btn btn-primary mr-3" @click="exportSheet">
导出文件
</button>
</div>
</div>
</TablePanel>
</template>
接下来添加点击时触发的 exportSheet方法,从名为 file-saver 的 NPM 包中导入一个函数:
import { saveAs } from 'file-saver';
然后将 exportSheet 添加到组件的方法对象中:
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,
function (blob) {
saveAs(blob, fileName);
},
function (e) {
console.log(e);
}
);
},
运行测试点击按钮,即可直接获取到导出的excel文件。
需要注意的是,我们设置了两个序列化选项:includeBindingSource 和 columnHeadersAsFrozenRows。以确保绑定到工作表的数据被正确导出,且工作表包含列标题,。
Excel 数据导入
在template中,添加以下代码添加一个file类型的input用于导入文件:
<div class="col-sm-8">
<button class="btn btn-primary float-end mx-2">导入文件</button>
<input
type="file"
class="fileSelect float-end mt-1"
@change="fileChange($event)"
/>
</div>
然后将fileChange方法添加到组件的method对象中:
fileChange: function (e) {
if (this._spread) {
const fileDom = e.target || e.srcElement;
const excelIO = new IO();
//const spread = this._spread;
const store = this.$store;
excelIO.open(fileDom.files[0], (data) => {
const newSalesData = extractSheetData(data);
store.commit("updateRecentSales", newSalesData);
});
}
},
选择文件后,使用SpreadJS中的 ExcelIO 导入它。获取其中的json数据。传入自定义的函数extractSheetData,从中提取需要的数据,然后将其提交回 Vuex store,来更新recentSales数据。
extractSheetData 函数可以在 src/util.util.js 文件中找到。extractSheetData函数假定导入工作表中的数据与原始数据集具有相同的列。如果有人上传的电子表格不符合此要求,将无法解析。这个应该是大多数客户可以接受的限制。数据不符时,也可以尝试给客户一个提示信息。
另外,还需要在main.js中为Vuex store添加updateRecentSales来更新数据,
修改后的store如下:
const store = new Vuex.Store({
state: {
recentSales
},
mutations: {
updateRecentSales (state,param) {
let sales=state.recentSales;
let arr=sales.map(function(o){return o.id});
param.forEach((newsale)=>{
if(arr.indexOf(newsale.id)>0){
console.log("update");
state.recentSales[arr.indexOf(newsale.id)]=newsale;
}
else{
console.log("add");
state.recentSales.push(newsale);
}
});
console.log(state.recentSales);
}
},
actions: {
updateRecentSales ({commit},param) {
commit('updateRecentSales',param)
}
}
});
可以看到,Vuex store调用 commit后,会触发updateRecentSales方法对recentSales进行更新,id相同时进行更新, 有新的id时进行新增。
最后,SpreadJS工作表和所有仪表板面板都会同步更新以反映新数据。
Vue、Vuex 和 SpreadJS 的配合使用让这个应用的增强开发变的非常方便。借助 Vue 的模板和数据绑定、Vuex 的管理共享状态,响应式数据存储和纯前端的交互式电子表格,可以在很短内创建复杂的企业 JavaScript 应用程序。
大家如果感兴趣可以访问更多在线实例:
https://demo.grapecity.com.cn/spreadjs/gc-sjs-samples/index.html
Vuex与前端表格施展“组合拳”,实现大屏展示应用的交互增强的更多相关文章
- ECharts + Jquery 做大屏展示
HTML <!doctype html> <html> <head> <meta charset="utf-8"> <meta ...
- 数据可视化界面UI设计大屏展示
- flex布局构建大屏框架并支持翻页动画、滚动表格功能
本文将利用flex属性构建大屏可视化界面.界面主要分标题栏.工具栏.数据可视化窗口.其中,翻页动画以及滚动表格功能分别分布在数据可视化界面两侧. 鼠标点击标题,可看到左侧窗口翻转动画: 整体布局效 ...
- 使用rem配置PC端自适应大屏
效果如下 使得大屏不论在什么宽高比例依然能展示全部数据 安装 npm install -S postcss-pxtorem rem配置思路 原先的rem函数是能解决大部分的问题的,如果展示不全,也可以 ...
- vue+echarts+datav大屏数据展示及实现中国地图省市县下钻
随着前端技术的飞速发展,大数据时代的来临,我们在开发项目时越来越多的客户会要求我们做一个数据展示的大屏,可以直观的展示用户想要的数据,同时炫酷的界面也会深受客户的喜欢. 大屏展示其实就是一堆的图表能够 ...
- 从零开始设计数据大屏—基于Vue ZT
虽然已经决定这个项目用Wyn来做了,但是,了解一下如何从头开始写一个数据大屏还是挺有好玩的. ------------- 为什么要做数据大屏? 现如今的大数据逐渐发挥出了它的力量,并无形的改变着我们的 ...
- 基于 HTML5 的工业组态高炉炼铁 3D 大屏可视化
前言 在大数据盛行的现在,大屏数据可视化也已经成为了一个热门的话题.大屏可视化可以运用在众多领域中,比如工业互联网.医疗.交通.工业控制等等.将各项重要指标数据以图表.各种图形等形式表现在一个页面上, ...
- 产品如何进行大屏数据可视化.md
最近接到一个需求,需要给公司的竞赛平台面对省/校/竞赛进行大屏的可视化话数据展示,闲暇之余对自己最近的工作进行一些总结; 一.数据可视化的定义 数据可视化主要是关于数据_视觉表现形式的科学技术研究 - ...
- 使用DataV制作实时销售数据可视化大屏(实验篇)
课时1:背景介绍 任务说明 ABC是一家销售公司,其客户可以通过网站下单订购该公司经营范围内的商品,并使用信用卡.银行卡.转账等方式付费.付费成功后,ABC公司会根据客户地址依据就近原则选择自己的货仓 ...
随机推荐
- 高通(QCOM)sensor bring up
高通7150平台 1.添加驱动文件 2.添加编译 3.配置json文件 4.高通默认配置 5.部分sensor外挂电源 6.遇到的问题 1.添加驱动文件 路径:adsp_proc/ssc/sensor ...
- 如何安装TypeScript编译器?
首先需要nodejs和npm工具.如果没有点击这里下载node(默认会附带安装npm工具):https://nodejs.org/en/ npm安装TypeScript npm install -g ...
- 论文阅读 Real-Time Streaming Graph Embedding Through Local Actions 11
9 Real-Time Streaming Graph Embedding Through Local Actions 11 link:https://scholar.google.com.sg/sc ...
- mybatis查询mysql 数据库中 BLOB字段,结果出现乱码
起因 mybatis-plus 通过Mapper 查询数据,映射出来的BLOB字段中的yml数据中文是乱码的 --- DefaultValue: '' Formula: '' HintContent: ...
- SAP 文件操作类 CL_GUI_FRONTEND_SERVICES
1 .文件下载. DATA: l_filename TYPE string, "file name l_path TYPE string, "file path l_fullpat ...
- XSS攻击(笔记)
XSS攻击 XSS概述 XSS即跨站脚本攻击,(Cross-Site Scripting, CSS),但是为了与层叠样式表(Cascading Style Sheets, CSS)缩写区分开来,所以命 ...
- ACM组合计数入门
1 排列组合 1.1 排列 \[A_n^m=n(n-1)(n-2)\cdots(n-m+1)=\frac{n!}{(n-m)!} \] 定义:从 n 个中选择 m 个组成有序数列,其中不同数列的数量. ...
- 强化学习-学习笔记9 | Multi-Step-TD-Target
这篇笔记依然属于TD算法的范畴.Multi-Step-TD-Target 是对 TD算法的改进. 9. Multi-Step-TD-Target 9.1 Review Sarsa & Q-Le ...
- PTA(BasicLevel)-1014 福尔摩斯的约会
一.问题描述 大侦探福尔摩斯接到一张奇怪的字条:我们约会吧! 3485djDkxh4hhGE 2984akDfkkkkggEdsb s&hgsfdk d&Hyscvnm.大侦探很快就明 ...
- 大家好,我是UCMP云管家,这是我的自我介绍
随着云计算的不断普及,构建在计算.存储.网络.数据库等基础资源之上的云平台逐渐大行其道:而随着多种云平台技术路线的发展成熟,多个云厂商的云平台开始出现在企业IT市场.对于企业而言,为满足成本.按需.隐 ...