前端实习周记7、8
echarts相关
配置属性
-
label
显示数据格式,可以使用formatter进行转换
label:{ show:true, formatter:'{b}({d}%)' }
可以用{value}表示,如为字符串则为轴的数值;如为函数,可根据官网配置
-
tooltip
使用tooltip自定义展示所想要展示的数据,打印出params查看其属性自行配置
使用K线图模拟折线图上柱状图
需求:实现如图所示的折线图上有柱状图上升下降
一开始计划使用echarts中的阶梯瀑布图,但是该图无法实现需求中需要的向下的柱状图,遂考虑使用echarts的K线图,但K线图的定义和使用与需求并不完全匹配,K线图中一个柱状的数据是一个数组,其中包含四个参数:[开盘价、收盘价、最高价、最低价],如果要按照图例中表示上升和下降,需要定义一个基准数据(图上为折线图的数据):
[
[67,55,55,55] //以开盘价>其他数值 表示柱状图上升
[67,55,67,67] //以收盘价<其他数值 表示柱状图下降
]
如此便实现图中效果且不展示K线图中的K线,但有一个缺点:不能实现图例中上升下降的颜色变化,因为K线图中的上升和下降表示的含义与这里不同。
改变了图中展示方式后,写了一个遍历判断生成dataset的方法,由于后端返回的同环比数据是以正负数表示的,所有需要遍历判断不同处理
function calculateArray(a, b) { //a原数据 b带有正负的同环比数据
if (!a) return
const n = a?.length //原数据长度==生成的二维数组的长度
const c = []
for (let i = 0; i < n; i++) {
const newArray = []
if (b[i] === 0) {
newArray.push(a[i], a[i], a[i], a[i])
} else if (b[i] > 0) {
newArray.push(a[i] + b[i], a[i], a[i], a[i])
} else {
newArray.push(a[i], a[i] + b[i], a[i], a[i])
}
c.push(newArray)
}
return c
}
const data=[20,20,20]
const ringdata=[5,-5,0]
const res=calculateArray(data,ringdata);
console.log(res)
/*[ [25,20,20,20],
[20,15,20,20],
[20,20,20,20]]
*/
接着,用户鼠标移动到图上的描述tooltip也要修改:
//labelType变量为用户选择的是“同比”还是"环比“
formatter: function (params) {
const label=params[1].data[1]-params[1].data[3] > 0 ? `${labelType}上升` : `${labelType}下降`;
const value= label===`${labelType}上升` ? params[1].data[1]-params[1].data[3] : params[1].data[3]-params[1].data[2]
return params[0].marker + params[0].seriesName + ':' + params[0].value
+ '<br/>' + params[1].marker+`${label}`+':'+`${value}`
},
树形列表点击传递id不生效
bug : 在树形中点击属性列表没有写传递ID的事件,且为了实现页面加载默认选择列表的第一个项目时用了useEffect每次都默认绑定了固定的id(这可想而知的错误,就导致了每次刷新页面项目的ID都不会变……)
解决方法:
给每次点击项目列表都添加点击获取到ID的事件
const onSelect = (keys, info) => {
if (!info.node.children) {
setSelectedKeys(keys)
props.click(info.node.entId)
}
}
但这里也出现了一个问题:id仍然没有传递过去,或是传递的id显示"undefined"这是因为一开始调用接口获取到id数据时需要一定时间,所以需要约束
const [paramsData, setParamsData] = useState({
entId: entId&&entId ... //双重&&判断存在,也可以使用entId && entId.length
})
useEffect(()=>{
if(entId){
getData()
}
},[entId]) //useEffect依赖项以及if判断
const getData=()=>{
if(entId){
...
}
}
树形结构多选
需求:树形结构多选获取id值,再次点击取消多选,删除id值,默认获取列表第一个id
antd有自带api,但需要按住ctrl键才能实现多选,遂自己实现,最好的实现方式应该是直接在生成树结构 时,用属性中的key:id
return{
title:...
key:t.entId
}
但这次因为任务时间紧迫,没有办法再重构代码,于是只好在生成代码的部分给node加一个entId的属性:
const [selectedKeys, setSelectedKeys] = useState(['0-0-0'])
const [selectId,setSelectId]=useState([])
return{
title:...,
key:t.entId,
entId: t.ent_id,
}
props.click(treeData[0].children[0].entId) //一点击就传递id给父组件
setSelectId([treeData?.[0].children[0].entId]) //重置点击的id数组
setSelectedKeys([treeData?.[0].children[0].key]) //重置点击状态
但这样做也有个很麻烦的地方,就是再写树形结构选择事件时,要写两次方法-key和id的方法
// 树形组件选择
const onSelect = (keys, info) => {
//如果不存在点击了的节点,默认选中为第一个
if (!info.node.children) {
let selectedIds = selectId //这里不能直接setState,因为setState是异步的,需要等到下一次页面更新的时候才会更新
if(selectedKeys.length===0){
setSelectedKeys([['0-0-0']])
}
//keys-如果选中已有的节点(取消选中)
if(selectedKeys.includes(keys[0]) && selectedKeys.length !== 1){
const filterarr=selectedKeys.filter(item=>item!==keys[0]);
setSelectedKeys(filterarr)//选中未包含的节点
}else if(!selectedKeys.includes(keys[0])){
setSelectedKeys([...selectedKeys,keys[0]])
}
//ids-如果选中已有的节点(取消选中)
if(selectedIds.includes(info.node.entId) && selectedIds.length !== 1){
selectedIds= selectedIds.filter(item=>item!==info.node.entId);
}else{//选中未包含的节点
selectedIds.push(info.node.entId)
}
const aa = new Set([...selectedIds])
setSelectId([...aa])
}
}
useEffect(() => {
props.click(selectId)
}, [selectId])
- 新增需求:
限制多选数量为3——if条件判断
const filterarr=selectedKeys.filter(item=>item!==keys[0]);
setSelectedKeys(filterarr)
}else if(!selectedKeys.includes(keys[0])&& selectedKeys.length<3){
setSelectedKeys([...selectedKeys,keys[0]])
}
if(selectedIds.includes(info.node.entId) && selectedIds.length !== 1){
selectedIds= selectedIds.filter(item=>item!==info.node.entId);
}else if(selectedIds.length<3){
selectedIds.push(info.node.entId)
}
下拉选择确保字段存在
需求:实现下拉选择,value根据后端传来的数据确定
实现:
const [devType,setDevType]=useState([]) //初始化state
//处理设备类型
const convertOptions = (arr) => {
return arr.map(item => ({
value: String(item.dev_type),
label: item.dev_type_name,
}));
}
useEffect(() => { //三重判断确保数据存在才执行
if(entData && entData.dev_type && entData.dev_type.length > 0){
const converted= convertOptions(entData.dev_type)
setDevType(converted)
}
}, [entData]);
return (<Select
allowClear
placeholder={`请选择`}
defaultValue="企业总电"
options={devType}>
</Select>)
Button实现多选按钮、样式切换
需求:包裹着echarts图的容器标题上显示可以多选的button,根据button状态判断是否展示echarts图的某个折线图
实现:
const [areaOn,setAreaOn]=useState(false)
const AreaHandleClick = () => {
setAreaOn(prev => !prev);
}
return(
<Button
type={areaOn ? 'primary':'default'} //不要求样式的话可以直接这么判断
onClick={AreaHandleClick}
>区均值</Button>
)