从前有匹马叫代码
心若没有栖息的地方,到哪里都是流浪

一转眼,2021年马上要过去。回顾这一年,真是跌宕起伏,经历了七月的暴雨,十月的疫情封闭...不过,好在结局还算可以,在年末前两个月,我也算是找了一份相对来说还算满意的工作


本文主要针对数据可视化项目做一些总结,希望通过笔者的总结能帮你节省不断查找各种搜索引擎的时间,愿你历经千帆,归来仍是少年。

本文主要有内容如下:

  1. 设备单位兼容
  2. 快速布局与常用UI设计稿的快速实现方案

设备单位兼容

笔者经过大量的数据可视化项目总结出来以下道理,凡是牵扯到数据可视化项目的都会牵扯进图表,笔者一直使用 echarts 来做图表部分,那么,我们在做设备单位兼容的时候也是需要考虑echarts的字体大小兼容的.

接下来直接干货

注意!笔者的UI设计图出的都是1920*1080分辨率,不同分辨率需要手动更改单位

rem.js

// 设置 rem 函数
function setRem() {
    //  PC端
    // 基准大小
    let baseSize = 100;
    let basePc = baseSize / 1920; // 表示1920的设计图,使用100PX的默认值
    let vW = window.innerWidth; // 当前窗口的宽度
    let vH = window.innerHeight; // 当前窗口的高度
    // 非正常屏幕下的尺寸换算
    let dueH = (vW * 1080) / 1920;
    if (vH < dueH) {
        // 当前屏幕高度小于应有的屏幕高度,就需要根据当前屏幕高度重新计算屏幕宽度
        vW = (vH * 1920) / 1080;
    }
    let rem = vW * basePc; // 以默认比例值乘以当前窗口宽度,得到该宽度下的相应font-size值
    document.documentElement.style.fontSize = rem + 'px';
}
// 初始化
setRem();
// 改变窗口大小时重新设置 rem
window.onresize = function () {
    setRem();
};

font.js

export default function fontSize(res) {
    let docEl = document.documentElement,
        clientWidth =
            window.innerWidth ||
            document.documentElement.clientWidth ||
            document.body.clientWidth;
    if (!clientWidth) return;
    let fontSize = 100 * (clientWidth / 1920);
    return res * fontSize;
}

然后在你需要导入的位置(一般是入口文件) 导入rem.js就可以了,至于font.js则是用来适配echarts字体的,比如你echarts配置里面写的 fontSize:12,则可以通过fontSize:font(0.12)来实现适配。因为我们内部逻辑通过动态计算出来的基础大小,然后乘以我们传进来的,实际上是一个比例(0.12)。

最后我们不要忘记 通过 postcss 和 postcss-pxtorem@5.1.1 来通过该插件将我们书写在style中的px单位转换成rem
postcss 配置文件如下:

    plugins: [
        require('postcss-pxtorem')({
            rootValue: 100,
            propList: ['*'],
            exclude: function(file) {
                return !file.includes('earlyWarning')
            }
        })
    ]

rootValue 需要跟之前两个文件的 baseSize 一致

注意!!! 标签的行内样式不进行转换!!!

快速布局与常用UI设计稿的快速实现方案

首先大屏的布局一般是上 -> 下(左中右)
导航栏一般位于“上”,导航栏一般会放一些天气,时时刷新的时间,等等...
天气 可以通过 ALAPI 来使用免费的套餐(1000次/天),时间相关的可以采用moment
实时刷新时间函数如下(这里是vue实现方案,其实无论什么框架,逻辑思维都一样):

<template>
    <div class="ew-header">
        <div class="ew-header-left">
            <span class="ew-header-left-location">余杭区</span>
            &#x3000;
            <span>今天&nbsp;</span>
            <span class="ew-header-left-tmp">2°~10°</span>
        </div>

        <div class="ew-header-right">
            <span>{{ byMonth }}&nbsp;</span>
            <span class="ew-header-right-weekday">{{ byWeek }}</span>
            &#x3000;
            <span class="ew-header-right-time">hh:mm:ss</span>
        </div>

        <div class="ew-header-left-bottom">
            统计周期 &#x3000; {{ timeFormat.start }} 至 {{ timeFormat.end }} ▼
            <div class="ew-header-ele-picker">
                <el-date-picker
                    v-model="userPicker"
                    type="daterange"
                    range-separator="至"
                    start-placeholder="开始日期"
                    end-placeholder="结束日期"
                    value-format="yyyy-MM-dd"
                >
                </el-date-picker>
            </div>
        </div>
    </div>
</template>
<script>
import { mapMutations } from 'vuex'
import moment from 'moment'
export default {
    data() {
        moment.locale('zh-cn')
        return {
            userPicker: [],
            clockRefresher: null,

            byMonth: moment().format('MMM Do'),
            byWeek: moment()
                .format('dddd')
                .replace('星期', '周')
        }
    },

    mounted() {
        this.clockRefresh()
    },

    watch: {
        userPicker(newvalue) {
            this.setDateOfVuex(newvalue)
        }
    },
    computed: {
        timeFormat({ userPicker }) {
            return {
                start: userPicker[0] || '开始时间',
                end: userPicker[1] || '结束时间'
            }
        }
    },
    methods: {
        ...mapMutations(['setDateOfVuex']),

        clockRefresh() {
            /**@description 通过手动更新dom,避免每次因为每秒时间的刷新而去走diff算法产生额外的消耗 */

            this.clockRefresher && clearTimeout(this.clockRefresher)
            this.clockRefresher = setTimeout(() => {
                const clockElement = document.querySelector(
                    '.ew-header-right-time'
                )
                clockElement.textContent = moment().format('LTS')
                this.clockRefresh()
            }, 1000)
        }
    }
}
</script>

请自行忽略无关的逻辑

写在结尾

一般数据可视化的左右两侧的数据或者多侧的数据都会依赖某个值来改变,比如,中间是地图的话,可以会依据地图上的贴图(某些指定地点)来实现数据切换,那么当我们在做模块化设计的时候,将不同的数据渲染组件 分散到不同的文件中,怎么来优雅的实现联动呢?

我这里的总结是:
把你的数据存放到数据仓库(vuex,pinia, ...)中,然后数据渲染组件通过混入一个公共js文件来实现。
举个例子(我这里需要根据不同的时间段来获取数据):

import { mapState } from 'vuex'
export default {
    computed: {
        ...mapState({
            dateArrayOfVuex: state => state.driver.dateArray,
            dateStartOfVuex: state => state.driver.dateStart,
            dateEndOfVuex: state => state.driver.dateEnd
        })
    },
    watch: {
        dateStartOfVuex() {
            if (!this.getSummary) {
                throw new SyntaxError(
                    'mixins 混入 必须在组件里面实现 getSummary方法'
                )
            }
            this.getSummary()
        }
    }
}

那么,我把该数据存到store里面,只要数据发生变更,就会同步提交修改到store中,store再去自动触发mixins中的watch中的函数,这样就可以有效的复用程序的公共逻辑了。

2021-12-30 21:57:16 星期四

posted on 2021-12-30 21:58  从前有匹马叫代码  阅读(118)  评论(0)    收藏  举报