最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue純前端實(shí)現(xiàn)導(dǎo)出excel中的圖片與文件超鏈接

 更新時(shí)間:2025年03月11日 09:04:57   作者:夜十前端  
這篇文章主要為大家詳細(xì)介紹了Vue如何純前端實(shí)現(xiàn)導(dǎo)出excel中的圖片與文件超鏈接,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下

最近公司的需求,要求Excel導(dǎo)出的時(shí)候?qū)?shù)據(jù)里的圖片、文件等都帶出來。

一頓溝通后,后端不做,那就只好我這個(gè)前端小白來了。上網(wǎng)搜索了好久,有很多大佬分享了怎么導(dǎo)出圖片,但沒有將圖片按單元格級(jí)批量導(dǎo)出的例子,只好研究了一整天時(shí)間,實(shí)現(xiàn)效果如下:

這是vue展示的樣式:

這是excel導(dǎo)出的樣式:

下面直接上代碼: 具體需要注意的部分在下面說

首先npm 安裝依賴: exceljs

數(shù)據(jù):(主要是展示el table ,順便也可以作為excel 導(dǎo)出的列模版)

data() {
		return {
			tableProp: [
				{
					prop: 'creator',
					label: '提出人',
					namei18n: 'tichucreator',
					width: 100,
					align: 'center'
				},
				{
					label: '提出時(shí)間',
					prop: 'creationTime',
					namei18n: 'creationTime',
					hidden: true
				},
				{
					prop: 'projectCode',
					label: '項(xiàng)目編碼',
					namei18n: 'projectCode',
					width: 150,
					align: 'center'
				},
 
				{
					prop: 'projectName',
					label: '項(xiàng)目名稱',
					namei18n: 'projectName',
					width: 240,
					align: 'center'
				},
				{
					prop: 'stationCode',
					label: '工位',
					namei18n: 'stationCode',
					width: 150,
					align: 'center'
				},
				{
					label: '負(fù)責(zé)人',
					prop: 'handler',
					namei18n: 'handler',
					hidden: true
				},
				{
					prop: 'questionType',
					label: '問題類型',
					namei18n: 'questionType',
					width: 150,
					align: 'center'
				},
				{
					prop: 'importance',
					label: '重要程度',
					namei18n: 'importance',
					width: 100,
					align: 'center',
					options: []
				},
				{
					prop: 'stage',
					label: '階段',
					namei18n: 'stage',
					width: 150,
					align: 'center',
					options: []
				},
				{
					label: '開始處理時(shí)間',
					prop: 'startDate',
					namei18n: 'startDate1',
					hidden: true
				},
				{
					label: '實(shí)際完成時(shí)間',
					prop: 'lastModificationTime',
					namei18n: 'lastModificationTime',
					hidden: true
				},
				{
					prop: 'questionDescribe',
					label: '問題描述',
					namei18n: 'questionDescribe',
					width: 200,
					align: 'center'
				},
				{
					prop: 'uploadPic',
					label: '圖片描述',
					namei18n: 'uploadPic',
					type: 'uploadPic',
					width: 330,
					align: 'center'
				},
				{
					prop: 'uploadFile',
					label: '附件描述',
					namei18n: 'uploadFile',
					type: 'uploadFile',
					width: 300,
					align: 'center'
				},
				{
					prop: 'questionAdvise',
					label: '問題解決建議',
					namei18n: 'questionAdvise',
					width: 200,
					align: 'center'
				},
				{
					label: '補(bǔ)充說明',
					prop: 'bRemarks',
					namei18n: 'bRemarks',
					hidden: true
				},
				{
					label: '解決方案',
					prop: 'solution',
					namei18n: 'solution',
					hidden: true
				},
				{
					prop: 'expectedDate',
					label: '需求完成時(shí)間',
					namei18n: 'expectedDate',
					width: 160,
					align: 'center'
				},
				{
					prop: 'isOverdue',
					label: '是否逾期',
					namei18n: 'isOverdue',
					width: 100,
					align: 'center',
					options: [
						{
							value: true,
							label: '是'
						},
						{
							value: false,
							label: '否'
						}
					]
					// formatter: (val) => {
					// 	if (val) {
					// 		return '是';
					// 	} else {
					// 		return '否';
					// 	}
					// }
				},
			],
		
	},

方法:

	methods: {
		async exportExcel1(exportDataList) {
		        //exportDataList 就是后端返回的數(shù)據(jù)
				exportDataList = this.tableDataFormat(JSON.parse(JSON.stringify(exportDataList)));
				// 定義表頭
				const columns = [];
                // this.tableProp 在上面有粘出來,主要是表格的表頭配置,el-table就是用這個(gè)循環(huán)出來的
                // 解釋一下這里的操作,excel并不支持同一單元格導(dǎo)出多個(gè)數(shù)據(jù)(也可能是我太菜)
                // 我們的項(xiàng)目是最多3個(gè)圖 3個(gè)文件,后端返回的是3個(gè)文件路徑的字符串在一個(gè)字段里
				this.tableProp.forEach((item) => {
					if (item.label != '圖片描述' && item.label != '附件描述') {
						columns.push({
							header: item.label,
							key: item.prop,
							width: item.width ? item.width / 10 : 14
						});
					}
                    // 所以將 圖片 和 文件變?yōu)?3項(xiàng),也就是在excel里占 3個(gè) 單元格
					if (item.label === '圖片描述') {
						columns.push({
							header: '',
							key: 'uploadPic1',
							width: 14
						});
						columns.push({
							header: '',
							key: 'uploadPic2',
							width: 14
						});
						columns.push({
							header: '',
							key: 'uploadPic3',
							width: 14
						});
					}
					if (item.label === '附件描述') {
						columns.push({
							header: '',
							key: 'uploadFile1',
							width: 14
						});
						columns.push({
							header: '',
							key: 'uploadFile2',
							width: 14
						});
						columns.push({
							header: '',
							key: 'uploadFile3',
							width: 14
						});
					}
				});
 
				const Exceljs = require('exceljs');
				// 創(chuàng)建工作簿
				const workbook = new Exceljs.Workbook();
				// 創(chuàng)建工作表
				const workSheet = workbook.addWorksheet('sheet1');
				// 工作表添加表頭
				workSheet.columns = columns;
				// imgFieldList:圖片字段名
				const imgFieldList = ['uploadPic1', 'uploadPic2', 'uploadPic3'];
				// fileFieldList:文件字段名
				const fileFieldList = ['uploadFile1', 'uploadFile2', 'uploadFile3'];
 
				// 往工作表插入數(shù)據(jù) (插入圖片后,鏈接也會(huì)被顯示,所以把圖片的數(shù)據(jù)干掉)
				workSheet.addRows(
					exportDataList.map((item) => {
						return {
							...item,
							uploadPic1: '',
							uploadPic2: '',
							uploadPic3: ''
							// uploadFile1: '',
							// uploadFile2: '',
							// uploadFile3: ''
						};
					})
				);
 
				// 往Excel插入圖片
				for (let ri = 0; ri < exportDataList.length; ri++) {
					// 獲取遍歷的當(dāng)前行
					const row = exportDataList[ri];
					// 過濾出當(dāng)前行圖片字段有值的
					const currentRowImgFieldList = imgFieldList.filter((e) => row[e]);
					// 遍歷圖片字段
					for (let ai = 0; ai < currentRowImgFieldList.length; ai++) {
						const imgField = currentRowImgFieldList[ai];
						// 圖片字段值,一個(gè)完整的url
						const url = row[imgField];
						// 根據(jù)url把圖片轉(zhuǎn)換成base64編碼,這里加了await, 方法名前面必須得加async,把這個(gè)imageToBase64方法變成同步方法
						const base64 = await this.imageToBase64(url);
						// 把base64編碼的圖片插入excel工作簿里面
						const imageId = workbook.addImage({
							base64: base64,
							extension: 'png'
						});
 
						// 當(dāng)前工作表(當(dāng)前excel頁)加入圖片,tl.col:excel第幾列,tl.row:excel第幾行,ext里面表示圖片寬高
                        // 這里需要細(xì)細(xì)調(diào)一下,加入單元格后是緊挨著單元格頂部,要做一些偏移
						workSheet.addImage(imageId, {
							tl: { col: columns.length + ai - 11.8, row: ri + 1.2 },
							// br: { col: columns.length + ai - 11.1, row: ri + 2 }
							ext: { width: 104, height: 73 }
						});
					}
				}
 
				for (let ri = 0; ri < exportDataList.length; ri++) {
					// 設(shè)置除了標(biāo)題之外,內(nèi)容的行高,避免圖片太高,這里太小,導(dǎo)致顯示很亂
					workSheet.getRow(ri + 2).height = 60;
				}
				// 設(shè)置標(biāo)題列的高度
				workSheet.getRow(1).height = 20;
 
				// 設(shè)置整個(gè)工作表的樣式
				const font = {
					name: '微軟雅黑',
					size: 10 // 字體大小
				};
				const font1 = {
					name: '宋體',
					size: 10, // 字體大小
					bold: true,
					color: {
						argb: '00000002'
					}
				};
				const border = {
					top: { style: 'thin' },
					left: { style: 'thin' },
					bottom: { style: 'thin' },
					right: { style: 'thin' }
				};
				const alignment = {
					horizontal: 'center',
					vertical: 'middle'
				};
				const headerFillColor = {
					type: 'pattern',
					pattern: 'solid',
					fgColor: { argb: 'F0F0F0F0' } // 淺灰色背景,您可以自定義顏色
				};
 
				for (let rowIndex = 1; rowIndex <= workSheet.actualRowCount; rowIndex++) {
					for (let colIndex = 1; colIndex <= workSheet.columnCount; colIndex++) {
						const cell = workSheet.getCell(rowIndex, colIndex);
						cell.font = font;
						cell.border = border;
						cell.alignment = alignment;
 
						// 如果是附件 (這里主要是文件的邏輯)
						if ((colIndex === 16 || colIndex === 17 || colIndex === 18) && rowIndex !== 1) {
							cell.font = {
								underline: true,
								color: { argb: 'FF1890FF' }
							};
							if (cell.value) {
								cell.value = {
									text: cell.value.split('/')[cell.value.split('/').length - 1],
									hyperlink: window.location.origin + cell.value,
									tooltip: '點(diǎn)擊跳轉(zhuǎn)'
								};
							}
						}
						// 如果是第一行,設(shè)置背景顏色
						if (rowIndex === 1) {
							cell.fill = headerFillColor;
							cell.font = font1;
						}
					}
					// 合并圖片單元格
					workSheet.mergeCells('M' + rowIndex + ':O' + rowIndex);
				}
				// 合并文件單元格
				workSheet.mergeCells('P1:R1');
 
				// 添加一些數(shù)據(jù)到合并后的單元格
				workSheet.getCell('M1').value = '圖片描述';
				// 添加一些數(shù)據(jù)到合并后的單元格
				workSheet.getCell('P1').value = '附件描述';
 
				// 工作簿寫入excel
				workbook.xlsx.writeBuffer().then((buffer) => {
					// // 轉(zhuǎn)換成Blob格式
					// const blob = new Blob([buffer], { type: 'application/octet-stream' });
					// // 導(dǎo)出excel,這里獲得了blob,有很多種導(dǎo)出方法,可以用FileSaver.js(百度一下就有了),我這里就簡單點(diǎn)了,用HTML的A標(biāo)簽導(dǎo)出
					// // 獲取下載鏈接
					// const url = URL.createObjectURL(blob);
 
					// // 動(dòng)態(tài)創(chuàng)建a標(biāo)簽
					// let downloadLink = document.createElement('a');
					// downloadLink.style.display = 'none'; // 隱藏這個(gè)a標(biāo)簽
					// document.body.appendChild(downloadLink); // 添加到DOM中
 
					// // 設(shè)置下載鏈接和文件名
					// downloadLink.href = url;
					// downloadLink.download = '問題匯總導(dǎo)出.xlsx'; // 自定義下載時(shí)的文件名
 
					// // 觸發(fā)點(diǎn)擊事件來開始下載
					// downloadLink.click();
 
					// // 下載后移除這個(gè)a標(biāo)簽
					// document.body.removeChild(downloadLink);
 
					// 使用saveAs下載 不會(huì)報(bào)出文件不安全
					saveAs(new Blob([buffer], { type: 'application/octet-stream' }), "問題匯總導(dǎo)出.xlsx")
				});
 
				this.loading.close();
		},
 
		imageToBase64(url, width, height) {
			return new Promise((resolve, reject) => {
				const image = new Image();
				image.src = url;
				image.crossOrigin = '*';
				image.onload = () => {
					const canvas = document.createElement('canvas');
					canvas.width = width || image.width;
					canvas.height = height || image.height;
					const ctx = canvas.getContext('2d');
					ctx.drawImage(image, 0, 0, width || image.width, height || image.height);
					const base64 = canvas.toDataURL('image/png');
					resolve(base64);
				};
			});
		},
		tableDataFormat(exportlist) {
			exportlist.forEach((item) => {
                // 這里是測試數(shù)據(jù),分割是;,要是用這個(gè)測試的話要改一下下面的分割符 和 文件后綴
				// item.annexUrl = 'https://img2.baidu.com/it/u=101236606,1785081092&fm=253&fmt=auto&app=138&f=JPEG?w=727&h=500;https://img1.baidu.com/it/u=2607921640,3248579257&fm=253&fmt=auto&app=138&f=JPEG?w=629&h=500;https://img1.baidu.com/it/u=2976068608,3323494935&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500'
                // 這里是后端返回id,處理成字符串,大家未必用得上
				this.tableProp.forEach((val) => {
					if (val.options && val.options.length > 0) {
						val.options.forEach((item1) => {
							if (item1.value == item[val.prop]) {
								item[val.prop] = item1.label;
							}
						});
					}
				});
				item.uploadPic = [];
				item.uploadPic1 = '';
				item.uploadPic2 = '';
				item.uploadPic3 = '';
				item.uploadFile = [];
				item.uploadFile1 = '';
				item.uploadFile2 = '';
				item.uploadFile3 = '';
 
				if (item.annexUrl) {
					let fileArr = item.annexUrl.split(',');
					let filetype = ['.doc', '.docx', '.pdf', '.vsdx', '.ppt', '.pptx', '.xlsx', '.xls', '.xmind', '.zip', '.rar', '.7z'];
					// 移除圖片類型以避免與圖片類型的判斷重疊,并統(tǒng)一轉(zhuǎn)換為小寫
					const exclusiveFiletype = filetype.map((type) => type.toLowerCase()).filter((type) => !['.png', '.jpg', '.jpeg', '.gif'].map((ext) => ext.toLowerCase()).includes(type));
 
					fileArr.forEach((fileUrl) => {
						// 將文件URL轉(zhuǎn)換為小寫,以便進(jìn)行不區(qū)分大小寫的比較
						const lowerCaseFileUrl = fileUrl.toLowerCase();
 
						// 先檢查是否為圖片類型
						['.png', '.jpg', '.jpeg', '.gif'].forEach((type) => {
							const lowerCaseType = type.toLowerCase();
							if (lowerCaseFileUrl.endsWith(lowerCaseType)) {
								item.uploadPic.push(fileUrl);
							}
						});
 
						// 然后檢查是否為其他文件類型
						exclusiveFiletype.forEach((type) => {
							if (lowerCaseFileUrl.endsWith(type)) {
								item.uploadFile.push(fileUrl);
							}
						});
					});
					if (item.uploadPic.length > 0) {
						item.uploadPic1 = item.uploadPic[0];
						item.uploadPic2 = item.uploadPic[1] || '';
						item.uploadPic3 = item.uploadPic[2] || '';
					}
					if (item.uploadFile.length > 0) {
						item.uploadFile1 = item.uploadFile[0];
						item.uploadFile2 = item.uploadFile[1] || '';
						item.uploadFile3 = item.uploadFile[2] || '';
					}
				}
			});
			return exportlist;
		},
}

因?yàn)?excel 插件都是按單元格級(jí)別的,圖片、超鏈接等如果想導(dǎo)出多個(gè),就要像我上面那樣一系列復(fù)雜操作,如果一行只有一個(gè)的話,會(huì)簡單很多!代碼肯定是可以運(yùn)行的,復(fù)制即可使用,就是要調(diào)整一下字段,對應(yīng)上你自己項(xiàng)目的真實(shí)返回?cái)?shù)據(jù)

到此這篇關(guān)于Vue純前端實(shí)現(xiàn)導(dǎo)出excel中的圖片與文件超鏈接的文章就介紹到這了,更多相關(guān)Vue導(dǎo)出excel內(nèi)容內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vue2 添加數(shù)據(jù)可視化支持的方法步驟

    Vue2 添加數(shù)據(jù)可視化支持的方法步驟

    這篇文章主要介紹了Vue2 添加數(shù)據(jù)可視化支持的方法步驟,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-01-01
  • vue中使用rem布局的兩種方法小結(jié)

    vue中使用rem布局的兩種方法小結(jié)

    這篇文章主要介紹了vue中使用rem布局的兩種方法小結(jié),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • vue?使用el-table循環(huán)生成表格的過程

    vue?使用el-table循環(huán)生成表格的過程

    這篇文章主要介紹了vue?使用el-table循環(huán)生成表格的過程,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • Vue3使用Suspense優(yōu)雅地處理異步組件加載的示例代碼

    Vue3使用Suspense優(yōu)雅地處理異步組件加載的示例代碼

    Vue3是Vue.js的最新版本,它帶來了許多令人興奮的新特性和改進(jìn),其中一個(gè)重要的特性是Suspense,它為我們提供了一種優(yōu)雅地處理異步組件加載和錯(cuò)誤處理的方式,本文給大家介紹了Vue3使用Suspense優(yōu)雅地處理異步組件加載的示例,需要的朋友可以參考下
    2024-01-01
  • vue 檢測用戶上傳圖片寬高的方法

    vue 檢測用戶上傳圖片寬高的方法

    這篇文章主要介紹了vue 檢測用戶上傳圖片寬高的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • vue3不同語法格式對比的實(shí)例代碼

    vue3不同語法格式對比的實(shí)例代碼

    vue3發(fā)布已有一段時(shí)間了,文檔也大概看了一下,不過對于學(xué)一門技術(shù),最好的方法還是實(shí)戰(zhàn),這篇文章主要給大家介紹了關(guān)于vue3不同語法格式對比的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • vue 組件中使用 transition 和 transition-group實(shí)現(xiàn)過渡動(dòng)畫

    vue 組件中使用 transition 和 transition-group實(shí)現(xiàn)過渡動(dòng)畫

    本文給大家分享一下vue 組件中使用 transition 和 transition-group 設(shè)置過渡動(dòng)畫,總結(jié)來說可分為分為 name 版, js 鉤子操作類名版, js 鉤子操作行內(nèi)樣式版,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2019-07-07
  • vue實(shí)現(xiàn)組件值的累加

    vue實(shí)現(xiàn)組件值的累加

    這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)組件值的累加,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • vue中mint-ui的使用方法

    vue中mint-ui的使用方法

    這篇文章主要為大家詳細(xì)介紹了vue中mint-ui的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • Vue3+elementui plus創(chuàng)建項(xiàng)目的方法

    Vue3+elementui plus創(chuàng)建項(xiàng)目的方法

    這篇文章主要介紹了Vue3+elementui plus創(chuàng)建項(xiàng)目的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12

最新評(píng)論

阜新市| 平湖市| 莒南县| 绥滨县| 孙吴县| 鸡东县| 镇沅| 泸西县| 开江县| 揭东县| 芮城县| 张家口市| 巨野县| 济阳县| 新昌县| 时尚| 乌拉特前旗| 湖口县| 商南县| 张掖市| 丽江市| 鸡西市| 湛江市| 吉安市| 那曲县| 阿尔山市| 江油市| 西青区| 连平县| 凤台县| 威远县| 普洱| 舞钢市| 垦利县| 仁布县| 手游| 涟水县| 财经| 响水县| 南投县| 遵化市|