vue使用luckyexcel實(shí)現(xiàn)在線表格及導(dǎo)出導(dǎo)入方式
話不多說(shuō)。
vue需要在public-index.html中在線導(dǎo)入以下這些
或者找到相應(yīng)的資源下載到本地,本地導(dǎo)入更快。
<link
rel="stylesheet"
rel="external nofollow"
/>
<link
rel="stylesheet"
rel="external nofollow"
/>
<link
rel="stylesheet"
rel="external nofollow"
/>
<link
rel="stylesheet"
rel="external nofollow"
/>
<script src="https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/js/plugin.js"></script>
<script src="https://cdn.jsdelivr.net/npm/luckysheet/dist/luckysheet.umd.js"></script>
引入
npm i -S exceljs file-saver luckyexcel
import { excelOptions } from "@/common/common.js"
const ExcelJS = require("exceljs");
import FileSaver from "file-saver";
import LuckyExcel from 'luckyexcel';
import XLSX from 'xlsx'
注意:
- 按照以上導(dǎo)入去下載相應(yīng)的包
- excelOptions 是表格功能的一一些配置
- 我只是放在外面了
版本:

定義當(dāng)前表格容器
我多加了一個(gè)表格名稱
<div class="allbtn">
<button class="btn" @click="saveExcel">保存</button>
<button class="btn" @click="outputExcel">導(dǎo)出表格</button>
<input type="file" accept=".xlsx" @change="importExcel($event)" value="導(dǎo)入表格" />
</div>
<h2>當(dāng)前表格名稱</h2>
<input class="inp" type="text" v-model="excelTitel">
<div id="luckysheet"></div>

導(dǎo)入excel并展示
// 導(dǎo)入表格
importExcel (event) {
let file = event.target.files[0]
let that = this;
const types = file.name.split(".")[1];
// 判斷類型
const fileType = ["xlsx"].some(
item => item === types
);
console.log(file)
if (!fileType) {
alert("只支持上傳xlsx后綴的表格!")
return
}
LuckyExcel.transformExcelToLucky(file, (exportJson, luckysheetfile) => {
if (exportJson.sheets === null || exportJson.sheets.length === 0) {
this.$message.error('無(wú)法讀取excel文件的內(nèi)容,當(dāng)前不支持xls文件!')
return
}
window.luckysheet.destroy()
this.changeExcelOption.data = exportJson.sheets
window.luckysheet.create(this.changeExcelOption)
})
},
導(dǎo)出表格
這里我做了一點(diǎn)處理,初次加載時(shí)獲取表格名稱,然后可編輯當(dāng)前表格名稱,點(diǎn)擊保存按鈕后進(jìn)行導(dǎo)出,則會(huì)導(dǎo)出你編輯的表格名稱
1.初始獲取表格名稱
// 初始化加載
init () {
let opt = excelOptions();
// 檢測(cè)本地庫(kù)中是否有配置
let excelValue = window.localStorage.getItem("excelValue");
if (excelValue != null) {//有值
let checkExcelValue = JSON.parse(excelValue)
opt.data[0] = checkExcelValue;
}
this.changeExcelOption = opt;
luckysheet.create(opt)
// 保存初始表格名稱
this.excelTitel = this.changeExcelOption.title;
},
// 保存excel數(shù)據(jù)
saveExcel () {
var objsheet = luckysheet.getAllSheets() // 得到表的數(shù)據(jù)
// options = objsheet // 將表的數(shù)據(jù)保存本地
// console.log(objsheet)
// 獲取標(biāo)內(nèi)容更新變化
luckysheet.setWorkbookName(this.excelTitel)
this.changeExcelOption.title = this.excelTitel;
},
// 導(dǎo)出表格
outputExcel () {
this.exportExcel(luckysheet.getluckysheetfile("修改"));
},
async exportExcel (luckysheet) {
// 參數(shù)為luckysheet.getluckysheetfile()獲取的對(duì)象
// 1.創(chuàng)建工作簿,可以為工作簿添加屬性
const workbook = new ExcelJS.Workbook();
// 2.創(chuàng)建表格,第二個(gè)參數(shù)可以配置創(chuàng)建什么樣的工作表
luckysheet.every((table) => {
if (table.data.length === 0) return true;
const worksheet = workbook.addWorksheet(table.name);
// 3.設(shè)置單元格合并,設(shè)置單元格邊框,設(shè)置單元格樣式,設(shè)置值
this.setStyleAndValue(table.data, worksheet);
this.setMerge(table.config.merge, worksheet);
this.setBorder(table.config.borderInfo, worksheet);
return true;
});
// 4.寫入 buffer
const buffer = await workbook.xlsx.writeBuffer();
//調(diào)用文件保存插件
FileSaver.saveAs(
new Blob([buffer], { type: "application/octet-stream" }),
this.changeExcelOption.title + ".xlsx"
);
return buffer;
},
setMerge (luckyMerge = {}, worksheet) {
const mergearr = Object.values(luckyMerge);
mergearr.forEach((elem) => {
// elem格式:{r: 0, c: 0, rs: 1, cs: 2}
// 按開始行,開始列,結(jié)束行,結(jié)束列合并(相當(dāng)于 K10:M12)
worksheet.mergeCells(elem.r + 1, elem.c + 1, elem.r + elem.rs, elem.c + elem.cs);
});
},
setBorder (luckyBorderInfo, worksheet) {
if (!Array.isArray(luckyBorderInfo)) return;
luckyBorderInfo.forEach(function (elem) {
var val = elem.value;
let border = {};
const luckyToExcel = {
type: {
"border-all": "all",
"border-top": "top",
"border-right": "right",
"border-bottom": "bottom",
"border-left": "left",
},
style: {
0: "none",
1: "thin",
2: "hair",
3: "dotted",
4: "dashDot", // 'Dashed',
5: "dashDot",
6: "dashDotDot",
7: "double",
8: "medium",
9: "mediumDashed",
10: "mediumDashDot",
11: "mediumDashDotDot",
12: "slantDashDot",
13: "thick",
},
};
if (val) {
if (val.t != undefined) {
border["top"] = {
style: luckyToExcel.style[val.t.style],
color: val.t.color,
};
}
if (val.r != undefined) {
border["right"] = {
style: luckyToExcel.style[val.r.style],
color: val.r.color,
};
}
if (val.b != undefined) {
border["bottom"] = {
style: luckyToExcel.style[val.b.style],
color: val.b.color,
};
}
if (val.l != undefined) {
border["left"] = {
style: luckyToExcel.style[val.l.style],
color: val.l.color,
};
}
worksheet.getCell(val.row_index + 1, val.col_index + 1).border = border;
}
});
},
setStyleAndValue (cellArr, worksheet) {
if (!Array.isArray(cellArr)) return;
cellArr.forEach((row, rowid) => {
row.every((cell, columnid) => {
if (!cell) return true;
let fill = this.fillConvert(cell.bg);
let font = this.fontConvert(
cell.ff,
cell.fc,
cell.bl,
cell.it,
cell.fs,
cell.cl,
cell.ul
);
let alignment = this.alignmentConvert(cell.vt, cell.ht, cell.tb, cell.tr);
let value;
if (cell.f) {
value = { formula: cell.f, result: cell.v };
} else {
value = cell.v;
}
let target = worksheet.getCell(rowid + 1, columnid + 1);
target.fill = fill;
target.font = font;
target.alignment = alignment;
target.value = value;
return true;
});
});
},
fillConvert (bg) {
if (!bg) {
return {
type: "pattern",
pattern: "solid",
fgColor: { argb: "#ffffff".replace("#", "") },
};
}
let fill = {
type: "pattern",
pattern: "solid",
fgColor: { argb: this.colorHex(bg).replace("#", "") },
};
console.log(fill);
return fill;
},
//將rgb()轉(zhuǎn)成16進(jìn)制
colorHex (color) {
// RGB顏色值的正則
var reg = /^(rgb|RGB)/;
if (reg.test(color)) {
var strHex = "#";
// 把RGB的3個(gè)數(shù)值變成數(shù)組
var colorArr = color.replace(/(?:\(|\)|rgb|RGB)*/g, "").split(",");
// 轉(zhuǎn)成16進(jìn)制
for (var i = 0; i < colorArr.length; i++) {
var hex = Number(colorArr[i]).toString(16);
if (hex === "0") {
hex += hex;
}
strHex += hex;
}
return strHex;
} else {
return String(color);
}
},
fontConvert (ff = 0, fc = "#000000", bl = 0, it = 0, fs = 10, cl = 0, ul = 0) {
// luckysheet:ff(樣式), fc(顏色), bl(粗體), it(斜體), fs(大小), cl(刪除線), ul(下劃線)
const luckyToExcel = {
0: "微軟雅黑",
1: "宋體(Song)",
2: "黑體(ST Heiti)",
3: "楷體(ST Kaiti)",
4: "仿宋(ST FangSong)",
5: "新宋體(ST Song)",
6: "華文新魏",
7: "華文行楷",
8: "華文隸書",
9: "Arial",
10: "Times New Roman ",
11: "Tahoma ",
12: "Verdana",
num2bl: function (num) {
return num === 0 ? false : true;
},
};
let font = {
name: luckyToExcel[ff],
family: 1,
size: fs,
color: { argb: fc.replace("#", "") },
bold: luckyToExcel.num2bl(bl),
italic: luckyToExcel.num2bl(it),
underline: luckyToExcel.num2bl(ul),
strike: luckyToExcel.num2bl(cl),
};
return font;
},
alignmentConvert (vt = "default", ht = "default", tb = "default", tr = "default") {
// luckysheet:vt(垂直), ht(水平), tb(換行), tr(旋轉(zhuǎn))
const luckyToExcel = {
vertical: {
0: "middle",
1: "top",
2: "bottom",
default: "top",
},
horizontal: {
0: "center",
1: "left",
2: "right",
default: "left",
},
wrapText: {
0: false,
1: false,
2: true,
default: false,
},
textRotation: {
0: 0,
1: 45,
2: -45,
3: "vertical",
4: 90,
5: -90,
default: 0,
},
};
let alignment = {
vertical: luckyToExcel.vertical[vt],
horizontal: luckyToExcel.horizontal[ht],
wrapText: luckyToExcel.wrapText[tb],
textRotation: luckyToExcel.textRotation[tr],
};
return alignment;
},
borderConvert (borderType, style = 1, color = "#000") {
// 對(duì)應(yīng)luckysheet的config中borderinfo的的參數(shù)
if (!borderType) {
return {};
}
const luckyToExcel = {
type: {
"border-all": "all",
"border-top": "top",
"border-right": "right",
"border-bottom": "bottom",
"border-left": "left",
},
style: {
0: "none",
1: "thin",
2: "hair",
3: "dotted",
4: "dashDot", // 'Dashed',
5: "dashDot",
6: "dashDotDot",
7: "double",
8: "medium",
9: "mediumDashed",
10: "mediumDashDot",
11: "mediumDashDotDot",
12: "slantDashDot",
13: "thick",
},
};
let template = {
style: luckyToExcel.style[style],
color: { argb: color.replace("#", "") },
};
let border = {};
if (luckyToExcel.type[borderType] === "all") {
border["top"] = template;
border["right"] = template;
border["bottom"] = template;
border["left"] = template;
} else {
border[luckyToExcel.type[borderType]] = template;
}
return border;
}
總結(jié)
該開源表格確實(shí)很好用,但是更多功能可以深度挖掘,我只是簡(jiǎn)單玩了一下,體驗(yàn)可以,不過(guò)配合后端一起食用效果更佳。
說(shuō)個(gè)題外話:
寫這個(gè)完全是被坑了,一天時(shí)間實(shí)現(xiàn)多人在線協(xié)同表格,我使用了本地緩存寫了個(gè)簡(jiǎn)易版的,完事了又問(wèn)我會(huì)不會(huì)pythonWeb…我應(yīng)屆生,也只會(huì)一點(diǎn)python語(yǔ)法,自然是掛了,雖然對(duì)這種外包公司印象一般,但是這樣搞我確實(shí)頭大。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Vue3如何利用xlsx、xlsx-js-style導(dǎo)出Excel表格使用(適合新手)
- 前端實(shí)現(xiàn)Excel文件導(dǎo)出功能的完整代碼解析(vue實(shí)現(xiàn)excel文件導(dǎo)出)
- vue2項(xiàng)目使用exceljs多表頭導(dǎo)出功能詳解
- Vue用Export2Excel導(dǎo)出excel,多級(jí)表頭數(shù)據(jù)方式
- vue使用Luckysheet插件實(shí)現(xiàn)excel導(dǎo)入導(dǎo)出
- vue使用xlsx庫(kù)和xlsx-style庫(kù)導(dǎo)入導(dǎo)出excel、設(shè)置單元格背景色、文字居中、合并單元格、設(shè)置列寬
- 在Vue中使用xlsx組件實(shí)現(xiàn)Excel導(dǎo)出功能的步驟詳解
- 在Vue中實(shí)現(xiàn)Excel導(dǎo)出功能(數(shù)據(jù)導(dǎo)出)
相關(guān)文章
vue實(shí)現(xiàn)自定義日期組件功能的實(shí)例代碼
這篇文章主要介紹了vue自定義日期組件的實(shí)現(xiàn)代碼,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-11-11
Vue開發(fā)高德地圖應(yīng)用的最佳實(shí)踐
要在Web頁(yè)面中加入地圖,我推薦你使用高德地圖,下面這篇文章主要給大家介紹了關(guān)于Vue開發(fā)高德地圖應(yīng)用的最佳實(shí)踐,需要的朋友可以參考下2021-07-07
Vue項(xiàng)目設(shè)置多個(gè)靜態(tài)文件及自定義靜態(tài)文件目錄的方案詳解
本文介紹了如何在Vue項(xiàng)目中配置多個(gè)靜態(tài)文件目錄,并提供了使用Vite和Webpack實(shí)現(xiàn)的示例,通過(guò)在vite.config.ts或vue.config.js中引入相關(guān)插件和配置,可以輕松實(shí)現(xiàn)自定義靜態(tài)文件目錄,希望這些內(nèi)容對(duì)您有所幫助,感興趣的朋友一起看看吧2025-01-01
解決vue項(xiàng)目跳轉(zhuǎn)同樣的頁(yè)面不刷新的問(wèn)題思路詳解
做公司官網(wǎng)項(xiàng)目的時(shí)候遇到的場(chǎng)景,頂部導(dǎo)航欄分類商品跳轉(zhuǎn)到分類詳情,然后在分類詳情再次點(diǎn)擊頂部導(dǎo)航欄里另外的分類商品,跳到同樣的頁(yè)面數(shù)據(jù)不刷新,下面小編給大家分享解決方式,關(guān)于vue跳轉(zhuǎn)不刷新問(wèn)題感興趣的朋友一起看看吧2023-09-09
Vue中對(duì)<style scoped> 中的scoped屬性解析
在Vue的單文件組件中,<style scoped> 的 scoped 屬性用于實(shí)現(xiàn)?樣式作用域隔離?,下面通過(guò)實(shí)例代碼講解Vue中對(duì)<style scoped>中的scoped屬性,感興趣的朋友一起看看吧2025-03-03
vue-quill-editor插入圖片路徑太長(zhǎng)問(wèn)題解決方法
這篇文章主要介紹了vue-quill-editor插入圖片路徑太長(zhǎng)問(wèn)題解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
詳解vue中的動(dòng)態(tài)組件component和keep-alive
這篇文章主要介紹了詳解vue中的動(dòng)態(tài)組件component和keep-alive的相關(guān)資料,這大家需要注意include屬性和exclude屬性只能用一個(gè),不能同時(shí)使用,本文給大家介紹的非常詳細(xì),需要的朋友參考下吧2023-11-11
詳解vue-router 2.0 常用基礎(chǔ)知識(shí)點(diǎn)之router-link
這篇文章主要介紹了詳解vue-router 2.0 常用基礎(chǔ)知識(shí)點(diǎn)之router-link,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05

