}
// 指定单元格样式
if (key === ‘A1’) {
sheet[key].s = {
…sheet[key].s,
fill: { //背景色
fgColor: { rgb: ‘E4DFEC’ }
}
}
}
// 列宽
let colsP = titles.map(item => {
let obj = {
‘wch’: 25 //列宽
}
return obj;
})
sheet[‘!cols’] = colsP;//列宽

// // 每列的列宽
// sheet[“!cols”] = [{
// wpx: 70 //单元格列宽
// }, {
// wpx: 70
// }, {
// wpx: 70
// }, {
// wpx: 70
// }, {
// wpx: 150
// }, {
// wpx: 120
// }];
}
let fileName = ‘Excel文件.xlsx’
let sheetName = ‘Excel文件’
this.openDownload(this.sheet2blob(sheet, sheetName), fileName);
},
sheet2blob (sheet, sheetName) {
let wb = XLSX.utils.book_new();
wb.SheetNames.push(sheetName)
wb.Sheets[sheetName] = sheet;
// 必须使用xlsx-style才能生成指定样式
var wbout = XLSXStyle.write(wb, { bookType: ‘’, bookSST: false, type: ‘binary’ })
var blob = new Blob([s2ab(wbout)], { type: “” }, sheetName);
// 字符串转ArrayBuffer
function s2ab (s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
return buf;
}
return blob;
},
openDownload (url, saveName) {
if (typeof url == “object” && url instanceof Blob) {
url = URL.createObjectURL(url); // 创建blob地址
}
var aLink = document.createElement(“a”);
aLink.href = url;
aLink.download = saveName || “”; // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
var event;
if (window.MouseEvent) event = new MouseEvent(“click”);
else {
event = document.createEvent(“MouseEvents”);
event.initMouseEvent(
“click”,
true,
false,
window,
0,
0,
0,
0,
0,
false,
false,
false,
false,
0,
null
);
}
aLink.dispatchEvent(event);
}
},
}


### 2. 结合el-table,根据勾选的内容,导出excel表格


**html和css就不写了,主要记录下js功能实现的过程**



// 导出函数
export async function exportBtn (payloadList) {
// payloadList是table表格勾选的内容数组
if (payloadList.length === 0) {
this.$message({
type: ‘warning’,
message: ‘请选择要导出的记录!’
})
} else {
// 最终生成sheet的aoelist
let finalList = []
// 一、准备枚举值
// 1.写死
let ywlxenum = [
{ label: ‘预审选址’, value: ‘YSXZ’ },
{ label: ‘土地储备’, value: ‘TDCBGM’ },
{ label: ‘农转用报批’, value: ‘YDBP’ },
{ label: ‘规划条件’, value: ‘GHTJ’ },
{ label: ‘行政划拨’, value: ‘XZHB’ },
{ label: ‘公开出让’, value: ‘GKCR’ },
{ label: ‘建设用地规划许可’, value: ‘JSYDGHXK’ },
{ label: ‘建设工程规划类许可证核发’, value: ‘JSGCGHXK’ },
{ label: ‘建设工程竣工规划核实’, value: ‘JGGHHY’ },
{ label: ‘竣工验收备案’, value: ‘JGYSBA’ }
]
// 2.通过请求获取
let ydxzenum = []
await getEnumByValue({ value: ‘TDLYXZ’ }).then(data => {
ydxzenum = mapListFunc(data.fieldEnum)
})
// 二、通过请求获取数据
let resList = [] // 保存请求数据
for (let i = 0; i < payloadList.length; i++) {
await this.queryInfo({ id: payloadList[i].xmguid }).then(res => {
// 这里是判断了返回值里还包含了list数组
if (res.data.bizGhtjGhqkList.length !== 0) {
let bizGhtjGhqkList = res.data.bizGhtjGhqkList
bizGhtjGhqkList.forEach(item => {
resList.push({ …res.data.bizSlsq, …res.data.bizGhtj, …item })
})
} else {
resList.push({ …res.data.bizSlsq, …res.data.bizGhtj })
}
})
}
// 三、映射关系list
let mappingList = [
{ field: ‘xmmc’, value: ‘项目名称’, merge: true }, // merge代表单元格是否合并
{ field: ‘ydxz’, value: ‘用地性质’, enum: true, merge: true }, // enum代表是否是枚举值
{ field: ‘dkbh’, value: ‘地块编号’ },
]
// 四、添加标题
let titleList = []
mappingList.forEach(item => {
titleList.push(item.value)
})
finalList.push(titleList)
// 五、添加内容
resList.forEach(row => {
// 行的list
let ctnList = []
let hyfltemp = []
let ydxztemp = []
mappingList.forEach(item => {
if (item.enum) {
// 带枚举值的处理
switch (item.field) {
case ‘hyfl’:
hyfltemp = row[item.field] && row[item.field].split(‘,’)
ctnList.push(queryEnumVal(hyflenum, hyfltemp && hyfltemp[(hyfltemp.length - 1)]))
break
case ‘ydxz’:
ydxztemp = row[item.field] && row[item.field].split(‘,’)
ctnList.push(queryEnumVal(ydxzenum, ydxztemp && ydxztemp[(ydxztemp.length - 1)]))
break
case ‘pzjg’:
ctnList.push(queryEnumVal(pzjgenum, row[item.field]))
break
case ‘ywlx’:
ctnList.push(queryEnumVal(ywlxenum, row[item.field]))
break
case ‘cbywlx’:
ctnList.push(queryEnumVal(cbywlxenum, row[item.field]))
break
default:
break
}
} else {
// 常规
ctnList.push(row[item.field])
}
})
finalList.push(ctnList)
})
// 六、处理合并单元格
let mergeArr = []
let { indices } = unipFunc(resList, ‘xmguid’)
mappingList.forEach((item, index) => {
if (item.merge) {
indices.forEach(itemlist => {
if (itemlist.length > 1) {
mergeArr.push({
s: { r: itemlist[0] + 1, c: index },
e: { r: itemlist[itemlist.length - 1] + 1, c: index }
})
}
})
}
})
// 七、生成sheet
let sheet = XLSX.utils.aoa_to_sheet(finalList)
// 八、合并单元格和添加样式
sheet[‘!merges’] = mergeArr
Object.keys(sheet).forEach((item, index) => {
if (sheet[item].t) {
sheet[item].s = { // 对齐方式相关样式
alignment: {
vertical: ‘center’, // 垂直对齐方式
horizontal: ‘center’ // 水平对齐方式
// wrapText: true // 自动换行
}
}
}
})
// 九、导出excel
openDownloadDialog(sheet2blob(sheet), new Date().getTime() + ‘.xlsx’ || ‘表名.xlsx’)
}
}

function queryEnumVal (enumList, field) {
// 获取枚举值对应的key
let enumVal = ‘’
enumList.forEach(item => {
if (item.value === field) {
enumVal = item.label
}
})
return enumVal
}
function mapListFunc (params) {
// 处理枚举值
let list = []
list = params.map(item => {
item.value = item.enumValue
item.label = item.enumName
return item
})
return list
}
// 处理数据重复值
function unipFunc (list, objKey) {
let key = {} // 存储的 key 是type的值,value是在indeces中对应数组的下标
let indices = [] // 数组中每一个值是一个数组,数组中的每一个元素是原数组中相同type的下标
list.map((item, index) => {
// 根据对应字段 分类(type)
let itemKey = item[objKey]
let _index = key[itemKey]
if (_index !== undefined) {
indices[_index].push(index)
} else {
key[itemKey] = indices.length
indices.push([index])
}
})
// 归类结果
let result = []
let resultIndex = []
indices.map((item) => {
item.map((index) => {
if (item.length > 1) {
result.push(list[index])
resultIndex.push(index)
}
})
})
return { result, resultIndex, indices }
}
// 下载excel
function openDownloadDialog (url, saveName) {
if (typeof url === ‘object’ && url instanceof Blob) {
url = URL.createObjectURL(url) // 创建blob地址
}
var aLink = document.createElement(‘a’)
aLink.href = url
aLink.download = saveName || ‘’ // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
var event
if (window.MouseEvent) event = new MouseEvent(‘click’)
else {
event = document.createEvent(‘MouseEvents’)
event.initMouseEvent(‘click’, true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
}
aLink.dispatchEvent(event)
}
// 字符串转ArrayBuffer
function s2ab (s) {
var buf = new ArrayBuffer(s.length)
var view = new Uint8Array(buf)
for (var i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF
return buf
}
// 将一个sheet转成最终的excel文件的blob对象,然后利用URL.createObjectURL下载
function sheet2blob (sheet, sheetName) {
sheetName = sheetName || ‘sheet1’
let workbook = XLSX.utils.book_new()
workbook.SheetNames.push(sheetName)
workbook.Sheets[sheetName] = sheet
// 生成excel的配置项
var wopts = {
bookType: ‘xlsx’, // 要生成的文件类型
bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
type: ‘binary’
}
var wbout = XLSXStyle.write(workbook, wopts)
var blob = new Blob([s2ab(wbout)], { type: ‘application/octet-stream’ })

return blob
}



> 
> **参考**
> 
> 
> 1. 带样式的导出参考代码:  
>  <https://blog.csdn.net/weixin_39246975/article/details/121639072>
> 2. 别人对xlsx-style的二次封装:  
>  <https://blog.csdn.net/weixin_51947053/article/details/127370479>
> 
> 
> 


## 五、打印功能


### 1.直接使用window自带的打印功能: window.print()



点击下面的按钮,可将页面进行打印

打印内容

打印内容

打印内容

打印内容


### 2.使用打印插件:vue-print-nb


#### 1、安装 vue-print-nb:



// vue2.x 版本
npm install vue-print-nb --save
// vue3.x 版本
npm install vue3-print-nb --save


#### 2、在项目中引入 vue-print-nb:



// vue2.x版本 – 全局引入:在项目中入口文件 main.js 文件中全局引入 vue-print-nb
import Vue from ‘vue’
import Print from ‘vue-print-nb’
Vue.use(Print)

// 局部引入报错,还不知道咋解决,建议是全局引入
// vue2.x版本 – 在需要打印功能的页面引入 vue-print-nb
import print from ‘vue-print-nb’
export default{
directives: { print }
}

// vue3.x版本 – 全局引入:在项目中入口文件 main.js 文件中全局引入 vue3-print-nb
import {createApp} from ‘vue’
import App from ‘./App’
import Print from ‘vue3-print-nb’
const app = createApp(App)
app.use(Print)
app.mount(‘#app’)

// vue3.x版本 – 在需要打印功能的页面引入 vue3-print-nb
import print from ‘vue3-print-nb’
export default{
directives: { print }
}


#### 3、使用 vue-print-nb 实现打印功能


##### ① 实现方式1:打印区域设置id, 打印按钮绑定此 id



点击下面的按钮,可将div里的内容区域进行打印

<div id="printDiv">
  <p>打印内容 </p>
  <p>打印内容 </p>
  <p>打印内容 </p>
  <p>打印内容 </p>
</div>

<button v-print="'#printDiv'">打印id为printDiv的div区域内容</button>

##### ② 实现方式2:打印区域设置id, 打印按钮进行打印配置



点击下面的按钮,可将div里的内容区域进行打印

<div id="printDiv">
  <p>打印内容 </p>
  <p>打印内容 </p>
  <p>打印内容 </p>
  <p>打印内容 </p>
</div>

<button v-print="'printSet'">打印id为printDiv的div区域内容</button>

##### ③ 打印网址:打印指定url(同一个同源策略)对应的内容



打印网址

##### ④ 打印预览功能



打印+预览功能

##### ⑤ 打印异步url



打印+预览功能

##### ⑥ 实现区域不打印方式



打印内容区域

打印内容区域

打印内容区域

打印内容区域

打印内容区域

        实现区域不打印方式1:设置class为 no-print 即可实现该区域不打印
        <p class="no-print">不要打印的内容区域</p>

        // 实现区域不打印方式2: 自定义不打印区域的class名
        <p class="do-not-print-div">不要打印的内容区域</p>

前端框架

前端框架太多了,真的学不动了,别慌,其实对于前端的三大马车,Angular、React、Vue 只要把其中一种框架学明白,底层原理实现,其他两个学起来不会很吃力,这也取决于你以后就职的公司要求你会哪一个框架了,当然,会的越多越好,但是往往每个人的时间是有限的,对于自学的学生,或者即将面试找工作的人,当然要选择一门框架深挖原理。

以 Vue 为例,我整理了如下的面试题。

Vue部分截图

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

Logo

前往低代码交流专区

更多推荐