疫情统计页面 H5 vue3+TypeScript+Echarts

Posted Little___Turtle

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了疫情统计页面 H5 vue3+TypeScript+Echarts相关的知识,希望对你有一定的参考价值。

目录🧰🧰

功能介绍🎨🎨

部分效果展示🌌🌌

全部功能展示效果🗺️🗺️

代码演示🌃🌃

🥰🥰demo目录结构

🍭🍭 DownRefresh.vue 下拉刷新 组件

🪜🪜EpidemicList.vue 数据列表 组件

🏹🏹UpRefreshAndToTop 上拉刷新 一键回到顶部 组件

🗿🗿type index.ts 数据声明

📕📕pageTS index.ts 数据处理

🌃🌃App.vue 疫情页面

📺📺vite.config.ts 代理开通 


功能介绍🎨🎨

下拉刷新🪄  一键回到顶部🚀 echarts中国地图运用🗺️ 数据列表展示🧰 代理🧆

部分效果展示🌌🌌

全部功能展示效果🗺️🗺️

因为功能有点多 所以专门录制了一期视频介绍功能

具体的全部素材 源码也放在评论区 大家可以去看看😁

视频链接地址

代码演示🌃🌃

🥰🥰demo目录结构

🍭🍭 DownRefresh.vue 下拉刷新 组件

<!-- 下拉刷新新数据 -->
<template>
  <div class="box">
    <!-- 内部属性  @scroll 监听滚动条事件 -->
    <div
      @scroll="scrollEvent"
      class="scroll-box"
    >
      <!-- 插槽 -->
      <slot></slot>
      <div class="end-text" v-if="!isScroll"> endText </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import  reactive, toRefs  from "@vue/reactivity";
const props = defineProps(
  //下拉高度
  distance: Number ,
  //判定是否下拉
  isScroll: Boolean,
  endText: 
    type: String,
    default: "没有更多了",
  ,
);
//子传父参数
const $emits = defineEmits(["getList"]);

const data = reactive(
  //离屏幕高度
  scrollTop: 0,
);

let 
  scrollTop,
 = toRefs(data);


//下拉刷新 判定
const scrollEvent = (e: any) => 
  scrollTop = e.srcElement.scrollTop;
  if (!props.isScroll) return;
  if (
    //判定下拉高度
    scrollTop + e.srcElement.offsetHeight >
    e.srcElement.scrollHeight - props.distance!
  ) 
    $emits("getList");
  
;
</script>

<style lang="scss" scoped>
.box 
  overflow: hidden;
  position: relative;
  width: 100%;
  height: 90vh;

.scroll-box 
  height: 90vh;
  width: 100%;
  overflow: auto;
  transition: all 0s ease 0s;
  position: absolute;
  right: 0;
  .end-text 
    text-align: center;
    height: 50px;
    line-height: 50px;
    color: #999;
  

</style>

🪜🪜EpidemicList.vue 数据列表 组件

<!-- 疫情list -->
<template>
  <div class="list-box">
    <div class="info-title info">
      <p>地区</p>
      <p>现有确诊</p>
      <p>确诊</p>
      <p>死亡</p>
      <p>治愈</p>
    </div>
    <div class="list" v-for="item in epideList" :key="item.id">
      <div class="p-box">
        <div @click="getChowChildren(item.id)" class="info">
          <p> item.name </p>
          <!-- 确诊病例 计数可能出现负数情况 -->
          <p>
            
              item.total.confirm - item.total.dead - item.total.heal >= 0
                ? item.total.confirm - item.total.dead - item.total.heal
                : 0
            
          </p>
          <p>
            <span> item.total.confirm </span>
            <span>较昨日+ item.today.confirm ? item.today.confirm : 0 </span>
          </p>
          <p> item.total.dead </p>
          <p> item.total.heal </p>
        </div>
        <div v-if="showChildren">
          <div>
            <div v-show="data.showChildrenId == item.id" class="children-box">
              <EpidemicList :epideList="item.children" />
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<!-- name  组件可以自己调用自己(递归调用) 只能通过name选项来做此事-->
<script name="EpidemicList" setup lang="ts">
// 声明props
import   reactive  from "vue";
import  IEpidData  from "../type";
//无需引入
const props = defineProps(
  //疫情数据
  epideList:Array<IEpidData>,
  //是否展示子数组 省=>市 区数据
  showChildren: Boolean,
);
//点击展示
const data = reactive(
  showChildrenId: "",
);
//判定 子列表点击是否展示 各个省下面具体的地区
const getChowChildren = (id: string) => 
  //原理:通过id来确定要展示的list 点击第二次则置空 不展示效果
  data.showChildrenId == id ? (data.showChildrenId = ""): (data.showChildrenId = id);
;
//确诊案例 存在
</script>

<style lang="scss" scoped>
.list-box 
  border: 1px solid #d1d1d1;
  margin: 1rem 0;
  .p-box 
    .children-box 
      margin-left: 1rem;
      .list-box 
        border: none;
      
      .info-title 
        height: 30px;
        line-height: 30px;
      
      p 
        &:nth-child(1) 
          font-weight: 600;
          color: #999;
        
      
    
  

.info-title 
  font-weight: 600;
  color: #000;
  font-size: 16px;
  height: 50px;
  line-height: 50px;
  background: #d1d1d1;


.info 
  display: flex;
  justify-content: space-between;
  align-items: center;
  > p 
    width: 15%;
    text-align: center;
    // white-space: nowrap;
    &:nth-child(1) 
      font-weight: 600;
      color: #000;
    
    &:nth-child(2) 
      width: 23%;
      color: red;
    
    &:nth-child(3) 
      width: 23%;
      white-space: nowrap;
      span 
        display: block;
        &:last-child 
          color: #999;
        
      
    
  

.list 
  &:nth-of-type(odd) 
    background: #f6f6f6;
  
  .info 
    height: 80px;
    line-height: 80px;
    p 
      line-height: 20px;
    
  

</style>

🏹🏹UpRefreshAndToTop 上拉刷新 一键回到顶部 组件

<!-- 顶部刷新 回退到顶部 -->
<template>
  <div class="box">
    <!-- 内部属性 事件: 触摸开始 @touchstart 触摸移动 @touchmove 触摸结束 @touchend  滚动条滑动 @scroll-->
    <div
      @touchend="touchend"
      @touchmove="touchmove"
      @touchstart="touchstart"
      @scroll="scrollEvent"
      :style=" top: `$translateYpx` "
      class="scroll-box"
    >
      <div class="loadingBox" v-if="touchstartTitleShow">释放可刷新...</div>
      <div class="loadingBox" v-if="touchEndTitleShow">加载中...</div>
      <!-- top 回退顶部的定位点 -->
      <div id="top"></div>
      <!-- 插槽 -->
      <slot></slot>
      <div v-show="data.isShowTop" class="back-box" @click="toTop">
      <img src="../assets/toTop.png">
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import  reactive, toRefs  from "@vue/reactivity";

const $emits = defineEmits(["refreshFun"]);

const data = reactive(
  startText: "释放即可刷新",
  scrollTop: 0,
  startY: 0,
  translateY: 0,
  touchEndTitleShow: false, //控制手指离开屏幕的title显示
  touchstartTitleShow: false, //控制手指按下屏幕的title显示
  isShowTop:false
);

let 
  touchstartTitleShow,
  touchEndTitleShow,
  translateY,
 = toRefs(data);

//手指触碰到屏幕
const touchstart = (e: any) => 
  let y = e.targetTouches[0].pageY;
  data.startY = y;
;
const scrollEvent = (e: any) => 
  data.scrollTop = e.srcElement.scrollTop;
  //判定是否展示回退顶部按钮
  data.scrollTop>400? (data.isShowTop=true) : (data.isShowTop=false); 

const toTop=()=>
     //定位到div->top
     let anchor = document.getElementById("top")!;
      anchor.scrollIntoView();

//手指开始滑动
const touchmove = (e: any) => 
  let y = e.targetTouches[0].pageY;
  if (y > data.startY && data.scrollTop == 0) 
    data.touchstartTitleShow = true;
    //如果当前移动距离大于初始点击坐标,则视为是下拉。并且要处于顶部才刷新,不能影响正常的列表滑动。
    data.translateY = (y - data.startY) / 2;
   else 
    data.touchstartTitleShow = false;
  
;
//手指松开
const touchend = (e: any) => 
  let y = e.changedTouches[0].pageY;
  if (y > data.startY && data.scrollTop == 0) 
    data.translateY = 0;
    data.touchstartTitleShow = false;
    data.touchEndTitleShow = true;
    $emits("refreshFun", () => 
      data.touchEndTitleShow = false;
    );
    data.startY = 0;
  
;

</script>

<style lang="scss" scoped>
.box 
  overflow: hidden;
  position: relative;
  width: 100%;
  height: 100vh;
  .loadingBox 
    padding: 20px;
    text-align: center;
  

.scroll-box 
  height: 100vh;
  width: 100%;
  overflow: auto;
  transition: all 0s ease 0s;
  position: absolute;
  right: 0;
   .back-box 
    height: 4rem;
    width: 4rem;
    // 如果对小火箭不满意 可以换成阴影盒子 样式也有
    // background-color: #fff;
    // 圆角弧度 添加圆角边框
    // border-radius: 50%;
    //盒子阴影
    // box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.4);
    // position 属性规定元素的定位类型 fixed元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。
    position: fixed;
    bottom: 3rem;
    right: 1rem;
    text-align: center;
    line-height: 4rem;
  

</style>

🗿🗿type index.ts 数据声明

interface IData 
  //全球疫情数据树
  areaTree: IEpidData[];
  chinaDayList: [];
  //全球疫情列表展示
  showList:IEpidData[];
  //全球疫情数组 用来完成分页功能 
  globalEpidemic: Array<IEpidData[]>
  // 疫情 中国总统计
  chinaTotal: IChinaTotal;
  //中国疫情
  china: IEpidData[] | undefined;
  //江西疫情
  jxData: IEpidData | undefined;
  // 进行判定 number 全国 1 江西
  type: number;
  // 判定展示那一个地图 全国现状 全国累计
  mapType: number;
  lineType: number;
  //最新更新时间
  lastUpdateTime: string;
  //下拉刷新判定
  isScroll:Boolean;

//疫情数据单位统计
interface IEpidData 
  today: 
    confirm: number;
    suspect: number;
    heal: number;
    dead: number;
    severe: number;
    storeConfirm: number;
  ;
  total: 
    confirm: number;
    suspect: number;
    heal: number;
    dead: number;
    severe: number;
    input: number;
  ;
  extData: ;
  name: string;
  id: string;
  lastUpdateTime: string;
  children: IEpidData[] | undefined;


//疫情 中国总统计
interface IChinaTotal 
  total: 
    confirm: number;
    suspect: number;
    heal: number;
    dead: number;
    severe: number;
    input: number;
  ;
  today: 
    input: number;
    storeConfirm: number;
    confirm: number;
    dead: number;
    heal: number;
  ;
  extData: 
    noSymptom: number;
    incrNoSymptom: number;
  ;

//中国地图数值定义
interface IMap
  name: string,
  value:number


export type  IData, IChinaTotal, IEpidData ,IMap;

📕📕pageTS index.ts 数据处理

import  IChinaTotal, IData, IEpidData, IMap  from "../type";
import axios from "axios";
import * as echarts from "echarts";
import chinaJson from "../assets/china.json";
//疫情实时数据
class InfoData implements IData 
  areaTree: IEpidData[] = [];
  chinaDayList: [] = [];
  globalEpidemic:Array<IEpidData[]>=[];
  showList: IEpidData[]=[];
  chinaTotal: IChinaTotal = 
    total: 
      confirm: 0,
      suspect: 0,
      heal: 0,
      dead: 0,
      severe: 0,
      input: 0,
    ,
    today: 
      input: 0,
      storeConfirm: 0,
      confirm: 0,
      dead: 0,
      heal: 0,
    ,
    extData: 
      noSymptom: 0,
      incrNoSymptom: 0,
    ,
  ;
  china: IEpidData[] | undefined = [];
  jxData: IEpidData | undefined = 
    today: 
      confirm: 0,
      suspect: 0,
      heal: 0,
      dead: 0,
      severe: 0,
      storeConfirm: 0,
    ,
    total: 
      confirm: 0,
      suspect: 0,
      heal: 0,
      dead: 0,
      severe: 0,
      input: 0,
    ,
    extData: ,
    name: "",
    id: "",
    lastUpdateTime: "",
    children: ([] = []),
  ;
  // 进行判定 0 全国 1 江西
  type = 0;
  mapType = 1;
  lineType = 0;
  lastUpdateTime = "";
  isScroll=true;

//数据分页处理 数组[][] 20一页
const getPageList = (list: IEpidData[]) => 
  const arr: Array<IEpidData[]> = [];
  for (let index = 0; index < list.length; index += 20) 
      arr.push(list.slice(index, index + 20))
  
  return arr

const initDataFun = async (data: InfoData) => 
  //疫情地图数据 初始化
  //绑定要渲染的地方
  let nowMapDom: htmlElement | null = document.getElementById("nowMap");
  let totalmapDom: HTMLElement | null = document.getElementById("totalMap");
  //初始化echarts实例
  let nowMap=echarts.getInstanceByDom(nowMapDom as HTMLElement); //有的话就获取已有echarts实例的DOM节点。
  let totalMap=echarts.getInstanceByDom(totalmapDom as HTMLElement);
  if(nowMap ==null || totalMap == null) // 如果不存在,就进行初始化。
    nowMap = echarts.init(nowMapDom as HTMLElement);
    totalMap = echarts.init(totalmapDom as HTMLElement);
   
  //显示加载圈圈
  nowMap.showLoading();
  totalMap.showLoading();
  //定义两个地图 类型
  let nowMapData: IMap[] = [];
  let totalMapData: IMap[] = [];
  //导入自定义地图数据 registerMap 注册的地图名称。
  echarts.registerMap("china", chinaJson as any);
  //定义 图表 类型
  type EChartsOption = echarts.EChartsOption;
  //定义地图配置
  let series = 
    type: "map",
    map: "china",
    colorBy: "series", //按照系列分配调色盘中的颜色,同一系列中的所有数据都是用相同的颜色
    zoom: 1.3, //当前视角的缩放比例
    top: 80, //组件离容器上侧的距离
    label: 
      show: true,
      color: "#333",
      fontSize: 10,
    ,
  ;
  //点击地图效果 
  let optionMap: EChartsOption = 
    title: 
      //标题内容
      // text: '中国疫情图',
      subtext: "单击省份可查看病例数",
    ,
    tooltip: 
      //提示框组件
      trigger: "item", //触发类型 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用。
      formatter: "现有确诊病例<br/>b: c ", //提示框浮层内容格式器,支持字符串模板和回调函数两种形式
      //  模板变量有  a ,  b , c , d , e ,分别表示系列名,数据名,数据值等。
      //在 trigger 为 'axis' 的时候,会有多个系列的数据,此时可以通过  a0 ,  a1 ,  a2  这种后面加索引的方式表示系列的索引。 不同图表类型下的  a , b , c , d  含义不一样。 其中变量 a ,  b ,  c ,  d  在不同图表类型下代表数据含义为:
      // 地图:  a (系列名称), b (区域名称), c (合并数值),  d (无)
    ,
    visualMap: 
      show: false,
    ,
  ;
  //获取疫情全部数据接口
  //await是等待的意思,await关键字只能放在async函数里
  //await配合async一起使用,相当于把异步函数变成了同步,await会等待后面表达式的返回结果之后才执行下一步。
  let res=await axios("/prod-api/ug/api/wuhan/app/data/list-total");
    //疫情实时数据处理
    //解构 [[1-30],[31-60],....]
    data.globalEpidemic = getPageList(res.data.data.areaTree);
    data.showList = data.globalEpidemic[0];
    //普通数据赋值
    data.areaTree = res.data.data.areaTree;
    data.chinaDayList = res.data.data.chinaDayList;
    data.chinaTotal = res.data.data.chinaTotal;
    data.lastUpdateTime=res.data.data.lastUpdateTime;
    //获取中国数据
    data.china = data.areaTree.find((v) => v.id === "0")?.children;
    //获取江西疫情数据
    data.jxData = data.china?.find((v) => v.id === "360000");
    //疫情地图数据处理
    data.china?.map((v:IEpidData ) => 
      //对于俩地图赋值
      nowMapData.push(
        name: v.name,
        value: v.total.confirm - v.total.dead - v.total.heal || 0,
      );
      totalMapData.push(
        name: v.name,
        value: v.total.confirm || 0,
      );
    );
    //隐藏加载 圈圈
    nowMap.hideLoading();
    totalMap.hideLoading();
    //数据入地图配置  绘制图表
    nowMap.setOption(
      ...optionMap,
      series: 
        ...series,
        data: nowMapData,
      ,
    );
    totalMap.setOption(
      ...optionMap,
      series: 
        ...series,
        data: totalMapData,
      ,
    );
;
export  InfoData, initDataFun ;

🌃🌃App.vue 疫情页面

<template>
  <UpRefreshAndToTop @refreshFun="refreshFun">
    <div class="box">
      <!-- 疫情实时数据 -->
      <div class="top-box">
        <img class="bg-img" src="./assets/bt.jpg" />
        <div class="title-text">
          <h1>科学防护 共渡难关</h1>
          <h2>肺炎疫情实时动态播报</h2>
          <span>更新时间: lastUpdateTime </span>
        </div>
        <div v-if="chinaTotal" class="cover-cards">
          <div class="cover-tab">
            <div @click="changeType(0)" :class=" active: data.type === 0 ">
              全国疫情数据(含港澳台)
            </div>
            <div @click="changeType(1)" :class=" active: data.type === 1 ">
              江西疫情数据
            </div>
          </div>
          <!-- 全国疫情 -->
          <div class="cover-info" v-show="data.type === 0">
            <div>
              <h4 class="title">境外输入</h4>
              <p class="number"> chinaTotal.total.input </p>
              <p class="tip">
                <span>较昨日</span>
                <span>+ chinaTotal.today.input </span>
              </p>
            </div>
            <div>
              <h4 class="title">无症状感染者</h4>
              <p class="number"> chinaTotal.extData.noSymptom </p>
              <p class="tip">
                <span>较昨日</span>
                <span>+ chinaTotal.extData.incrNoSymptom </span>
              </p>
            </div>
            <div>
              <h4 class="title">现有确诊</h4>
              <p class="number">
                
                  chinaTotal.total.confirm -
                  chinaTotal.total.dead -
                  chinaTotal.total.heal
                
              </p>
              <p class="tip">
                <span>较昨日</span>
                <span>+ chinaTotal.today.storeConfirm </span>
              </p>
            </div>
            <div>
              <h4 class="title">累计确诊</h4>
              <p class="number"> chinaTotal.total.confirm </p>
              <p class="tip">
                <span>较昨日</span>
                <span>+ chinaTotal.today.confirm </span>
              </p>
            </div>
            <div>
              <h4 class="title">累计死亡</h4>
              <p class="number"> chinaTotal.total.dead </p>
              <p class="tip">
                <span>较昨日</span>
                <span>+ chinaTotal.today.dead </span>
              </p>
            </div>
            <div>
              <h4 class="title">累计治愈</h4>
              <p class="number"> chinaTotal.total.heal </p>
              <p class="tip">
                <span>较昨日</span>
                <span>+ chinaTotal.today.heal </span>
              </p>
            </div>
          </div>
          <!-- 江西疫情 -->
          <div v-if="jxData" v-show="data.type === 1" class="cover-info">
            <div>
              <h4 class="title">累计确诊</h4>
              <p class="number"> jxData.total.confirm </p>
              <p class="tip">
                较昨日
                <span>+ jxData.today.confirm </span>
              </p>
            </div>
            <div>
              <h4 class="title">累计死亡</h4>
              <p class="number"> jxData.total.dead </p>
              <p class="tip">
                较昨日
                <span>+ jxData.today.dead </span>
              </p>
            </div>
            <div>
              <h4 class="title">累计治愈</h4>
              <p class="number"> jxData.total.heal </p>
              <p class="tip">
                较昨日
                <span>+ jxData.today.heal </span>
              </p>
            </div>
          </div>
        </div>
      </div>
      <!-- 疫情地图 -->
      <div class="data-map content">
        <h3>中国疫情</h3>
        <div class="map-box">
          <div
            :class="data.mapType == 1 ? 'to-left' : 'to-right'"
            id="nowMap"
          ></div>
          <div
            :class="data.mapType == 1 ? 'to-left' : 'to-right'"
            id="totalMap"
          ></div>
        </div>
        <div class="map-btn">
          <div @click="mapTypeChange(1)" :class=" active: data.mapType == 1 ">
            现有确诊
          </div>
          <div @click="mapTypeChange(2)" :class=" active: data.mapType == 2 ">
            累计确诊
          </div>
        </div>
      </div>
      <!-- 中国疫情列表 -->
      <div class="data-list content">
        <h3>中国病例</h3>
        <span class="hint">温馨提示:点击可展示具体城市</span>
        <EpidemicList :epideList="china" :showChildren="true"></EpidemicList>
      </div>
      <!-- 世界疫情 无点击子模块 -->
      <div v-if="data.showList.length" class="data-list content">
        <h3>世界病例</h3>
        <DownRefresh
          :distance="100"
          :isScroll="data.isScroll"
          @getList="getList"
        >
          <EpidemicList :showChildren="false" :epideList="data.showList" />
        </DownRefresh>
      </div>
    </div>
  </UpRefreshAndToTop>
</template>

<script setup lang="ts">
import  onMounted, reactive, toRefs  from "vue";
import  InfoData, initDataFun  from "./pageTs/index";
import EpidemicList from "./components/EpidemicList.vue";
import UpRefreshAndToTop from "./components/UpRefreshAndToTop.vue";
import DownRefresh from "./components/DownRefresh.vue";
const data = reactive(new InfoData());
onMounted(() => 
  initDataFun(data);
);
//解构数据
const  chinaTotal, jxData, china, lastUpdateTime  = toRefs(data);

//切换 疫情实时数据 全国 江西
const changeType = (toType: number) => 
  data.type = toType;
;
//地图 切换
const mapTypeChange = (type: number) => 
  console.log(type);
  data.mapType = type;
;
//下拉效果 全球疫情列表
let page: number = 0;
const getList = () => 
  if (page === data.globalEpidemic.length - 1) 
    data.isScroll = false;
    return;
  
  console.log("加载下一页");

  // 子组件触发,加载下一页数据
  page++;
  data.showList.push(...data.globalEpidemic[page]);
;
//重新加载数据
const refreshFun = (fun: Function) => 
  initDataFun(data).then(() => 
    //疫情实时数据切换成全国数据
    data.type = 0;
    //重置全球疫情下拉功能
    page = 0;
    data.isScroll = true;
    //控制手指按下屏幕的title显示 去除
    fun();
  );
;
</script>

<style lang="scss" scoped>
// 滑动动画
@keyframes toRight 
  from 
    left: 0;
  

  to 
    left: calc(0px - 100vw + 1rem);
  


@keyframes toLeft 
  from 
    left: calc(0px - 100vw + 1rem);
  

  to 
    left: 0;
  

.bg-img 
  width: 100%;

//疫情实时数据样式
.top-box 
  position: relative;

  .title-text 
    position: absolute;
    z-index: 2;
    color: #fff;
    top: 20px;
    left: 1rem;
    span 
      color: #000;
    
  

  .cover-cards 
    position: absolute;
    top: 12rem;
    background: #fff;
    border-radius: 20px;
    width: calc(100% - 2rem);
    left: 1rem;
    overflow: hidden;
    box-shadow: 0 2px 20px rgb(0 0 0 / 10%);

    > div 
      display: flex;
      justify-content: space-between;
      align-items: center;
      flex-wrap: wrap;

      &.cover-tab 
        > div 
          width: 50%;
          background: #efefef;
          text-align: center;
          height: 40px;
          line-height: 40px;

          &.active 
            background: #fff;
          
        
      

      &.cover-info 
        > div 
          width: 33%;
          text-align: center;
          margin: 10px 0;

          &:nth-child(2) 
            .number,
            span 
              color: #ffa352;
            
          

          &:nth-child(3) 
            .number,
            span 
              color: #791618;
            
          

          &:nth-child(4) 
            .number,
            span 
              color: #e44a3d;
            
          

          &:nth-child(5) 
            .number,
            span 
              color: #333;
            
          

          &:nth-child(6) 
            .number,
            span 
              color: #34aa70;
            
          

          .title 
            font-size: 12px;
          

          .number 
            font-size: 1.5rem;
            font-weight: 600;
            margin: 5px 0;
            color: #a31d13;

            span 
              color: #a31d13;
            
          

          .tip 
            font-size: 12px;
          
        
      
    
  

//疫情地图 数组样式
.content 
  padding: 0 1rem;


.data-map,
.data-list 
  margin-top: 300px;
  overflow: hidden;

  h3 
    border-left: 8px solid #e10000;
    padding-left: 1rem;
  
  .hint
   font-size: 0.5rem;
   color: coral;
  


.map-box 
  display: flex;
  width: 200%;


#nowMap,
#totalMap 
  height: 350px;
  width: 50%;
  animation-fill-mode: forwards;
  left: 0;


#nowMap 
  margin-right: 1rem;


#totalMap 
  margin-left: 1rem;


.to-left 
  animation: toLeft 1s;


.to-right 
  animation: toRight 1s;


.map-btn,
.line-btn 
  display: flex;
  justify-content: space-between;
  align-items: center;

  > div 
    width: 45%;
    height: 40px;
    line-height: 40px;
    border: 1px solid #d2d2d2;
    box-shadow: 0 5px 7px 1px rgb(0 0 0 / 5%);
    border-radius: 5px;
    text-align: center;

    &.active 
      border-color: #ce4733;
      background-color: #fef7f7;
      color: #ce2c1e;
    
  


.line-btn 
  > div 
    width: 30%;
    height: 55px;
    line-height: 25px;
    padding-top: 5px;
  


.data-list 
  margin-top: 20px;

</style>

📺📺vite.config.ts 代理开通 

温馨提示:数据来源 网易云🤭

import  defineConfig  from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig(
  plugins: [vue()],
  server: 
    proxy: 
       //网易代理
      '/prod-api':
       
        target: "https://c.m.163.com",
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\\/prod-api/,'')
      
    
  
)

 完结

以上是关于疫情统计页面 H5 vue3+TypeScript+Echarts的主要内容,如果未能解决你的问题,请参考以下文章

EasyRTC如何基于Vue3+TypeScript技术实现在线会议室功能的分析

uniapp系列-超详细教你在uni-app+vue3里通过web-view组件传递信息打开H5页面写入localstorage并解决兼容性

vue3 移动端h5适配ipad ios android rem 适配(很简单,秒懂)

H5跳转微信小程序

在基于vue-next-admin的Vue3+TypeScript前端项目中,为了使用方便全局挂载的对象接口

vue3provide和inject实现跨层级组件间通信祖孙组件