一周又过去了,10月的最后一天,时间真的过的好快,最近自己好懒干什么都没动力,感觉自己技术越来越菜了,也不知道如何提升,大伙茫期的时候都是如何度过呢,每天看掘金各种大佬开源各种新项目,自己连公司项目之前的代码好像还都没弄明白,工作俩月了业务也没搞明白,心里的落差有点大,希望下周能调整过来吧!
推荐一下阿里开源的ahooks,用React的小伙伴可以了解一下,里面有很多好用的自定义hook!
1、判断类型
不要用type of,不够准确,例如用type of判断null的类型是对象。
export const isType = (obj, type) => Object.prototype.toString.call(obj) === `[object ${type}]`;
//Object.prototype.toString.call是最准确判断类型的方法
2、文本省略
一般可能用在表单、表格里文字超出部分,其实如果想简单的话只是超出省略号的话css三行就能搞定 但是可能遇到想显示前面和后面省略中间类似于银行卡号的,可以用这个组件
const Ellipsis = (props) => {
const {title, length = 6, style = {}, ext =false, ellipsis= '...'} = props
//title:文本,length:限制长度,style:文字样式,ext:中间省略号后面的是否显示
let affix = ''
if(ext){
const titleArr = title.splice('.')
const extName = titleArr[titleArr.length -1] //获取最后一部分
const lastSecondName = titleArr[titleArr.length - 2] //获取倒数第二部分
const llast = lastSecondName[lastSecondName.length -1] //获取倒数第二部分的最后一个字符
affix = titleArr.length >= 2 ? `${llast}.${extName}` : ''
}
if(title.length <= length){ //实际的长度小于设定的
return (
<span style={style}>
{title}
{affix}
</span>
}
return (
<Tooltip title={title}>
<span style={style}>
{title.slice(0, length)}
{ellipsis}
{affix}
</span>
</Tooltip>
);
}
简易版文字省略
const Ellipsis = (props) => {
const { title, length = 6 } = props;
if (!title || title === '-') return '-';
if (title.length <= length) {
return title;
}
return (
<Tooltip title={title}>
<span>{title.slice(0, length)}...</span>
</Tooltip>
);
};
export default Ellipsis;
3、获取每一级产品的数量
当时有个需求是统计1、2、3、4级及4级以下的企业数量渲染到页面,后端返回的是树形结构的数据,需要用递归进行处理,我这里只是到四层,如果有更多children,自己再声明个变量就行了,递归是个比较常用的处理数据的思路尤其是在树结构、下拉框这种,但是我感觉后端应该也能处理hhhhh,如果你们后端能处理就让他处理好了嘿嘿嘿
const getInfoData =(
data=[], level=1, infoDt={level1:0, level2:0, level3:0, level4:0, level4_down:0}
) => {
data.forEach(item => {
if(item.level > 4) {
infoDt.level4_down +=1
}else{
infoDt[`level${level}`] +=1
}
})
if(item.children && item.children.length > 0){
infoDt = {...infoDt, ...getInfoData(item.children, level+1, infoDt)}
}
return infoDt
}
4、平级转树
这种要看后端返回的数据是什么结构的,这里的场景是后端传来的每一条企业数据他有一个parentId的字段属性,需要转换为Tree数据,一个children字段属性是一个数组,里面有他的所有子企业。
1、先把所有的数据遍历,把id放到map里当key保存
2、先把每一条数据的孩子都设置为空
3、再次遍历1588条数据,每一条当前数据为 node
4、展开把第二个参数合并到新的对象 newNode
5、判断当前node节点是否有父节点id,找出对应的索引,放入他的子节点中
map ={ //1000条
"1002672720837609472": 0
"1002672721315760128": 1
"1002672722255284224": 2
...
}
const refactorTreeData(treeData, refactorNode) {
const map = {} //保存节点的id
let node //遍历的每一条临时数据
const children = []
const roots = []
let i
const newList = list
for(i=0, i < newList.length, i++){
map[newList[i].id] = i
newList[i].children = []
}
for(i=0, i < newList.length, i++){
node = newList[i]
const newNode = { ...node, ...refactorNode(node) }
if(newList[map[node.parentId]] && newList[map[node.parentId]].children){
newList[map[node.parentId]].children.push(newNode)
}else{
roots.push(newNode)
}
}
return roots
}
5、Table表格组件的滚动条样式
当columns的属性比较多时肯定要向右滚动,默认滚动条有点丑....
//Antd中的Table表格组件的滚动条样式
:global {
.ant-space-align-center {
align-items: flex-start;
}
.ant-table-wrapper {
.ant-table-content {
&::-webkit-scrollbar {
width: 10px;
height: 10px;
background-color: #f5f5f5;
}
/*定义滚动条轨道 内阴影+圆角*/
&::-webkit-scrollbar-track {
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
border-radius: 10px;
background-color: #fff;
}
/*定义滑块 内阴影+圆角*/
&::-webkit-scrollbar-thumb {
border-radius: 10px;
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
background-color: #aaa;
}
}
}
}
6、Excel导出
import XLSX from 'xlsx';
const exportExcel = ({ headers, data, fileName = 'default.xlsx' }, refactorWorkbook) => {
const xlsxHeaders = headers
.map((item, i) => ({
key: item.key,
title: item.title,
position: String.fromCharCode(65 + i) + 1,
}))
.reduce(
(prev, next) => ({
...prev,
[next.position]: { key: next.key, v: next.title },
}),
{},
);
const xlsxData = data
.map((item, i) =>
headers.map((key, j) => ({
content: item[key.key],
position: String.fromCharCode(65 + j) + (i + 2),
})),
)
.reduce((prev, next) => [...prev, ...next])
.reduce(
(prev, next) => ({
...prev,
[next.position]: { v: next.content },
}),
{},
);
const output = { ...xlsxHeaders, ...xlsxData }; //横排的数据和纵排的数据
const outputPos = Object.keys(output);
const ref = `${outputPos[0]}:${outputPos[outputPos.length - 1]}`;
//这个是定义一个字符串 也就是表的范围[A1:C5]
if (!refactorWorkbook) throw new Error('Require refactorWorkbook function to refactor workbook.');
if (!isType(refactorWorkbook, 'Function'))
throw new Error('refactorWorkbook should be a function with object value.');
const wb = refactorWorkbook(output, ref);
XLSX.writeFile(wb, fileName);
};
export default exportExcel;
组件内使用:
//使用excel导出组件
IExcel(
{
headers: columns, //这是表格头横排的数据
data: dataSource.map((item, i) => ({ //单元格具体的数据
index: i + 1,
name:item.name,
age:item.age,
createTime:moment(item.createTime).formatter()
})),
fileName: `表.xlsx`,
},
(output, ref) => {
return {
SheetNames: ['明细表'],
Sheets: {
明细表: {
...output,
'!ref': ref,
'!cols': [ //每一列的宽度
{ wpx: 60 },
{ wpx: 150 },
{ wpx: 250 },
{ wpx: 250 },
],
},
},
};
},
);
7、文本差异
用的是 diff-match-patch 库,使用于变更前变更后对比的这种业务
import TextDiff from '@/components/TextDiff/index.min.js';
const diffText = (oldTxt, newTxt) => {
const tDiff = new TextDiff();
const diff = tDiff.diff_main(oldTxt, newTxt);
tDiff.diff_cleanupSemantic(diff);
return tDiff.diff_prettyHtml(diff);
};
//表单columns对应的render项
render: (text, record) => {
return (
// eslint-disable-next-line react/no-danger
<span dangerouslySetInnerHTML={{ __html: diffText(record?.bgjlBgqxx || '', text) }} />
);
},
8、切换页码滚动到顶部
当页面的内容比较多,一般来说点击下一页会从上面找数据或操作,此时需要在请求数据时加返回顶部的动画
前面是获取数据用async和await也行都一样,主要是requestAnimationFrame这个Api,
listRef指的是滚动列表最外层的div标签绑定的ref
.then(res => {
if(res?.code === '200' && listRef && listRef.current && !firstRender){ //外层标签的ref
window.requestAnimationFrame(() => {
listRef.current.scrollIntoView({
behavior: 'smooth'
})
})
}
})
9、 封装GET请求的自定义hook
一般获取数据用的最多的是get请求,而且每次有参数改变例如分页页码,需要根据依赖调用useEffect,此时可以封装一个useRequest,根据传过来的里面的changeParams,这是一个布尔值,如果需要重新根据参数调用接口获取新的数据,把changeParams直接取反,由于useRequest的依赖为changeParams,会直接重新调用接口,省去写很多useEffect
const useRequest = (props: any) => {
const { url, changeParams, ...rest } = props;
const [loading, setLoading] = useState<boolean>(false);
const [res, setRes] = useState<{}>({});
useEffect(() => {
setLoading(true);
try {
querySingle({
path: `${url}`,
...rest,
}).then((response) => {
if (response?.code === "200") {
setRes(response?.data);
}
setLoading(false);
});
} catch (error) {
setLoading(false);
}
}, [changeParams]);
return { res, loading };
};
举例使用:
//组件内举例使用,这个页面是一个带分页的组件
const [params, setParams] = useState({
pageSize: '10',
pageNumber: '0',
title: '',
});
const [changeIt, seChangeIt] = useState<boolean>(false); //useEffect的依赖
const { res, loading } = useRequest({
url: 'data/channelList', //接口地址,前面的部分地址省去了
changeParams: changeIt,
...params,
});
//这是分页页码变换的回调
const onPageChange = (pagination: any) => {
const { current } = pagination;
setParams({
...params,
pageNumber: `${current - 1}`,
});
seChangeIt(!changeIt); // 此时会重新调用接口
};
10、qs库常用Api
这个库特别好用,尤其是在封装网络请求方法的参数需要拼到url里的时候 stringify是对象转url, parse是url转对象
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'indices' })
// 'a[0]=b&a[1]=c'
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'brackets' })
// 'a[]=b&a[]=c'
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'repeat' })
// 'a=b&a=c'
qs.stringify({ a: ['b', 'c'] }, { arrayFormat: 'comma' })
// 'a=b,c'
export async function getData(params) {
return request(`/api/channel?${stringify(params)}`, {
method: 'GET',
data: params,
});
}
2021/10/31 15:43
希望对你有帮助!