记录开发工作中过程中的小收获或者小技巧,解决一些小问题的方式等,勿以收获小而不为,常更!!!
-
多行文本溢出省略
overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
-
微应用项目中,ant中的弹窗,确认框等组件会被遮盖,需要配置ant中的ConfigProvider 包裹在微应用最外层,这样弹窗这些就会挂载到当前微应用的根节点,默认是挂载到body的!
<ConfigProvider prefixCls={process.env.ANT_PREFIX} getPopupContainer={() => container} locale={zhCN}> ...router </ConfigProvider>
-
树结构隔级收起
const [state,setState] = useState({ autoExpandParent:true }) autoExpandParent={state.autoExpandParent} onExpand={(expandedKeys) => { setState({ expandedKeys, autoExpandParent: false }); }}
-
使用ant中 table,dataSource为useState的值,state改变table不刷新
const ConfigTables = () => { const [state,setState] = useState([]) const onOk = () =>{ //valuecopy = state这样写就不会刷新 let valuecopy = [...state]; state?.forEach((item,index)=>{ if(item.key == currentItem.key){ valuecopy.splice(index,1) } }) setState(valuecopy) } return <Table dataSource={state} columns={columns} rowKey="email" /> ) } export default ConfigTables
-
本地联调的时候接口路由无统一前缀,ng代理配置
1.统一给接口路由加一个统一前缀const urlPrefix = '/api' //示例接口 queryConfig (data) { return Service.$http({ url: `${urlPrefix}/configManager/queryConfig/query`, method: 'post', data, headers: getHeader(), requestId: 'queryConfig', }); //ng代理这里 const proxy = require('http-proxy-middleware'); const ip = 'http://192.168.152.106:10011/' const proxyConfig = { '/api': { target: `${ip}`, changeOrigin: true, pathRewrite: { //主要是这个属性 '/api': '', }, }, }; }
-
犯了个异步引发的错误(一个页面两个数据不同的Tree,同时请求接口,返回结果慢的会覆盖另一个Tree的数据,导致两个Tree一模一样)
扁平数据结构的数据,统一再最外层加一层行政区划,然后传入转化为Tree结构的函数内输出Tree结构的数据!我是这样写的:
1.在最外面定义了公用的最外层数据
let imitateAll: catelogField[] = [
{
name: '行政区划树',
code: null,
child: [],
level: 0,
parentCode: null,
deviceCount: 0,
tollgateCount: 0,
totalDeviceCount: 0,
totalTollgateCount: 0,
},
];
2.分别请求各自数据的接口
useEffect(() => {
getTreeconfig('device').then((res) => {
setdeviceConfig(res);
});
getTreeconfig('bayonet').then((res) => {
setbayonetConfig(res);
});
}, [currentItem, selectedPlatformId]);
3.我getTreeconfig里面这样写:
const getTreeconfig = (type: string) => {
return new Promise((resolve, reject) => {
ApiService.queryAdministrativeDivisionsCatelog({ type: type === 'device' ? '0' : '1' }).then((res: any) => {
const data = computTreeList(res.data, 'code', 'parentCode', false);
const deepdata = cloneDeep(data); //这里deepdata 都是各自的结果没有错
resolve({
data:
updateTreeData(
// 从这里开始,相当于每次传入的都是返回慢的那个tree的数据,deepdata每次都是后面的,所以返回的数据两 个一模一样,但是上面deepdata是各自结果啊,val.child = deepdata;替换了啊,所以我调试了半天都没找到问题!!!!
imitateAll.map((val: catelogField) => {
val.child = deepdata;
return val;
})
) || [],
});
})
});
};
4. 于是我改成这样就好了
const getTreeconfig = (type: string) => {
return new Promise((resolve, reject) => {
ApiService.queryAdministrativeDivisionsCatelog({ type: type === 'device' ? '0' : '1' }).then((res: any) => {
//公共部分我写进来就对了
let imitateAll: catelogField[] = [
{
name: '行政区划树',
code: null,
child: [],
level: 0,
parentCode: null,
deviceCount: 0,
tollgateCount: 0,
totalDeviceCount: 0,
totalTollgateCount: 0,
},
];
const data = computTreeList(res.data, 'code', 'parentCode', false);
const deepdata = cloneDeep(data);
resolve({
data:
updateTreeData(
imitateAll.map((val: catelogField) => {
val.child = deepdata;
return val;
})
) || [],
});
})
});
};
原因:两个请求接口是异步的,虽然同时请求但是,接口数据不同返回结果的速度也就不一样,但是速度差距很小很小,就导致在进入 updateTreeData这个函数之前,imitateAll其实是经历了两次变化的,他先是由最初状态变为了将接口返回快的那个数据塞入了自己的child,紧接着几乎同时第二个接口返回的数据也在imitateAll内处理完了,由于imitateAll是外部公用的,所以可以理解为进入updateTreeData的数据都是第二个接口的!!!!唉~~~~~ 一上午又没了
- 最优的扁平化数据结构,转Tree数据结构
扁平数据结构:
[
{
"id": 1226,
"name": "江西省",
"code": 360000,
"level": 1,
"parentCode": null,
"parentCodes": null
},
{
"id": 1237,
"name": "景德镇市",
"code": 360200,
"level": 2,
"parentCode": 360000,
"parentCodes": [
360000
]
},
{
"id": 1240,
"name": "浮梁县",
"code": 360222,
"level": 3,
"parentCode": 360200,
"parentCodes": [
360000,
360200
]
},
{
"id": 1238,
"name": "昌江区",
"code": 360202,
"level": 3,
"parentCode": 360200,
"parentCodes": [
360000,
360200
]
}
]
//树结构:
{
"id": 1226,
"name": "江西省",
"code": 360000,
"level": 1,
"parentCode": null,
"parentCodes": null
"children": [
{
"id": 1237,
"name": "景德镇市",
"code": 360200,
"level": 2,
"parentCode": 360000,
"parentCodes": [
360000
]
"children": [
{
"id": 1240,
"name": "浮梁县",
"code": 360222,
"level": 3,
"parentCode": 360200,
"parentCodes": [
360000,
360200
]
},
{
"id": 1238,
"name": "昌江区",
"code": 360202,
"level": 3,
"parentCode": 360200,
"parentCodes": [
360000,
360200
]
}
]
}
]
}
// 数据源,唯一标识,父级字段,是否深克隆
const computTreeList = (list: [ ], id = 'id', pid = 'parentId', isNoDeep: boolean) => {
let treeData;
if (!isNoDeep) {
treeData = cloneDeep(list);
} else {
treeData = list;
}
let treeMap: any = {};
treeData.forEach((v: any) => {
treeMap[v[id]] = v;
});
//treeMap:
// {
// "360000": {
// "id": 1226,
// "name": "江西省",
// "code": 360000,
// "level": 1,
// "parentCode": null,
// "parentCodes": null
// },
// "360200": {
// "id": 1237,
// "name": "景德镇市",
// "code": 360200,
// "level": 2,
// "parentCode": 360000,
// "parentCodes": [
// 360000
// ]
// },
// "360202": {
// "id": 1238,
// "name": "昌江区",
// "code": 360202,
// "level": 3,
// "parentCode": 360200,
// "parentCodes": [
// 360000,
// 360200
// ]
// },
// "360222": {
// "id": 1240,
// "name": "浮梁县",
// "code": 360222,
// "level": 3,
// "parentCode": 360200,
// "parentCodes": [
// 360000,
// 360200
// ]
// }
// }
let arr: [] = [];
for (let i: never | number = 0, l = treeData.length; i < l; i++) {
//当前元素
const item: any = treeData[i];
let hasParent = false;
//是否有父元素
if (item[pid] && treeMap[item[pid]]) {
hasParent = true;
//父元素
const item2 = treeMap[item[pid]];
!Array.isArray(item2.children) && (item2.children = []);
//将当前元素添加到父元素children
item2.children.push(item);
}
//不存在父元素直接添加到新数组
!hasParent && arr.push(i as never);
}
treeMap = null;
return treeData.filter((_, index) => arr.includes(index as never));
};
- 编码习惯:
一般编码的时候喜欢使用一些es6的数组api,为了避免不存在值写的时候一般是
data?.forEarch(item=>{
...
})
但是今天才发现,'?'防不住空字符串!!! 然后我就喜提bug!
-
bug:毛玻璃这种模糊背景与高保真不一致(测试看不到模糊样式,我用的谷歌最新,测试用的谷歌72)
原因:我使用CSS样式backdrop-filter: blur(10px); 实现的,但是这个属性只兼容谷歌76以上,并切不兼容火狐浏览器。但是可以使用filter属性进行兼容,backdrop-filter 和 filter还是有很多区别,filter实现相对麻烦并且有一定缺陷不如backdrop-filter。 -
导入接口联调,如图:
使用ant中的上传组件(uoload),使用其中属性:
//手动拦截文件上传,自定义上传方式
customRequest:(file) => adddevice(file),
//限制文件类型
accept: ".xlsx",
自定义上传方式
const adddevice = (value) => {
const formData = new FormData()
formData.append('xlsx', value.file)
console.log(formData,44444) //这里打印永远是空
Service.batchimport(formData).then(res => {
if (res.code === 200) {
.......
}
}).catch(error => {
console.log(error)
})
}
对请求中的formData没听过,以为和Fome组件的formdata是一样的,一开始直接formdata={xlsx:file},接口报错,其次,这种请求需要设置请求头,“Content-Type”: “multipart/form-data”,最后在打印哪里纠结半天,因为哪里打印出来是空一直就没有写下面的逻辑。
原因:FormData是一种特殊的对象类型,不可序列化,因此使用console.log()直接打印显示的是FormData原型
解决:遍历FormData,逐个打印键值对
form.forEach((key, val) => {
console.log("key %s: value %s", key, val)
})
- 使用antd中的Form组件,Fome.Item标签下只接受一个children时,才能够使用它的默认值,校验,更改某个表单值等等属性。但是遇到这种:
1.定义个组件,暴露onchonge方法,和value
const MySwitch = ({ value, onChange }) => {
return (
<div >
<Switch checked={value} onChange={onChange} />
<div >开启后此订阅任务订阅类别数据将共享给视频云。</div>
</div>
);
};
2.使用
<Form.Item
label={<LabelVal title={'数据推送'} required={false} />}
initialValue={false}
name="resourceFeatureDeclare"
rules={[{ required: true, message: '请选择返回结果特征值约定' }]}
>
<MySwitch />
</Form.Item>
这样就可以表单在多个元素是,一样可以使用ant中form的便利了!!!
- 滑动验证插件不兼容,手写滑动验证时,由于红色区域是img标签,点击红色区域img鼠标拖动时,这个img会被拖,img会作为鼠标事件元素,而中断我原本的拖拽事件,使得不好用,使用css中:pointer-event属性,可以指定在什么情况下元素可以成为鼠标事件,在img中添加css属性pointer-event:none;可以解决!
- React中配置js,ts的@src路径
// js:在package.json同级下创建jsconfig.json
{
"compilerOptions": {
"experimentalDecorators": true,
"baseUrl": "src",
"paths": {
"src/*": ["./src/*"],
"@src/*": ["./src/*"]
},
"jsx": "react"
},
"exclude": ["node_modules", "public/static", "public/library", "build"],
//重启
}
//ts:在package.json同级下创建tsPaths.json
//tsPaths.json:
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@src/*": [
"src/*"
]
}
}
}
在tsconfig.json中加入一行(“extends”: “./tsPaths.json”)