• 数据可视化项目(一)


    简介

    • 什么是数据可视化
      • 基础是计算机图形学(CG),但是太底层,没必要研究
      • 早起的代表作是Excel,随着技术飞速发展,结合了其他编程语言
    • 应用场景
      • 简单应用:单机离线,数据量小;典型场景:
        1
        2
        3
        4
      • 复杂应用:数据量大,联网应用;典型场景:数据大屏,数据报表,地图
    • 数据可视化逐步成为前端工程师的标准技能
      • 大厂已经将可视化做成了产品,可见应用广泛需求大

    技术选型

    • 技术栈层级结构,记一记
      5
    • Chrome使用Skia作为绘图引擎,并且向上开放了Canvas、Svg、WebGL、HTML接口,使我们编写简单的代码就可以实现在浏览器绘图
    • 分别介绍一下不同层级的组件

    canvas

    • HTML5新特性,Chrome默认支持,不需要引入任何库
    • 例子:画线、画圆
      • 编写canvas标签
      • 获取DOM对象
      • 获取canvas对象
      • 设置绘图属性
      • 调用绘图API
      DOCTYPE html>
      <html>
        <head>head>
        <body>
          <canvas id="canvas" width="800" height="800">canvas>
          <script>
            const canvas = document.getElementById('canvas');
            const ctx = canvas.getContext('2d'); // 获取到 Canvas 对象
            ctx.fillStyle = 'red'; // 修改填充色为红色
            ctx.fillRect(0, 0, 50, 50); // 绘制矩形
      
            ctx.beginPath();
            ctx.lineWidth = 1; // 线条宽度
            ctx.strokeStyle = 'blue'; // 线条填充色
            ctx.moveTo(100, 100); // 起点坐标
            ctx.lineTo(250, 75); // 中间点坐标
            ctx.lineTo(300, 100); // 终点坐标
            ctx.stroke(); // 绘制线段
      
            ctx.beginPath();
            ctx.lineWidth = 2;
            ctx.strokeStyle = 'green';
            ctx.fillStyle = 'red';
            ctx.arc(200, 200, 50, 0, 2 * Math.PI); // 绘制圆形
            ctx.stroke();
            ctx.fill();
      
            ctx.beginPath();
            ctx.lineWidth = 1; // 线条宽度
            ctx.strokeStyle = 'red'; // 线条填充色
            ctx.moveTo(300, 300); // 起点坐标
            ctx.lineTo(301, 301); // 中间点坐标
            ctx.stroke(); // 绘制线段
          script>
        body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36

    svg

    • 基于XML的图像文件格式,放大不失真,适合做图标
      DOCTYPE html>
      <html>
        <head>head>
        <body>
          <svg width="800" height="800">
            <rect 
              width="50"
              height="50"
              style="fill:red;"
            />
            <line
              x1="100"
              y1="100"
              x2="250"
              y2="75"
              style="stroke:blue;stroke-width: 1;"
            />
            <line
              x1="250"
              y1="75"
              x2="300"
              y2="100"
              style="stroke:blue;stroke-width: 1;"
            />
            <circle
              cx="200"
              cy="200"
              r="50"
              stroke="green"
              stroke-width="2"
              fill="red"
            />
            <line
              x1="300"
              y1="300"
              x2="301"
              y2="301"
              style="stroke:red;stroke-width: 1;"
            />
          svg>
        body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42

    WebGL

    • 一种3D绘图协议,可以为HTML5的canvas提供硬件(显卡)加速渲染(就是个加速器),更加流畅的展示3D模型
    • 画个点
      # 涉及到系统的3D绘图的知识,超纲了
      # 有兴趣可自学
      
      • 1
      • 2

    zrender

    • 二维绘图引擎(类似skia),是ECharts的渲染器;也提供了canvas、SVG、VML等多种渲染方式
    • zrender是一个js库,在canvas上层,因为封装了Chrome默认支持的这些渲染方式,提供的是更高级的接口,给ECharts使用
    • 渲染流程
      DOCTYPE html>
      <html>
        <head>
          <script src="https://cdn.jsdelivr.net/npm/zrender@4.3.0/dist/zrender.js">script>
        head>
        <body>
          <div id="container" style="width: 800px;height: 800px;">div>
          <script>
            const zr = zrender.init(document.getElementById('container'));
            const rect = new zrender.Rect({
              shape: {
                x: 0,
                y: 0,
                width: 50,
                height: 50
              },
              style: {
                fill: 'red',
                lineWidth: 0
              }
            });
            const line = new zrender.Polyline({
              shape: {
                points: [
                  [100, 100],
                  [250, 75],
                  [300, 100]
                ]
              },
              style: {
                stroke: 'blue',
                lineWidth: 1
              }
            });
            const circle = new zrender.Circle({
              shape: {
                cx: 200,
                cy: 200,
                r: 50
              },
              style: {
                fill: 'red',
                stroke: 'green',
                lineWidth: 2
              }
            });
            const point = new zrender.Polyline({
              shape: {
                points: [
                  [300, 300],
                  [301, 301]
                ]
              },
              style: {
                stroke: 'red',
                lineWidth: 1
              }
            });
            zr.add(rect)
            zr.add(line)
            zr.add(circle)
            zr.add(point)
          script>
        body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
    • 官方案例

    D3

    • 是一个JavaScript图形库,数据可视化常用库,不是现成的图表库,可以定义基础元素,更加灵活
    • 案例,基本流程是:获取D3 DOM,开发,不是JS的DOM
    • 写个例子,数据变换
      DOCTYPE html>
      <html>
        <head>
          <script src="https://d3js.org/d3.v5.js">script>
        head>
        <body>
          <p>Vuep>
          <p>Reactp>
          <p>Agularp>
          <button id="datum">datumbutton>
          <button id="data">databutton>
          <script>
            const body = d3.select('body');	// 获取d3 dom	
            const p = body.selectAll('p');
            function doDatum() {
              const str = 'Framework';
              p.datum(str);
              p.text(function(d, i) {
                return `${d}-${i}`;
              });
            }
            function doData() {
              const dataset = ['Vue', 'React', 'Agular'];
              p.data(dataset)
                .text(function(d, i) {
                  return `${d}-${i}`;
                })
            }
            document.getElementById('datum').addEventListener('click', function(e) {
              doDatum();
            })
            document.getElementById('data').addEventListener('click', function(e) {
              doData();
            })
          script>
        body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
    • 可以学这个思维导图的案例

    three.js

    • 基于WebGL的JavaScript 3D图形库,方便好用,特别是3D场景
    • 源码仓库;可以根据里面的文档学习,或者官网文档
    • 这里的项目主要使用2D,所以用的少

    图片压缩案例

    • 使用canvas在前端压缩图片,主要还是JS语法,比较复杂
      DOCTYPE html>
      <html>
        <head>
          <meta charset="utf-8">
        head>
        <body>
          <input type="file" id="upload">
          <script>
            const ACCEPT = ['image/jpg', 'image/png', 'image/jpeg'];
            const MAXSIZE = 3 * 1024 * 1024;
            const MAXSIZE_STR = '3MB';
            function convertImageToBase64(file, callback) {
              let reader = new FileReader();
              reader.addEventListener('load', function(e) {
                const base64Image = e.target.result;
                callback && callback(base64Image);
                reader = null;
              });
              reader.readAsDataURL(file);
            }
            function compress(base64Image, callback) {
              let maxW = 1024;
              let maxH = 1024;
              const image = new Image();
              image.addEventListener('load', function(e) {	// event load == onload, 表示一张页面或一幅图像完成加载时触发
                let ratio; // 图片的压缩比
                let needCompress = false; // 是否需要压缩
                if (maxW < image.naturalWidth) {
                  needCompress = true;
                  ratio = image.naturalWidth / maxW;
                  maxH = image.naturalHeight / ratio;
                } // 经过处理后,实际图片的尺寸为 1024 * 640
                if (maxH < image.naturalHeight) {
                  needCompress = true;
                  ratio = image.naturalHeight / maxH;
                  maxW = image.naturalWidth / ratio;
                }
                if (!needCompress) {
                  maxW = image.naturalWidth;
                  maxH = image.naturalHeight;
                } // 如果不需要压缩,需要获取图片的实际尺寸
                const canvas = document.createElement('canvas');
                canvas.setAttribute('id', '__compress__');
                canvas.width = maxW;
                canvas.height = maxH;
                canvas.style.visibility = 'hidden';
                document.body.appendChild(canvas);
      
                const ctx = canvas.getContext('2d');
                ctx.clearRect(0, 0, maxW, maxH);
                ctx.drawImage(image, 0, 0, maxW, maxH);
                const compressImage = canvas.toDataURL('image/jpeg', 0.9);
                callback && callback(compressImage);
                canvas.remove();
              });
              image.src = base64Image;
            }
            function uploadToServer(compressImage) {
              console.log('upload to server...', compressImage);
            }
            const upload = document.getElementById('upload');
            upload.addEventListener('change', function(e) {
              const [file] = e.target.files;
              if (!file) {
                return;
              }
              const { type: fileType, size: fileSize } = file;
              if (!ACCEPT.includes(fileType)) {
                alert(`不支持[${fileType}]文件类型!`);
                upload.value = '';
                return;
              } // 图片类型检查
              if (fileSize > MAXSIZE) {
                alert(`文件超出${MAXSIZE_STR}`);
                upload.value = '';
                return;
              } // 图片容量检查
              // 压缩图片
              convertImageToBase64(file, (base64Image) => compress(base64Image));
            })
          script>
        body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83

    HighCharts

    • 是一个纯JavaScript的图表库,文档很细致
      1
    • 举例
      2
      3
      4
      5

    Antv

    • 蚂蚁金服全新一代的数据可视化解决方案,提供了一整套数据可视化的最佳实践,包含内容以及文档可以看官网,自研了G2引擎(潜力很大)
    • 使用G2实现折线图,打开检查可以看到底层也是使用canvas
      DOCTYPE html>
      <html>
        <head>
          <meta charset="utf-8">
          <script src="https://unpkg.com/@antv/g2plot@latest/dist/g2plot.min.js">script>
        head>
        <body>
          <div id="g2-chart">div>
          <script>
            const data = [
              { year: '1991', value: 3 },
              { year: '1992', value: 4 },
              { year: '1993', value: 3.5 },
              { year: '1994', value: 5 },
              { year: '1995', value: 4.9 },
              { year: '1996', value: 6 },
              { year: '1997', value: 7 },
              { year: '1998', value: 9 },
              { year: '1999', value: 13 },
            ];
            const chartDom = document.getElementById('g2-chart');
            const line = new G2Plot.Line(chartDom, {
              title: {
                visible: true,
                text: 'g2折线图示例'
              },
              description: {
                visible: true,
                text: '折线图示例,这是一个副标题'
              },
              data,
              xField: 'year',
              yField: 'value',
              point: {
                visible: true,
                size: 5,
                color: '#fff',
                style: {
                  stroke: '#fe740c',
                  lineWidth: 2,
                  fillOpacity: 0.6
                }
              },
              label: {
                visible: true
              },
              color: '#f2740c',
              yAxis: {
                formatter: (v) => {
                  return `${v}k`;
                }
              }
            });
            line.render();
          script>
        body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
    • 使用流程
      • 引入js库
      • 准备数据
      • 获取DOM对象
      • 初始化G2对象,G2Plot.Line,设置参数
      • 调用render完成渲染 line.render();
    • 使用G6绘制矢量图
      DOCTYPE html>
      <html>
        <head>
          <meta charset="utf-8">
          <script src="https://gw.alipayobjects.com/os/antv/pkg/_antv.g6-3.4.7/dist/g6.min.js">script>
        head>
        <body>
          <div id="g6-chart">div>
          <script>
            const data = {
              nodes: [{
                id: 'node1',
                x: 100,
                y: 200,
                label: '起始点',
                size: 60,
                labelCfg: {
                  position: 'center',
                  style: {
                    fontSize: 12,
                    fill: '#fff'
                  }
                },
                style: {
                  fill: '#ff0000',
                  stroke: '#888',
                  lineWidth: 1
                }
              }, {
                id: 'node2',
                x: 300,
                y: 200,
                label: '目标点1',
                size: 80
              }, {
                id: 'node4',
                x: 300,
                y: 400,
                label: '目标点4',
                size: 80
              }, {
                id: 'node3',
                x: 500,
                y: 200,
                label: '目标点2',
                size: 100
              }], // 点集
              edges: [{
                source: 'node1',
                target: 'node2',
                label: '连接线1'
              }, {
                source: 'node1',
                target: 'node4',
                label: '连接线3'
              }, {
                source: 'node2',
                target: 'node3',
                label: '连接线2'
              }] // 边集
            };
            const graph = new G6.Graph({
              container: 'g6-chart',
              width: 800,
              height: 500
            }); // 完成 G6 图的初始化
            graph.data(data); // 绑定数据源
            graph.render(); // 绘制矢量图
          script>
        body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
    • 使用流程,和G2类似
    • L7地理空间数据可视分析引擎,官网案例:全球发电站气泡图
      DOCTYPE html>
      <html>
        <head>
          <meta charset="utf-8">
          <script src="https://unpkg.com/@antv/l7">script>
          <style>
            html, body {
              padding: 0;
              margin: 0;
            }
          style>
        head>
        <body>
          <div id="l7-map">div>
          <script>
            const scene = new L7.Scene({
              id: 'l7-map',
              map: new L7.GaodeMap({  // 加载高德地图
                style: 'dark',
                center: [120.19382669582967, 30.258134],
                pitch: 0, // 地图显示的角度,默认为0,俯视
                zoom: 12,  // 粒度
                token: 'e8653883477c1e38d190463340771816'
              })
            });
            scene.on('loaded', function() {
              // 全国发电站的数据
              fetch(
                'https://gw.alipayobjects.com/os/basement_prod/337ddbb7-aa3f-4679-ab60-d64359241955.json'
              )
                .then(res => res.json())
                .then(data => {
                  console.log(data);
                  data.features = data.features.filter(item => item.properties.capacity > 1000); // 过滤器
                  const pointLayer = new L7.PointLayer({})
                    .source(data)
                    .shape('circle')
                    .size('capacity', [0, 16])
                    .color('capacity', [
                      '#34B6B7',
                      '#4AC5AF',
                      '#5FD3A6',
                      '#7BE39E',
                      '#A1EDB8',
                      '#CEF8D6'
                    ])
                    .style({
                      strokeWidth: 0,
                      opacity: 0.5
                    })
                    .active(true);
      
                  scene.addLayer(pointLayer);
                });
            });
          script>
        body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58

    ECharts

    • 基于zrender,有绚丽的特效;文档
      1

    • 画个柱状折线图

      DOCTYPE html>
      <html>
        <head>
          <meta charset="utf-8">
          <script src="https://cdn.jsdelivr.net/npm/echarts@4.7.0/dist/echarts.js">script>
          <style>
            #chart {
              width: 800px;
              height: 400px;
            }
          style>
        head>
        <body>
          <div id="chart">div>
          <script>
            const chartDom = document.getElementById('chart');
            const chart = echarts.init(chartDom);
            chart.setOption({
              dataset: {
                source: [
                  ['一季度', 100, 79, '分类1', 50],
                  ['二季度', 112, 81, '分类2', 60],
                  ['三季度', 96, 88, '分类3', 55],
                  ['四季度', 123, 72, '分类4', 70]
                ]
              },
              title: {
                text: 'ECharts 多系列案例',
                subtext: '慕课网数据可视化课程'
              },
              xAxis: {
                data: ['一季度', '二季度', '三季度', '四季度']
              },
              yAxis: {},  // 不设定,自己按照数据画
              legend: {
                data: [{
                  name: '分类',
                  icon: 'circle',
                  textStyle: {
                    color: 'red'
                  }
                }, '折线图', '柱状图'],
                left: 300
              },
              grid: {
                  top: 100,
                  left: '10%',
                  right: '10%',
                  bottom: 100
              },
              toolbox: {
                  feature: {
                      saveAsImage: {},
                      dataZoom: {
                          yAxisIndex: false
                      },
                      restore: {}
                  }
              },
              dataZoom: [
                  {
                      show: true,
                      start: 30,
                      end: 70
                  }
              ],
              series: [{
                name: '折线图',
                type: 'line',
                encode: { x: 0, y: 1 }
              }, {
                name: '柱状图',
                type: 'bar',
                encode: { x: 0, y: 2 }
              }]
            });
          script>
        body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79

      5

    • 自定义样式,这是ECharts里最实用的功能,官方只给出了两个主题

      DOCTYPE html>
      <html>
        <head>
          <meta charset="utf-8">
          <script src="https://cdn.jsdelivr.net/npm/echarts@4.7.0/dist/echarts.js">script>
          <style>
            #chart {
              width: 800px;
              height: 400px;
            }
          style>
          <script>      
      (function (root, factory) {
          if (typeof define === 'function' && define.amd) {
              // AMD. Register as an anonymous module.
              define(['exports', 'echarts'], factory);
          } else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
              // CommonJS
              factory(exports, require('echarts'));
          } else {
              // Browser globals
              factory({}, root.echarts);
          }
      }(this, function (exports, echarts) {
          var log = function (msg) {
              if (typeof console !== 'undefined') {
                  console && console.error && console.error(msg);
              }
          };
          if (!echarts) {
              log('ECharts is not Loaded');
              return;
          }
          echarts.registerTheme('westeros', {
              "color": [
                  "#516b91",
                  "#59c4e6",
                  "#edafda",
                  "#93b7e3",
                  "#a5e7f0",
                  "#cbb0e3"
              ],
              "backgroundColor": "rgba(0,0,0,0)",
              "textStyle": {},
              "title": {
                  "textStyle": {
                      "color": "#516b91"
                  },
                  "subtextStyle": {
                      "color": "#93b7e3"
                  }
              },
              "line": {
                  "itemStyle": {
                      "normal": {
                          "borderWidth": "2"
                      }
                  },
                  "lineStyle": {
                      "normal": {
                          "width": "2"
                      }
                  },
                  "symbolSize": "6",
                  "symbol": "emptyCircle",
                  "smooth": true
              },
              "radar": {
                  "itemStyle": {
                      "normal": {
                          "borderWidth": "2"
                      }
                  },
                  "lineStyle": {
                      "normal": {
                          "width": "2"
                      }
                  },
                  "symbolSize": "6",
                  "symbol": "emptyCircle",
                  "smooth": true
              },
              "bar": {
                  "itemStyle": {
                      "normal": {
                          "barBorderWidth": 0,
                          "barBorderColor": "#ccc"
                      },
                      "emphasis": {
                          "barBorderWidth": 0,
                          "barBorderColor": "#ccc"
                      }
                  }
              },
              "pie": {
                  "itemStyle": {
                      "normal": {
                          "borderWidth": 0,
                          "borderColor": "#ccc"
                      },
                      "emphasis": {
                          "borderWidth": 0,
                          "borderColor": "#ccc"
                      }
                  }
              },
              "scatter": {
                  "itemStyle": {
                      "normal": {
                          "borderWidth": 0,
                          "borderColor": "#ccc"
                      },
                      "emphasis": {
                          "borderWidth": 0,
                          "borderColor": "#ccc"
                      }
                  }
              },
              "boxplot": {
                  "itemStyle": {
                      "normal": {
                          "borderWidth": 0,
                          "borderColor": "#ccc"
                      },
                      "emphasis": {
                          "borderWidth": 0,
                          "borderColor": "#ccc"
                      }
                  }
              },
              "parallel": {
                  "itemStyle": {
                      "normal": {
                          "borderWidth": 0,
                          "borderColor": "#ccc"
                      },
                      "emphasis": {
                          "borderWidth": 0,
                          "borderColor": "#ccc"
                      }
                  }
              },
              "sankey": {
                  "itemStyle": {
                      "normal": {
                          "borderWidth": 0,
                          "borderColor": "#ccc"
                      },
                      "emphasis": {
                          "borderWidth": 0,
                          "borderColor": "#ccc"
                      }
                  }
              },
              "funnel": {
                  "itemStyle": {
                      "normal": {
                          "borderWidth": 0,
                          "borderColor": "#ccc"
                      },
                      "emphasis": {
                          "borderWidth": 0,
                          "borderColor": "#ccc"
                      }
                  }
              },
              "gauge": {
                  "itemStyle": {
                      "normal": {
                          "borderWidth": 0,
                          "borderColor": "#ccc"
                      },
                      "emphasis": {
                          "borderWidth": 0,
                          "borderColor": "#ccc"
                      }
                  }
              },
              "candlestick": {
                  "itemStyle": {
                      "normal": {
                          "color": "#edafda",
                          "color0": "transparent",
                          "borderColor": "#d680bc",
                          "borderColor0": "#8fd3e8",
                          "borderWidth": "2"
                      }
                  }
              },
              "graph": {
                  "itemStyle": {
                      "normal": {
                          "borderWidth": 0,
                          "borderColor": "#ccc"
                      }
                  },
                  "lineStyle": {
                      "normal": {
                          "width": 1,
                          "color": "#aaaaaa"
                      }
                  },
                  "symbolSize": "6",
                  "symbol": "emptyCircle",
                  "smooth": true,
                  "color": [
                      "#516b91",
                      "#59c4e6",
                      "#edafda",
                      "#93b7e3",
                      "#a5e7f0",
                      "#cbb0e3"
                  ],
                  "label": {
                      "normal": {
                          "textStyle": {
                              "color": "#eeeeee"
                          }
                      }
                  }
              },
              "map": {
                  "itemStyle": {
                      "normal": {
                          "areaColor": "#f3f3f3",
                          "borderColor": "#516b91",
                          "borderWidth": 0.5
                      },
                      "emphasis": {
                          "areaColor": "#a5e7f0",
                          "borderColor": "#516b91",
                          "borderWidth": 1
                      }
                  },
                  "label": {
                      "normal": {
                          "textStyle": {
                              "color": "#000"
                          }
                      },
                      "emphasis": {
                          "textStyle": {
                              "color": "#516b91"
                          }
                      }
                  }
              },
              "geo": {
                  "itemStyle": {
                      "normal": {
                          "areaColor": "#f3f3f3",
                          "borderColor": "#516b91",
                          "borderWidth": 0.5
                      },
                      "emphasis": {
                          "areaColor": "#a5e7f0",
                          "borderColor": "#516b91",
                          "borderWidth": 1
                      }
                  },
                  "label": {
                      "normal": {
                          "textStyle": {
                              "color": "#000"
                          }
                      },
                      "emphasis": {
                          "textStyle": {
                              "color": "#516b91"
                          }
                      }
                  }
              },
              "categoryAxis": {
                  "axisLine": {
                      "show": true,
                      "lineStyle": {
                          "color": "#cccccc"
                      }
                  },
                  "axisTick": {
                      "show": false,
                      "lineStyle": {
                          "color": "#333"
                      }
                  },
                  "axisLabel": {
                      "show": true,
                      "textStyle": {
                          "color": "#999999"
                      }
                  },
                  "splitLine": {
                      "show": true,
                      "lineStyle": {
                          "color": [
                              "#eeeeee"
                          ]
                      }
                  },
                  "splitArea": {
                      "show": false,
                      "areaStyle": {
                          "color": [
                              "rgba(250,250,250,0.05)",
                              "rgba(200,200,200,0.02)"
                          ]
                      }
                  }
              },
              "valueAxis": {
                  "axisLine": {
                      "show": true,
                      "lineStyle": {
                          "color": "#cccccc"
                      }
                  },
                  "axisTick": {
                      "show": false,
                      "lineStyle": {
                          "color": "#333"
                      }
                  },
                  "axisLabel": {
                      "show": true,
                      "textStyle": {
                          "color": "#999999"
                      }
                  },
                  "splitLine": {
                      "show": true,
                      "lineStyle": {
                          "color": [
                              "#eeeeee"
                          ]
                      }
                  },
                  "splitArea": {
                      "show": false,
                      "areaStyle": {
                          "color": [
                              "rgba(250,250,250,0.05)",
                              "rgba(200,200,200,0.02)"
                          ]
                      }
                  }
              },
              "logAxis": {
                  "axisLine": {
                      "show": true,
                      "lineStyle": {
                          "color": "#cccccc"
                      }
                  },
                  "axisTick": {
                      "show": false,
                      "lineStyle": {
                          "color": "#333"
                      }
                  },
                  "axisLabel": {
                      "show": true,
                      "textStyle": {
                          "color": "#999999"
                      }
                  },
                  "splitLine": {
                      "show": true,
                      "lineStyle": {
                          "color": [
                              "#eeeeee"
                          ]
                      }
                  },
                  "splitArea": {
                      "show": false,
                      "areaStyle": {
                          "color": [
                              "rgba(250,250,250,0.05)",
                              "rgba(200,200,200,0.02)"
                          ]
                      }
                  }
              },
              "timeAxis": {
                  "axisLine": {
                      "show": true,
                      "lineStyle": {
                          "color": "#cccccc"
                      }
                  },
                  "axisTick": {
                      "show": false,
                      "lineStyle": {
                          "color": "#333"
                      }
                  },
                  "axisLabel": {
                      "show": true,
                      "textStyle": {
                          "color": "#999999"
                      }
                  },
                  "splitLine": {
                      "show": true,
                      "lineStyle": {
                          "color": [
                              "#eeeeee"
                          ]
                      }
                  },
                  "splitArea": {
                      "show": false,
                      "areaStyle": {
                          "color": [
                              "rgba(250,250,250,0.05)",
                              "rgba(200,200,200,0.02)"
                          ]
                      }
                  }
              },
              "toolbox": {
                  "iconStyle": {
                      "normal": {
                          "borderColor": "#999999"
                      },
                      "emphasis": {
                          "borderColor": "#666666"
                      }
                  }
              },
              "legend": {
                  "textStyle": {
                      "color": "#999999"
                  }
              },
              "tooltip": {
                  "axisPointer": {
                      "lineStyle": {
                          "color": "#cccccc",
                          "width": 1
                      },
                      "crossStyle": {
                          "color": "#cccccc",
                          "width": 1
                      }
                  }
              },
              "timeline": {
                  "lineStyle": {
                      "color": "#8fd3e8",
                      "width": 1
                  },
                  "itemStyle": {
                      "normal": {
                          "color": "#8fd3e8",
                          "borderWidth": 1
                      },
                      "emphasis": {
                          "color": "#8fd3e8"
                      }
                  },
                  "controlStyle": {
                      "normal": {
                          "color": "#8fd3e8",
                          "borderColor": "#8fd3e8",
                          "borderWidth": 0.5
                      },
                      "emphasis": {
                          "color": "#8fd3e8",
                          "borderColor": "#8fd3e8",
                          "borderWidth": 0.5
                      }
                  },
                  "checkpointStyle": {
                      "color": "#8fd3e8",
                      "borderColor": "rgba(138,124,168,0.37)"
                  },
                  "label": {
                      "normal": {
                          "textStyle": {
                              "color": "#8fd3e8"
                          }
                      },
                      "emphasis": {
                          "textStyle": {
                              "color": "#8fd3e8"
                          }
                      }
                  }
              },
              "visualMap": {
                  "color": [
                      "#516b91",
                      "#59c4e6",
                      "#a5e7f0"
                  ]
              },
              "dataZoom": {
                  "backgroundColor": "rgba(0,0,0,0)",
                  "dataBackgroundColor": "rgba(255,255,255,0.3)",
                  "fillerColor": "rgba(167,183,204,0.4)",
                  "handleColor": "#a7b7cc",
                  "handleSize": "100%",
                  "textStyle": {
                      "color": "#333333"
                  }
              },
              "markPoint": {
                  "label": {
                      "normal": {
                          "textStyle": {
                              "color": "#eeeeee"
                          }
                      },
                      "emphasis": {
                          "textStyle": {
                              "color": "#eeeeee"
                          }
                      }
                  }
              }
          });
      }));
          script>
        head>
        <body>
          <div id="chart">div>
          <script>
            const chartDom = document.getElementById('chart');
            // westeros是设置自定义主题
      	  // svg是底层转化为svg画布,页面可选中了
            const chart = echarts.init(chartDom, 'westeros', { renderer: 'svg' });
            chart.setOption({
              title: {
                text: 'ECharts 入门案例'
              },
              xAxis: {
                data: ['食品', '数码', '服饰', '箱包']
              },
              yAxis: {},
              series: {
                type: 'bar',  // 柱状图
                data: [100, 120, 90, 150]
              }
            });
          script>
        body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83
      • 84
      • 85
      • 86
      • 87
      • 88
      • 89
      • 90
      • 91
      • 92
      • 93
      • 94
      • 95
      • 96
      • 97
      • 98
      • 99
      • 100
      • 101
      • 102
      • 103
      • 104
      • 105
      • 106
      • 107
      • 108
      • 109
      • 110
      • 111
      • 112
      • 113
      • 114
      • 115
      • 116
      • 117
      • 118
      • 119
      • 120
      • 121
      • 122
      • 123
      • 124
      • 125
      • 126
      • 127
      • 128
      • 129
      • 130
      • 131
      • 132
      • 133
      • 134
      • 135
      • 136
      • 137
      • 138
      • 139
      • 140
      • 141
      • 142
      • 143
      • 144
      • 145
      • 146
      • 147
      • 148
      • 149
      • 150
      • 151
      • 152
      • 153
      • 154
      • 155
      • 156
      • 157
      • 158
      • 159
      • 160
      • 161
      • 162
      • 163
      • 164
      • 165
      • 166
      • 167
      • 168
      • 169
      • 170
      • 171
      • 172
      • 173
      • 174
      • 175
      • 176
      • 177
      • 178
      • 179
      • 180
      • 181
      • 182
      • 183
      • 184
      • 185
      • 186
      • 187
      • 188
      • 189
      • 190
      • 191
      • 192
      • 193
      • 194
      • 195
      • 196
      • 197
      • 198
      • 199
      • 200
      • 201
      • 202
      • 203
      • 204
      • 205
      • 206
      • 207
      • 208
      • 209
      • 210
      • 211
      • 212
      • 213
      • 214
      • 215
      • 216
      • 217
      • 218
      • 219
      • 220
      • 221
      • 222
      • 223
      • 224
      • 225
      • 226
      • 227
      • 228
      • 229
      • 230
      • 231
      • 232
      • 233
      • 234
      • 235
      • 236
      • 237
      • 238
      • 239
      • 240
      • 241
      • 242
      • 243
      • 244
      • 245
      • 246
      • 247
      • 248
      • 249
      • 250
      • 251
      • 252
      • 253
      • 254
      • 255
      • 256
      • 257
      • 258
      • 259
      • 260
      • 261
      • 262
      • 263
      • 264
      • 265
      • 266
      • 267
      • 268
      • 269
      • 270
      • 271
      • 272
      • 273
      • 274
      • 275
      • 276
      • 277
      • 278
      • 279
      • 280
      • 281
      • 282
      • 283
      • 284
      • 285
      • 286
      • 287
      • 288
      • 289
      • 290
      • 291
      • 292
      • 293
      • 294
      • 295
      • 296
      • 297
      • 298
      • 299
      • 300
      • 301
      • 302
      • 303
      • 304
      • 305
      • 306
      • 307
      • 308
      • 309
      • 310
      • 311
      • 312
      • 313
      • 314
      • 315
      • 316
      • 317
      • 318
      • 319
      • 320
      • 321
      • 322
      • 323
      • 324
      • 325
      • 326
      • 327
      • 328
      • 329
      • 330
      • 331
      • 332
      • 333
      • 334
      • 335
      • 336
      • 337
      • 338
      • 339
      • 340
      • 341
      • 342
      • 343
      • 344
      • 345
      • 346
      • 347
      • 348
      • 349
      • 350
      • 351
      • 352
      • 353
      • 354
      • 355
      • 356
      • 357
      • 358
      • 359
      • 360
      • 361
      • 362
      • 363
      • 364
      • 365
      • 366
      • 367
      • 368
      • 369
      • 370
      • 371
      • 372
      • 373
      • 374
      • 375
      • 376
      • 377
      • 378
      • 379
      • 380
      • 381
      • 382
      • 383
      • 384
      • 385
      • 386
      • 387
      • 388
      • 389
      • 390
      • 391
      • 392
      • 393
      • 394
      • 395
      • 396
      • 397
      • 398
      • 399
      • 400
      • 401
      • 402
      • 403
      • 404
      • 405
      • 406
      • 407
      • 408
      • 409
      • 410
      • 411
      • 412
      • 413
      • 414
      • 415
      • 416
      • 417
      • 418
      • 419
      • 420
      • 421
      • 422
      • 423
      • 424
      • 425
      • 426
      • 427
      • 428
      • 429
      • 430
      • 431
      • 432
      • 433
      • 434
      • 435
      • 436
      • 437
      • 438
      • 439
      • 440
      • 441
      • 442
      • 443
      • 444
      • 445
      • 446
      • 447
      • 448
      • 449
      • 450
      • 451
      • 452
      • 453
      • 454
      • 455
      • 456
      • 457
      • 458
      • 459
      • 460
      • 461
      • 462
      • 463
      • 464
      • 465
      • 466
      • 467
      • 468
      • 469
      • 470
      • 471
      • 472
      • 473
      • 474
      • 475
      • 476
      • 477
      • 478
      • 479
      • 480
      • 481
      • 482
      • 483
      • 484
      • 485
      • 486
      • 487
      • 488
      • 489
      • 490
      • 491
      • 492
      • 493
      • 494
      • 495
      • 496
      • 497
      • 498
      • 499
      • 500
      • 501
      • 502
      • 503
      • 504
      • 505
      • 506
      • 507
      • 508
      • 509
      • 510
      • 511
      • 512
      • 513
      • 514
      • 515
      • 516
      • 517
      • 518
      • 519
      • 520
      • 521
      • 522
      • 523
      • 524
      • 525
      • 526
      • 527
      • 528
      • 529
      • 530
      • 531
      • 532
      • 533
      • 534
      • 535
      • 536
      • 537
      • 538
      • 539
      • 540
      • 541
      • 542
      • 543
      • 544
      • 545
      • 546
      • 547
      • 548
      • 549

    ECharts

    • 详细学习这个工具,官网也可学到哦!
    • 系列(series):一组数值以及他们映射成的图(绘图),柱状图、折线图、饼图都是在这画的
      DOCTYPE html>
      <html>
        <head>
          <meta charset="utf-8">
          <script src="https://cdn.jsdelivr.net/npm/echarts@4.7.0/dist/echarts.js">script>
          <style>
            #chart {
              width: 800px;
              height: 400px;
            }
          style>
        head>
        <body>
          <div id="chart">div>
          <script>
            const chartDom = document.getElementById('chart');
            const chart = echarts.init(chartDom);
            chart.setOption({
              dataset: {
                source: [
                  ['一季度', 100, 79, '分类1', 50],
                  ['二季度', 112, 81, '分类2', 60],
                  ['三季度', 96, 88, '分类3', 55],
                  ['四季度', 123, 72, '分类4', 70]
                ]
              },
              title: {
                text: 'ECharts 多系列案例',
                subtext: '慕课网数据可视化课程'
              },
              xAxis: {
                data: ['一季度', '二季度', '三季度', '四季度']
              },
              yAxis: {},
              legend: {
                data: [{
                  name: '分类',
                  icon: 'circle',
                  textStyle: {
                    color: 'red'
                  }
                }, '折线图', '柱状图'],
                left: 300
              },
              grid: {
                  top: 100,
                  left: '10%',
                  right: '10%',
                  bottom: 100
              },
              toolbox: {
                  feature: {
                      saveAsImage: {},
                      dataZoom: {
                          yAxisIndex: false
                      },
                      restore: {}
                  }
              },
              dataZoom: [
                  {
                      show: true,
                      start: 30,
                      end: 70
                  }
              ],
              series: [{
                name: '分类',
                type: 'pie',
                center: ['65%', 60],
                radius: 35,
                encode: { itemName: 3, value: 4 }
              }, {
                name: '折线图',
                type: 'line',
                encode: { x: 0, y: 1 }
              }, {
                name: '柱状图',
                type: 'bar',
                encode: { x: 0, y: 2 }
              }]
            });
          script>
        body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83
      • 84
      • 85

    4

    • 数据集(dataset):让数据可以单独管理(数据一起被放在不同的列),被多个组件复用(各取各的列)
    • 组件,画布的基础部分,横纵轴(不是坐标系)、grid(直角坐标系地板)等
      1
    • 定位:类似CSS的绝对定位,以container(画布)为边界设置组件或者系列的位置
      2
    • 坐标系:最常见的直角坐标系是由三个组件组成的(yAxis/xAxis/grid),双坐标系(一个直角系有两个图)和多坐标系
      DOCTYPE html>
      <html>
        <head>
          <meta charset="utf-8">
          <script src="https://cdn.jsdelivr.net/npm/echarts@4.7.0/dist/echarts.js">script>
          <style>
            #chart {
              width: 800px;
              height: 400px;
            }
          style>
        head>
        <body>
          <div id="chart">div>
          <script>
            const chartDom = document.getElementById('chart');
            const chart = echarts.init(chartDom);
            chart.setOption({
              xAxis: [{
                type: 'category', // 必须指定为category
                gridIndex: 0
              }, {
                type: 'category',	// 第二个直角坐标系
                gridIndex: 1
              }],
              yAxis: [{
                min: 0,	// 限定y轴范围,让画面更好看
                max: 100,
                gridIndex: 0	// x轴和y轴都要指定grid
              }, {
                splitLine: {
                  show: false	// 不显示右边坐标轴的线,更好看
                },
                gridIndex: 0
              }, {
                min: 0,	// 第二个坐标系的
                max: 150,
                gridIndex: 1
              }],
              grid: [{	// 两个grid,xAxis的gridIndex对应这里
                bottom: '55%'	// 分开两个坐标系
              }, {
                top: '55%'	// 第二个坐标系举例顶部55%,两个就相距10%
              }],
              dataset: {
                source: [
                  ['product', '2012', '2013', '2014', '2015'],
                  ['Matcha Latte', 41.1, 30.4, 65.1, 53.3],
                  ['Milk Tea', 86.5, 92.1, 85.7, 83.1]
                ]
              },
              series: [{
                type: 'bar',
                seriesLayoutBy: 'row',
                xAxisIndex: 0,
                yAxisIndex: 0
              }, {
                type: 'line',
                seriesLayoutBy: 'row',	// 设置按行使用数据
                xAxisIndex: 0,	// 这两个都是0,表示共用第一个x轴
                yAxisIndex: 1		// 使用第二行数据
              }, {
                type: 'bar',
                seriesLayoutBy: 'row',
                xAxisIndex: 1,	// 使用第二个x轴
                yAxisIndex: 2
              }]
            });
          script>
        body>
      html>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      3

    对比

    • 总得来说,还是更推荐ECharts的,文档社区也很完善!移动端支持良好
      6

    数据报表项目

    • 项目初始化,静态页面开发,API联调,发布上线
    • 配置node
      • 直接下载安装node,可以参考
      • 配置环境变量如果出错需要先删除C:/User下面的.npmrc文件才能重新配置
      • nodeJS安装文件夹下创建文件需要打开管理员cmd(全局安装包的时候也需要)
      • 需要配置NODE_PATH
        1
      • 安装Vue脚手架:cnpm i -g @vue/cli
      • 创建项目:切换到想创建项目的目录,vue create roy-datav-report-dev,按空格选中
        2
        3
        4
      • Vue也是用npm管理的包,需要将npm的包模块添加到Path环境变量:E:\nodeJS\node_global,否则vue命令不能用
      • 学一下Vue基础用法
      • Vue2和3的区别建议使用Vue2,因为element-ui不支持Vue3,需要element-plus
    • 运行项目:npm run serve,如果有文件权限问题,可以在文件夹属性设置打开
      • 项目初始化,修改一下文件
      • 安装element-ui和ECharts的库
        • vue add element,按需引入;启动前可将elint的检查关掉:'indent': 'off'
          5
        • 在plugins下面可以看到element.js,需要什么组件在这引入即可
        • cnpm i -S echarts,-S表示将依赖加到dependency,方便每次使用,在main.js
          import ECharts from 'echarts'   // 直接使用$echarts,不用每次import
          Vue.prototype.$echarts = ECharts
          
          • 1
          • 2
        • package.json
          "dependencies": {
              "core-js": "^3.8.3",
              "element-ui": "^2.4.5",
              "echarts": "^5.3.3",
              "vue": "^2.6.14",
              "vue-router": "^3.5.1"
          },
          
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
      • App.vue
        <template>
          <div id="app">
          	
        	
            <router-view/>
          div>
        template>
        
        <script>
        
        export default {
          name: 'app'
        }
        script>
        
        <style lang="scss">
        html, body, #app {
          width: 100%;
          height: 100%;
          margin: 0;
          padding: 0;
        }
        style>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
    • 引入其他4个组件
      • 自定义vue文件模板
      • TopView,components下新建文件夹和index.vue
      • SalesView
      • BottomView
      • MapView
        <template>
          <div class="home">
            
            
            <top-view />
            <sales-view />
            <bottom-view />
            <map-view />
          div>
        template>
        
        <script>
          import TopView from "../components/TopView"
          import SalesView from "../components/SalesView"
          import BottomView from "../components/BottomView"
          import MapView from "../components/MapView"
        
          export default {
            name: 'Home',
            components: {
              TopView,
              SalesView,
              BottomView,
              MapView
            }
          }
        script>
        
        <style>
          .home {
            width: 100%;
            height: 100%;
            padding: 20px;	
            background: #eee;
          }
        style>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35
        • 36

    TopView组件开发

    • 页面布局主要使用elementCard,接下来逐个开发四个component
      1
    • 引入Card
      • 修改element.js和TopView/index.vue
      • 并且加入Row和Col,水平布局
        2
        // element.js
        import Vue from 'vue'
        import { Card, Row, Col } from 'element-ui'
        
        Vue.use(Card)
        Vue.use(Row)
        Vue.use(Col)
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        // index.vue
        <template>
          <div class="top-view">
            
            <el-row :gutter="20">
            	
                <el-col :span="6">
                    <el-card shadow="hover">
                        鼠标悬浮显示
                    el-card>
                el-col>
                <el-col :span="6">
                    <el-card shadow="hover">
                        鼠标悬浮显示
                    el-card>
                el-col>
                <el-col :span="6">
                    <el-card shadow="hover">
                        鼠标悬浮显示
                    el-card>
                el-col>
                <el-col :span="6">
                    <el-card shadow="hover">
                        鼠标悬浮显示
                    el-card>
                el-col>
            el-row>
          div>
        template>
        
        <script>
        export default {
          data () {
            return {}
          },
          methods: {},
        }
        script>
        
        <style scoped>
        style>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35
        • 36
        • 37
        • 38
        • 39
        • 40
        • 41
    • 封装通用组件
      • 组件引用关系:TopView <- TotalSales/TotalUsers…(针对TopView的四部分) <- CommonCard(公共组件,方便后续统一操作共有属性)
        // TotalUsers/index.vue,其他三部分同理
        <template>
          <common-card />
        template>
        
        <script>
            import CommonCard from '../CommonCard'
            export default {
                components: {
                    CommonCard
                }
            }
        script>
        
        <style scoped>
        style>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        // CommonCard/index.vue
        <template>
            <div class="common-card">
              <div class="title">{{title}}div>
              <div class="value">{{value}}div>
              <div class="chart">
                <slot>slot>
              div>
              <div class="line" />
              <div class="total">
                
                <slot name="footer">slot>
              div>
            div>
          template>
          
          <script>
            export default {
              // 接收别的组件传过来的数据(在别的组件调用)
              props: {
                title: String,
                value: [String, Number]
              }
            }
          script>
          
          <style lang="scss" scoped>
            .title {
              font-size: 12px;
              color: #999;
            }
            .value {
              font-size: 25px;
              color: #000;
              margin-top: 5px;
              letter-spacing: 1px;
            }
            .chart {
              height: 50px;
            }
            .line {
              margin: 10px 0;
              border-top: 1px solid #eee;
            }
            .total {
              font-size: 12px;
              color: #666;
            }
          style>
          
          <style lang="scss">
            .emphasis {
              margin-left: 5px;
              color: #333;
              font-weight: 700;
            }
            .increase {
              width: 0;
              height: 0;
              border-width: 3px;
              border-color: transparent transparent red transparent;
              border-style: solid;
              margin: 0 0 3px 5px;
            }
            .decrease {
              width: 0;
              height: 0;
              border-width: 3px;
              border-color: green transparent transparent transparent;
              border-style: solid;
              margin: 7px 0 0 5px;
            }
          style>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35
        • 36
        • 37
        • 38
        • 39
        • 40
        • 41
        • 42
        • 43
        • 44
        • 45
        • 46
        • 47
        • 48
        • 49
        • 50
        • 51
        • 52
        • 53
        • 54
        • 55
        • 56
        • 57
        • 58
        • 59
        • 60
        • 61
        • 62
        • 63
        • 64
        • 65
        • 66
        • 67
        • 68
        • 69
        • 70
        • 71
        • 72
        • 73
    • 新建src/mixins,减少共用代码的编写
      // commonCardMixin.js
      import CommonCard from '../components/CommonCard/index'
      
      // 这些是TopView中各组件用到的公共代码
      export default {
          components: {
              CommonCard
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      <script>
      	// 在各组件使用
          import commonCardMixin from '@/mixins/commonCardMixin';
          export default {
              mixins: [commonCardMixin]
          }
      script>
      // TopView <- TotalSales/TotalUsers... <- mixin <- CommonCard
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    • 使用props传递数据,使用插槽slot传递标签和数据,使用CSS绘制三角形箭头
      // TotalSales/index.vue
      <template>
        
        <common-card title='累积销售额' value="¥ 666666">
          <template>
              <div class="compare-wrapper">
                  <div class="compare">
                  <span>日同比span>
                  <span>7.33%span>
                  <div class="increase">div>
              div>
              <div class="compare">
                  <span>月同比span>
                  <span>7.33%span>
                  <div class="decrease">div>
              div>
              div>
          template>
          <template v-slot:footer>
              <span>昨日销售额 span>
              <span class="emphasis">¥ 30000span>
          template>
        common-card>
      template>
      
      <script>
          import commonCardMixin from '@/mixins/commonCardMixin';
          export default {
              mixins: [commonCardMixin]
          }
      script>
      
      <style lang="scss" scoped>
          .compare-wrapper {
              height: 100%;
              display: flex;
              flex-direction: column;
              justify-content: center;
          }
          .compare {
              display: flex;
              align-items: center;
              font-size: 12px;
              margin-top: 3px;
              color: #666;
              // 下面这些公共样式也放在CommonCard
              .increase {
                  width: 0;
                  height: 0;
                  border-width: 5px;
                  border-color: transparent transparent red transparent;
                  border-style: solid;
                  margin: 0 0 3px 5px;
              }
              .decrease {
                  width: 0;
                  height: 0;
                  border-width: 5px;
                  border-color: green transparent transparent transparent;
                  border-style: solid;
                  margin: 7px 0 0 5px;    // 上右下左
              }
          }
      style>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
    • 上面完整搞完了total-sales,接下来是total-orders,主要是使用ECharts,其他的不说了
      4
      <template>
          
        <common-card title='累积订单量' value="¥ 777777">
          <template>
            
            <div id="total-order-chart" :style="{width:'100%', height:'100%'}">div>
          template>
          <template v-slot:footer>
              <span>昨日订单量 span>
              <span class="emphasis">¥ 777777span>
          template>
        common-card>
      template>
      
      <script>
          import commonCardMixin from '@/mixins/commonCardMixin'
          // import commonDataMixin from '@/mixins/commonDataMixin'
      
          export default {
              mixins: [commonCardMixin],
              mounted() {
                  const chartDom = document.getElementById('total-order-chart')
                  const chart = this.$echarts.init(chartDom)  // 全局的实例都可以用这个变量
                  chart.setOption({
                      xAxis: {
                          type: 'category',   // 分类(不同的柱子)
                          show: false,
                          boundaryGap: false  // 让chart完全伸展开,占满
                      },
                      yAxis: {
                          show: false // 不显示
                      },
                      series: [{
                          type: 'line',   // 折线图
                          data: [234, 456, 567, 345, 678, 123, 345, 478, 627],
                          areaStyle: {    // 显示面积(填充)
                              color: 'purple'
                          },
                          lineStyle: {
                              width: 0    // 不显示线
                          },
                          itemStyle: {
                              opacity: 0  // 不显示圈
                          },
                          smooth: true    // 平滑显示
                      }],
                      grid: {
                          // 顶格显示
                          top: 0,
                          bottom: 0,
                          left: 0,
                          right: 0
                      }
                  })
              }
          }
      script>
      
      <style scoped>
      style>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
    • 今日交易用户数类似,比较难的是累积用户数那个图;首先明确,绘图就要用到series;这里用到stack合并图
    • 图标库找到三角形的svg参数
    • 设置绘图参数可以看文档
      <template>
        <common-card title='累积用户数' value="¥ 18877"> 
          <template>
            <div id="total-users-chart" :style="{width:'100%', height:'100%'}">div>
          template>
          <template v-slot:footer>
              <div class="total-users">
                  <span>日同比 span>
                  <span class="emphasis">8.77%span>
                  
                  <div class="increase">div>
                  <span>月同比 span>
                  <span class="emphasis">8.77%span>
                  <div class="decrease">div>
              div>
          template>
        common-card>
      template>
      
      <script>
          import commonCardMixin from '@/mixins/commonCardMixin';
          export default {
              mixins: [commonCardMixin],
              mounted() {
                  const chartDom = document.getElementById('total-users-chart')
                  const chart = this.$echarts.init(chartDom)
                  chart.setOption({
                      color: ['#3398DB'],
                      // 让x轴放值,y轴作为类别,相当于放倒的柱状图
                      xAxis: {
                          type: 'value',
                          show: false,
                      },
                      yAxis: {
                          type: 'category',
                          show: false,
                      },
                      series: [{
                          type: 'bar',   // 柱状图
                          data: [207],
                          stack: '总量',  // stack一样的系列可以放在一个柱子上
                          barWidth: 10, // 柱子的宽度
                          itemStyle: {
                              color: '#45c946'
                          }
                      },{
                          type: 'bar',
                          data: [107],
                          stack: '总量',
                          // barWidth: 10 写一个就行
                          itemStyle: {
                              color: '#eee'
                          }
                      },{
                          // 绘制那两个三角形
                          type: 'custom',
                          data: [207],
                          stack: '总量',
                          itemStyle: {
                              color: '#45c946'
                          },
                          renderItem: (param, api) => {
                              // 查看功能
                              // console.log(param, api)
                              // 找到绘制点
                              const value = api.value(0)
                              const endPoint = api.coord([value], 0)
                              // 绘制
                              return {
                                  type: 'group',  // 绘制多个
                                  position: endPoint,
                                  children: [{
                                      type: 'path',
                                      shape: {
                                      // 在矢量图库找到这个参数
                                      d: 'M957.056 338.624C951.84 327.296 940.512 320 928 320L96 320c-12.512 0-23.84 7.296-29.088 18.624-5.216 11.36-3.328 24.704 4.768 34.208l416 485.344c6.08 7.104 14.944 11.2 24.288 11.2s18.208-4.096 24.288-11.2l416-485.344C960.448 363.328 962.272 349.984 957.056 338.624z',  // 指定svg图片
                                      x: -5,  // 在绘制点的基础上微调
                                      y: -15,
                                      width: 10,
                                      height: 10,
                                      layout: 'cover' // 拉伸填充
                                      },
                                      style: {
                                          fill: 'red'
                                      }
                                  },{
                                      type: 'path',
                                      shape: {
                                      d: 'M952.32 715.2l-416-485.376c-12.16-14.176-36.448-14.176-48.608 0l-416 485.376c-8.128 9.472-9.984 22.848-4.768 34.176C72.16 760.704 83.488 768 96 768l832 0c12.512 0 23.84-7.296 29.056-18.624S960.448 724.672 952.32 715.2z',
                                      x: -5,  // 在绘制点的基础上微调
                                      y: 5,
                                      width: 10,
                                      height: 10,
                                      layout: 'center' // 保持原来svg比例
                                      },
                                      style: {
                                          fill: 'red'
                                      }
                                  }
                              ]
                              }
                          }
                      }],
                      grid: {
                          // 顶格显示
                          top: 0,
                          bottom: 0,
                          left: 0,
                          right: 0
                      }
                  })
              }
          }
      script>
      
      <style scoped>
          .total-users {
              display: flex;
              /* 垂直居中 */
              align-items: center;
          }
      style>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83
      • 84
      • 85
      • 86
      • 87
      • 88
      • 89
      • 90
      • 91
      • 92
      • 93
      • 94
      • 95
      • 96
      • 97
      • 98
      • 99
      • 100
      • 101
      • 102
      • 103
      • 104
      • 105
      • 106
      • 107
      • 108
      • 109
      • 110
      • 111
      • 112
      • 113
      • 114
      • 115
      • 116
      • 117
      • 118
      • 119
      • 120
      • 121
      • 122
      5
      • 问:能不能让最后这两个bar占满chart部分,并按比例自动调整?可能需要换个写法
    • 这部分基本完成,只不过数据还是写死的
      • 发现代码还是比较复杂,下面介绍两个新的框架

    vue-echarts

    • 基于ECharts5和Vue2/3开发出来的,官方文档
    • 安装:npm install echarts vue-echarts --force,和之前的依赖有些冲突
    • main.js全局注册
      import VueEcharts from 'vue-echarts'
      // 和prototype有啥区别
      Vue.component('v-chart', VueEcharts) // import + export to global
      
      • 1
      • 2
      • 3
    • 在SalesView测试使用,就是显示不出来?升级了Vue到2.7.0无济于事
      <template>
        <div id="app">
          <!-- 默认都是100%,用div限制一下 -->
          <v-chart :options="data" />
        </div>
      </template>
      
      <script>
        export default {
            data() {
                return {
                    data: {
                        xAxis: {
                            type: 'category',
                        },
                        yAxis: {
                        },
                        series: [{
                            type: 'line',   // 折线图
                            data: [234, 678, 123, 345, 478, 627],
                        }]
                    }
                }
            }
        }
      </script>
      
      <style scoped>
        #app {
          height: 300px;
        }
      </style>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
    • 优点:写法更加简洁,兼容ECharts

    v-charts

    • 和上面的不太一样,官方文档
    • 安装:cnpm i -S v-charts,还是依赖ECharts的
    • 类似element,创建vcharts.js,在main.js导入
      import Vue from 'vue'
      import { VeLine } from "v-charts/lib/line.common";
      
      Vue.component('ve-line', VeLine)    // 直接提供组件
      
      • 1
      • 2
      • 3
      • 4
    • 使用
      <template>
        <ve-line 
          :data="datas"
        />
      </template>
      
      <script>
      export default {
        data () {
          return {
            datas: {
              columns: ['日期', '销售额'],
              rows: [
                { '日期': '1月1日', '销售额': 123 },
                { '日期': '1月2日', '销售额': 1223 },
                { '日期': '1月3日', '销售额': 2123 },
                { '日期': '1月4日', '销售额': 4123 },
                { '日期': '1月5日', '销售额': 3123 },
                { '日期': '1月6日', '销售额': 7123 }
              ]
            }
          }
        }
      }
      </script>
      
      <style scoped>
      </style>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
    • 优点:可以使用它封装的很多图表,比如词云图、水球图等
    • 缺点:和ECharts有些不兼容,需要二次学习,改变样式可能会比较复杂,建议使用vue-echarts

    替换

    • 将之前写的TopView更新,vue-echarts能用了,可能是因为换了闭合标签;这里用了methods,因为后面数据时动态传递的,需要调用方法更新
      <template>
          
        <common-card title='累积订单量' value="¥ 777777">
          <template v-slot:middle>
              
              
              <v-chart :option="getOptions()">v-chart>
          template>
          <template v-slot:footer>
              <span>昨日订单量 span>
              <span class="emphasis">¥ 777777span>
          template>
        common-card>
      template>
      
      <script>
          import commonCardMixin from '@/mixins/commonCardMixin'
          // import commonDataMixin from '@/mixins/commonDataMixin'
      
          export default {
              mixins: [commonCardMixin],
              methods: {
                  getOptions() {
                      return {
                          xAxis: {
                              type: 'category',   // 区分data的每个数据
                              show: false,
                              boundaryGap: false  // 让chart完全伸展开,占满
                          },
                          yAxis: {
                              show: false // 不显示
                          },
                          series: [{
                              type: 'line',   // 折线图
                              data: [234, 456, 567, 345, 678, 123, 345, 478, 627],
                              areaStyle: {    // 显示面积(填充)
                                  color: 'purple'
                              },
                              lineStyle: {
                                  width: 0    // 不显示线
                              },
                              itemStyle: {
                                  opacity: 0  // 不显示圈
                              },
                              smooth: true    // 平滑显示
                          }],
                          grid: {
                              // 顶格显示
                              top: 0,
                              bottom: 0,
                              left: 0,
                              right: 0
                          }
                      }
                  }
              }
          }
      script>
      
      <style scoped>
      style>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
    • 其他组件的修改也是类似的
    • 可以创建src/style/index.css存放全局公共样式,记得在main.js引入
    • 继续组件的开发

    SalesView

    • header部分主要是element-ui的一些使用技巧,先开发上面的日期;记得在element.js注册(按需加载)
      1
      <template>
        <div class="sales-view">
          <el-card shadow="hover">
            
            
            <template v-slot:header>
              <div class="menu-wrapper">
                
                <el-menu class="sales-menu" mode="horizontal" :default-active="activeIndex" @select="onMenuSelect">
                  
                  <el-menu-item index="1">销售额el-menu-item>
                  <el-menu-item index="2">访问量el-menu-item>
                el-menu>
                <div class="menu-right">
                  
                  <el-radio-group v-model="radioSelect">
                    <el-radio-button label="今日">el-radio-button>
                    <el-radio-button label="本周">el-radio-button>
                    <el-radio-button label="本月">el-radio-button>
                    <el-radio-button label="本年">el-radio-button>
                  el-radio-group>
                  
                  <el-date-picker 
                    type="daterange" 
                    v-model="date" 
                    range-separator="" 
                    start-placeholder="开始日期" 
                    end-placeholder="开始日期" 
                    size="small" 
                    :picker-options="pickerOptions"
                    unlink-panels
                    class="sales-picker"
                  />
                div>
              div>
            template>
          el-card>
        div>
      template>
      
      <script>
      export default {
        // data()是默认的方法
        data() {
          return {
            activeIndex: '1',
            radioSelect: '今日',
            date: null,
            pickerOptions: {
              // 配置左侧快捷键
              shortcuts: [{
                text: "最近一周",
                onClick(picker) {
                  const start = new Date()
                  const end = new Date()
                  start.setTime(start.getTime() - 3600 * 24 * 1000 * 7) // 毫秒运算
                  // debugger 开启调试,方便追踪代码,F12继续执行
                  picker.$emit('pick', [start, end], true)  // visiable=true 即选中日期后不关闭框
                }
              },{
                text: "最近一月",
                onClick(picker) {
                  const start = new Date()
                  const end = new Date()
                  start.setTime(start.getTime() - 3600 * 24 * 1000 * 30) // 毫秒运算
                  picker.$emit('pick', [start, end])
                }
              },{
                text: "最近三月",
                onClick(picker) {
                  const start = new Date()
                  const end = new Date()
                  start.setTime(start.getTime() - 3600 * 24 * 1000 * 90) // 毫秒运算
                  picker.$emit('pick', [start, end])
                }
              }]
            }
          };
        },
        methods: {
          onMenuSelect(index) {
            this.activeIndex = index
            console.log(this.activeIndex)
          }
        }
      };
      script>
      
      <style lang="scss" scoped>
        .sales-view {
          margin-top: 20px;
          .menu-wrapper {
            position: relative;
            display: flex;
            .sales-menu {
              width: 100%;
              padding-left: 20px;
              .el-menu-item {
                height: 50px;
                line-height: 50px;
                margin: 0 20px;
              }
            }
            .menu-right {
              position: absolute;
              top: 0;
              right: 20px;
              height: 50px;
              display: flex;
              align-items: center;
              // 水平方向
              justify-content: flex-end;
              .sales-picker {
                margin-left: 20px;
              }
            }
          }
        }
      style>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83
      • 84
      • 85
      • 86
      • 87
      • 88
      • 89
      • 90
      • 91
      • 92
      • 93
      • 94
      • 95
      • 96
      • 97
      • 98
      • 99
      • 100
      • 101
      • 102
      • 103
      • 104
      • 105
      • 106
      • 107
      • 108
      • 109
      • 110
      • 111
      • 112
      • 113
      • 114
      • 115
      • 116
      • 117
      • 118
      • 119
    • header搞完,用vue-echarts搞柱状图,用CSS搞右侧排行榜(一层套一层)
      <template>
        <div class="sales-view">
          <el-card shadow="hover" :body-style="{padding: '0 0 20px 0'}">
            
            
            <template v-slot:header>
              <div class="menu-wrapper">
                
                <el-menu class="sales-menu" mode="horizontal" :default-active="activeIndex" @select="onMenuSelect">
                  
                  <el-menu-item index="1">销售额el-menu-item>
                  <el-menu-item index="2">访问量el-menu-item>
                el-menu>
                <div class="menu-right">
                  
                  <el-radio-group v-model="radioSelect">
                    <el-radio-button label="今日">el-radio-button>
                    <el-radio-button label="本周">el-radio-button>
                    <el-radio-button label="本月">el-radio-button>
                    <el-radio-button label="本年">el-radio-button>
                  el-radio-group>
                  
                  <el-date-picker 
                    type="daterange" 
                    v-model="date" 
                    range-separator="" 
                    start-placeholder="开始日期" 
                    end-placeholder="开始日期" 
                    size="small" 
                    :picker-options="pickerOptions"
                    unlink-panels
                    class="sales-picker"
                  />
                div>
              div>
            template>
            <tempate>
              <div class="sales-chart-wrapper">
                
                <v-chart :option="chartOption">v-chart>
                
                <div class="sales-list">
                  <div class="sales-list-title">排行榜div>
                  <div class="list-item-wrapper">
                    
                    <div class="list-item" v-for="item in rankData" :key="item.no">
                    
                    
                    
                    <div class="list-item-no" :class="+item.no <= 3 ? 'top-no' : ''">{{item.no}}div>
                    <div class="list-item-name">{{item.name}}div>
                    <div class="list-item-money">{{item.money}}div>
                  div>
                  div>
                div>
              div>
            tempate>
          el-card>
        div>
      template>
      
      <script>
      export default {
        // data()是默认的方法
        data() {
          return {
            activeIndex: '1',
            radioSelect: '今日',
            date: null,
            // element-ui的日期组件参数定义
            pickerOptions: {
              // 配置左侧快捷键
              shortcuts: [{
                text: "最近一周",
                onClick(picker) {
                  const start = new Date()
                  const end = new Date()
                  start.setTime(start.getTime() - 3600 * 24 * 1000 * 7) // 毫秒运算
                  // debugger 开启调试,方便追踪代码,F12继续执行
                  picker.$emit('pick', [start, end], true)  // visiable=true 即选中日期后不关闭框
                }
              },{
                text: "最近一月",
                onClick(picker) {
                  const start = new Date()
                  const end = new Date()
                  start.setTime(start.getTime() - 3600 * 24 * 1000 * 30) // 毫秒运算
                  picker.$emit('pick', [start, end])
                }
              },{
                text: "最近三月",
                onClick(picker) {
                  const start = new Date()
                  const end = new Date()
                  start.setTime(start.getTime() - 3600 * 24 * 1000 * 90) // 毫秒运算
                  picker.$emit('pick', [start, end])
                }
              }]
            },
            // 右侧数据
            rankData: [
                {
                  no: 1,
                  name: '麦当劳',
                  money: '666666'
                },
                {
                  no: 2,
                  name: '肯德基',
                  money: '666666'
                },
                {
                  no: 3,
                  name: '德克士',
                  money: '666666'
                },
                {
                  no: 4,
                  name: '华莱士',
                  money: '666666'
                },
                {
                  no: 5,
                  name: '汉堡王',
                  money: '666666'
                },
                {
                  no: 6,
                  name: '马格格',
                  money: '666666'
                }
            ],
            // 左侧柱状图
            chartOption: {
              title: {
                text: '年度销售额',
                textStyle: {
                  fontSize: 12,
                  color: '#666',
                },
                left: 25,
                top: 20
              },
              xAxis: {
                  type: 'category',
                  data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
                  axisTick: {
                    // show: false
                    alignWithLabel: true,  // 坐标轴上的短线放在柱子正下方
                    lineStyle: {
                      color: '#999'
                    }
                  },
                  axisLine: {
                    lineStyle: {
                      color: '#999'
                    }
                  }
              },
              yAxis: {
                axisLine: {
                  show: false // 坐标轴
                },
                axisTick: {
                  show: false // 坐标轴上的小短线
                },
                splitLine: {
                  lineStyle: {
                    type: 'dotted', // 网格线,用点画,浅色
                    color: '#eee'
                  }
                }
              },
              series: [{
                  type: 'bar',
                  data: [307, 200, 400, 390, 800, 122, 307, 200, 400, 390, 800, 122],
                  barWidth: '35%',
                  itemStyle: {
                      color: '#45c946'
                  }
              }],
              grid: {
                  // 顶格显示
                  top: 70,
                  bottom: 50,
                  left: 60,
                  right: 60
              },
              color: ['#3398DB']
            }
          };
        },
        methods: {
          onMenuSelect(index) {
            this.activeIndex = index
            console.log(this.activeIndex)
          }
        }
      };
      script>
      
      <style lang="scss" scoped>
        .sales-view {
          margin-top: 20px;
          .menu-wrapper {
            position: relative;
            display: flex;
            .sales-menu {
              width: 100%;
              padding-left: 20px;
              .el-menu-item {
                height: 50px;
                line-height: 50px;
                margin: 0 20px;
              }
            }
            .menu-right {
              position: absolute;
              top: 0;
              right: 20px;
              height: 50px;
              display: flex;
              align-items: center;
              // 水平方向
              justify-content: flex-end;
              .sales-picker {
                margin-left: 20px;
              }
            }
          }
          .sales-chart-wrapper {
            display: flex;
            height: 270px;
            // 左侧的vue-echarts
            .echarts {
              flex: 0 0 70%;
              width: 70%;
              height: 100%;
            }
            // 占据剩余部分
            .sales-list {
              flex: 1;
              width: 100%;
              height: 100%;
              overflow: hidden; // ?
              .sales-list-title {
                margin-top: 20px;
                font-size: 12px;
                color: #666;
                font-weight: 500;
              }
              .list-item-wrapper {
                margin-top: 15px;
                .list-item {
                  display: flex;  // 序号 内容
                  align-items: center;
                  font-size: 12px;
                  height: 20px;
                  padding: 6px 20px 6px 0;
                  .list-item-no {
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    width: 20px;
                    height: 20px;
                    color: #333;
                    &.top-no {
                      background: #000;
                      border-radius: 50%;
                      color: #fff;
                      font-weight: 500;
                    }
                  }
                  .list-item-name {
                    margin-left: 10px;
                    color: #333;
                  }
                  .list-item-money {
                    flex: 1;  // 把剩下的占满
                    text-align: right;
                  }
                }
              }
            }
      
          }
        }
      style>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83
      • 84
      • 85
      • 86
      • 87
      • 88
      • 89
      • 90
      • 91
      • 92
      • 93
      • 94
      • 95
      • 96
      • 97
      • 98
      • 99
      • 100
      • 101
      • 102
      • 103
      • 104
      • 105
      • 106
      • 107
      • 108
      • 109
      • 110
      • 111
      • 112
      • 113
      • 114
      • 115
      • 116
      • 117
      • 118
      • 119
      • 120
      • 121
      • 122
      • 123
      • 124
      • 125
      • 126
      • 127
      • 128
      • 129
      • 130
      • 131
      • 132
      • 133
      • 134
      • 135
      • 136
      • 137
      • 138
      • 139
      • 140
      • 141
      • 142
      • 143
      • 144
      • 145
      • 146
      • 147
      • 148
      • 149
      • 150
      • 151
      • 152
      • 153
      • 154
      • 155
      • 156
      • 157
      • 158
      • 159
      • 160
      • 161
      • 162
      • 163
      • 164
      • 165
      • 166
      • 167
      • 168
      • 169
      • 170
      • 171
      • 172
      • 173
      • 174
      • 175
      • 176
      • 177
      • 178
      • 179
      • 180
      • 181
      • 182
      • 183
      • 184
      • 185
      • 186
      • 187
      • 188
      • 189
      • 190
      • 191
      • 192
      • 193
      • 194
      • 195
      • 196
      • 197
      • 198
      • 199
      • 200
      • 201
      • 202
      • 203
      • 204
      • 205
      • 206
      • 207
      • 208
      • 209
      • 210
      • 211
      • 212
      • 213
      • 214
      • 215
      • 216
      • 217
      • 218
      • 219
      • 220
      • 221
      • 222
      • 223
      • 224
      • 225
      • 226
      • 227
      • 228
      • 229
      • 230
      • 231
      • 232
      • 233
      • 234
      • 235
      • 236
      • 237
      • 238
      • 239
      • 240
      • 241
      • 242
      • 243
      • 244
      • 245
      • 246
      • 247
      • 248
      • 249
      • 250
      • 251
      • 252
      • 253
      • 254
      • 255
      • 256
      • 257
      • 258
      • 259
      • 260
      • 261
      • 262
      • 263
      • 264
      • 265
      • 266
      • 267
      • 268
      • 269
      • 270
      • 271
      • 272
      • 273
      • 274
      • 275
      • 276
      • 277
      • 278
      • 279
      • 280
      • 281
      • 282
      • 283
      • 284
      • 285
      • 286
      • 287
      • 288

    BottomView

    • 关键词搜索这几个字就用el-card,chart也放在这里面,用vue-echarts搞
    • 相关操作的注释放在代码里,主要包括:数据分页(el-table)、环形饼图的定制、CSS样式的调整
      <template>
        <div class="bottom-view">
          <div class="view">
            <el-card shadow="hover">
              <template v-slot:header>
                <div class="title-wrapper">
                  <div class="title">关键词搜索div>
                div>
              template>
              
              <div class="chart-wrapper">
                <div class="chart-inner">
                  <div class="chart">
                    <div class="chart-title">搜索用户数div>
                    <div class="chart-data">93634div>
                    <v-chart :option="searchUserOption">v-chart>
                  div>
                  <div class="chart">
                    <div class="chart-title">搜索量div>
                    <div class="chart-data">12345div>
                    <v-chart :option="searchUserOption">v-chart>
                  div>
                div>
                
                <div class="table-wrapper">
                  
                  <el-table :data="tableData">
                    <el-table-column prop="rank" label="排名" width="180">el-table-column>
                    <el-table-column prop="keyword" label="地区" width="180">el-table-column>
                    <el-table-column prop="count" label="数量" width="180">el-table-column>
                    <el-table-column prop="users" label="用户" width="180">el-table-column>
                  el-table>
                  
                  <el-pagination layout="prev, pager, next" :total="100" :page-size=4 background @current-change="onPageChange">el-pagination>
                div>
              div>
            el-card>
          div>
          
          <div class="view">
            <el-card shadow="hover">
              
              <template v-slot:header>
                <div class="title-wrapper">
                  <div class="title">分类销售排行div>
                  <div class="radio-wrapper">
                    <el-radio-group v-model="radioSelect" size="small">
                      <el-radio-button label="品类">el-radio-button>
                      <el-radio-button label="商品">el-radio-button>
                    el-radio-group>
                  div>
                div>
              template>
              
              <template>
                <div class="chart-wrapper">
                  <v-chart :option="categoryOption">v-chart>
                div>
              template>
            el-card>
          div>
        div>
      template>
      
      <script>
      
      export default {
        data () {
          return {
            radioSelect: '品类',
            searchUserOption: {
              xAxis: {
                  type: 'category',
                  boundaryGap: false
              },
              yAxis: {
                show: false,
                min: 0,
                max: 800  // 设计一个算法找到最大值
              },
              series: [{
                  type: 'line',
                  areaStyle: {
                    color: 'rgba(95, 187, 255, .5)'
                  },
                  data: [307, 200, 400, 390, 800, 122, 307, 200, 400, 390, 800, 122],
                  lineStyle: {
                    color: 'rgba(95, 187, 255, .5)'
                  },
              }],
              grid: {
                  // 顶格显示
                  top: 0,
                  bottom: 0,
                  left: 0,
                  right: 0
              },
              color: ['#3398DB']
            },
            // searchNumOption: {
            // },
            tableData: [
              {id:1, rank:1, keyword:'北京', count:100, users:90, range:'90%'},
              {id:1, rank:2, keyword:'宁夏', count:100, users:90, range:'90%'},
              {id:1, rank:3, keyword:'北京', count:100, users:90, range:'90%'},
              {id:1, rank:4, keyword:'北京', count:100, users:90, range:'90%'},
              {id:1, rank:5, keyword:'北京', count:100, users:90, range:'90%'},
            ],
            categoryOption: {
              // 这里不定义,放在renderPieChart,在mounted调用
              // 新的方式吧
            },
          }
        },
        methods: {
          onPageChange(page) {
      
          },
          // 右侧饼图定制
          // 因为有数据和图,在这里统一封装
          renderPieChart() {
            const mockData = [
              {
                // 这些字段名是定义好的,series-data会来取,不能随便定义
                legendname: '粥和鸡蛋',
                value: 20,
                percent: '20%',
                itemStyle: {
                  color: '#8d7fec' 
                },
                name: '粥和鸡蛋 | 20%', // 单独在右边的图例
              },
              {
                legendname: '简餐便当',
                value: 20,
                percent: '20%',
                name: '简餐便当 | 20%',
              },
              {
                legendname: '面条米饭',
                value: 20,
                percent: '20%',
                name: '面条米饭 | 20%',
              },
              {
                legendname: '牛奶面包',
                value: 20,
                percent: '20%',
                name: '牛奶面包 | 20%',
              },
              {
                legendname: '酱牛肉',
                value: 20,
                percent: '20%',
                name: '酱牛肉 | 20%',
              },
            ]
            this.categoryOption = {
              title: [
                {
                  text: '品类分布',
                  textStyle: {
                    fontSize: 14,
                    color: '#666',
                  },
                  left: 20,
                  top: 20
                },
                {
                  // 展示在圆环中
                  text: '累积订单量',
                  subtext: '320', // 副标题
                  x: '29%',
                  y: '45%',
                  textAlign: 'center',
                  textStyle: {
                    fontSize: 12,
                    color: '#666',
                  },
                  subtextStyle: {
                    fontSize: 24,
                    color: '#666',
                  },
                }
              ],
              series: [{
                  name: '品类分布', // 多个图标可以通过name区分
                  type: 'pie',
                  data: mockData,
                  label: {
                    normal: {
                      show: true,
                      poaition: 'outter', // 让介绍文字在外侧
                      formatter: function(params) {
                        return `${params.data.legendname} | ${params.data.percent}`
                      }
                    }
                  },
                  center: ['30%', '50%'],  // 放到原图宽度的30%处,即左移;或者canvas的某个位置,传数字
                  // 环形饼图
                  radius: ['45%', '60%'],  // 内半径,外半径(用canvas宽/高的较小值来算)
                  labelLine: {
                    // 靠近环的是线段1
                    normal: {
                      length: 5,
                      length2: 3,
                      smooth: true
                    }
                  },
                  clockwise: false, // 逆时针展示数据
                  itemStyle: {
                    borderWidth: 3,
                    borderColor: '#fff'
                  }
              }],
              legend: {
                type: 'scroll',
                orient: 'vertical',
                height: 250,  // 大概能显示5行legend,多出去了会出现箭头
                left: '70%',  // canvas的70%
                top: 'middle',
                textStyle: {
                  fontSize: 12,
                  color: '#8c8c8c',
                },
              },
              // 弹层(鼠标放在饼图上弹出来的信息)
              tooltip: {
                trigger: 'item',
                // 格式定制
                formatter: function(params) {
                  // console.log(params)
                  const str = params.seriesName + '
      '
      + params.marker + params.data.legendname + '
      '
      + '数量' + params.data.value + '
      '
      + '占比' + params.data.percent return str }, } } } }, mounted() { this.renderPieChart() } }
      script> <style lang="scss" scoped> .bottom-view { display: flex; margin-top: 20px; background-color: #eee; .view { /* 占满 */ flex: 1; width: 50%; &:first-child { padding: 0 10px 0 0 ; } &:last-child { padding: 0 0 0 10px; } .title-wrapper { display: flex; align-items: center; height: 60px; box-sizing: border-box; border-bottom: 1px solid #eee; font-size: 14px; font-weight: 500; padding: 0 0 0 20px; .radio-wrapper { flex: 1; display: flex; justify-content: flex-end; padding-right: 20px; } } // 避免混乱,可以先在这里写嵌套关系 .chart-wrapper { display: flex; flex-direction: column; height: 452px; .chart-inner { display: flex; // 上下 左右 padding: 0 10px; margin-top: 10px; .chart { flex:1; padding: 0 10px; .chart-title { color: #999; font-size: 14px; } .chart-data { font-size: 20px; color: #333; font-weight: 500; letter-spacing: 2px; } .echarts { height: 50px; } } } .table-wrapper { flex:1; margin-top: 20px; padding: 0 10px 10px; .el-pagination { display: flex; justify-content: center; margin-top: 10px; } } } } } style>
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83
      • 84
      • 85
      • 86
      • 87
      • 88
      • 89
      • 90
      • 91
      • 92
      • 93
      • 94
      • 95
      • 96
      • 97
      • 98
      • 99
      • 100
      • 101
      • 102
      • 103
      • 104
      • 105
      • 106
      • 107
      • 108
      • 109
      • 110
      • 111
      • 112
      • 113
      • 114
      • 115
      • 116
      • 117
      • 118
      • 119
      • 120
      • 121
      • 122
      • 123
      • 124
      • 125
      • 126
      • 127
      • 128
      • 129
      • 130
      • 131
      • 132
      • 133
      • 134
      • 135
      • 136
      • 137
      • 138
      • 139
      • 140
      • 141
      • 142
      • 143
      • 144
      • 145
      • 146
      • 147
      • 148
      • 149
      • 150
      • 151
      • 152
      • 153
      • 154
      • 155
      • 156
      • 157
      • 158
      • 159
      • 160
      • 161
      • 162
      • 163
      • 164
      • 165
      • 166
      • 167
      • 168
      • 169
      • 170
      • 171
      • 172
      • 173
      • 174
      • 175
      • 176
      • 177
      • 178
      • 179
      • 180
      • 181
      • 182
      • 183
      • 184
      • 185
      • 186
      • 187
      • 188
      • 189
      • 190
      • 191
      • 192
      • 193
      • 194
      • 195
      • 196
      • 197
      • 198
      • 199
      • 200
      • 201
      • 202
      • 203
      • 204
      • 205
      • 206
      • 207
      • 208
      • 209
      • 210
      • 211
      • 212
      • 213
      • 214
      • 215
      • 216
      • 217
      • 218
      • 219
      • 220
      • 221
      • 222
      • 223
      • 224
      • 225
      • 226
      • 227
      • 228
      • 229
      • 230
      • 231
      • 232
      • 233
      • 234
      • 235
      • 236
      • 237
      • 238
      • 239
      • 240
      • 241
      • 242
      • 243
      • 244
      • 245
      • 246
      • 247
      • 248
      • 249
      • 250
      • 251
      • 252
      • 253
      • 254
      • 255
      • 256
      • 257
      • 258
      • 259
      • 260
      • 261
      • 262
      • 263
      • 264
      • 265
      • 266
      • 267
      • 268
      • 269
      • 270
      • 271
      • 272
      • 273
      • 274
      • 275
      • 276
      • 277
      • 278
      • 279
      • 280
      • 281
      • 282
      • 283
      • 284
      • 285
      • 286
      • 287
      • 288
      • 289
      • 290
      • 291
      • 292
      • 293
      • 294
      • 295
      • 296
      • 297
      • 298
      • 299
      • 300
      • 301
      • 302
      • 303
      • 304
      • 305
      • 306
      • 307
      • 308
      • 309
      • 310
      • 311
      • 312
      • 313
      • 314
      • 315
      • 316
      • 317
      • 318
      • 319
      • 320
    • 接下来应该是地图部分,但是比较复杂,需要先了解百度地图
  • 相关阅读:
    源代码防泄密和工控安全方案简介
    Java多线程-初阶1
    Topaz Video AI参数详解
    Chapter9.2:线性系统的状态空间分析与综合(上)
    【jquery ajax】实现文件上传提交
    【两周学会FPGA】从0到1学习紫光同创FPGA开发|盘古PGL22G开发板学习之DDR3 IP简单读写测试(六)
    camunda_10_script_task_access_variable
    FPGA_IIC代码-正点原子 野火 小梅哥 特权同学对比写法(3)
    内网渗透之Linux反弹shell(一)
    非关系型数据库之Redis【redis集群详细搭建】
  • 原文地址:https://blog.csdn.net/weixin_39757637/article/details/126768678