本篇参考:
https://developer.salesforce.com/docs/component-library/bundle/lightning-file-upload/documentation
https://developer.salesforce.com/docs/component-library/bundle/lightning-input/specification
在salesforce中,上传附件是一个经常做的操作,在标准的功能基础上,lwc自然也封装了自定义的实现。我们有上传文档需求的时候,通常有以下的几点需求和考虑:
- 是否支持多文件上传
- 是否支持大文件上传
- 是否可以限制上传文件的类型
- 是否可以对文件进行解析(目前demo中仅限csv)
根据上述的几点需求和考虑,本篇采用两种方式来实现文件上传操作来契合这些要求。
一. lightning-file-upload实现大文件上传
使用此种方式的优缺点:
优点:
- 支持大文件上传;
- 可以限制上传文件类型;
- 支持多文件上传;
缺点:
- 不支持文件解析。
demo如下:
fileUploadSample.html:上面的链接中给出了 lightning-file-upload的使用方法,通过设置 label展示上传组件的label名称,record-id用来指定当前上传的这些文件将作为 note & Attachment绑定在哪条数据下,accept指定了限制的格式, uploadfinished是组件自身封装的事件,用于上传完成之后执行的事件,multiple设置 true/false来指定当前的组件是否支持多个文件上传。
<template> <lightning-card title="File Upload"> <lightning-file-upload label="上传附件" name="fileUploader" accept={acceptedFormats} record-id={recordId} onuploadfinished={handleUploadFinishedEvent} multiple> lightning-file-upload> lightning-card> template>
fileUploadSample.js:方法用来指定当前只接受csv,上传成功以后toast信息展示相关的上传文件名称。
import { LightningElement, api } from 'lwc'; import {ShowToastEvent} from 'lightning/platformShowToastEvent'; export default class FileUploadSample extends LightningElement { @api recordId; get acceptedFormats() { return ['.csv']; } handleUploadFinishedEvent(event) { const uploadedFiles = event.detail.files; let uploadedFilesName = uploadedFiles.map(element => element.name); let uploadedFileNamesStr = uploadedFilesName.join(','); this.dispatchEvent( new ShowToastEvent({ title: 'Success', message: uploadedFiles.length + ' Files uploaded Successfully: ' + uploadedFileNamesStr, variant: 'success', }), ); } }
结果展示:
1. 页面初始化样子
2. 上传两个文件的UI效果,点击done即调用 onuploadfinished这个对应的handler
3. 展示toast消息
4. 上传的文件正常的挂到了 Notes & Attachment上面
二. lightning-input 实现csv文件上传以及解析
此种方法优点
- 支持上传文件解析
此种方法缺点
- 对文件上传大小有严格限制
demo如下:
FileUploadUsingInputController:用于存储文件以及对csv内容进行解析,需要注意的是,当前方法只针对单个csv的单个sheet页进行解析。
public with sharing class FileUploadUsingInputController { @AuraEnabled public static String saveFile(Id recordId, String fileName, String base64Data) { base64Data = EncodingUtil.urlDecode(base64Data, 'UTF-8'); Blob contentBlob = EncodingUtil.base64Decode(base64Data); String content = bitToString(contentBlob, 'UTF-8'); content = content.replaceAll('\r\n', '\n'); content = content.replaceAll('\r', '\n'); String[] fileLines = content.split('\n'); System.debug('*** ' + JSON.serialize(fileLines)); for(Integer i = 1; i < fileLines.size(); i++) { //TODO 遍历操作 system.debug('execute'); } // inserting file ContentVersion cv = new ContentVersion(); cv.Title = fileName; cv.PathOnClient = '/' + fileName; cv.FirstPublishLocationId = recordId; cv.VersionData = EncodingUtil.base64Decode(base64Data); cv.IsMajorVersion = true; Insert cv; return 'successfully'; } public static String bitToString(Blob input, String inCharset){ //转换成16进制 String hex = EncodingUtil.convertToHex(input); //一个String类型两个字节 32位(bit),则一个String长度应该为两个16进制的长度,所以此处向右平移一个单位,即除以2 //向右平移一个单位在正数情况下等同于除以2,负数情况下不等 //eg 9 00001001 >>1 00000100 结果为4 final Integer bytesCount = hex.length() >> 1; //声明String数组,长度为16进制转换成字符串的长度 String[] bytes = new String[bytesCount]; for(Integer i = 0; i < bytesCount; ++i) { //将相邻两位的16进制字符串放在一个String中 bytes[i] = hex.mid(i << 1, 2); } //解码成指定charset的字符串 return EncodingUtil.urlDecode('%' + String.join(bytes, '%'), inCharset); } }
fileUploadUsingInput.html:展示上传组件以及button
<template> <lightning-card title="File Upload Using Input"> <lightning-layout multiple-rows="true"> <lightning-layout-item size="12"> <lightning-input label="" name="file uploader" onchange={handleFilesChange} type="file" accept={acceptedType}>lightning-input><br/> <div class="slds-text-body_small">{fileName} div> lightning-layout-item> <lightning-layout-item> <lightning-button label={UploadFile} onclick={handleSave} variant="brand">lightning-button> lightning-layout-item> lightning-layout> <template if:true={showLoadingSpinner}> <lightning-spinner alternative-text="Uploading now">lightning-spinner> template> lightning-card> template>
fileUploadUsingInput.js:因为用string存储,所以对文件大小有字节的限制。
import { LightningElement, track, api } from 'lwc'; import saveFile from '@salesforce/apex/FileUploadUsingInputController.saveFile'; import {ShowToastEvent} from 'lightning/platformShowToastEvent'; export default class FileUploadUsingInput extends LightningElement { @api recordId; @track fileName = ''; @track UploadFile = 'Upload File'; @track showLoadingSpinner = false; filesUploaded = []; file; fileContents; fileReader; content; MAX_FILE_SIZE = 1500000; get acceptedType() { return ['.csv']; } handleFilesChange(event) { if(event.target.files.length > 0) { this.filesUploaded = event.target.files; this.fileName = event.target.files[0].name; } } handleSave() { if(this.filesUploaded.length > 0) { this.file = this.filesUploaded[0]; if (this.file.size > this.MAX_FILE_SIZE) { window.console.log('文件过大'); return ; } this.showLoadingSpinner = true; this.fileReader= new FileReader(); this.fileReader.onloadend = (() => { this.fileContents = this.fileReader.result; let base64 = 'base64,'; this.content = this.fileContents.indexOf(base64) + base64.length; this.fileContents = this.fileContents.substring(this.content); this.saveToFile(); }); this.fileReader.readAsDataURL(this.file); } else { this.fileName = '选择一个csv文件上传'; } } saveToFile() { saveFile({ recordId: this.recordId, fileName: this.file.name, base64Data: encodeURIComponent(this.fileContents)}) .then(result => { this.isTrue = true; this.showLoadingSpinner = false; this.dispatchEvent( new ShowToastEvent({ title: 'Success!!', message: this.fileName + ' - 上传成功', variant: 'success', }), ); }) .catch(error => { this.dispatchEvent( new ShowToastEvent({ title: '上传失败', message: error.message, variant: 'error', }), ); }); } }
结果展示:
1. csv中做以下的数据
2. UI效果
3. debug log中打印出来的内容
4. 格式化以后的效果 ,我们可以对数组进行二次操作,通过逗号进行分割就可以获取每一个cell对应的值,通常我们获取数据中的for循环 index为1,即跳过首行标题行。
总结:篇中主要讲述了关于lwc中文件上传以及文件解析的简单操作。第一种方式适合大文件上传,可自定制化不强但功能强悍。第二种方式可以对数据在apex端进行相关解析,但是有大小的限制。篇中有错误地方欢迎指出,有不懂欢迎留言。