# antd
# antd 组件中 default 属性的坑
default 属性只在第一次渲染时有效,只要组件渲染了 2 次(或以上)则此属性无效,解决方式就是类似如下:
# Tree
const generateTree = () => {
return treeData.length === 0 ? null : (
<Tree treeData={treeData} onSelect={onSelect} defaultExpandAll></Tree>
);
};
2
3
4
5
# Select
placeholder
如果需要显示【placeholder】信息,则 value 值必须为undefined,否则不会显示,即使 value 值为''或者null
generateUserSelect = () => {
const otherProps = this.props;
const { fetching, data, value } = this.state;
if (!!data && data.length > 0) {
return (
<Select
showSearch
showArrow={false}
value={value}
notFoundContent={fetching ? <Spin size="small" /> : null}
filterOption={false}
onSearch={this.fetchUser}
onChange={this.onChange}
style={{ width: "120px" }}
{...otherProps}
>
{data.map((d) => (
<Option key={d.id}>{d.name}</Option>
))}
</Select>
);
}
return <Spin size="small" />;
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
支持搜索功能:Option 增加自定义属性,如下为:name,Select 中增加optionFilterProp,并指定其过滤属性即可
<Select
placeholder={formatMessage({ id: "all.circuits" })}
showArrow
style={{ width: "141px" }}
getPopupContainer={(triggerNode) => triggerNode.parentElement}
allowClear
optionFilterProp="name"
showSearch
>
<Option value="" disabled>
{formatMessage({ id: "all.circuits" })}
</Option>
{linkedDevices.length > 0 &&
linkedDevices.map((item) => (
<Option
key={item.id}
name={`${item.name}${item.no}`}
>{`${item.name}-${item.no}`}</Option>
))}
</Select>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# antd 清除 select 内容
通过给 Select 组件新增 allowClear 属性。注意:allowClear 也会触发 onChange 方法,所以,也要单独处理一下,因为 value 和 element 为 undefined。
<Select {...this.props} placeholder="请选择" allowClear={true}>
...
</Select>
2
3
# 自定义 antd Select 组件样式
.ant-select-dropdown {
/* 定义下拉框背景色 */
background: #4e5458;
/* 定义下拉框中文字颜色 */
.ant-select-dropdown-menu-item {
color: #ffffff;
}
/* 定义选中的选项的背景色 */
.ant-select-dropdown-menu-item-selected {
background: #457173;
}
}
/* 定义鼠标移动到选项上时,背景色 */
.ant-select-dropdown-menu-item:hover:not(.ant-select-dropdown-menu-item-disabled) {
background: #163240;
}
/* 定义展开下拉框时,第一个选项的背景色 */
.ant-select-dropdown-menu-item-active:not(.ant-select-dropdown-menu-item-disabled) {
background: #163240;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Input
const inputRef = useRef();
useEffect(() => {
const { types, keyWord } = defaultSelected;
setCheckedList(types);
// console.info({ types }, '--------------');
// console.info({ keyWord }, '+++++++++++++++++++');
// console.info({ selectCount }, '+++++++++++++');
setIndeterminate(types && types.length > 0 && types.length < selectCount);
setCheckAll(types && types.length > 0 && types.length === selectCount);
// console.info(defaultSelected.length, selectCount, '00000000000000000');
setDefaultKeyWord(keyWord);
// inputRef.current = keyWord;
if (keyWord) {
inputRef.current.state.value = keyWord;
// console.info(inputRef.current?.state?.value, '000000000000');
}
}, [defaultSelected, selectCount]);
<Input
placeholder={formatMessage({ id: "oneMapComp.device.detail.keyWord" })}
onChange={changeValue}
style={{ marginLeft: 10, width: 160 }}
ref={inputRef}
/>;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
form
当然如果使用 antd 的 form 组件的话,可以使用 initialValue 来显示初始值
# input-defaultvalue
关于 defaultValue
由于 defaultValue 只在第一次绘制时会启用。
这意味着,如果首次绘制为"",而后面绘制为"value",则 defalutValue 始终为""
# maxLength
<Input
placeholder="请输入账号"
disabled={account}
maxLength="30"
autoComplete="off"
/>
2
3
4
5
6
# inputNumber
<InputNumber
formatter={(value) => value}
parser={(value) => parseInt(value) || ""}
style={{ width: "100%" }}
step={1}
onChange={(val) => this.onChangeIpt(1, val)}
/>
2
3
4
5
6
7
# 关于数字的校验问题
- 增加
whitespace为 true
rules: [
{
required: true,
whitespace: true,
message: formatMessage({
id: 'devices.device.form.factory',
}),
},
],
2
3
4
5
6
7
8
9
此时即使存在初始值,也会报错,此时可采取两种解决方法
- 删掉
whitespace: true, - 增加
type: 'number'
rules: [
{
required: true,
whitespace: true,
type: 'number',
message: formatMessage({
id: 'devices.device.form.factory',
}),
},
],
2
3
4
5
6
7
8
9
10
Type Indicates the type of validator to use. Recognised type values are:
- string: Must be of type string. This is the default type.
- number: Must be of type number.
- boolean: Must be of type boolean.
- method: Must be of type function.
- regexp: Must be an instance of RegExp or a string that does not generate an exception when creating a new - RegExp.
- integer: Must be of type number and an integer.
- float: Must be of type number and a floating point number.
- array: Must be an array as determined by Array.isArray.
- object: Must be of type object and not Array.isArray.
- enum: Value must exist in the enum.
- date: Value must be valid as determined by Date
- url: Must be of type url.
- hex: Must be of type hex.
- email: Must be of type email.
- any: Can be any type.
# 关于 Tab 组件
- 删除 tab 组件下方的线条
.ant-tabs-card-bar {
border: none;
}
2
3
# 路由
{
path: '/weibao',
name: 'wb',
routes: [
{
path: '/weibao/im',
name: 'im',
routes: [
{
path: '/weibao/im/items',
name: 'items',
component: './wb/im/items',
},
{
path: '/weibao/im/train',
name: 'train',
component: './wb/im/train',
},
],
},
{
path: 'weibao/dm',
name: 'dm',
}
],
},
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
设置成上述,则可以刷新页面时正常,但是设置成下述,则刷新时会 404
{
path: '/wb',
name: 'wb',
routes: [
{
path: '/wb/im',
name: 'im',
routes: [
{
path: '/wb/im/items',
name: 'items',
component: './wb/im/items',
},
{
path: '/wb/im/train',
name: 'train',
component: './wb/im/train',
},
],
},
{
path: 'wb/dm',
name: 'dm',
}
],
},
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 路由跳转总结
- 1、直接点击跳转页面:
<a href="跳转路径>点击跳转</a>
<Link to="跳转路径">点击跳转</Link>
2
3
- 2、点击按钮之后跳转:
引入:
import { hashHistory } from 'react-router';
// 在方法里面加入:
hashHistory.push('跳转路径')
2
3
4
- 3、browserHistory 带参数跳转
import{browserHistory}from'dva/router';
browserHistory.push('/orders/orderdetail?oderId='+item.order);
// 在router里面设置路径的时候不需要加入参数
path:'orders/orderdetail',
2
3
4
5
6
7
- 4、关于路由获取参数的问题:
location.pathname 设置或获取对象指定的文件名或路径。
location.href 设置或获取整个 URL 为字符串。
location.port 设置或获取与 URL 关联的端口号码。
location.protocol 设置或获取 URL 的协议部分。
location.hash 设置或获取 href 属性中在井号“#”后面的分段。
location.host 设置或获取 location 或 URL 的 hostname 和 port 号码。
location.search 设置或获取 href 属性中跟在问号后面的部分。
2
3
4
5
6
7
- 5、routerRedux 路由跳转
1、不带参数跳转:
dispatch(
routerRedux.push({
pathname: "/couponDetail",
})
);
2
3
4
5
2、带参数跳转
dispatch(
routerRedux.push({ pathname: "/couponDetail", query: 要携带的参数object })
);
// 注意:通过location.query.参数字段来获取参数值
2
3
4
3、在 effect 里面跳转
yield put (routerRedux.replace({ pathname: '/domains/buy/pay', query: payload }));
# modal
# modal 位置
书写 modal 的位置,以防出现不必要的点击事件,放到最外层的节点中去
<ShowDeviceLocation
onCancel={hideLocation}
visible={locationVisible}
deviceId={deviceData.id}
/>
<Modal
visible={energyVisible}
closable
destroyOnClose
onCancel={hideEnergy}
width={1024}
height={400}
footer={null}
title={null}
maskClosable={false}
className={styles.blackModal}
closeIcon={<img alt="" src={closeIcon} />}
>
{generateTabPane()}
</Modal>
</React.Fragment>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
不要放到父组件的某个节点中
<ShowDeviceLocation
onCancel={hideLocation}
visible={locationVisible}
deviceId={deviceData.id}
/>
<Modal
visible={energyVisible}
closable
destroyOnClose
onCancel={hideEnergy}
width={1024}
height={400}
footer={null}
title={null}
maskClosable={false}
className={styles.blackModal}
closeIcon={<img alt="" src={closeIcon} />}
>
{generateTabPane()}
</Modal>
</div>
</React.Fragment>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# modelFoot
一般应用场景,详情不需要底部按钮,新增和修改需要。
通过父组件传递一个空的字符串或者 {footer: null} 给 Modal 组件进行属性解构。
# 自定义 Modal
查看元素可知,Modal 是在界面构建完成之后,由 js 控制,动态的添加,所以想事先获取 ant-modal-body 中 DOM 元素的节点是不可能的,但是一般情况也不会去获取它。
自定义 Modal,解决上述的问题。
- 1:因为我们使用的是 antd,所以,下面的样式是不需要引入的。这个跟 antd 的 Modal 样式重复。
- 2:Modal 的隐藏和显示,是通过控制 class 为 ant-modal-mask 和 ant-modal-wrap 两个 div 的显示和隐藏。
- 通过给 ant-modal-mask 的 div,添加另外一个 className:ant-modal-mask-hidden,来控制其隐藏,也可以通过 display 来控制。
- 通过给 ant-modal-wrap 设置行内样式 display: none,来控制其隐藏。不过,也可以使用 className,随便都可以。
// 界面布局:
<div className="ant-modal-mask" ></div>
<div tabIndex="-1" className="ant-modal-wrap " role="dialog" aria-labelledby="rcDialogTitle0" style={{}}>
<div role="document" className="ant-modal" style={{ width: '920px' }}>
<div className="ant-modal-content">
<div className="ant-modal-header">
...
</div>
<div className="ant-modal-body" style={{ background: 'rgb(16, 16, 17)' }}>
...
</div>
</div>
</div>
<div tabIndex="0" style={{ width: '0px', height: '0px', overflow: 'hidden' }}>
sentinel
</div>
</div>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* // 样式: */
.ant-modal-mask {
/* // 遮罩层 */
position: fixed;
top: 0;
right: 0;
left: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.65);
height: 100%;
z-index: 1000;
filter: alpha(opacity=50);
}
.ant-modal-wrap {
position: fixed;
overflow: auto;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1000;
-webkit-overflow-scrolling: touch;
outline: 0;
}
.ant-modal {
font-family: "Chinese Quote", -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
"Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 14px;
font-variant: tabular-nums;
line-height: 1.5;
color: rgba(0, 0, 0, 0.65);
-webkit-box-sizing: border-box;
box-sizing: border-box;
margin: 0;
padding: 0;
list-style: none;
position: relative;
width: 920px;
margin: 0 auto;
top: 100px;
padding-bottom: 24px;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 左侧菜单调整宽度设置
通过在 Sider 组件,
设置 width,调整菜单的宽度,通过设置 collapsedWidth,调整调整缩进的宽度。
<Sider
style={{ background: "#1D2023", height: "100%" }}
trigger={null}
collapsible
collapsed={this.state.collapsed}
width={140}
collapsedWidth={40}
>
<BaseMenu
toggle={this.toggle}
collapsed={this.state.collapsed}
history={history}
location={location}
/>
</Sider>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# menu
menu 必须放在 Sider 中,才能实现缩回去的,这个有特定的布局。
<Sider
style={{ background: "#1D2023", height: "100%" }}
trigger={null}
collapsible
collapsed={this.state.collapsed}
width={140}
collapsedWidth={40}
>
<BaseMenu
toggle={this.toggle}
collapsed={this.state.collapsed}
history={history}
location={location}
/>
</Sider>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Button 组件
Antd Select 组件(onBlur)+Button 按钮 (handleClick)如何让 handleClick 优先触发
TIP
按钮不要用onClick,用onMouseDown,可以保证在 onBlur 事件之前触发。
# 过渡组件 dva-loading
该组件仅仅监听异步加载状态,这从它的调用方式就可以看出来
const isLoading = loading.effects['user/query'],其中user/query 是 model 中的异步请求方法。
loading 在异步请求发出那一刻会持续监听该异步请求方法的状态,在异步请求结束之前 isLoading 的值一直是 true,当此次异步请求结束时 isLoading 的值变成 false,同时 loading 对象停止监听。
loading 有三个方法,其中 loading.effects['user/query'] 为监听单一异步请求状态,当页面处于异步加载状态时该值为 true,当页面加载完成时,自动监听该值为 false。
# Progress
针对【type="dashboard"】的仪表盘类型的进度条,如何调整未覆盖进度的背景色(svg 中的 class="ant-progress-circle-trail"的 stroke 属性)
.ant-progress-circle-trail {
stroke: transparent !important;
}
2
3
# Upload
# Upload错误集锦
must set key for <rc-animate> children
初始回填的文件列表是从后端拿的,直接传给了upload组件,虽然设置的uid为filename但是名字有''的情况,此时识别为无uid。antd文档写了uid是唯一标识符,没有
uid导致了此错误