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>
)
}