主頁 > 企業開發 > vue3+three.js實作疫情可視化

vue3+three.js實作疫情可視化

2022-09-14 06:51:44 企業開發

前言

自成都九月份以來疫情原因被封了一兩周,居家著實無聊,每天都是盯著微信公眾號發布的疫情資料看,那種頁面,就我一個前端仔來說,看著是真的丑啊!(⊙_⊙)?既然丑,那就自己動手開整!專案是2022.9.5開始的,截止2022.9.12我完成了大概有八成,主要是想讓資料更加直觀,而且可離線下載(當然還有裝逼!┑( ̄Д  ̄)┍),

專案描述

為證明是有料的,先看效果圖(提前裝逼!┗|`O′|┛ 嗷~~):

image
image
image
image
專案我是公開了的( ̄m ̄)有興趣的可以下下來玩玩,這是我第一次使用vue3+ts構建專案,肯定還有不足的地方(比如ts中瘋狂的:any,一直any一直爽^o^/),
這里是在線鏈接
這里是專案鏈接(歡迎star!歡迎star!歡迎star!(●'?'●)嘿嘿嘿~)
專案中使用到的技術有:vue3、TypeScript、Three.js、Echarts、elementPlus,

專案目標

1、以為3D形式展示全球疫情分布,
2、顯示實時疫情數值,
3、以圖表形式分析疫情資料,
4、允許下載各地疫情excel表格,
5、自動獲取用戶位置,
6、分析當地疫情資料,
7、生成當地疫情word報告,

api說明

本專案資料來源:新浪公共疫情api(新浪的資料來源于國家衛健委、各省市區衛健委、各省市區政府、港澳臺官方渠道等公開資料,這也是夠權威官方了),我主要使用了兩個新浪的api和一個太平洋網路ip地址查詢web介面,
1、https://news.sina.com.cn/project/fymap/ncp2020_full_data.json
get方式,無入參,該api可獲取全球各國大致疫情資料,以及國內的詳情疫情資料,這里就api中的欄位做一下說明,欄位是我自己推測出來的含義,不會100%全而準(→_→):
在這里插入圖片描述

{
    "add_daily(國內今日資料)": {
        "addcon(今日確診新增數)": "",
        "addcure(今日治愈新增)": "",
        "adddeath(今日死亡新增)": "",
        "addjwsr(今日境外輸入新增)": "",
        "addlocIncrNum(今日本土新增)"
    },
    "cachetime(資料快取時間)": "",
    "curetotal(國內治愈總數)": "",
    "deathtotal(國內死亡總數)": "",
    "gntotal(國內確診總數)": "",
    "highAndMiddle(中高風險地串列)": [
        {
            "allname(全名)": "",
            "list(城市串列)": "",
            "province(省名)": "",
            "province_high_areas(高風險區域)": "",
            "province_middle_areas(中風險區域)": "",
            "province_high_num(高風險區域數)": "",
            "province_middle_num(中風險區域數)": "",
            "province_total(風險地總數)": ""
        }
    ],
    "historylist(國內疫情歷史資料)": [
        {
            "cn_conNum(確診總數)": "",
            "cn_cureNum(治愈總數)": "",
            "cn_deathNum(死亡數)": "",
            "cn_jwsrNum(境外輸入)": "",
            "ymd(當前時間)": ""
        }
    ],
    "jwsrTop(境外資料前10串列)": [],
    "list(全國各省疫情資料串列)": [
        {
            "asymptomNum(較昨日新增數)": "",
            "city(城市串列)": [],
            "cureNum(治愈數)": "",
            "deathNum(死亡數)": "",
            "econNum(現存確診數)": "",
            "ename(英文省名)": "",
            "jwsrNum(境外輸入數)": "",
            "name(省名)": "",
            "value(累計數)": ""
        }
    ],
    "locIncrProTop(本土新增前十串列)": [],
    "othertotal(其他總數)": {
        "certain(全球現存確診)": "",
        "certain_inc(今日確診新增數)": "",
        "die(全球死亡數)": "",
        "die_inc(死亡新增數)": "",
        "ecertain(全球治愈數)": "",
        "ecertain_inc(治愈新增數)": ""
    },
    "times(資料截止時間)": "",
    "worldlist(世界各國疫情串列)": [
        {
            "name(國名)": "",
            "value(累計數)": "",
            "econNum(確診數)": "",
            "deathNum(死亡數)": "",
            "cureNum(治愈數)": ""
        }
    ]
}

2、https://gwpre.sina.cn/interface/news/ncp/data.d.json
get方式,入參:

{
	mod:"province",
	province(英文省名):""
}

該api可獲取國內指定省份的疫情資料,欄位我就不推斷了,可自行根據上一個api和部分英文單詞大概推斷出來(沒錯!就是我不想打字了!太TM累了!?_?其實這還不算折磨人的,后面使用api的時候那才叫個曲折),
3、https://whois.pconline.com.cn/ipJson.jsp
get方式,無入參,該api可獲取使用者ip地址、省份、城市,回傳結果如下:
在這里插入圖片描述

資料使用

剛開始開發的時候,我跟以前專案開發一樣,跨域嘛,直接整個vue代理(不會vue代理模式的看這兒)不就完事兒了,果然,資料一經過代理,回來是回來了,但漢字全是\n什么什么鬼?亂碼?費了一番功夫查了下,不是亂碼,是unicode解碼的問題,然后我又整了個解碼的方法:

//解碼回傳的unicode
function decodingStr(str: any) {
  let repStr: any = str.replace(/\\/g, "%");//用%替換\
  let str1 = repStr.split("jsoncallback(")[1]
  let str2 = str1.split(");")[0]//截取出需要的字串
  let unStr = unescape(str2);//解碼出漢字
  let jsonObj = JSON.parse(unStr);//轉換成json物件
  return jsonObj;
};

這下應該可以了吧?一切很順利,開發差不多了,npm run build、git add . 、git commit -m""、git push,行云流水!直接上gitee Pages部署發布,完成!打開頁面一看?臥槽?f12,404?直到后面我又在網上扒拉后才明白,vue的代理在打包成dist后會被抽離失效,在gitee Pages中是不能使用vue的代理模式獲取資料的!接下來就是各種嘗試跨域,直到看到跨域兩個字人都麻了,最后發現不同域下,使用jsonp的方式來處理跨域最為簡單,jsonp原理和使用方法在這里,

專案開始

專案是vue3的,首先你得創建啊,這里建議使用vue腳手架的圖形化界面創建專案,命令為:vue ui
選擇手動配置:
在這里插入圖片描述
打開TypeScript支持:
在這里插入圖片描述
選擇vue3選項:
在這里插入圖片描述

安裝依賴

1、npm install [email protected](安裝echarts的指定版本,因為專案中需要使用中國地圖,在4.9.0之后echarts官方移除了地圖支持,之后的版本需要下載chain.js,還得手動下載引入一遍,麻煩,這里直接用老版本)
2、npm i element-plus(vue3對應的element-ui就是element-plus,這是官方使用檔案)
3、npm i three(看見首頁那個大地球了吧?沒錯,它就是three.js做的,感興趣的可以看這兒,還有個太陽系)
4、npm i xlsx(這個是下載excel表格的必備插件,具體使用方法看這里)

首頁球體

1、創建宇宙(叼不叼!是不是感覺自己就是創世主!( ̄_, ̄ )):初始化場景時一定記得設定alpha: true,這里創建宇宙我使用了這篇文章創建背景的第三種方法,

import * as THREE from "three";

//初始化球體
function init(data: any) {
  dom = document.getElementById("sphereDiv"); //獲取dom
  let width = dom.clientWidth;
  let height = dom.clientHeight;
  scene = new THREE.Scene(); //場景場景
  camera = new THREE.PerspectiveCamera(45, width / height, 1, 1000); //創建透視相機(視場、長寬比、近面、遠面)
  camera.position.set(0, 0, 270); //設定相機位置
  camera.lookAt(0, 0, 0);
  //創建渲染器
  renderer = new THREE.WebGLRenderer({
    antialias: true, //抗鋸齒
    alpha: true, //透明
  });
  renderer.setClearColor(0x000000, 0.1); //設定場景透明度
  renderer.setSize(width, height); //設定渲染區域尺寸
  dom.appendChild(renderer.domElement); //將渲染器添加到dom中形成canvas
  createUniverse(); //創建宇宙
  createStars(); //創建星辰
  createLight(); //創建光源
  createSphere(data); //創建球體
  createOrbitControls();
  render();
};

//創建宇宙(球形宇宙)
function createUniverse() {
  let universeGeometry = new THREE.SphereGeometry(500, 100, 100);
  let universeMaterial = new THREE.MeshLambertMaterial({
    //高光材質
    map: new THREE.TextureLoader().load(universeImg),
    side: THREE.DoubleSide, //雙面顯示
  });
  //宇宙網格
  let universeMesh = new THREE.Mesh(universeGeometry, universeMaterial);
  universeMesh.name = "宇宙";
  scene.add(universeMesh);
};

2、創建光源:為了效果,我使用了環境光與平行光源,這兩種光都會影響貼圖原本顏色,建議光源顏色設定為白色,

//創建光源
function createLight() {
  let lightColor = new THREE.Color(0xffffff);
  let ambient = new THREE.AmbientLight(lightColor); //環境光
  ambient.name = "環境光";
  scene.add(ambient);
  let directionalLight1 = new THREE.DirectionalLight(lightColor);
  directionalLight1.position.set(0, 0, 1000);
  scene.add(directionalLight1); //平行光源添加到場景中
  let directionalLight2 = new THREE.DirectionalLight(lightColor);
  directionalLight2.position.set(0, 0, -1000);
  scene.add(directionalLight2); //平行光源添加到場景中
  let directionalLight3 = new THREE.DirectionalLight(lightColor);
  directionalLight3.position.set(1000, 0, 0);
  scene.add(directionalLight3); //平行光源添加到場景中
  let directionalLight4 = new THREE.DirectionalLight(lightColor);
  directionalLight4.position.set(-1000, 0, 0);
  scene.add(directionalLight4); //平行光源添加到場景中
  let directionalLight5 = new THREE.DirectionalLight(lightColor);
  directionalLight5.position.set(0, 1000, 0);
  scene.add(directionalLight5); //平行光源添加到場景中
  let directionalLight6 = new THREE.DirectionalLight(lightColor);
  directionalLight6.position.set(0, -1000, 0);
  scene.add(directionalLight6); //平行光源添加到場景中
};

3、創建球體:

//創建球體
function createSphere(data: any) {
  let earthSize = 100; //地球尺寸
  let earthGroup = new THREE.Group(); //地球的組
  let earthGeometry = new THREE.SphereGeometry(earthSize, 100, 100); //地球幾何體
  let nightColor = new THREE.Color(0x999999);
  let dayColor = new THREE.Color(0x444444);
  //地球材質
  let earthMaterial = new THREE.MeshPhongMaterial({
    map: new THREE.TextureLoader().load(
      isDay ? earthImg : earthNightImg //區分晝夜紋理
    ),
    color: isDay ? dayColor : nightColor,
    // metalness: 1, //生銹的金屬外觀(MeshStandardMaterial材質時使用)
    // roughness: 0.5, // 材料的粗糙程度(MeshStandardMaterial材質時使用)
    normalScale: new THREE.Vector2(0, 5), //凹凸深度
    normalMap: new THREE.TextureLoader().load(normalImg), //法線貼圖
  });
  let earthMesh = new THREE.Mesh(earthGeometry, earthMaterial); //地球網格
  earthMesh.name = "地球";
  earthGroup.add(earthMesh); //將地球網格添加到地球組中
  earthGroup.name = "地球組";
  scene.add(earthGroup);
  createVirus(data, earthSize); //創建球面病毒
};

在這里插入圖片描述
放大專案中的地球你會發現球體表面是有凹凸而且反光的(就像稀泥巴一樣≡(▔﹏▔)≡),這是因為使用了three中MeshPhongMaterial材質同時設定了屬性normalScale與normalMap,
在這里插入圖片描述
4、渲染:創建完成后記得渲染,否則是不會生效的,

//渲染
function render() {
  anId.value = https://www.cnblogs.com/xi12/archive/2022/09/13/requestAnimationFrame(render);
  document.getElementById("sphereDiv") &&
    document
      .getElementById("sphereDiv")!
      .addEventListener("mousemove", onm ousemove, false);

  orbitControls.update(); //滑鼠控制元件實時更新
  renderer.render(scene, camera);
};

控制球體

首頁的3D球體是可以進行滑鼠控制的,
在這里插入圖片描述
這是使用的three.js自帶的滑鼠控制元件OrbitControls ,它的引數可以自己設定,這是滑鼠控制的方法:

import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

//創建滑鼠控制元件
function createOrbitControls() {
  orbitControls = new OrbitControls(camera, renderer.domElement);
  orbitControls.enablePan = false; //右鍵平移拖拽
  orbitControls.enableZoom = true; //滑鼠縮放
  orbitControls.enableDamping = true; //滑動阻尼
  orbitControls.dampingFactor = 0.05; //(默認.25)
  orbitControls.minDistance = 150; //相機距離目標最小距離
  orbitControls.maxDistance = 500; //相機距離目標最大距離
  orbitControls.autoRotate = true; //自轉(相機)
  orbitControls.autoRotateSpeed = 1; //自轉速度
  orbitControls.enableRotate = true;//滑鼠左鍵控制旋轉
};

創建病毒

被瞎說!covid19可不是我創造的!(;′д`)ゞ

//創建病毒
function createVirus(data: any, earthSize: any) {
  let colors = [
    new THREE.Color(0xf9b8b8),
    new THREE.Color(0xfe4242),
    new THREE.Color(0xff0000),
  ]; //病毒顏色串列
  let virSize = 4; //病毒大小
  let pointsGroup = new THREE.Group(); //點的組
  let list = JSON.parse(JSON.stringify(data));
  list.forEach((e: { value: number; color: any; position: any[]; }) => {
    e.value >= 10000000 && (e.color = colors[2]); //根據病毒數賦予不同顏色
    e.value >= 500000 && e.value < 10000000 && (e.color = colors[1]);
    e.value < 500000 && (e.color = colors[0]);
    if (e.position) {
      let virusMaterial = new THREE.SpriteMaterial({
        color: e.color,
        map: new THREE.TextureLoader().load(virusImg),
        side: THREE.FrontSide, //只顯示前面
      }); //病毒材質
      let Sprite = new THREE.Sprite(virusMaterial); //點精靈材質
      Sprite.scale.set(virSize, virSize, 1); //點大小
      let lat = e.position[1]; //緯度
      let lon = e.position[0]; //經度
      let s = latLongToVector3(lat, lon, earthSize, 1); //坐標轉換
      Sprite.position.set(s.x, s.y, s.z); //設定點的位置
      Sprite.dotData = https://www.cnblogs.com/xi12/archive/2022/09/13/e; //將點的資料添加到dotData屬性中
      Sprite.name ="病毒";
      pointsGroup.add(Sprite); //添加進點的組中
    }
  });
  pointsGroup.name = "病毒組";
  scene.add(pointsGroup); //點的組添加到旋轉組中
};

球面上那些紅的、粉的、白的玩意兒就是病毒,其實就是利用three的SpriteMaterial材質加入點精靈Sprite中,再遍歷病毒的坐標串列資料,回圈設定Sprite的position屬性,最后再將創建好的病毒組添加到宇宙場景中,值得注意的是,你一般獲取到的資料均為經緯度坐標,需要轉換為three能用的三維向量坐標,這是坐標轉換的方法:

//經緯度坐標變換(傳入e:緯度、a經度、t球半徑、o球額外距離)
function latLongToVector3(e: any, a: any, t: any, o: any) {
  var r = (e * Math.PI) / 180,
    i = ((a - 180) * Math.PI) / 180,
    n = -(t + o) * Math.cos(r) * Math.cos(i),
    s = (t + o) * Math.sin(r),
    l = (t + o) * Math.cos(r) * Math.sin(i);
  return new THREE.Vector3(n, s, l); //計算三維向量
};

數值增加影片

在首頁右側和“國內分析”右側,有一排數字,那個數字在加載時是有數值增加影片的,
在這里插入圖片描述

本來想直接使用vue-count-to或者vue-countupjs的,但網上我扒拉了一下,發現原理好像不是很難,無非就是利用vue的資料回應式原理,但我看到的大多封裝的組件都是vue2的,vue3好像沒有,這里我就整一個vue3+ts的版本:

<template>
    <span :data-time="time" :data-https://www.cnblogs.com/xi12/archive/2022/09/13/value="value">{{addNum}}</span>
</template>

<script lang='ts' setup>
import { ref, computed, watch, onMounted } from 'vue';
let props = defineProps({
    //影片時間
    time: {
        type: Number,
        default: 2
    },
    //停止時的值
    value: {
        type: Number,
        default: 0
    },
    //千位的逗號
    thousandSign: {
        type: Boolean,
        default: () => false
    }
}),
    oldValue: any = ref(0),
    addNum: any = ref(0);//回應式的數值

watch(
    () => props.value,
    () => {
        startAnimation();//值改變時開始影片
    })

function startAnimation() {
    let value: number = props.value - oldValue.value;
    let step = (value * 10) / (props.time * 100);
    let current = 0;
    let start = oldValue.value;
    //定時器
    let t: any = setInterval(() => {
        start += step;
        if (start > value) {
            clearInterval(t);
            start = value;
            t = null;
        }
        if (current === start) {
            return;
        }
        current = Math.floor(start);//取整
        oldValue.value = https://www.cnblogs.com/xi12/archive/2022/09/13/current;
        if (props.thousandSign) {
            addNum.value = current.toString().replace(/(/d)(?=(?:\d{3}[+]?)+$)/g,'$1,');//添加千位符
        } else {
            addNum.value = https://www.cnblogs.com/xi12/archive/2022/09/13/current.toString();//無千位符
        }
    }, 10)
}

onMounted(() => {
    startAnimation();
})
</script>

value是影片終止時數值,time是影片時間,thousandSign表示是否添加千分位符,必須保證value與time型別為Number,這是使用方法:

<addNumber  :value="https://www.cnblogs.com/xi12/archive/2022/09/13/addcure" :time="10" :thousandSign="true" />

表格展示

頁面上的所有表格都是使用的element-plus的表格組件,這是具體使用方法,當表格做出來之后發現樣式顏色之類的并不是自己想要的,其實可以更改css變數,注意,不是全域修改,是區域修改樣式,比如你想讓表格變成這樣透明的:
在這里插入圖片描述
那么你可以這樣做:

<el-table :data="https://www.cnblogs.com/xi12/archive/2022/09/13/tabData" style="width: 100%;height: calc(100vh - 100px);
            --el-table-bg-color:rgba(0,0,0,.8);
            --el-table-tr-bg-color:transparent;
            --el-table-header-bg-color:#333;
            --el-table-header-text-color:#fff;
            --el-table-text-color:#fff;
            --el-table-row-hover-bg-color:#333;
            --el-table-border-color:#333">
                <el-table-column type="index" label="序號"  />
                <el-table-column prop="name" label="國家" />
                <el-table-column prop="value" label="累計數" sortable />
                <el-table-column prop="deathNum" label="死亡數" sortable />
                <el-table-column prop="cureNum" label="治愈數" sortable />
                <el-table-column prop="citycode" label="地區代碼" />
                <el-table-column label="坐標">
                    <template #default="scope">{{ scope.row.position ? scope.row.position : "-" }}</template>
                </el-table-column>
            </el-table>

其中的css變數名,你可以f12獲取到,

橫向柱狀圖

首頁左側和“國內分析”這樣的橫向柱狀圖,
在這里插入圖片描述
在echarts里面配置項是這樣的:

//柱狀圖資料
  let option: any = {
    title: {
      text: titName + sliceNum,
      left: "center",
      textStyle: {
        color: "#fff",
      },
    },
    tooltip: {
      backgroundColor: "rgba(0,0,0,.5)",
      borderWidth: "0",
      trigger: 'axis',
      textStyle: {
        color: "#fff",
        fontWeight: "bolder"
      },
    },
    grid: {
      top: "10%",
      left: "10%",
      right: "10%",
      bottom: "0%",
    },
    xAxis: {
      type: 'value',
      show: false,
    },
    yAxis: {
      type: 'category',
      axisLabel: {
        color: "#fff",
      },
      data: [],
    },
    series: [
      {
        data: [],
        type: 'bar',
        showBackground: true,
        backgroundStyle: {
          color: 'rgba(180, 180, 180, 0.2)'
        },
        itemStyle: {
          color: color,
        },
        label: {
          color: "#fff",
          fontWeight: "bolder",
          show: true,
          align: "left",
          formatter: "{c}",
        },
      }
    ]
  }

顏色、位置、標題可自己設定,

中國地圖

在“國內分析”中有一個中國地圖,用來展示國內現存確診分布,支持縮放拖拽,
image
如果你下載的最新的echarts的話,那么你得折騰下,自己另外單獨找chain.js下載,然后引入專案,4.9.0是內置地圖的,可以直接使用,這是地圖的配置項:

  let option: any = {
    title: {
      text: '國內各省現存分布',
      left: "center",
      top: '1%',
      textStyle: {
        color: "#fff",
      },
    },
    visualMap: {
      min: 0,
      max: 500,
      left: '5%',
      bottom: '5%',
      text: ['高', '低'],
      textStyle: {
        color: '#fff',
      },
      calculable: true,
      inRange: {
        color: ['#fff', '#f00'],//顏色范圍
      },
    },
    tooltip: {
      padding: 10,
      enterable: true,
      transitionDuration: 0,//影片時間
      backgroundColor: "rgb(0,0,0,.8)",
      borderRadius: 20,
      textStyle: {
        color: '#fff',
      },
      formatter: function (params: any) {
        let tipString = "";
        if (params.data.value) {
          tipString =
            "<div style='font-size:25px;font-weight:900;margin:10px 0px'>" + params.data.name + "</div>" +
            "<div style='color:#f00;font-weight:900;'>現存:" + params.data.value + "</div>" +
            "<div style='color:#888;font-weight:900;'>累計:" + params.data.allNum + "</div>" +
            "<div style='color:#888;font-weight:900;'>死亡:" + params.data.deathNum + "</div>" +
            "<div style='color:#888;font-weight:900;'>治愈:" + params.data.cureNum + "</div>" +
            "<div style='color:#888;font-weight:900;'>較昨日新增:" + params.data.asymptomNum + "</div>" +
            "<div style='color:#888;font-weight:900;'>境外輸入:" + params.data.jwsrNum + "</div>"
        }
        return tipString;
      }
    },
    series: [{
      name: '接入醫院數量',
      type: 'map',
      mapType: 'china',
      zoom: 1.2,//縮放
      roam: true,
      scaleLimit: {
        min: 1.2,//縮放限制
        max: 2
      },
      itemStyle: {
        normal: {
          label: {
            show: true
          }
        },
        emphasis: {
          show: true,
          areaColor: '#6eb5ff',//滑鼠滑過區域顏色
          label: {
            show: true
          }
        }
      },
      label: {
        normal: { //靜態的時候展示樣式
          show: true, //是否顯示地圖省份得名稱
          textStyle: {
            color: "#000",
            fontSize: 12
          }
        },
        emphasis: { //動態展示的樣式
          color: '#fff',
        },
      },
      data: []
    }]
  };

formatter也就是hover出來的資訊框,可以自定義,

歷史分析

“國內分析”是有個歷史資料展示的折線圖的,它是允許縮放調節的,
在這里插入圖片描述
這是它的echarts配置項:

  let option: any = {
    // backgroundColor: "",
    grid: {
      // top: "15%",
      // left: "5%",
      // right: "5%",
      // bottom: "10%",
    },
    title: {
      text: '國內歷史資料',
      left: "center",
      top: '5%',
      textStyle: {
        color: "#fff",
      },
    },
    tooltip: {
      backgroundColor: "rgba(0,0,0,.5)",
      borderWidth: "0",
      trigger: 'axis',
      textStyle: {
        color: "#fff",
        fontWeight: "bolder"
      },
      axisPointer: {
        type: 'cross'
      },
    },
    legend: {
      data: ['確診數', '治愈數', '死亡數', '境外輸入'],
      textStyle: {
        color: "#fff"
      },
      orient: "vertical",
      top: "15%",
      right: "2%"
    },
    xAxis: {
      data: lineData.map(function (item: any) {
        return item.ymd;
      }),
      textStyle: {
        color: "#fff"
      }
    },
    yAxis: {
      textStyle: {
        color: "#fff",
      },
    },
    dataZoom: [
      {
        startValue: ''
      },
      {
        type: 'inside'
      }
    ],
    series: [
      {
        name: '確診數',
        type: 'line',
        lineStyle: {
          color: '#f4c25e'
        },
        itemStyle: {
          color: '#f4c25e'
        },
        data: lineData.map(function (item: any) {
          return item.cn_conNum;
        }),
        zlevel: 1,
        z: 1,
      },
      {
        name: '治愈數',
        type: 'line',
        lineStyle: {
          color: '#48c56b'
        },
        itemStyle: {
          color: '#48c56b'
        },
        data: lineData.map(function (item: any) {
          return item.cn_cureNum;
        }),
        zlevel: 1,
        z: 1,
      },
      {
        name: '死亡數',
        type: 'line',
        lineStyle: {
          color: '#f00'
        },
        itemStyle: {
          color: '#f00'
        },
        data: lineData.map(function (item: any) {
          return item.cn_deathNum;
        }),
        zlevel: 1,
        z: 1
      },
      {
        name: '境外輸入',
        type: 'line',
        lineStyle: {
          color: '#8903ba'
        },
        itemStyle: {
          color: '#8903ba'
        },
        data: lineData.map(function (item: any) {
          return item.cn_jwsrNum;
        }),
        zlevel: 1,
        z: 1
      }
    ]
  };

表格下載

主要是利用xlsx插件,好用得很,直接傳入資料就出表格了,這是我的使用方法:

import * as XLSX from "xlsx";

//入參示例
let eg = {
    fileName: "測驗",//檔案名
    tabHead: ["國家", "人口", "測驗"],//表頭串列
    keyList: ["name", "population", "test"],//表頭對應的屬性名,順序必須與表頭對應
    tabData: [
        { name: "中國", population: "11", test: "t1" },
        { name: "美國", population: "22", test: "t2" },
        { name: "日本", population: "35", test: "t3" }
    ]//物件陣列
}

//匯出資料表格
export default async function downloadXlsx(tabObj: any) {
    let aoaList: any = [];
    aoaList[0] = tabObj.tabHead; //賦值表頭串列
    tabObj.tabData.forEach((tabItem: any, tabIndex: number) => {
        aoaList[tabIndex + 1] = [];//該二維度陣列必須多加一個元素,因為表頭占第一個元素
        tabObj.keyList.forEach((keyItem: any, keyIndex: number) => {
            let val = tabItem[keyItem];//獲取表格屬性的值
            ((typeof val == "undefined") || (val == "")) ?
                (aoaList[tabIndex + 1][keyIndex] = "-") ://資料未定義或者為空則用"-"代替
                (aoaList[tabIndex + 1][keyIndex] = val + "");//添加空字串,防型別為非字串
        })
    });
    let workSheet = null;
    workSheet = XLSX.utils.aoa_to_sheet(aoaList); //將串列資料添加到作業表
    let workBook = XLSX.utils.book_new(); //創建一個作業薄
    XLSX.utils.book_append_sheet(workBook, workSheet, "1"); //將作業表添加到作業薄中
    await XLSX.writeFile(workBook, tabObj.fileName + ".xlsx"); //寫入檔案,下載作業薄
};

結語

我做這個其實還是學到了很多東西,主要是vue2與vue3的區別,以前的this算是可以徹底拋棄了,還有就是組合式api配合setup語法糖,爽啊!就連組件引入后都不用注冊了,直接使用,不過也有注意點,用ref()宣告的回應式變數使用時需要加.vaule,至于ts,我感覺自己還是很菜啊,一直any一直爽,,,,,,ts型別系統直接被我無視了,后面還得觀摩觀摩其他大佬咋寫的,截止到現在2022.9.13成都疫情好轉要復工了,專案其實都是沒有完成的,主要還差“省內分析”和“下載當地疫情報告”,我做了alert提示,反正資料獲取到了,后面在搞,我專案是完全開源了的,有牛逼的可以直接clone下來開發完成(我想要白嫖!(╯▔皿▔)╯),
在這里插入圖片描述
在這里插入圖片描述

原創者:曦12

原文鏈接:https://www.cnblogs.com/xi12/p/16690119.html

轉載請注明原創者添加原文鏈接!

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/507236.html

標籤:其他

上一篇:vue中代理解決跨域

下一篇:?探秘 Web 水印技術

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more