• 疫情统计页面 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 下拉刷新 组件

    1. <template>
    2. <div class="box">
    3. <div
    4. @scroll="scrollEvent"
    5. class="scroll-box"
    6. >
    7. <slot>slot>
    8. <div class="end-text" v-if="!isScroll">{{ endText }}div>
    9. div>
    10. div>
    11. template>
    12. <script setup lang="ts">
    13. import { reactive, toRefs } from "@vue/reactivity";
    14. const props = defineProps({
    15. //下拉高度
    16. distance: Number ,
    17. //判定是否下拉
    18. isScroll: Boolean,
    19. endText: {
    20. type: String,
    21. default: "没有更多了",
    22. },
    23. });
    24. //子传父参数
    25. const $emits = defineEmits(["getList"]);
    26. const data = reactive({
    27. //离屏幕高度
    28. scrollTop: 0,
    29. });
    30. let {
    31. scrollTop,
    32. } = toRefs(data);
    33. //下拉刷新 判定
    34. const scrollEvent = (e: any) => {
    35. scrollTop = e.srcElement.scrollTop;
    36. if (!props.isScroll) return;
    37. if (
    38. //判定下拉高度
    39. scrollTop + e.srcElement.offsetHeight >
    40. e.srcElement.scrollHeight - props.distance!
    41. ) {
    42. $emits("getList");
    43. }
    44. };
    45. script>
    46. <style lang="scss" scoped>
    47. .box {
    48. overflow: hidden;
    49. position: relative;
    50. width: 100%;
    51. height: 90vh;
    52. }
    53. .scroll-box {
    54. height: 90vh;
    55. width: 100%;
    56. overflow: auto;
    57. transition: all 0s ease 0s;
    58. position: absolute;
    59. right: 0;
    60. .end-text {
    61. text-align: center;
    62. height: 50px;
    63. line-height: 50px;
    64. color: #999;
    65. }
    66. }
    67. style>

    🪜🪜EpidemicList.vue 数据列表 组件

    1. <template>
    2. <div class="list-box">
    3. <div class="info-title info">
    4. <p>地区p>
    5. <p>现有确诊p>
    6. <p>确诊p>
    7. <p>死亡p>
    8. <p>治愈p>
    9. div>
    10. <div class="list" v-for="item in epideList" :key="item.id">
    11. <div class="p-box">
    12. <div @click="getChowChildren(item.id)" class="info">
    13. <p>{{ item.name }}p>
    14. <p>
    15. {{
    16. item.total.confirm - item.total.dead - item.total.heal >= 0
    17. ? item.total.confirm - item.total.dead - item.total.heal
    18. : 0
    19. }}
    20. p>
    21. <p>
    22. <span>{{ item.total.confirm }}span>
    23. <span>较昨日+{{ item.today.confirm ? item.today.confirm : 0 }}span>
    24. p>
    25. <p>{{ item.total.dead }}p>
    26. <p>{{ item.total.heal }}p>
    27. div>
    28. <div v-if="showChildren">
    29. <div>
    30. <div v-show="data.showChildrenId == item.id" class="children-box">
    31. <EpidemicList :epideList="item.children" />
    32. div>
    33. div>
    34. div>
    35. div>
    36. div>
    37. div>
    38. template>
    39. <script name="EpidemicList" setup lang="ts">
    40. // 声明props
    41. import { reactive } from "vue";
    42. import { IEpidData } from "../type";
    43. //无需引入
    44. const props = defineProps({
    45. //疫情数据
    46. epideList:Array<IEpidData>,
    47. //是否展示子数组 省=>市 区数据
    48. showChildren: Boolean,
    49. });
    50. //点击展示
    51. const data = reactive({
    52. showChildrenId: "",
    53. });
    54. //判定 子列表点击是否展示 各个省下面具体的地区
    55. const getChowChildren = (id: string) => {
    56. //原理:通过id来确定要展示的list 点击第二次则置空 不展示效果
    57. data.showChildrenId == id ? (data.showChildrenId = ""): (data.showChildrenId = id);
    58. };
    59. //确诊案例 存在
    60. script>
    61. <style lang="scss" scoped>
    62. .list-box {
    63. border: 1px solid #d1d1d1;
    64. margin: 1rem 0;
    65. .p-box {
    66. .children-box {
    67. margin-left: 1rem;
    68. .list-box {
    69. border: none;
    70. }
    71. .info-title {
    72. height: 30px;
    73. line-height: 30px;
    74. }
    75. p {
    76. &:nth-child(1) {
    77. font-weight: 600;
    78. color: #999;
    79. }
    80. }
    81. }
    82. }
    83. }
    84. .info-title {
    85. font-weight: 600;
    86. color: #000;
    87. font-size: 16px;
    88. height: 50px;
    89. line-height: 50px;
    90. background: #d1d1d1;
    91. }
    92. .info {
    93. display: flex;
    94. justify-content: space-between;
    95. align-items: center;
    96. > p {
    97. width: 15%;
    98. text-align: center;
    99. // white-space: nowrap;
    100. &:nth-child(1) {
    101. font-weight: 600;
    102. color: #000;
    103. }
    104. &:nth-child(2) {
    105. width: 23%;
    106. color: red;
    107. }
    108. &:nth-child(3) {
    109. width: 23%;
    110. white-space: nowrap;
    111. span {
    112. display: block;
    113. &:last-child {
    114. color: #999;
    115. }
    116. }
    117. }
    118. }
    119. }
    120. .list {
    121. &:nth-of-type(odd) {
    122. background: #f6f6f6;
    123. }
    124. .info {
    125. height: 80px;
    126. line-height: 80px;
    127. p {
    128. line-height: 20px;
    129. }
    130. }
    131. }
    132. style>

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

    1. <template>
    2. <div class="box">
    3. <div
    4. @touchend="touchend"
    5. @touchmove="touchmove"
    6. @touchstart="touchstart"
    7. @scroll="scrollEvent"
    8. :style="{ top: `${translateY}px` }"
    9. class="scroll-box"
    10. >
    11. <div class="loadingBox" v-if="touchstartTitleShow">释放可刷新...div>
    12. <div class="loadingBox" v-if="touchEndTitleShow">加载中...div>
    13. <div id="top">div>
    14. <slot>slot>
    15. <div v-show="data.isShowTop" class="back-box" @click="toTop">
    16. <img src="../assets/toTop.png">
    17. div>
    18. div>
    19. div>
    20. template>
    21. <script setup lang="ts">
    22. import { reactive, toRefs } from "@vue/reactivity";
    23. const $emits = defineEmits(["refreshFun"]);
    24. const data = reactive({
    25. startText: "释放即可刷新",
    26. scrollTop: 0,
    27. startY: 0,
    28. translateY: 0,
    29. touchEndTitleShow: false, //控制手指离开屏幕的title显示
    30. touchstartTitleShow: false, //控制手指按下屏幕的title显示
    31. isShowTop:false
    32. });
    33. let {
    34. touchstartTitleShow,
    35. touchEndTitleShow,
    36. translateY,
    37. } = toRefs(data);
    38. //手指触碰到屏幕
    39. const touchstart = (e: any) => {
    40. let y = e.targetTouches[0].pageY;
    41. data.startY = y;
    42. };
    43. const scrollEvent = (e: any) => {
    44. data.scrollTop = e.srcElement.scrollTop;
    45. //判定是否展示回退顶部按钮
    46. data.scrollTop>400? (data.isShowTop=true) : (data.isShowTop=false);
    47. }
    48. const toTop=()=>{
    49. //定位到div->top
    50. let anchor = document.getElementById("top")!;
    51. anchor.scrollIntoView();
    52. }
    53. //手指开始滑动
    54. const touchmove = (e: any) => {
    55. let y = e.targetTouches[0].pageY;
    56. if (y > data.startY && data.scrollTop == 0) {
    57. data.touchstartTitleShow = true;
    58. //如果当前移动距离大于初始点击坐标,则视为是下拉。并且要处于顶部才刷新,不能影响正常的列表滑动。
    59. data.translateY = (y - data.startY) / 2;
    60. } else {
    61. data.touchstartTitleShow = false;
    62. }
    63. };
    64. //手指松开
    65. const touchend = (e: any) => {
    66. let y = e.changedTouches[0].pageY;
    67. if (y > data.startY && data.scrollTop == 0) {
    68. data.translateY = 0;
    69. data.touchstartTitleShow = false;
    70. data.touchEndTitleShow = true;
    71. $emits("refreshFun", () => {
    72. data.touchEndTitleShow = false;
    73. });
    74. data.startY = 0;
    75. }
    76. };
    77. script>
    78. <style lang="scss" scoped>
    79. .box {
    80. overflow: hidden;
    81. position: relative;
    82. width: 100%;
    83. height: 100vh;
    84. .loadingBox {
    85. padding: 20px;
    86. text-align: center;
    87. }
    88. }
    89. .scroll-box {
    90. height: 100vh;
    91. width: 100%;
    92. overflow: auto;
    93. transition: all 0s ease 0s;
    94. position: absolute;
    95. right: 0;
    96. .back-box {
    97. height: 4rem;
    98. width: 4rem;
    99. // 如果对小火箭不满意 可以换成阴影盒子 样式也有
    100. // background-color: #fff;
    101. // 圆角弧度 添加圆角边框
    102. // border-radius: 50%;
    103. //盒子阴影
    104. // box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.4);
    105. // position 属性规定元素的定位类型 fixed元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。
    106. position: fixed;
    107. bottom: 3rem;
    108. right: 1rem;
    109. text-align: center;
    110. line-height: 4rem;
    111. }
    112. }
    113. style>

    🗿🗿type index.ts 数据声明

    1. interface IData {
    2. //全球疫情数据树
    3. areaTree: IEpidData[];
    4. chinaDayList: [];
    5. //全球疫情列表展示
    6. showList:IEpidData[];
    7. //全球疫情数组 用来完成分页功能
    8. globalEpidemic: Array<IEpidData[]>
    9. // 疫情 中国总统计
    10. chinaTotal: IChinaTotal;
    11. //中国疫情
    12. china: IEpidData[] | undefined;
    13. //江西疫情
    14. jxData: IEpidData | undefined;
    15. // 进行判定 number 全国 1 江西
    16. type: number;
    17. // 判定展示那一个地图 全国现状 全国累计
    18. mapType: number;
    19. lineType: number;
    20. //最新更新时间
    21. lastUpdateTime: string;
    22. //下拉刷新判定
    23. isScroll:Boolean;
    24. }
    25. //疫情数据单位统计
    26. interface IEpidData {
    27. today: {
    28. confirm: number;
    29. suspect: number;
    30. heal: number;
    31. dead: number;
    32. severe: number;
    33. storeConfirm: number;
    34. };
    35. total: {
    36. confirm: number;
    37. suspect: number;
    38. heal: number;
    39. dead: number;
    40. severe: number;
    41. input: number;
    42. };
    43. extData: {};
    44. name: string;
    45. id: string;
    46. lastUpdateTime: string;
    47. children: IEpidData[] | undefined;
    48. }
    49. //疫情 中国总统计
    50. interface IChinaTotal {
    51. total: {
    52. confirm: number;
    53. suspect: number;
    54. heal: number;
    55. dead: number;
    56. severe: number;
    57. input: number;
    58. };
    59. today: {
    60. input: number;
    61. storeConfirm: number;
    62. confirm: number;
    63. dead: number;
    64. heal: number;
    65. };
    66. extData: {
    67. noSymptom: number;
    68. incrNoSymptom: number;
    69. };
    70. }
    71. //中国地图数值定义
    72. interface IMap{
    73. name: string,
    74. value:number
    75. }
    76. export type { IData, IChinaTotal, IEpidData ,IMap};

    📕📕pageTS index.ts 数据处理

    1. import { IChinaTotal, IData, IEpidData, IMap } from "../type";
    2. import axios from "axios";
    3. import * as echarts from "echarts";
    4. import chinaJson from "../assets/china.json";
    5. //疫情实时数据
    6. class InfoData implements IData {
    7. areaTree: IEpidData[] = [];
    8. chinaDayList: [] = [];
    9. globalEpidemic:Array<IEpidData[]>=[];
    10. showList: IEpidData[]=[];
    11. chinaTotal: IChinaTotal = {
    12. total: {
    13. confirm: 0,
    14. suspect: 0,
    15. heal: 0,
    16. dead: 0,
    17. severe: 0,
    18. input: 0,
    19. },
    20. today: {
    21. input: 0,
    22. storeConfirm: 0,
    23. confirm: 0,
    24. dead: 0,
    25. heal: 0,
    26. },
    27. extData: {
    28. noSymptom: 0,
    29. incrNoSymptom: 0,
    30. },
    31. };
    32. china: IEpidData[] | undefined = [];
    33. jxData: IEpidData | undefined = {
    34. today: {
    35. confirm: 0,
    36. suspect: 0,
    37. heal: 0,
    38. dead: 0,
    39. severe: 0,
    40. storeConfirm: 0,
    41. },
    42. total: {
    43. confirm: 0,
    44. suspect: 0,
    45. heal: 0,
    46. dead: 0,
    47. severe: 0,
    48. input: 0,
    49. },
    50. extData: {},
    51. name: "",
    52. id: "",
    53. lastUpdateTime: "",
    54. children: ([] = []),
    55. };
    56. // 进行判定 0 全国 1 江西
    57. type = 0;
    58. mapType = 1;
    59. lineType = 0;
    60. lastUpdateTime = "";
    61. isScroll=true;
    62. }
    63. //数据分页处理 数组[][] 20一页
    64. const getPageList = (list: IEpidData[]) => {
    65. const arr: Array<IEpidData[]> = [];
    66. for (let index = 0; index < list.length; index += 20) {
    67. arr.push(list.slice(index, index + 20))
    68. }
    69. return arr
    70. }
    71. const initDataFun = async (data: InfoData) => {
    72. //疫情地图数据 初始化
    73. //绑定要渲染的地方
    74. let nowMapDom: HTMLElement | null = document.getElementById("nowMap");
    75. let totalmapDom: HTMLElement | null = document.getElementById("totalMap");
    76. //初始化echarts实例
    77. let nowMap=echarts.getInstanceByDom(nowMapDom as HTMLElement); //有的话就获取已有echarts实例的DOM节点。
    78. let totalMap=echarts.getInstanceByDom(totalmapDom as HTMLElement);
    79. if(nowMap ==null || totalMap == null){ // 如果不存在,就进行初始化。
    80. nowMap = echarts.init(nowMapDom as HTMLElement);
    81. totalMap = echarts.init(totalmapDom as HTMLElement);
    82. }
    83. //显示加载圈圈
    84. nowMap.showLoading();
    85. totalMap.showLoading();
    86. //定义两个地图 类型
    87. let nowMapData: IMap[] = [];
    88. let totalMapData: IMap[] = [];
    89. //导入自定义地图数据 registerMap 注册的地图名称。
    90. echarts.registerMap("china", chinaJson as any);
    91. //定义 图表 类型
    92. type EChartsOption = echarts.EChartsOption;
    93. //定义地图配置
    94. let series = {
    95. type: "map",
    96. map: "china",
    97. colorBy: "series", //按照系列分配调色盘中的颜色,同一系列中的所有数据都是用相同的颜色
    98. zoom: 1.3, //当前视角的缩放比例
    99. top: 80, //组件离容器上侧的距离
    100. label: {
    101. show: true,
    102. color: "#333",
    103. fontSize: 10,
    104. },
    105. };
    106. //点击地图效果
    107. let optionMap: EChartsOption = {
    108. title: {
    109. //标题内容
    110. // text: '中国疫情图',
    111. subtext: "单击省份可查看病例数",
    112. },
    113. tooltip: {
    114. //提示框组件
    115. trigger: "item", //触发类型 数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用。
    116. formatter: "现有确诊病例
      {b}: {c} "
      , //提示框浮层内容格式器,支持字符串模板和回调函数两种形式
    117. // 模板变量有 { a }, { b },{ c },{ d },{ e },分别表示系列名,数据名,数据值等。
    118. //在 trigger 为 'axis' 的时候,会有多个系列的数据,此时可以通过 { a0 }, { a1 }, { a2 } 这种后面加索引的方式表示系列的索引。 不同图表类型下的 { a },{ b },{ c },{ d } 含义不一样。 其中变量{ a }, { b }, { c }, { d } 在不同图表类型下代表数据含义为:
    119. // 地图: { a }(系列名称),{ b }(区域名称),{ c }(合并数值), { d }(无)
    120. },
    121. visualMap: {
    122. show: false,
    123. },
    124. };
    125. //获取疫情全部数据接口
    126. //await是等待的意思,await关键字只能放在async函数里
    127. //await配合async一起使用,相当于把异步函数变成了同步,await会等待后面表达式的返回结果之后才执行下一步。
    128. let res=await axios("/prod-api/ug/api/wuhan/app/data/list-total");
    129. //疫情实时数据处理
    130. //解构 [[1-30],[31-60],....]
    131. data.globalEpidemic = getPageList(res.data.data.areaTree);
    132. data.showList = data.globalEpidemic[0];
    133. //普通数据赋值
    134. data.areaTree = res.data.data.areaTree;
    135. data.chinaDayList = res.data.data.chinaDayList;
    136. data.chinaTotal = res.data.data.chinaTotal;
    137. data.lastUpdateTime=res.data.data.lastUpdateTime;
    138. //获取中国数据
    139. data.china = data.areaTree.find((v) => v.id === "0")?.children;
    140. //获取江西疫情数据
    141. data.jxData = data.china?.find((v) => v.id === "360000");
    142. //疫情地图数据处理
    143. data.china?.map((v:IEpidData ) => {
    144. //对于俩地图赋值
    145. nowMapData.push({
    146. name: v.name,
    147. value: v.total.confirm - v.total.dead - v.total.heal || 0,
    148. });
    149. totalMapData.push({
    150. name: v.name,
    151. value: v.total.confirm || 0,
    152. });
    153. });
    154. //隐藏加载 圈圈
    155. nowMap.hideLoading();
    156. totalMap.hideLoading();
    157. //数据入地图配置 绘制图表
    158. nowMap.setOption({
    159. ...optionMap,
    160. series: {
    161. ...series,
    162. data: nowMapData,
    163. },
    164. });
    165. totalMap.setOption({
    166. ...optionMap,
    167. series: {
    168. ...series,
    169. data: totalMapData,
    170. },
    171. });
    172. };
    173. export { InfoData, initDataFun };

    🌃🌃App.vue 疫情页面

    1. <template>
    2. <UpRefreshAndToTop @refreshFun="refreshFun">
    3. <div class="box">
    4. <div class="top-box">
    5. <img class="bg-img" src="./assets/bt.jpg" />
    6. <div class="title-text">
    7. <h1>科学防护 共渡难关h1>
    8. <h2>肺炎疫情实时动态播报h2>
    9. <span>更新时间:{{ lastUpdateTime }}span>
    10. div>
    11. <div v-if="chinaTotal" class="cover-cards">
    12. <div class="cover-tab">
    13. <div @click="changeType(0)" :class="{ active: data.type === 0 }">
    14. 全国疫情数据(含港澳台)
    15. div>
    16. <div @click="changeType(1)" :class="{ active: data.type === 1 }">
    17. 江西疫情数据
    18. div>
    19. div>
    20. <div class="cover-info" v-show="data.type === 0">
    21. <div>
    22. <h4 class="title">境外输入h4>
    23. <p class="number">{{ chinaTotal.total.input }}p>
    24. <p class="tip">
    25. <span>较昨日span>
    26. <span>+{{ chinaTotal.today.input }}span>
    27. p>
    28. div>
    29. <div>
    30. <h4 class="title">无症状感染者h4>
    31. <p class="number">{{ chinaTotal.extData.noSymptom }}p>
    32. <p class="tip">
    33. <span>较昨日span>
    34. <span>+{{ chinaTotal.extData.incrNoSymptom }}span>
    35. p>
    36. div>
    37. <div>
    38. <h4 class="title">现有确诊h4>
    39. <p class="number">
    40. {{
    41. chinaTotal.total.confirm -
    42. chinaTotal.total.dead -
    43. chinaTotal.total.heal
    44. }}
    45. p>
    46. <p class="tip">
    47. <span>较昨日span>
    48. <span>+{{ chinaTotal.today.storeConfirm }}span>
    49. p>
    50. div>
    51. <div>
    52. <h4 class="title">累计确诊h4>
    53. <p class="number">{{ chinaTotal.total.confirm }}p>
    54. <p class="tip">
    55. <span>较昨日span>
    56. <span>+{{ chinaTotal.today.confirm }}span>
    57. p>
    58. div>
    59. <div>
    60. <h4 class="title">累计死亡h4>
    61. <p class="number">{{ chinaTotal.total.dead }}p>
    62. <p class="tip">
    63. <span>较昨日span>
    64. <span>+{{ chinaTotal.today.dead }}span>
    65. p>
    66. div>
    67. <div>
    68. <h4 class="title">累计治愈h4>
    69. <p class="number">{{ chinaTotal.total.heal }}p>
    70. <p class="tip">
    71. <span>较昨日span>
    72. <span>+{{ chinaTotal.today.heal }}span>
    73. p>
    74. div>
    75. div>
    76. <div v-if="jxData" v-show="data.type === 1" class="cover-info">
    77. <div>
    78. <h4 class="title">累计确诊h4>
    79. <p class="number">{{ jxData.total.confirm }}p>
    80. <p class="tip">
    81. 较昨日
    82. <span>+{{ jxData.today.confirm }}span>
    83. p>
    84. div>
    85. <div>
    86. <h4 class="title">累计死亡h4>
    87. <p class="number">{{ jxData.total.dead }}p>
    88. <p class="tip">
    89. 较昨日
    90. <span>+{{ jxData.today.dead }}span>
    91. p>
    92. div>
    93. <div>
    94. <h4 class="title">累计治愈h4>
    95. <p class="number">{{ jxData.total.heal }}p>
    96. <p class="tip">
    97. 较昨日
    98. <span>+{{ jxData.today.heal }}span>
    99. p>
    100. div>
    101. div>
    102. div>
    103. div>
    104. <div class="data-map content">
    105. <h3>中国疫情h3>
    106. <div class="map-box">
    107. <div
    108. :class="data.mapType == 1 ? 'to-left' : 'to-right'"
    109. id="nowMap"
    110. >div>
    111. <div
    112. :class="data.mapType == 1 ? 'to-left' : 'to-right'"
    113. id="totalMap"
    114. >div>
    115. div>
    116. <div class="map-btn">
    117. <div @click="mapTypeChange(1)" :class="{ active: data.mapType == 1 }">
    118. 现有确诊
    119. div>
    120. <div @click="mapTypeChange(2)" :class="{ active: data.mapType == 2 }">
    121. 累计确诊
    122. div>
    123. div>
    124. div>
    125. <div class="data-list content">
    126. <h3>中国病例h3>
    127. <span class="hint">温馨提示:点击可展示具体城市span>
    128. <EpidemicList :epideList="china" :showChildren="true">EpidemicList>
    129. div>
    130. <div v-if="data.showList.length" class="data-list content">
    131. <h3>世界病例h3>
    132. <DownRefresh
    133. :distance="100"
    134. :isScroll="data.isScroll"
    135. @getList="getList"
    136. >
    137. <EpidemicList :showChildren="false" :epideList="data.showList" />
    138. DownRefresh>
    139. div>
    140. div>
    141. UpRefreshAndToTop>
    142. template>
    143. <script setup lang="ts">
    144. import { onMounted, reactive, toRefs } from "vue";
    145. import { InfoData, initDataFun } from "./pageTs/index";
    146. import EpidemicList from "./components/EpidemicList.vue";
    147. import UpRefreshAndToTop from "./components/UpRefreshAndToTop.vue";
    148. import DownRefresh from "./components/DownRefresh.vue";
    149. const data = reactive(new InfoData());
    150. onMounted(() => {
    151. initDataFun(data);
    152. });
    153. //解构数据
    154. const { chinaTotal, jxData, china, lastUpdateTime } = toRefs(data);
    155. //切换 疫情实时数据 全国 江西
    156. const changeType = (toType: number) => {
    157. data.type = toType;
    158. };
    159. //地图 切换
    160. const mapTypeChange = (type: number) => {
    161. console.log(type);
    162. data.mapType = type;
    163. };
    164. //下拉效果 全球疫情列表
    165. let page: number = 0;
    166. const getList = () => {
    167. if (page === data.globalEpidemic.length - 1) {
    168. data.isScroll = false;
    169. return;
    170. }
    171. console.log("加载下一页");
    172. // 子组件触发,加载下一页数据
    173. page++;
    174. data.showList.push(...data.globalEpidemic[page]);
    175. };
    176. //重新加载数据
    177. const refreshFun = (fun: Function) => {
    178. initDataFun(data).then(() => {
    179. //疫情实时数据切换成全国数据
    180. data.type = 0;
    181. //重置全球疫情下拉功能
    182. page = 0;
    183. data.isScroll = true;
    184. //控制手指按下屏幕的title显示 去除
    185. fun();
    186. });
    187. };
    188. script>
    189. <style lang="scss" scoped>
    190. // 滑动动画
    191. @keyframes toRight {
    192. from {
    193. left: 0;
    194. }
    195. to {
    196. left: calc(0px - 100vw + 1rem);
    197. }
    198. }
    199. @keyframes toLeft {
    200. from {
    201. left: calc(0px - 100vw + 1rem);
    202. }
    203. to {
    204. left: 0;
    205. }
    206. }
    207. .bg-img {
    208. width: 100%;
    209. }
    210. //疫情实时数据样式
    211. .top-box {
    212. position: relative;
    213. .title-text {
    214. position: absolute;
    215. z-index: 2;
    216. color: #fff;
    217. top: 20px;
    218. left: 1rem;
    219. span {
    220. color: #000;
    221. }
    222. }
    223. .cover-cards {
    224. position: absolute;
    225. top: 12rem;
    226. background: #fff;
    227. border-radius: 20px;
    228. width: calc(100% - 2rem);
    229. left: 1rem;
    230. overflow: hidden;
    231. box-shadow: 0 2px 20px rgb(0 0 0 / 10%);
    232. > div {
    233. display: flex;
    234. justify-content: space-between;
    235. align-items: center;
    236. flex-wrap: wrap;
    237. &.cover-tab {
    238. > div {
    239. width: 50%;
    240. background: #efefef;
    241. text-align: center;
    242. height: 40px;
    243. line-height: 40px;
    244. &.active {
    245. background: #fff;
    246. }
    247. }
    248. }
    249. &.cover-info {
    250. > div {
    251. width: 33%;
    252. text-align: center;
    253. margin: 10px 0;
    254. &:nth-child(2) {
    255. .number,
    256. span {
    257. color: #ffa352;
    258. }
    259. }
    260. &:nth-child(3) {
    261. .number,
    262. span {
    263. color: #791618;
    264. }
    265. }
    266. &:nth-child(4) {
    267. .number,
    268. span {
    269. color: #e44a3d;
    270. }
    271. }
    272. &:nth-child(5) {
    273. .number,
    274. span {
    275. color: #333;
    276. }
    277. }
    278. &:nth-child(6) {
    279. .number,
    280. span {
    281. color: #34aa70;
    282. }
    283. }
    284. .title {
    285. font-size: 12px;
    286. }
    287. .number {
    288. font-size: 1.5rem;
    289. font-weight: 600;
    290. margin: 5px 0;
    291. color: #a31d13;
    292. span {
    293. color: #a31d13;
    294. }
    295. }
    296. .tip {
    297. font-size: 12px;
    298. }
    299. }
    300. }
    301. }
    302. }
    303. }
    304. //疫情地图 数组样式
    305. .content {
    306. padding: 0 1rem;
    307. }
    308. .data-map,
    309. .data-list {
    310. margin-top: 300px;
    311. overflow: hidden;
    312. h3 {
    313. border-left: 8px solid #e10000;
    314. padding-left: 1rem;
    315. }
    316. .hint{
    317. font-size: 0.5rem;
    318. color: coral;
    319. }
    320. }
    321. .map-box {
    322. display: flex;
    323. width: 200%;
    324. }
    325. #nowMap,
    326. #totalMap {
    327. height: 350px;
    328. width: 50%;
    329. animation-fill-mode: forwards;
    330. left: 0;
    331. }
    332. #nowMap {
    333. margin-right: 1rem;
    334. }
    335. #totalMap {
    336. margin-left: 1rem;
    337. }
    338. .to-left {
    339. animation: toLeft 1s;
    340. }
    341. .to-right {
    342. animation: toRight 1s;
    343. }
    344. .map-btn,
    345. .line-btn {
    346. display: flex;
    347. justify-content: space-between;
    348. align-items: center;
    349. > div {
    350. width: 45%;
    351. height: 40px;
    352. line-height: 40px;
    353. border: 1px solid #d2d2d2;
    354. box-shadow: 0 5px 7px 1px rgb(0 0 0 / 5%);
    355. border-radius: 5px;
    356. text-align: center;
    357. &.active {
    358. border-color: #ce4733;
    359. background-color: #fef7f7;
    360. color: #ce2c1e;
    361. }
    362. }
    363. }
    364. .line-btn {
    365. > div {
    366. width: 30%;
    367. height: 55px;
    368. line-height: 25px;
    369. padding-top: 5px;
    370. }
    371. }
    372. .data-list {
    373. margin-top: 20px;
    374. }
    375. style>

    📺📺vite.config.ts 代理开通 

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

    1. import { defineConfig } from 'vite'
    2. import vue from '@vitejs/plugin-vue'
    3. // https://vitejs.dev/config/
    4. export default defineConfig({
    5. plugins: [vue()],
    6. server: {
    7. proxy: {
    8. //网易代理
    9. '/prod-api':
    10. {
    11. target: "https://c.m.163.com",
    12. changeOrigin: true,
    13. rewrite: (path) => path.replace(/^\/prod-api/,'')
    14. }
    15. }
    16. }
    17. })

     完结

  • 相关阅读:
    JWT——讲解
    体系结构31_机群计算机
    ETCD中MVCC的运用
    外国固定资产管理系统功能有哪些
    MongoDB 文档更新update
    文件管理:目录管理
    【Kafka面试演练】那Kafka消费者手动提交、自动提交有什么区别?
    携职教育:【建议收藏】14个热门证书,最全考证时间表
    ARM接口实验—串口实验
    【力扣hot100】刷题笔记Day17
  • 原文地址:https://blog.csdn.net/Little___Turtle/article/details/126467993