实习-记录一下做需求时遇到的小问题

loading 2023年04月28日 50次浏览

1. echarts formatter

1.1 基本实现

需求是计算当前数据和天同比/周同比数据的上升下降趋势,并且在鼠标悬浮在图表上时渲染到tooltips上。

有几种方法,一种方法是由后端直接返回对应的数据,但是后端刚好比较忙,便自己看看能不能解决这个问题。

一开始思路是手动计算后赋值给data,但是尝试了之后发现很显然这样会导致数据点渲染不出来,因为图表是识别不了上升/下降等中文的,因此只能看看有没有别的方法,比如说鼠标悬浮时动态提供一个回调函数计算后渲染出来?

官网看了半天,还是发现了一个方法formatter,这个方法可以动态改变tooltips的格式,因此尝试在组件中使用该方法:

思路其实就是根据params解构出来的value进行计算最后追加到原本的返回值上,只不过因为后端返回的数据类型不一,所以需要写一些冗杂的判断。

formatter: (params, ticket, callBack) => {
    let startHtml = params[0].axisValue + '<br/>';
    let listArr = [];
    if(this.chainFlag) {
        for (let i = 0 ; i < params.length ; i++) {
            let item = params[i];
            let str = item.marker;
            let baseData = Array.isArray(params[0].value) ? params[0].value[1] : params[0].value;
            if (i > 0) {
                let curData = Array.isArray(item.value) ? item.value[1] : item.value;
                let curToBaseGap = (((baseData - curData) / curData) * 100).toFixed(2);
                if(curToBaseGap > 0) {
                    str += Array.isArray(item.value) ? (`${item.seriesName}: ${item.value[1]}(上升${curToBaseGap}%)`) : (`${item.seriesName}: ${item.value}(上升${curToBaseGap}%)`);
                } else if(curToBaseGap < 0) {
                    str += Array.isArray(item.value) ? (`${item.seriesName}: ${item.value[1]}(下降${Math.abs(curToBaseGap)}%)`) : (`${item.seriesName}: ${item.value}(下降${Math.abs(curToBaseGap)}%)`);
                } else {
                    str += Array.isArray(item.value) ? (`${item.seriesName}: ${item.value[1]}(基本不变)`) : (`${item.seriesName}: ${item.value}(基本不变)`);
                }
            } else {
                str += Array.isArray(item.value) ? (`${item.seriesName}: ${item.value[1]}`) : (`${item.seriesName}: ${item.value}`);
            }
            listArr.push(str);
        }
    } else {
        for(let i = 0 ; i < params.length ; i++) {
            let item = params[i];
            let str = item.marker;
            str += Array.isArray(item.value) ? (`${item.seriesName}: ${item.value[1]}`) : (`${item.seriesName}: ${item.value}`);
            listArr.push(str); 
        }
    }
    return startHtml + listArr.join('<br/>');
}

1.2 追加功能

由于在chart组件里写这个是会应用到所有的折线图上的,因此写完这个功能几天后发现了个bug,有的折线图是不带天同比/周同比的,会导致计算出undefined值:

因此需要在定义图表时判断该图表是否需要进行环比计算来避免这种情况:
文档
总的来说就是在定义时如果需要计算就传一个prop给图表组件,图表组件再在里面做具体的计算判断。

2. echarts resize

需求是不点击具体预览卡片时图表以两列展示

点击后图表以一列展示

一开始感觉是比较简单的,但是遇到个问题,点击了之后套着图表的div扩展开了,但是图表没有扩展开:

一开始的解决思路是能不能通过改样式动态触发一下回流和重绘,结果发现对于图表还是不起效果,因此还是去看官方文档有没有类似的方法,然后发现了一个resize方法。

然而这个方法是必须应用在echarts的实例中的,因此思路转换为如何在父组件中影响到子组件的实例,那思路很明显了,通过props和watch:

首先父组件传一个resize-flag过去,表示需要触发resize方法了:

<charts-temp v-if="index === chartShowFlag" :option="adChartData" :resize-flag="resizeFlag"> </charts-temp>

子组件监听这个prop,并且触发resize方法即可:

watch: {
    resizeFlag: {
        handler(newValue, oldValue) {
            this.charts.resize();
        }
    }
},

3. vue .native修饰符

目的很简单,点击Card组件触发点击事件,一开始不知道这个修饰符,所以不得不套一层div然后把事件绑定到div上,后来上网查到了处理这种给组件库组件绑定原生事件的方法,问题解决:

<Card v-for="(adChartData , index) in adChartDatasArr" :key="adChartData.title + index" class="preview-card" @click.native="onShowChart(index)">

4. vue nextTick/js scrollIntoView

需求是点击预览卡片自动滑到下方的对应图表中

第一步是要获取到下方图表的dom节点,通过传统的方法或者ref均可,这里就直接用传统的方法了,加了个id。

但是存在一个问题,第一次点击卡片时获取不到图表,上网查到是由于vue会将多次渲染合并到一起,所以有可能第一次点击时渲染还未完成,因此用到nextTick方法,它在下次DOM更新循环结束之后执行回调。

获取到节点之后可以通过scrollTo,scrollBy等方法滚动,但这种方法需要动态地把距离计算出来然后再滚动,上mdn看到了一个更方便的方法,可以直接定位到对应的节点。

最终实现如下(此处还用到了方法提供的behavior选项,可以使得滚动更平缓):

this.$nextTick(() => {
    let chart = document.querySelector('#chart');
    chart.scrollIntoView({
        behavior: 'smooth',
    });
});

5. CSS scoped

目标是改变组件库中tab栏的样式:

但是一开始发现怎么改样式都不生效,后来发现是因为在定义style标签时增加了个scoped属性。

这个属性会使得样式只作用于当前组件中的元素,那么肯定就对于组件库中的组件不起作用了,去掉该属性即可实现目标。

如果不想去掉该属性,也可以通过增加修饰符来实现在父组件中影响到子组件,详情见链接

6. this.$set

项目中遇到一个问题,直接通过下标修改data中的数组时,模版监听不到数据的变化。

上网了解后知道了vue中只有通过push(),pop()等方法去操控数组时视图才能监听到,如果要监听到下标的修改,需要用到this.$set方法,三个参数分别是(数组,下标,数据):

this.$set(this.latestCurData, i, this.adChartDatasArr[i].data[0].data[this.adChartDatasArr[i].data[0].data.length - 1][1]);

7. 通过具名slot定制表格列

需求是表格中名为监控名称的列内容要改为超链接,但是组件库中没有提供对应的定制单元格内容的方法(只能定制样式),因此需要自己通过slot搭配组件库实现。

首先在获取表格的列数据时判断列名,识别到对应列名时手动赋值一个名为m_name的插槽:

this.columns.forEach((item) => {
    if(item.key === 'm_name') {
        this.$set(item,'slot','m_name');
    }
});

之后在表格内容中使用插槽,注意匹配上上面定义的插槽名字即可,插槽内容就可以根据需求定制了(row是组件库提供的参数,表示当前行的数据):

<Table class="table"
        :columns="tableColumns"
        :data="tableDatas"
        :loading="tableLoading"
        :row-class-name="rowClassName"
        size="small"
        @on-selection-change="onSelectIds"
>
    <template #m_name="{ row }">
        <a @click="openDrawer(row.id)">{{ row.m_name }}</a>
    </template>
</Table>