工作中的小收获

记录开发工作中过程中的小收获或者小技巧,解决一些小问题的方式等,勿以收获小而不为,常更!!!

  • 多行文本溢出省略

    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-filterfilter还是有很多区别,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”)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值