react上传文件
① 如何制作react组件包上传到npm
虽说现在市面上组件库相当多了,但是还有一些组件特定场景市面上没有,公司内部一些不同项目,有类似相同组件可以直接复用,避免重复造轮子,就可以直接制作一个npm包,下次直接使用。
注意:文中的每一步都很重要,都是踩过的坑
1、注册npm账号
地址: https://www.npmjs.com/signup
注意:注册完后,记得验证你的邮件地址!一定!否则会在提交组件包的时候报403错误,那是因为没有验证你的邮箱。
1、创建新的文件夹
2、进入该文件夹,使用cmd命令,npm进入安装项目流程
3、对应的字段:
有需要可以自行安装自己要的依赖,上面几个是我写组件必要的几个依赖,因为我没有写对应的依赖版本所以安装时候会以最新版本安装。
1、新建如下目录结构和文件
2、编写webpack.config.js的配置,以下是最基础的配置
上面的less-loader没有启用lessmoles模块化比较不好,假设现在项目有好几个组件,那么模块化就可以避免我们不同组件的样式污染,如果不开启就不生效,如下例子:
所以得将webpack.config.js修改如下:
接下来往babel.config.js添加编译时候需要的loader配置:
3、编写组件
这个是核心部分,就是说这里是你的组件
------------- ./src/index.jsx
------------- ./src/index.less
4、对外暴露组件,编辑根目录下的index.js文件
我这里叫Test,使用组件包引入时候就是Test组件。别人在引用组件包时候会从该文件作为入口(package.json的main字段可以配置),这个文件有两种写法,第一种:
第二种:
5、编写webpack读取的入口文件 public/app.js
webpack启动、编译、打包都会从这个文件作为入口(webpack那边配置的)
6、编写html模板,public/index.html文件。
我们知道spa单页面都是依据一个html模板上面引入js创建虚拟dom生成到这个html上面,所以需要有一个挂载的实例模板。
7、编写.gitignore文件
这个文件可以配置git上传时候忽略哪些文件不想传上去,同时发布组件包的时候它也会按照这个文件来,忽略哪些不上传。
8、添加项目启动命令:修改package.json文件
给该文件的scripts里添加两个系统命令,一个是启动命令,一个是打包命令(制作组件包用的比较少)。注意webpack4的版本可能不是 webpack server --mode development,这个需要自己对应版本。
说明是node版本问题,需要安装高点版本的node,可以使用nvm来管理node版本,这里不多说,我切换为node 12.0.0版本就可以。
到此为止,我们已经配置好了工程,接下来需要把组件包发布上去
1、发布规则
例如你是淘宝源你需要:
查看设置过的所有的源:npm config get registry
设置当前源为npm: npm config set registry https://registry.npmjs.org/
发布完成后设置回淘宝源:npm config set registry https://registry.npm.taobao.org
2、发布流程
1、登录注册好的npm账号:npm login
输入对应的账号、密码、邮箱即可
② React 使用Upload插件上传读取文件内容
某一天,公司里需要一个功能,一个可以把一份参数多如牛毛的配置文件本地存储下来,本地也可以把文件读取出来这样便利的功能。分析一下这个需求,主要就是要以json的格式,保存,和web页面读取json文件的这样两个功能。公司的工程是react编写的,可能对vue和原生js都有一定了解的你,对react并不熟悉,那么,如何解决这个问题
首先,我们假定拿到了一个json格式的变量
那么,再写一个download的工具类
发现问题!直接download下来的是没有格式化过的文本,乱成一团,毫无可读性可言。一个formatjson非常重要!
一行调用!
react有很多轮子,upload当然也有相应封装好的工具,引入!
(在这之前别忘了npm install react-fileupload -save)
写一份配置文件,这个文件中写出的API这边有 https://www.jianshu.com/p/3aa9d5ad41b0
操作在那边已经很清晰啦,我就不多说了
拿到文件之后,当然要把文件内容在web上就解析出来
好啦,fileContent就是里面的内容,json对象,拿到之后,就可以为所欲为了!
③ 利用antd添加文件预览
import styles from './style.scss'; // 自定义样式,文件名称不可修改
import { Button, Upload, Modal, Alert } from 'antd';
import React, { Children, cloneElement, isValidElement, useState, useEffect, useRef } from 'react';
import axios from 'axios'
const Previewer = ({ url, onClose, isEditing, onEditSave }) => {
return (
<Modal className={styles.modalshow} title={isEditing ? "文档编辑" : "文档预览"} visible width={1200} onCancel={onClose} footer={
isEditing ? [
<Button key="back" onClick={onClose}>
返回
</Button>,
<Button key="submit" type="primary" onClick={onEditSave}>
提交
</Button >
] : null} >
<iframe src={url} title='wps' width='100%' height='592' />
</Modal >
)
}
const mapDOMTree = (children, matchChild) => {
if (typeof children === 'function') return null
return Children.map(children, (child) => {
if (!child) return null;
if (matchChild(child)) return matchChild(child);
return isValidElement(child) ? cloneElement(child, child.props, mapDOMTree(child.props.children, matchChild)) : child;
});
};
const baseUrl2 = getUrl('/contract/api/xft-contract-procode/object/v1/attachments/service/create-uri-by-id');
function CUpload({ onPreview, onEdit, onEditSave, children, showDownloadIcon = true, showRemoveIcon = true, showEditButton = true, showPreviewIcon = true, ...rest }) {
const [visible, setVisible] = useState(false)
const [url, setUrl] = useState()
const [editing, setEditing] = useState(false)
const toggle = () => {
setVisible(prevVisible => !prevVisible)
}
const onPreviewFile = async (file) => {
const previerUrl = await onPreview?.(file)
setUrl(previerUrl)
toggle()
}
const onEditFile = async (file) => {
const previerUrl = await onEdit?.(file)
setUrl(previerUrl)
setEditing(true)
toggle()
}
const handleUpload = files => {
return {
fileName: files.name,
fileType: files.type
}
}
const onClose = () => {
setEditing(false)
toggle()
}
const downloadd = (file) => {
axios.post(`${baseUrl2}?id=${file.id} `)
.then(res => {
let data = res.data.data;
download(data.tempUri, data.fileName)
}
).catch((error) => {
Modal.showServeError(error);
})
}
const download = (url, fileName) => {
// for IE
// if (window.navigator.msSaveOrOpenBlob) {
// window.navigator.msSaveOrOpenBlob(url, fileName);
// } else {
const link = document.createElement('a');
link.style.display = 'none';
link.href = url;
link.download = fileName;
// document.body.appendChild(link);
link.click();
// window.URL.revokeObjectURL(link.href);
link.remove();
// }
};
const editClose = async () => {
await onEditSave()
onClose()
}
const baseUrl = getUrl('contract/api/xft-contract-procode/object/v1/attachments')
return (
<>
<Upload
{...rest}
maxCount={1}
data={handleUpload}
accept='application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/msword'
action={baseUrl}
showUploadList={{
showDownloadIcon,
showRemoveIcon,
}}
onDownload={downloadd}
itemRender={(originNode, file) => {
if (originNode.type !== 'div' || !showPreviewIcon) return originNode;
return mapDOMTree(originNode, (children) => {
if (children.key === 'download-delete') {
return cloneElement(
children,
children.props,
<>
<Button
type="text"
size="small"
onClick={() => onPreviewFile(file)}
className="ant-upload-list-item-card-actions-btn"
icon={<EyeOutlined />}
title="Preview File"
/>
{showEditButton && <Button
type="text"
size="small"
onClick={() => onEditFile(file)}
className="ant-upload-list-item-card-actions-btn"
icon={<EditOutlined />}
title="Edit File"
/>}
{children.props.children}
</>,
);
}
return false;
});
}}
>{children}</Upload>
{visible && <Previewer url={url} onClose={onClose} isEditing={editing} onEditSave={editClose} />}
</>
);
};
export default function UploadButton(props) {
const { setValue, id, mingzi, formItemValue, setPrinstineValue, isEdit } = props;
const [list, setList] = useState([]);
const editingRef = useRef(false);
console.log('props--', props)
useEffect(() => {
if (formItemValue?.fileId) {
setList([{ ...formItemValue, name: formItemValue?.fileName, id: formItemValue?.fileId, status: 'done' }])
}
}, [formItemValue])
const onChange = (info) => {
console.log('info---', info);
if (info.file.status === 'done') {
setValue({ [id]: info.file.response.data.data, [mingzi]: info.fileList[0].name });
}
if (info.file.status === 'removed') {
setPrinstineValue(undefined);
setValue(undefined)
}
setList(info.fileList)
}
const onPreview = (e) => {
editingRef.current = false
return Http.get('/contract/api/xft-contract-procode/common/v1/preview?attachId=' + e.fileId).then(res => res.data.data.data).catch((error) => {
Modal.showServeError(error);
})
}
const onEdit = (e) => {
editingRef.current = true
return Http.get(`/contract/api/xft-contract-procode/contract/v1/institution/file/onlineEdit?attachId=${props.formItemValue?.fileId}&id=${props.data.__super.id}`).then(
res => res.data.data.data).catch((error) => {
Modal.showServeError(error);
})
}
const onEditSave = () => {
if (editingRef.current) {
editingRef.current = false
return Http.get(`/contract/api/xft-contract-procode/common/v1/complete/fileEdit/${props.formItemValue?.fileId}`)
}
}
const uploadButton = <Button>上传</Button>
return (
<CUpload
onPreview={onPreview}
onEdit={onEdit}
onEditSave={onEditSave}
onChange={onChange}
fileList={list}
showRemoveIcon={isEdit}
showEditButton={isEdit}
>
{list.length >= 1 ? null : uploadButton}
</CUpload>
)
}