@aozi6666/bee-design 0.1.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/App.d.ts +4 -0
- package/{build → dist}/components/AutoComplete/autoComplete.d.ts +2 -2
- package/{build → dist}/components/AutoComplete/autoComplete.types.d.ts +4 -4
- package/{build → dist}/components/AutoComplete/autoCompleteDropdown.d.ts +2 -2
- package/dist/components/AutoComplete/index.d.ts +4 -0
- package/{build → dist}/components/Button/button.d.ts +2 -2
- package/{build → dist}/components/Button/button.types.d.ts +1 -1
- package/dist/components/Button/index.d.ts +2 -0
- package/{build → dist}/components/Icon/icon.d.ts +2 -2
- package/dist/components/Icon/icon.types.d.ts +6 -0
- package/dist/components/Icon/index.d.ts +2 -0
- package/dist/components/Input/index.d.ts +4 -0
- package/dist/components/Input/input.d.ts +5 -0
- package/{build → dist}/components/Input/input.types.d.ts +4 -4
- package/{build → dist}/components/Menu/index.d.ts +4 -4
- package/{build → dist}/components/Menu/menu.d.ts +2 -10
- package/dist/components/Menu/menuContext.d.ts +9 -0
- package/{build → dist}/components/Menu/menuItem.d.ts +2 -2
- package/{build → dist}/components/Menu/subMenu.d.ts +1 -1
- package/dist/components/Progress/index.d.ts +2 -0
- package/dist/components/Progress/progress.d.ts +4 -0
- package/{build → dist}/components/Progress/progress.types.d.ts +2 -2
- package/dist/components/Transition/index.d.ts +3 -0
- package/dist/components/Transition/transition.d.ts +4 -0
- package/dist/components/Transition/transition.types.d.ts +9 -0
- package/{build → dist}/components/Upload/dragger.d.ts +1 -1
- package/dist/components/Upload/index.d.ts +2 -0
- package/{build → dist}/components/Upload/upload.d.ts +2 -2
- package/{build → dist}/components/Upload/upload.types.d.ts +7 -11
- package/{build → dist}/components/Upload/uploadList.d.ts +2 -2
- package/dist/hooks/useClickOutside.d.ts +3 -0
- package/dist/hooks/useDebounce.d.ts +2 -0
- package/dist/index.cjs +16272 -0
- package/dist/index.cjs.map +1 -0
- package/{build → dist}/index.css +24 -24
- package/dist/index.d.ts +9 -0
- package/dist/index.esm.js +709 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.umd.js +14381 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/main.d.ts +1 -0
- package/dist/setupIcons.d.ts +1 -0
- package/dist/setupTests.d.ts +1 -0
- package/package.json +61 -48
- package/README.md +0 -73
- package/build/App.d.ts +0 -4
- package/build/App.js +0 -137
- package/build/components/AutoComplete/autoComplete.js +0 -123
- package/build/components/AutoComplete/autoComplete.types.js +0 -1
- package/build/components/AutoComplete/autoCompleteDropdown.js +0 -17
- package/build/components/AutoComplete/index.d.ts +0 -4
- package/build/components/AutoComplete/index.js +0 -3
- package/build/components/Button/button.js +0 -43
- package/build/components/Button/button.types.js +0 -19
- package/build/components/Button/index.d.ts +0 -2
- package/build/components/Button/index.js +0 -2
- package/build/components/Icon/icon.js +0 -24
- package/build/components/Icon/icon.types.d.ts +0 -6
- package/build/components/Icon/icon.types.js +0 -2
- package/build/components/Icon/index.d.ts +0 -2
- package/build/components/Icon/index.js +0 -2
- package/build/components/Input/index.d.ts +0 -4
- package/build/components/Input/index.js +0 -3
- package/build/components/Input/input.d.ts +0 -5
- package/build/components/Input/input.js +0 -32
- package/build/components/Input/input.types.js +0 -1
- package/build/components/Menu/index.js +0 -9
- package/build/components/Menu/menu.js +0 -48
- package/build/components/Menu/menuItem.js +0 -20
- package/build/components/Menu/subMenu.js +0 -56
- package/build/components/Progress/index.d.ts +0 -2
- package/build/components/Progress/index.js +0 -2
- package/build/components/Progress/progress.d.ts +0 -4
- package/build/components/Progress/progress.js +0 -6
- package/build/components/Progress/progress.types.js +0 -2
- package/build/components/Transition/index.d.ts +0 -3
- package/build/components/Transition/index.js +0 -2
- package/build/components/Transition/transition.d.ts +0 -4
- package/build/components/Transition/transition.js +0 -18
- package/build/components/Transition/transition.types.d.ts +0 -10
- package/build/components/Transition/transition.types.js +0 -1
- package/build/components/Upload/dragger.js +0 -42
- package/build/components/Upload/index.d.ts +0 -2
- package/build/components/Upload/index.js +0 -2
- package/build/components/Upload/native/axios-react.js +0 -99
- package/build/components/Upload/native/from-html.js +0 -5
- package/build/components/Upload/upload.js +0 -192
- package/build/components/Upload/upload.types.js +0 -3
- package/build/components/Upload/uploadList.js +0 -13
- package/build/hooks/useClickOutside.d.ts +0 -3
- package/build/hooks/useClickOutside.js +0 -18
- package/build/hooks/useDebounce.d.ts +0 -2
- package/build/hooks/useDebounce.js +0 -14
- package/build/index.css.map +0 -1
- package/build/index.d.ts +0 -9
- package/build/index.js +0 -12
- package/build/main.d.ts +0 -1
- package/build/main.js +0 -7
- package/build/setupTests.d.ts +0 -1
- package/build/setupTests.js +0 -1
- /package/{build → dist}/components/Upload/native/axios-react.d.ts +0 -0
- /package/{build → dist}/components/Upload/native/from-html.d.ts +0 -0
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { FontAwesomeIconProps } from '@fortawesome/react-fontawesome';
|
|
2
|
-
export type ThemeProps = 'primary' | 'secondary' | 'success' | 'info' | 'warning' | 'danger' | 'light' | 'dark';
|
|
3
|
-
export interface IconProps extends FontAwesomeIconProps {
|
|
4
|
-
/** 支持框架主题,根据主题显示不同的颜色 */
|
|
5
|
-
theme?: ThemeProps;
|
|
6
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useMemo } from 'react';
|
|
3
|
-
import classNames from 'classnames';
|
|
4
|
-
import Icon from '../Icon/icon';
|
|
5
|
-
export const Input = (props) => {
|
|
6
|
-
const { disabled, size, icon, prepend, append, style, onChange, ...restProps } = props;
|
|
7
|
-
const classes = useMemo(() => classNames('viking-input-wrapper', {
|
|
8
|
-
[`input-size-${size}`]: size,
|
|
9
|
-
'input-group': prepend || append,
|
|
10
|
-
'input-group-prepend': !!prepend,
|
|
11
|
-
'input-group-append': !!append,
|
|
12
|
-
}), [append, prepend, size]);
|
|
13
|
-
const inputClasses = classNames('viking-input-inner', {
|
|
14
|
-
'is-disabled': disabled,
|
|
15
|
-
});
|
|
16
|
-
const handleChange = (e) => {
|
|
17
|
-
if (onChange)
|
|
18
|
-
onChange(e);
|
|
19
|
-
};
|
|
20
|
-
const renderPrepend = () => {
|
|
21
|
-
if (!prepend)
|
|
22
|
-
return null;
|
|
23
|
-
return _jsx("div", { className: "viking-input-group-prepend", children: prepend });
|
|
24
|
-
};
|
|
25
|
-
const renderAppend = () => {
|
|
26
|
-
if (!append && !icon)
|
|
27
|
-
return null;
|
|
28
|
-
return (_jsxs("div", { className: "viking-input-group-append", children: [append, icon ? (_jsx("div", { className: "icon-wrapper", children: _jsx(Icon, { icon: icon }) })) : null] }));
|
|
29
|
-
};
|
|
30
|
-
return (_jsxs("div", { className: classes, style: style, children: [renderPrepend(), _jsx("input", { className: inputClasses, disabled: disabled, onChange: handleChange, ...restProps }), renderAppend()] }));
|
|
31
|
-
};
|
|
32
|
-
export default Input;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import React, { useState, createContext } from 'react';
|
|
3
|
-
import classNames from 'classnames';
|
|
4
|
-
export const MenuContext = createContext({ index: '0' });
|
|
5
|
-
/**
|
|
6
|
-
* 为网站提供导航功能的菜单。支持横向纵向两种模式,支持下拉菜单。
|
|
7
|
-
*
|
|
8
|
-
* ```javascript
|
|
9
|
-
* import { Menu } from 'vikingship'
|
|
10
|
-
*
|
|
11
|
-
* //然后可以使用 Menu.Item 和 Menu.Submenu 访问选项和子下拉菜单组件
|
|
12
|
-
* ```
|
|
13
|
-
*/
|
|
14
|
-
export const Menu = ({ className, mode = 'horizontal', style, children, defaultIndex = '0', onSelect, defaultOpenSubMenus = [], }) => {
|
|
15
|
-
const [currentActive, setActive] = useState(defaultIndex);
|
|
16
|
-
const classes = classNames('viking-menu', className, {
|
|
17
|
-
'menu-vertical': mode === 'vertical',
|
|
18
|
-
'menu-horizontal': mode !== 'vertical',
|
|
19
|
-
});
|
|
20
|
-
const handleClick = (index) => {
|
|
21
|
-
setActive(index);
|
|
22
|
-
if (onSelect) {
|
|
23
|
-
onSelect(index);
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
const passedContext = {
|
|
27
|
-
index: currentActive ? currentActive : '0',
|
|
28
|
-
onSelect: handleClick,
|
|
29
|
-
mode,
|
|
30
|
-
defaultOpenSubMenus,
|
|
31
|
-
};
|
|
32
|
-
const renderChildren = () => {
|
|
33
|
-
return React.Children.map(children, (child, index) => {
|
|
34
|
-
const childElement = child;
|
|
35
|
-
const { displayName } = childElement.type;
|
|
36
|
-
if (displayName === 'MenuItem' || displayName === 'SubMenu') {
|
|
37
|
-
return React.cloneElement(childElement, {
|
|
38
|
-
index: index.toString()
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
console.error("Warning: Menu has a child which is not a MenuItem component");
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
};
|
|
46
|
-
return (_jsx("ul", { className: classes, style: style, "data-testid": "test-menu", children: _jsx(MenuContext.Provider, { value: passedContext, children: renderChildren() }) }));
|
|
47
|
-
};
|
|
48
|
-
export default Menu;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import React, { useContext } from 'react';
|
|
3
|
-
import classNames from 'classnames';
|
|
4
|
-
import { MenuContext } from './menu';
|
|
5
|
-
export const MenuItem = (props) => {
|
|
6
|
-
const { index, disabled, className, style, children } = props;
|
|
7
|
-
const context = useContext(MenuContext);
|
|
8
|
-
const classes = classNames('menu-item', className, {
|
|
9
|
-
'is-disabled': disabled,
|
|
10
|
-
'is-active': context.index === index
|
|
11
|
-
});
|
|
12
|
-
const handleClick = () => {
|
|
13
|
-
if (context.onSelect && !disabled && (typeof index === 'string')) {
|
|
14
|
-
context.onSelect(index);
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
return (_jsx("li", { className: classes, style: style, onClick: handleClick, children: children }));
|
|
18
|
-
};
|
|
19
|
-
MenuItem.displayName = 'MenuItem';
|
|
20
|
-
export default MenuItem;
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React, { useContext, useState } from 'react';
|
|
3
|
-
import classNames from 'classnames';
|
|
4
|
-
import { MenuContext } from './menu';
|
|
5
|
-
import Icon from '../Icon/icon';
|
|
6
|
-
import Transition from '../Transition/transition';
|
|
7
|
-
export const SubMenu = ({ index, title, children, className }) => {
|
|
8
|
-
const context = useContext(MenuContext);
|
|
9
|
-
const openedSubMenus = context.defaultOpenSubMenus;
|
|
10
|
-
const isOpend = (index && context.mode === 'vertical') ? openedSubMenus.includes(index) : false;
|
|
11
|
-
const [menuOpen, setOpen] = useState(isOpend);
|
|
12
|
-
const classes = classNames('menu-item submenu-item', className, {
|
|
13
|
-
'is-active': context.index === index,
|
|
14
|
-
'is-opened': menuOpen,
|
|
15
|
-
'is-vertical': context.mode === 'vertical'
|
|
16
|
-
});
|
|
17
|
-
const handleClick = (e) => {
|
|
18
|
-
e.preventDefault();
|
|
19
|
-
setOpen(!menuOpen);
|
|
20
|
-
};
|
|
21
|
-
let timer;
|
|
22
|
-
const handleMouse = (e, toggle) => {
|
|
23
|
-
clearTimeout(timer);
|
|
24
|
-
e.preventDefault();
|
|
25
|
-
timer = setTimeout(() => {
|
|
26
|
-
setOpen(toggle);
|
|
27
|
-
}, 300);
|
|
28
|
-
};
|
|
29
|
-
const clickEvents = context.mode === 'vertical' ? {
|
|
30
|
-
onClick: handleClick
|
|
31
|
-
} : {};
|
|
32
|
-
const hoverEvents = context.mode !== 'vertical' ? {
|
|
33
|
-
onMouseEnter: (e) => { handleMouse(e, true); },
|
|
34
|
-
onMouseLeave: (e) => { handleMouse(e, false); }
|
|
35
|
-
} : {};
|
|
36
|
-
const renderChildren = () => {
|
|
37
|
-
const subMenuClasses = classNames('viking-submenu', {
|
|
38
|
-
'menu-opened': menuOpen
|
|
39
|
-
});
|
|
40
|
-
const childrenComponent = React.Children.map(children, (child, i) => {
|
|
41
|
-
const childElement = child;
|
|
42
|
-
if (childElement.type.displayName === 'MenuItem') {
|
|
43
|
-
return React.cloneElement(childElement, {
|
|
44
|
-
index: `${index}-${i}`
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
console.error("Warning: SubMenu has a child which is not a MenuItem component");
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
return (_jsx(Transition, { in: menuOpen, timeout: 300, animation: "zoom-in-top", children: _jsx("ul", { className: subMenuClasses, children: childrenComponent }) }));
|
|
52
|
-
};
|
|
53
|
-
return (_jsxs("li", { className: classes, ...hoverEvents, children: [_jsxs("div", { className: "submenu-title", ...clickEvents, children: [title, _jsx(Icon, { icon: "angle-down", className: "arrow-icon" })] }), renderChildren()] }, index));
|
|
54
|
-
};
|
|
55
|
-
SubMenu.displayName = 'SubMenu';
|
|
56
|
-
export default SubMenu;
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
const Progress = (props) => {
|
|
3
|
-
const { percent, strokeHeight = 15, showText = true, styles, theme = 'primary', } = props;
|
|
4
|
-
return (_jsx("div", { className: "viking-progress-bar", style: styles, children: _jsx("div", { className: "viking-progress-bar-outer", style: { height: `${strokeHeight}px` }, children: _jsx("div", { className: `viking-progress-bar-inner color-${theme}`, style: { width: `${percent}%` }, children: showText && _jsx("span", { className: "inner-text", children: `${percent}%` }) }) }) }));
|
|
5
|
-
};
|
|
6
|
-
export default Progress;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useRef } from 'react';
|
|
3
|
-
import { CSSTransition } from 'react-transition-group';
|
|
4
|
-
const Transition = (props) => {
|
|
5
|
-
const { children, classNames: classNamesProp, animation, wrapper = false, unmountOnExit = true, appear = true, addEndListener, ...restProps } = props;
|
|
6
|
-
const cls = animation ? animation : classNamesProp;
|
|
7
|
-
const nodeRef = useRef(null);
|
|
8
|
-
const transitionProps = {
|
|
9
|
-
classNames: cls,
|
|
10
|
-
unmountOnExit,
|
|
11
|
-
appear,
|
|
12
|
-
...restProps,
|
|
13
|
-
};
|
|
14
|
-
if (addEndListener)
|
|
15
|
-
transitionProps.addEndListener = addEndListener;
|
|
16
|
-
return (_jsx(CSSTransition, { nodeRef: nodeRef, ...transitionProps, children: _jsx("div", { ref: nodeRef, "data-transition-wrapper": wrapper ? 'true' : 'false', children: children }) }));
|
|
17
|
-
};
|
|
18
|
-
export default Transition;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
2
|
-
import type { CSSTransitionProps } from 'react-transition-group/CSSTransition';
|
|
3
|
-
export type AnimationName = 'zoom-in-top' | 'zoom-in-left' | 'zoom-in-bottom' | 'zoom-in-right';
|
|
4
|
-
export type TransitionProps = Omit<CSSTransitionProps<HTMLElement>, 'addEndListener' | 'timeout'> & {
|
|
5
|
-
animation?: AnimationName;
|
|
6
|
-
wrapper?: boolean;
|
|
7
|
-
children?: ReactNode;
|
|
8
|
-
timeout: CSSTransitionProps<HTMLElement>['timeout'];
|
|
9
|
-
addEndListener?: (node: HTMLElement, done: () => void) => void;
|
|
10
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
/* Dragger 是专门处理拖拽上传逻辑的子组件:
|
|
3
|
-
- 只负责获取拖拽的文件
|
|
4
|
-
- 上传文件还是靠 Upload
|
|
5
|
-
监听浏览器拖拽事件 → 拿到拖进来的文件 → 传回 Upload 组件
|
|
6
|
-
|
|
7
|
-
浏览器 Drag & Drop API 事件:
|
|
8
|
-
dragenter → 进入区域
|
|
9
|
-
dragover → 在区域上方拖动
|
|
10
|
-
dragleave → 离开区域
|
|
11
|
-
drop → 松手放下文件(包含拖进来的文件)
|
|
12
|
-
*/
|
|
13
|
-
import { useState } from 'react';
|
|
14
|
-
import classNames from 'classnames';
|
|
15
|
-
export const Dragger = (props) => {
|
|
16
|
-
const { onFile, children } = props;
|
|
17
|
-
// 负责拖拽样式
|
|
18
|
-
const [dragOver, setDragOver] = useState(false);
|
|
19
|
-
// 使用 `classNames` 拼 `className`:
|
|
20
|
-
const klass = classNames('viking-uploader-dragger', {
|
|
21
|
-
// 如果 `dragOver === true` 时,再加一个:`is-dragover`
|
|
22
|
-
'is-dragover': dragOver
|
|
23
|
-
});
|
|
24
|
-
// 上传流程
|
|
25
|
-
const handleDrop = (e) => {
|
|
26
|
-
e.preventDefault(); // 阻止默认行为
|
|
27
|
-
setDragOver(false); // 拖拽结束:改变拖拽样式
|
|
28
|
-
// dataTransfer: 浏览器 drop-API 的对象
|
|
29
|
-
// 包含: files(文件列表FileList)、items、types
|
|
30
|
-
// 通过 onFile回调 传回 Upload 处理
|
|
31
|
-
onFile(e.dataTransfer.files);
|
|
32
|
-
};
|
|
33
|
-
// 回调: 控制拖拽状态(改变样式)
|
|
34
|
-
const handleDrag = (e, over) => {
|
|
35
|
-
e.preventDefault();
|
|
36
|
-
setDragOver(over);
|
|
37
|
-
};
|
|
38
|
-
return (_jsx("div", { className: klass,
|
|
39
|
-
// e: 监听DragEvent拖拽事件对象
|
|
40
|
-
onDragOver: e => { handleDrag(e, true); }, onDragLeave: e => { handleDrag(e, false); }, onDrop: handleDrop, children: children }));
|
|
41
|
-
};
|
|
42
|
-
export default Dragger;
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import axios from 'axios';
|
|
3
|
-
const AxiosReact = () => {
|
|
4
|
-
/*
|
|
5
|
-
e: 这次变化事件的事件对象 -- “事件说明单”
|
|
6
|
-
e = {
|
|
7
|
-
谁触发的这次变化,
|
|
8
|
-
发生了什么,
|
|
9
|
-
当前 input 里有什么值
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
e.target: 触发这次事件的那个 DOM 元素(input 节点本身)
|
|
13
|
-
e: React.ChangeEvent<HTMLInputElement>: 给参数 e 标注类型
|
|
14
|
-
- React 里的 ChangeEvent
|
|
15
|
-
- 这个事件来自 <HTMLInputElement> 泛型参数
|
|
16
|
-
|
|
17
|
-
提前告诉大家:e 是“来自 input 元素的 change 事件对象” (贴标签)
|
|
18
|
-
- 放心大胆用:e.target.files
|
|
19
|
-
*/
|
|
20
|
-
const handleFileChange = (e) => {
|
|
21
|
-
// 1)取出 用户上传的 文件
|
|
22
|
-
/*
|
|
23
|
-
input type="file" 文件类型输入框:
|
|
24
|
-
- 有一个特殊属性 files: 用户当前选中的 文件列表 FileList
|
|
25
|
-
- 用户一次性可以选3个文件
|
|
26
|
-
FileList {
|
|
27
|
-
// File对象
|
|
28
|
-
0: File {
|
|
29
|
-
name: "a.png",
|
|
30
|
-
size: 12345,
|
|
31
|
-
type: "image/png"
|
|
32
|
-
|
|
33
|
-
// 内部隐藏
|
|
34
|
-
[[BinaryData]]: <文件二进制>0100110101...
|
|
35
|
-
},
|
|
36
|
-
|
|
37
|
-
1: File {
|
|
38
|
-
name: "b.jpg",
|
|
39
|
-
size: 23456,
|
|
40
|
-
type: "image/jpeg"
|
|
41
|
-
},
|
|
42
|
-
|
|
43
|
-
2: File {
|
|
44
|
-
name: "c.pdf",
|
|
45
|
-
size: 34567,
|
|
46
|
-
type: "application/pdf"
|
|
47
|
-
},
|
|
48
|
-
|
|
49
|
-
length: 3
|
|
50
|
-
}
|
|
51
|
-
*/
|
|
52
|
-
// 获取 文件列表
|
|
53
|
-
const files = e.target.files;
|
|
54
|
-
if (files) {
|
|
55
|
-
// 从文件列表中取出 第一个 File 对象 : 文件信息 + 文件内容(二进制)
|
|
56
|
-
const uploadedFile = files[0];
|
|
57
|
-
// 2)将 本次文件 放进 formData
|
|
58
|
-
const formData = new FormData();
|
|
59
|
-
// key-value 形式
|
|
60
|
-
formData.append("file", uploadedFile);
|
|
61
|
-
// 3)使用 Axios 发送请求
|
|
62
|
-
/*
|
|
63
|
-
常见参数: axios.post(url, data, config)
|
|
64
|
-
- url:地址
|
|
65
|
-
- data: 请求体body (这次 POST 请求要携带的数据)
|
|
66
|
-
- config配置项 对象:
|
|
67
|
-
*/
|
|
68
|
-
axios.post("https://jsonplaceholder.typicode.com/posts",
|
|
69
|
-
// Axios 发出去的不是 FormData 对象本身
|
|
70
|
-
/*
|
|
71
|
-
FormData 里装的是一个 File 对象引用
|
|
72
|
-
-> 当 Axios / fetch 看到: body: formData
|
|
73
|
-
-> 浏览器会开始做“编码
|
|
74
|
-
-> 先遍历 FormData 里的每一项
|
|
75
|
-
-> 变成 HTTP body 里的某一个 "part"
|
|
76
|
-
-> 每一个"part"包含:(文件相关的描述信息 + 二进制内容)
|
|
77
|
-
------WebKitBoundary123【包裹边界】
|
|
78
|
-
Content-Disposition: form-data; name="file"; filename="a.png"
|
|
79
|
-
Content-Type: image/png
|
|
80
|
-
|
|
81
|
-
<文件二进制内容>
|
|
82
|
-
------WebKitBoundary123--【结束边界】
|
|
83
|
-
*/
|
|
84
|
-
formData, {
|
|
85
|
-
// 设置 请求头信息
|
|
86
|
-
headers: {
|
|
87
|
-
// 表单文件数据
|
|
88
|
-
'Content-Type': 'multipart/form-data'
|
|
89
|
-
}
|
|
90
|
-
}).then(resp => {
|
|
91
|
-
console.log(resp);
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
return (_jsx("div", { className: "AxiosReact", style: { marginTop: '100px', marginLeft: '100px' }, children: _jsx("input", { type: "file",
|
|
96
|
-
// {/* 原生必须传,自定义不用传 name="myFile" */}
|
|
97
|
-
onChange: handleFileChange }) }));
|
|
98
|
-
};
|
|
99
|
-
export default AxiosReact;
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
const FromHtml = () => {
|
|
3
|
-
return (_jsx("div", { className: "App", style: { marginTop: '100px', marginLeft: '100px' }, children: _jsxs("form", { method: "post", encType: "multipart/form-data", action: "https://jsonplaceholder.typicode.com/posts", children: [_jsx("input", { type: "file", name: "myFile" }), _jsx("button", { type: "submit", children: "Submit" })] }) }));
|
|
4
|
-
};
|
|
5
|
-
export default FromHtml;
|
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useRef, useState } from 'react';
|
|
3
|
-
import axios from 'axios';
|
|
4
|
-
import UploadList from './uploadList';
|
|
5
|
-
import Dragger from './dragger';
|
|
6
|
-
/**
|
|
7
|
-
* 通过点击或者拖拽上传文件
|
|
8
|
-
* ### 引用方法
|
|
9
|
-
*
|
|
10
|
-
* ~~~js
|
|
11
|
-
* import { Upload } from 'vikingship'
|
|
12
|
-
* ~~~
|
|
13
|
-
*/
|
|
14
|
-
export const Upload = (props) => {
|
|
15
|
-
const { action, defaultFileList, beforeUpload, onProgress, onSuccess, onError, onChange, onRemove, name = 'file', headers, data, withCredentials, accept, multiple, children, drag, } = props;
|
|
16
|
-
// 文件输入框 ref 引用
|
|
17
|
-
const fileInput = useRef(null);
|
|
18
|
-
// (子组件)页面上 正在显示 的 上传文件列表
|
|
19
|
-
const [fileList, setFileList] = useState(defaultFileList || []);
|
|
20
|
-
// **`UploadList`** 子组件: 从 上传文件列表fileList 渲染一堆 列表项 class
|
|
21
|
-
// 上传列表状态更新器
|
|
22
|
-
const updateFileList = (updateFile, updateObj) => {
|
|
23
|
-
setFileList(prevList => {
|
|
24
|
-
return prevList.map(file => {
|
|
25
|
-
// 在列表里找到同一个 uid 文件
|
|
26
|
-
if (file.uid === updateFile.uid) {
|
|
27
|
-
// 更新部分字段
|
|
28
|
-
return { ...file, ...updateObj };
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
31
|
-
return file;
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
};
|
|
36
|
-
// 点击上传回调:用户点击 上传文件 输入框
|
|
37
|
-
const handleClick = () => {
|
|
38
|
-
// 用 ref 拿到“隐藏的” input元素
|
|
39
|
-
if (fileInput.current) {
|
|
40
|
-
// 调用浏览器的原生能力: 弹出 系统级文件选择框
|
|
41
|
-
fileInput.current.click();
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
// 文件上传回调:当有文件传来的时候触发
|
|
45
|
-
const handleFileChange = (e) => {
|
|
46
|
-
// 获取文件列表:类型为 FileList
|
|
47
|
-
const files = e.target.files;
|
|
48
|
-
if (!files) {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
// 调用 上传文件函数(含发送请求):决定 每个/不同文件 怎么处理
|
|
52
|
-
uploadFiles(files);
|
|
53
|
-
// 清空 文件输入框
|
|
54
|
-
if (fileInput.current) {
|
|
55
|
-
fileInput.current.value = '';
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
// 传递给 UploadList 子组件的 回调函数
|
|
59
|
-
const handleRemove = (file) => {
|
|
60
|
-
setFileList((prevList) => {
|
|
61
|
-
return prevList.filter(item => item.uid !== file.uid);
|
|
62
|
-
});
|
|
63
|
-
if (onRemove) {
|
|
64
|
-
onRemove(file);
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
// 函数: 上传文件: 决定 每个文件 上传
|
|
68
|
-
// (beforeUpload: “上传前钩子”)
|
|
69
|
-
const uploadFiles = (files, test) => {
|
|
70
|
-
// 传来的文件列表 FileList类型,不是数组 =》 转为数组
|
|
71
|
-
let postFiles = Array.from(files);
|
|
72
|
-
//
|
|
73
|
-
if (test) {
|
|
74
|
-
console.log('drag', postFiles[0]);
|
|
75
|
-
}
|
|
76
|
-
// 遍历 数组 每一项
|
|
77
|
-
postFiles.forEach(file => {
|
|
78
|
-
// 没有配置 beforeUpload,直接上传
|
|
79
|
-
if (!beforeUpload) {
|
|
80
|
-
post(file);
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
// 用户使用了 beforeUpload => 需要等待 用户的异步处理结果(例如压缩图片)
|
|
84
|
-
// beforeUpload(file)用户在钩子里写的回调: 会返回 Promise<newFile>
|
|
85
|
-
// 获取 Promise<newFile> 用这个处理完的 File 对象发送
|
|
86
|
-
// 执行用户传进来的回调函数,并把它的返回值接住,放进 result
|
|
87
|
-
const result = beforeUpload(file);
|
|
88
|
-
//
|
|
89
|
-
if (result && result instanceof Promise) {
|
|
90
|
-
// 获取 异步回调 reslove(newFile)后的 newFile
|
|
91
|
-
result.then(processedFile => {
|
|
92
|
-
post(processedFile); // 发送用户异步处理完的 新File文件
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
else if (result !== false) {
|
|
96
|
-
// 用户使用了拦截:return false ==> 永远不会触发 post, 不上传
|
|
97
|
-
// 返回 true → 上传原文件
|
|
98
|
-
post(file);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
};
|
|
103
|
-
// 函数: 发axios请求
|
|
104
|
-
const post = (file) => {
|
|
105
|
-
// 改造浏览器原生File,创建 内部文件对象 `_file` (文件本体 + 上传状态)
|
|
106
|
-
let _file = {
|
|
107
|
-
uid: Date.now() + 'upload-file',
|
|
108
|
-
status: 'ready',
|
|
109
|
-
name: file.name,
|
|
110
|
-
size: file.size,
|
|
111
|
-
percent: 0,
|
|
112
|
-
raw: file
|
|
113
|
-
};
|
|
114
|
-
// 请求发送之前放进 fileList,列表先显示出来
|
|
115
|
-
setFileList(prevList => {
|
|
116
|
-
return [_file, ...prevList];
|
|
117
|
-
});
|
|
118
|
-
// 2) 构建 `FormData`
|
|
119
|
-
const formData = new FormData();
|
|
120
|
-
formData.append(name || 'file', file);
|
|
121
|
-
// 如果传了 `data`, 额外字段也 append 进 FormData
|
|
122
|
-
// (例如 `userId`、`token`)
|
|
123
|
-
if (data) {
|
|
124
|
-
Object.keys(data).forEach(key => {
|
|
125
|
-
formData.append(key, data[key]);
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
// 使用 axios 发送 POST 请求
|
|
129
|
-
axios.post(action, formData, {
|
|
130
|
-
headers: {
|
|
131
|
-
...headers,
|
|
132
|
-
'Content-Type': 'multipart/form-data'
|
|
133
|
-
},
|
|
134
|
-
// 跨域请求 凭证信息(Cookie)
|
|
135
|
-
// 需要 后端 允许跨域携带凭证: Access-Control-Allow-Credentials: true
|
|
136
|
-
withCredentials,
|
|
137
|
-
// axios 提供的 请求配置回调(“系统回调”)
|
|
138
|
-
// (不需要手动调用)上传过程中,axios 内部自动不断触发 onUploadProgress
|
|
139
|
-
onUploadProgress: (e) => {
|
|
140
|
-
// 把字节进度算成百分比
|
|
141
|
-
const total = e.total ?? 0;
|
|
142
|
-
const percentage = total ? Math.round((e.loaded * 100) / total) : 0;
|
|
143
|
-
// 更新 fileList 中这条文件的 percent/status
|
|
144
|
-
if (percentage < 100) {
|
|
145
|
-
// 更新 React state(驱动UI):让 UploadList 子组件重新渲染
|
|
146
|
-
updateFileList(_file, { percent: percentage, status: 'uploading' });
|
|
147
|
-
// 更新当前 _file 对象,保证传给回调的值是新的
|
|
148
|
-
_file.status = 'uploading';
|
|
149
|
-
_file.percent = percentage;
|
|
150
|
-
// 将 axios 的 onUploadProgress 得到的上传进度结果,包装一层
|
|
151
|
-
// 提供给 Upload 组件的外部使用者 外部钩子onProgress:给组件外部使用
|
|
152
|
-
if (onProgress) {
|
|
153
|
-
onProgress(percentage, _file);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}).then(resp => {
|
|
158
|
-
// 成功时:更新React UI内部状态
|
|
159
|
-
updateFileList(_file, { status: 'success', response: resp.data });
|
|
160
|
-
// 更新当前 _file 对象,保证传给回调的值是新的
|
|
161
|
-
_file.status = 'success';
|
|
162
|
-
_file.response = resp.data;
|
|
163
|
-
// 通知外部 onSuccess / onChange 钩子
|
|
164
|
-
if (onSuccess) {
|
|
165
|
-
onSuccess(resp.data, _file);
|
|
166
|
-
}
|
|
167
|
-
if (onChange) {
|
|
168
|
-
onChange(_file);
|
|
169
|
-
}
|
|
170
|
-
}).catch(err => {
|
|
171
|
-
// 失败时:更新React UI内部状态
|
|
172
|
-
updateFileList(_file, { status: 'error', error: err });
|
|
173
|
-
// 更新当前 _file 对象,保证传给回调的值是新的
|
|
174
|
-
_file.status = 'error';
|
|
175
|
-
_file.error = err;
|
|
176
|
-
//
|
|
177
|
-
if (onError) {
|
|
178
|
-
onError(err, _file);
|
|
179
|
-
}
|
|
180
|
-
if (onChange) {
|
|
181
|
-
onChange(_file);
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
};
|
|
185
|
-
return (_jsxs("div", { className: "viking-upload-component", children: [_jsxs("div", { className: "viking-upload-input", style: { display: 'inline-block' }, onClick: handleClick, children: [children, drag ?
|
|
186
|
-
// 传给 Dragger子组件回调函数 onFile
|
|
187
|
-
// 当用户拖拽文件,Dragger 的onDrop状态触发 onFile(files)
|
|
188
|
-
_jsx(Dragger, { onFile: (files) => { uploadFiles(files, true); }, children: children }) :
|
|
189
|
-
// 如果 drag = false, 直接渲染 children(普通模式)
|
|
190
|
-
children, _jsx("input", { className: "viking-file-input", style: { display: 'none' }, ref: fileInput, onChange: handleFileChange, type: "file", accept: accept, multiple: multiple })] }), _jsx(UploadList, { fileList: fileList, onRemove: handleRemove })] }));
|
|
191
|
-
};
|
|
192
|
-
export default Upload;
|