如何为SPFx解决方案(Web部件)创建附件组件?
SPFx 自定义附件组件实现方案
由于Office UI Fabric没有原生的附件上传组件,下面提供一个适配SPFx Web部件的自定义附件组件,和你已有的TextFieldInput组件风格保持一致,支持文件选择、预览、移除等核心功能:
附件组件代码
import * as React from 'react'; import * as PropTypes from 'prop-types'; import { Button, List, Icon, Tooltip } from 'office-ui-fabric-react'; import { getFileSizeString } from '@microsoft/sp-core-library'; const AttachmentInput = ({ props, otherProps = null, onFilesChange }) => { const fileInputRef = React.useRef<HTMLInputElement>(null); const [selectedFiles, setSelectedFiles] = React.useState<File[]>([]); // 处理文件选择事件 const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => { const files = event.target.files; if (!files) return; const newFiles = Array.from(files); // 若允许重复添加则合并,否则替换现有列表 const updatedFiles = props.allowDuplicate ? [...selectedFiles, ...newFiles] : newFiles; setSelectedFiles(updatedFiles); onFilesChange(updatedFiles); }; // 移除单个文件 const handleRemoveFile = (index: number) => { const updatedFiles = selectedFiles.filter((_, i) => i !== index); setSelectedFiles(updatedFiles); onFilesChange(updatedFiles); }; // 触发文件选择框 const triggerFileInput = () => { fileInputRef.current?.click(); }; // 渲染单个文件项 const renderFileItem = (item: File, index: number) => ( <div key={index} style={{ display: 'flex', alignItems: 'center', padding: '8px 0', borderBottom: '1px solid #eee' }}> <Icon iconName="Document" style={{ fontSize: 24, marginRight: 8 }} /> <div style={{ flexGrow: 1 }}> <div style={{ fontWeight: 500 }}>{item.name}</div> <div style={{ fontSize: 12, color: '#666' }}>{getFileSizeString(item.size)}</div> </div> <Tooltip content="移除文件"> <Button iconName="Delete" onClick={() => handleRemoveFile(index)} disabled={props.disabled} styles={{ root: { padding: '4px' } }} /> </Tooltip> </div> ); return ( <div className={props.class ? props.class : ""} {...otherProps}> {/* 隐藏原生文件输入框 */} <input ref={fileInputRef} type="file" multiple={props.multiple} accept={props.accept} disabled={props.disabled} onChange={handleFileChange} style={{ display: 'none' }} /> {/* 触发按钮 */} <Button iconName="Upload" onClick={triggerFileInput} disabled={props.disabled} text={props.buttonText ? props.buttonText : "添加附件"} /> {/* 已选文件列表 */} {selectedFiles.length > 0 && ( <div style={{ marginTop: 16 }}> <div style={{ marginBottom: 8, fontWeight: 500 }}>{props.label ? props.label : "已选附件"}</div> <List items={selectedFiles} onRenderCell={renderFileItem} /> </div> )} {/* 错误提示 */} {props.error && <div style={{ color: '#a80000', fontSize: 12, marginTop: 8 }}>{props.error}</div>} </div> ); }; AttachmentInput.propTypes = { props: PropTypes.shape({ class: PropTypes.string, error: PropTypes.string, label: PropTypes.string, buttonText: PropTypes.string, multiple: PropTypes.bool, // 是否允许选择多个文件 accept: PropTypes.string, // 限制文件类型,如".pdf,.docx" disabled: PropTypes.bool, allowDuplicate: PropTypes.bool, // 是否允许重复添加相同文件 required: PropTypes.bool, }), otherProps: PropTypes.object, onFilesChange: PropTypes.func.isRequired, // 返回选中的文件数组 }; // 默认属性 AttachmentInput.defaultProps = { props: { multiple: true, allowDuplicate: false, disabled: false, required: false, }, }; export default AttachmentInput;
关键功能说明
- UI一致性:使用Office UI Fabric组件构建,和你的
TextFieldInput风格统一,避免样式冲突。 - 核心能力:支持单/多文件选择、文件类型限制、文件预览(名称/大小)、单个文件移除。
- SPFx适配:依赖
@microsoft/sp-core-library的getFileSizeString方法格式化文件大小,符合SPFx生态。 - 回调机制:通过
onFilesChange返回选中的File数组,方便后续实现上传到SharePoint的逻辑。
组件使用示例
import AttachmentInput from './AttachmentInput'; // 在你的Web部件或父组件中使用 const YourComponent = () => { const [files, setFiles] = React.useState<File[]>([]); const [isSubmitted, setIsSubmitted] = React.useState(false); const handleFilesChange = (selectedFiles: File[]) => { setFiles(selectedFiles); // 这里可以添加上传到SharePoint的逻辑 }; const handleSubmit = () => { setIsSubmitted(true); if (files.length === 0) return; // 提交逻辑 }; return ( <div> <AttachmentInput props={{ label: "文档附件", buttonText: "上传文档", accept: ".pdf,.docx,.xlsx", required: true, error: files.length === 0 && isSubmitted ? "请至少添加一个附件" : "" }} onFilesChange={handleFilesChange} /> <Button onClick={handleSubmit} text="提交" style={{ marginTop: 16 }} /> </div> ); };
后续上传逻辑提示
如果需要将文件上传到SharePoint文档库,可以在handleFilesChange中调用SPFx的SPHttpClient:
import { SPHttpClient } from '@microsoft/sp-http'; // 示例:上传单个文件到指定文档库 const uploadFileToSP = async (file: File, context: any, libraryName: string) => { const fileName = file.name; const fileUrl = `${context.pageContext.web.absoluteUrl}/_api/web/lists/getbytitle('${libraryName}')/rootfolder/files/add(overwrite=true,url='${fileName}')`; const response = await context.spHttpClient.post( fileUrl, SPHttpClient.configurations.v1, { body: file, headers: { "Accept": "application/json;odata=nometadata", "Content-Type": file.type } } ); return response.json(); };
内容的提问来源于stack exchange,提问作者jck4real
相关产品推荐
相关产品推荐

