移动端和PC端对比【组件库+调试vconsole +构建vite/webpack+可视化echarts/antv】

目录

组件库

移动端

vue

vant

PC端

react

antd

vue

element

调试:vconsole vs dev tools中的控制台(Console)

​​​​​​​vconsole:在真机上调试

构建工具

webpack

原理

Babel:JS编译器(es6->es5,jsx->js)

loader:编译

less-loader:less->css

css-loader:css->js

style-loader:创建style标签,将js中的样式资源插入标签内,并将标签添加到head中生效

ts-loader:打包编译Typescript文件

plugin:压缩

html-webpack-plugin :处理html资源,默认会创建一个空的HTML,自动引入打包输出的所有资源(js/css)

mini-css-extract-plugin: 打包过后的css在js文件里,该插件可以把css单独抽出来

clean-webpack-plugin :每次打包时候,CleanWebpackPlugin 插件就会自动把上一次打的包删除

loader和plugin的区别:loader运行在编译阶段,plugins 在整个周期都起作用

热加载原理:实时看到代码变化

vite(快,简,小)

源文件的处理

resolve :解析 url,找到源文件的绝对路径;

load :加载源文件。

第三方依赖:直接将预构建内容返回给浏览器;

业务代码:继续 transform、parser。

transfrom :对源文件内容做转换,即 ts -> js, less -> css 等。转换完成的内容可以直接返回给浏览器了。

parser: 对转换以后的内容做分析,找到依赖模块,对依赖模块做预转换 - pre transform 操作,即重复 1 - 4。

快:启动/热更新

ESM+unbundle

性能下降:大量http请求,按需动态编译

首屏

懒加载

可视化引擎

移动端

antv f2​​​​​​​

PC端

antv

antv G6

Vue2

scss

​​​​​​​Echarts

Vue3

radar

React

原生echarts+TS

ListChart(列表切换echarts图表,同类数据为x轴的bar)

ListChart.tsx

ListChart.css

ListChartUtil.tsx

Recharts​​​​​​​

D3


移动端需要考虑:轻量级

类似参考链接:搭建一个vue-cli4+webpack移动端框架(开箱即用) - 掘金

组件库

移动端

vue

vant

PC端

react

antd

vue

element

调试:vconsole vs dev tools中的控制台(Console)

​​​​​​​vconsole:在真机上调试

浏览器中显示log和调试信息的 JS 库

 npm install vconsole

import VConsole from 'vconsole';
if (import.meta.env.MODE === 'development') {
    const vConsole = new VConsole();
    Vue.prototype.vconsole = vConsole //把这个方法放到vue原型上,方便在页面中调用 
}

构建工具

ctrl+c终止运行(webpack需要重启,vite不需要)

webpack

它将根据模块的依赖关系进行静态分析,然后将这些模块( js、css、less )按照指定的规则生成对应的静态资源减少了页面的请求。Webpack是以公共JS的形式来书写脚本的,方便旧项目进行代码迁移

原理

Webpack通过一个给定的主文件(如:index.js)开始找到项目的所有依赖文件,

使用loaders处理它们,plugin可以压缩代码和图片

把所有依赖打包成一个 或多个bundle.js文件(捆bundle)浏览器可识别的JavaScript文件。

Babel:JS编译器(es6->es5,jsx->js)

将es6、es7、es8等语法转换成浏览器可识别的es5或es3语法,即浏览器兼容的语法,比如将箭头函数转换为普通函数

将jsx转换成浏览器认的js

loader:编译

webpack只认识JS和JSON,所以Loader相当于翻译官,将其他类型资源进行预处理,最终变为js代码。

less-loader:less->css

开发中,会使用less预处理器编写css样式,使开发效率提高)

css-loader:css->js

将css文件变成commonjs模块(模块化的规范)加载到js中,模块内容是样式字符串

style-loader:创建style标签,将js中的样式资源插入标签内,并将标签添加到head中生效
ts-loader:打包编译Typescript文件

plugin:压缩

Plugin解决loader 无法实现的事情,比如打包优化代码压缩等。

html-webpack-plugin :处理html资源,默认会创建一个的HTML,自动引入打包输出的所有资源(js/css)
mini-css-extract-plugin: 打包过后的css在js文件里,该插件可以把css单独抽出来
clean-webpack-plugin :每次打包时候,CleanWebpackPlugin 插件就会自动把上一次打的包删除

loader和plugin的区别:loader运行在编译阶段,plugins 在整个周期都起作用

热加载原理:实时看到代码变化

热加载是通过内置的 HotModuleReplacementPlugin 实现的

  1. 构建 bundle 的时候,监听文件变化。
  2. 文件修改会触发 webpack 重新构建
  3. 服务器通过向浏览器发送更新消息
  4. 浏览器通过 jsonp 拉取更新的模块文件,
  5. jsonp 回调触发模块热替换逻辑

vite(快,简,小)

源文件的处理

resolve :解析 url,找到源文件的绝对路径;

load :加载源文件。

第三方依赖:直接将预构建内容返回给浏览器;
业务代码:继续 transformparser

transfrom :对源文件内容做转换,即 ts -> jsless -> css 等。转换完成的内容可以直接返回给浏览器了。

parser: 对转换以后的内容做分析,找到依赖模块,对依赖模块做预转换 - pre transform 操作,即重复 1 - 4

pre transform 是 Vite 做的一个优化点。预转换的内容会先做缓存,等浏览器发起请求以后,如果已经完成转换,直接将缓存的内容返回给浏览器。

快:启动/热更新

ESM+unbundle

(ES modules 是 JavaScript 官方的标准化模块系统。)

vite源文件之间的依赖通过浏览器对 ESM 规范的支持来解析,不再需要额外打包处理。

请求模块时按需动态编译显示

webpack启动慢主要是因为模块依赖图 - module graph

构建 module graph 的过程中,涉及到大量的文件 IO、文件 transfrom、文件 parse 操作;

分解 module graph 的过程中,需要遍历 module graph、文件 transform、文件 IO 

性能下降:大量http请求,按需动态编译

首屏

  1. 不对源文件做合并捆绑操作,导致大量的http请求
  2. dev server运行期间对源文件做resolve、load、transform、parse操作
  3. 预构建、二次预构建操作也会阻塞首屏请求,直到预构建完成为止

Vite把需要在启动过程中完成的工作,转移到响应浏览器请求的过程中

之后reload页面时,首屏的性能会好很多(缓存

懒加载

动态加载的文件,需要做 resolve、load、transform、parse 操作,并且还有大量的 http请求

可视化引擎

  1. 灵活度:ECharts
  2. 使用难度:Echart≈G2PLot
  3. 场景:画三维图用Three,三维地图AntV的L7|L7Plot也可以做到,画二维图用ECharts或者G2、G2Plot均可

移动端

antv f2​​​​​​​

移动端使用antv f2​​​​​​​

vue使用antv f2

yarn add @antv/f2

yarn add @antv/f-vue

npm install @antv/f2 --save

npm install @antv/f-vue --save

//配置 F2 的 JSX 编译

npm install @babel/plugin-transform-react-jsx --save-dev

jsx

F2 使用 JSX 语法来构建图表,所以需要在运行前对 JSX 语法进行编译, JSX 更多细节可参考 React 的官方文档 JSX 简介

BabelTypeScript 都可以编译 JSX 语法,并且在编译时 JSX 语法时,会有 2 种编译模式,在实际项目中可根据自己实际情况选择和使用

经典配置

如果你希望在 Vue 3 组件中使用普通的 JSX 语法,你可以选择经典的配置方式。这种情况下,你需要设置 jsxFactoryjsxFragmentFactory 选项。以下是示例的 tsconfig.json 文件:

{
  "compilerOptions": {
    "jsx": "preserve", // 保留 JSX 语法
    "jsxFactory": "jsx", // 指定 JSX 的工厂函数
    "jsxFragmentFactory": "Fragment" // 指定 JSX 片段的工厂函数
  }
}

在这种配置下,你需要确保你的 Vue 组件中使用的 JSX 工厂函数和片段工厂函数与你在配置中指定的名称相匹配。

自动配置

如果你想要使用自动化的 JSX 语法,你可以使用 jsxjsxImportSource 选项。这种情况下,你可以将 AntV F2 的组件库作为 JSX 的导入来源。以下是示例的 tsconfig.json 文件:

{
  "compilerOptions": {
    "jsx": "react-jsx", // 使用 React 的 JSX 语法
    "jsxImportSource": "@antv/f2" // 指定 JSX 的导入来源
  }
}

​​​​​​​在这种配置下,你可以在 Vue 组件中使用类似 React 的 JSX 语法,不过你需要确保在组件中导入了所需的 AntV F2 组件。

选择哪种配置取决于你更喜欢的语法和使用方式。如果你使用经典配置,你可以继续使用普通的 JSX 语法;如果你使用自动配置,你可以借助 AntV F2 提供的 JSX 语法来创建图表组件。

vue

vue 默认是不支持直接在组件的

移动端和PC端对比【组件库+调试vconsole +构建vite/webpack+可视化echarts/antv】_第3张图片

React

原生echarts+TS

原生echats官方文档和功能比echarts-for-react全,

但echarts-for-react对react支持更友好,使用更简单​​​​​​​

ListChart(列表切换echarts图表,同类数据为x轴的bar)

移动端和PC端对比【组件库+调试vconsole +构建vite/webpack+可视化echarts/antv】_第4张图片

 移动端和PC端对比【组件库+调试vconsole +构建vite/webpack+可视化echarts/antv】_第5张图片

ListChart.tsx
import React, { useEffect, useRef, useState } from 'react';
import { List, Button} from 'antd';
import { LineChartOutlined, BarChartOutlined } from '@ant-design/icons';
import { ProCard } from '@ant-design/pro-components';
import * as echarts from "echarts";

import './ListChart.css'
import { LIST_NAME, CHART_OPTION,resize,findSubstrIdx } from '../utils/ListChartUtil';
import { ListChartStatus } from "./ListChartStatus";

const ListChart: React.FC = ({ urlPre, proc_datas, board_name }) => {

    const chartRef = useRef(null); 
    const [selectedIdx, setselectedIdx] = useState(0);
    const [isLine, setIsLine] = React.useState(true);
    const proc_list = new Array(proc_datas.length).fill(null).map((val, i) => {
        return proc_datas[i].proc_name;
    });
    let chart: any = null;
    
    useEffect(() => {
        if (chartRef.current) {
            chart = echarts.init(chartRef.current);
            const {option,urlSufs}=getOption(proc_datas[selectedIdx])
            chart.setOption(option);
            resize(chart);
            chart.on('click', isLine ? 'xAxis' : 'series', function (params: any) {
                const clickDate= isLine ? params.value:params.seriesName;
                window.open(urlPre + '/' + urlSufs[findSubstrIdx(urlSufs, clickDate)] + '/index.html', '_blank');
            });
        }  
    }, [chartRef, selectedIdx, isLine]);

    const initDate_UrlSufs=(proc_data:any)=>{
        let urlSufs: string[] = [];
        let dates: string[] = [];
        proc_data.date_list.forEach((date: string, idx: number) => {
            urlSufs.push(date + '/' + proc_data.report_id_list[idx]);
            dates.push(date.substring(5));
        });
        return {dates,urlSufs};
    }
    const  getBarDates=(series:any)=>{
        const barDatas: any = [];
        LIST_NAME.forEach((_, idx) => {
            if (series[idx] && series[idx].length) {
                barDatas.push([LIST_NAME[idx], ...series[idx]])
            }
        })
        return barDatas;
    }
    const getOption=(proc_data:any)=>{
        const {dates,urlSufs}=initDate_UrlSufs(proc_data)
        const series = [proc_data.avg_list, proc_data.sigma3_up_list, proc_data.sigma3_up_target_list, proc_data.sigma3_down_list, proc_data.max_list, proc_data.min_list]
        let option = {  
            tooltip: CHART_OPTION.tooltip,
            legend: CHART_OPTION.legend,
            toolbox: CHART_OPTION.toolbox,
            yAxis: CHART_OPTION.yAxis,
            title: {
                text: proc_data ? board_name + ":" + proc_data.proc_name : board_name,
                subtext: "点击日期可跳转到详情报告",
            },
            xAxis: {
                type: 'category', // 类型为分类轴
                triggerEvent: true, // 是否触发鼠标事件
                data: isLine ? proc_data.date_list.map((date: string, idx: number) => {
                    return dates[idx]
                }) : null,
            },
            series: isLine ? LIST_NAME.map((_, idx) => {
                if (series[idx] && series[idx].length) {
                    return {
                        name: LIST_NAME[idx],
                        type: 'line',
                        data: series[idx],
                        emphasis: {
                            focus: 'series'
                        },
                    }
                }
            }) : dates.map((_, idx) => {
                return {
                    name: dates[idx],
                    type: 'bar',
                    event: 'click',
                    emphasis: {
                        focus: 'series'
                    },
                }
            }),

            dataset: isLine ? null : {
                source: [
                    ['pref', ...dates],
                    ...getBarDates(series)
                ]
            },
        };
        return {option,urlSufs};
    }
    return (
        
              setselectedIdx(index)}>
                    {item}}
            />
        
        
            
) } export default ListChart;
ListChart.css
.procard {
    display: flex;
    padding-top: 10px;
}
.procard-list {
    overflow-y: scroll;
    height: 45vh;
}
.selected {
    background-color: #e6f7ff !important;
  }
.procard-button{
    display: flex;
    justify-content: flex-end;
    padding-right: 7vw;
}
ListChartUtil.tsx
​
export const LIST_NAME = ['avg', '3∑-up', '3∑-up-target', '3∑-down', 'max', 'min']

export const CHART_OPTION = {
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      type: "shadow"
    },
  },
  legend: {
    left: 'center',
    width: '35%',
    selected: {
      'min': false,
      '3∑-down': false,
    }
  },
  toolbox: {
    show: true,
    feature: {
      dataZoom: {
        yAxisIndex: 'none'
      },
      dataView: { readOnly: false },
      //   magicType: { type: ['line'] },
      restore: {},
      saveAsImage: {}
    },
    right: "10%"
  },
  yAxis: {
    type: 'value',
    axisLabel: {
      formatter: '{value}  '
    }
  },
}
const dom: any = [];  //所有echarts图表的数组
/**
 * 当屏幕尺寸变化时,循环数组里的每一项调用resize方法来实现自适应。
 * @param {*} eDom 
 */
export function resize(eDom: any) {
  dom.push(eDom);
  window.onresize = () => {
    dom.forEach((it: any) => {
      it.resize();
    })
  };
}

export function findSubstrIdx(arr: string[], substr: string): number {
  for (let i = 0; i < arr.length; i++) {
    if (arr[i].indexOf(substr) !== -1) {
      return i;
    }
  }
  return -1;
}

​

 React hooks 封装 ECharts5 通用组件 - 掘金

React+TypeScript封装ECharts_typescript+react 封装调用方法_KzXuanCn的博客-CSDN博客​​​​​​​

GitHub - hustcc/echarts-for-react: ⛳️ Apache ECharts components for React wrapper. 一个简单的 Apache echarts 的 React 封装。

Recharts​​​​​​​

是一个基于React封装的库,使用了D3强大的绘图功能,使得使用React进行数据可视化变得更加简单

优点

  • Recharts易于使用,因为它具有数量较少的自定义选项。

  • 集成了React的生命周期方法,使它易于添加到React应用程序中,并可支持Redux状态管理器。

  • 轻量级,对内存和CPU的影响较小。

  • 支持多种样式、自定义颜色和动画。

缺点

  • 不支持所有类型的图表,没有Echarts种类繁多。

  • 功能相比于Echarts较少

综上所述,如果需要设计高度自定义的图表并且有足够的开发经验,那么使用Echarts可能更方便。另一方面,Recharts对于快速简单的数据可视化任务可能更适合,并且易于集成到React应用程序中。

D3

是一个基于数据驱动文档的JavaScript库,具有高度灵活性和自定义性,但需要更多的编码工作。

你可能感兴趣的:(前端面试,开发,React和Vue,vue.js,前端,javascript)