Vue3+vite+Echarts案例大屏可视化--千峰(推荐)

https://www.bilibili.com/video/BV14u411D7qK?p=33&spm_id_from=pageDriver&vd_source=e2cfe74d93fb5b3f60bd7487ede60218

主题展示

 

 Vue3.2中

<template>
    <!-- 为 ECharts 准备一个定义了宽高的 DOM -->
    <!--vue3中 id=‘’ 变更 ref=-->
    <div ref="chart" style="width:100%;height:200px;"></div>
</template>

<script setup >
import {onMounted, reactive, ref} from "vue";
// 局部引入echarts核心模块
import * as echarts from 'echarts'

// const props = defineProps({ // 宏接收:父传参
// 结构优化
const {chartType,chartData}= defineProps({ // 宏接收:父传参
    chartType:{
        type: String
    },
    chartData: {
        type: Array
    }
})

const chart =ref(); // 创建DOM引用

// 第二种方法:初始化方法
const option = reactive({
    // 指定图表的配置项和数据
    title: { // 标题
        // left: 'center', // 居中
        text: 'ECharts 入门示例',
        left: 'center',
        textStyle: {
            color: '#f60',
            fontSize: 20,
        }
    },
    color: '#f00', // 系列柱的颜色
    tooltip: {},  // 提示
    legend: {  // 图例
        data: ['销量'],
        top: '5%',
        left: 'right',
        textStyle: { // 文字样式
            color: '#f68',
        }
    },
    xAxis: { // x轴
        data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子'],
        axisLine: { // 设置轴
            lineStyle: { // 样式
                color:'#000' // 颜色
            }
        },

        axisLabel:{
            interval: 0,
            formatter: value => value.split('').join('\n') //报红:取消lang='ts'
        }
    },
    yAxis: { // y轴
        axisLine: { // 设置轴
            lineStyle: { // 样式
                color:'#000' // 颜色
            }
        },
        axisLabel:{
            // formatter: '{value} 件'
            formatter: function(value,index){ // 报红:取消lang='ts'
                return value %2 == 0 ? value + '' : value  // 可写各种逻辑判断: 奇偶数
            }
        }
    },
    series: [ // data数据
        {
            name: '销量',
            // type: 'bar', // 图样类型
            // type: props.chartType, // 父传参:自定义
            type:chartType, // 结构优化
            // data: [5, 20, 36, 10, 10, 20], // 图标数据
            // data: props.chartData,
            data: chartData,
            label: {
                show: true,
                position: 'top'
            },
        }
    ]
})

// 使用生命钩子
onMounted(() => {
    // 基于准备好的dom,初始化echarts实例
    // var myChart = echarts.init(document.getElementById('main'));
    // Vue3中: 需要引入
    var myChart = echarts.init(chart.value)

    // init(); // vue3.2没有this
    // 使用刚指定的配置项和数据显示图表。
    myChart.setOption(option);

    // 单图表响应式: 跟随浏览器大小改变
    window.addEventListener('resize',()=>{
        myChart.resize()
    })

})

</script>

<style scoped>

</style>

 

自定义主题

 

 在About.vue组件中引用assets/index.js文件

 

 地图展示

 

 

 

 Json.api地址拷贝后,浏览器地址栏打开

 

 数据拷贝文档中起名 XXX.js

1.引用XXX.js地图数据

import {XXX} from "../assets/XXX.js"
// 引入echarts核心模块
import * as echarts from 'echarts'
// 还需引入地图文件
import chinaMap from '../../assets/china1.json'

2.注册地图:Vue3.2

// 使用生命钩子
onMounted(() => {
    // 基于准备好的dom,初始化echarts实例
    // var myChart = echarts.init(document.getElementById('main'));
    // Vue3中: 需要引入
    var myChart = echarts.init(chart.value)

    // 注册可用的地图
    echarts.registerMap('china',chinaMap);

    // init(); // vue3.2没有this
    // 使用刚指定的配置项和数据显示图表。
    myChart.setOption(option);

3.地图中的设定

如何获取地图经纬度:百度地图开放平台

map.baidu.com

 

 

 

 点击后右上方

  

const option = reactive({// 指定图表的配置项和数据
    geo: { // 地理坐标组件
        type:"map",
        map: "china",
        roam:true, // 地图可拖拽、平移
        zoom: 5, // 缩放大小
        center: [116.387803,39.940361], // 地图中心点:经纬度

    },

省份地图展示和优化

1.阿里云DataV.GeoAtlas地理小工具系列 (aliyun.com),获取地图省份信息

2.特效展示

 option中 geo 和 series 功能相同,需注意处理:注意:echarts绘制地图提示框不出现。echarts绘制地图有两种方式,一种是geo对象,一种是series数组,geo对象生成的地图没有提示框,只有series数组生成的地图有提示框

地图标记设置与效果

option中series:常用重要属性设置

series: [{ // 地图不需XY轴
        type: 'map', // 图表类型:散点图scatter:用到坐标系设置
        map: 'china', // 地图类型
        roam: true, // 地图可拖拽、平移
        data: mapData, // 使用动态Api接口文档数据
        /*[ // 展示数据项的名字,经纬度,数据量
            {name:'河南省',value:32300,4000},
            {name: '山东省',value: 21203},
            {name: '四川省',value: 41203},
            {name: '青海省',value: 31203},
        ],*/
        coordinateSystem: "geo", // 当前坐标系设置:经纬度定位

完整代码

<template>
    <!-- 为 ECharts 准备一个定义了宽高的 DOM -->
    <!--vue3中 id=‘’ 变更 ref=-->
    <div ref="chart" style="width:650px;height:650px;"></div>
</template>

<script setup >
import {onMounted, reactive, ref} from "vue";
// 引入echarts核心模块
import * as echarts from 'echarts'
// 还需引入地图文件
import chinaMap from '../../assets/china1.json'
// 引入动态数据axios,二次封装
import axios from "../../http/request";

// const mapData = await fetch(`/api/post/1`).then(r => r.json())
// 根据接口文档:实际参数获取数据
const mapData = await axios.get('student_location').then(res => res.data.result)

const chart =ref(); // 创建DOM引用

// 第二种方法:初始化方法
const option = reactive({// 指定图表的配置项和数据
    geo: { // 地理坐标组件,series
        type:"map",
        map: "china",
        roam:true, // 地图可拖拽、平移
        zoom: 5, // 缩放大小
        center: [116.387803,39.940361], // 地图中心点:经纬度

        label: {
            show: true, // // 标签:地图中的标签、文字
            color: ""
        }
    },
    //  option中 geo 和 series 功能相同,
    //  需注意处理:注意:echarts绘制地图提示框不出现。
    //  echarts绘制地图有两种方式,一种是geo对象,一种是series数组,
    //  geo对象生成的地图没有提示框,只有series数组生成的地图有提示框
    series: [{ // 地图不需XY轴
        type: 'map', // 图表类型:散点图scatter:用到坐标系设置
        map: 'china', // 地图类型
        roam: true, // 地图可拖拽、平移
        // data: mapData, // 使用动态Api接口文档数据
        /*[ // 展示数据项的名字,经纬度,数据量
            {name:'河南省',value:[32300,4000]},
            {name: '山东省',value: 21203},
            {name: '四川省',value: 41203},
            {name: '青海省',value: 31203},
        ],*/
        data: [// 展示数据项的名字,经纬度,数据量
            {
                name:'河南省',value:[32300,4000]
            },
        ],
        coordinateSystem: "geo", // 当前坐标系设置:经纬度定位
        symbolSize: 30, // 大小

        label: { // 标签:地图中的标签、文字
            show: true, // 开启地图中的标签、文字等,(必须开启)
            color: '#fff',
            fontSize:11,
        },
        itemStyle:{ // 修改地图区域标签样式
            areaColor: '#219edb', // 区域颜色
            borderColor: '#fff', // 区域边框价格
        },
        emphasis: { // 地图高亮状态的多边形和标签样式
            label:{
                color: '#000',
                fontSize: 12,
            },
            itemStyle: {
                areaColor: '#f60',
                borderColor: '#329edb'
            }
        },
    },
        {
            type: "effectScatter", // 涟漪(lianyi)效果
            coordinateSystem: "geo",
            data: [
                {
                    name: "郑州",
                    value:[
                        108.95,
                        34.26
                    ]
                }
            ]
        }
    ],
    // 设置涟漪效果的相关配置
    rippleEffect: {
        number: 2, // 波纹数量
        scale: 4, // 波纹大小
    },
    itemStyle: {
        color: "red",
    }
    visualMap: {
        min: 800,
        max: 50000,
        text: ['High', 'Low'],
        realtime: false,
        calculable: true,
        inRange: {
            color: ['lightskyblue', 'yellow', 'orangered']
        },
        textStyle: {
            color:'#000'
        }
    },
})

// 使用生命钩子
onMounted(() => {
    // 基于准备好的dom,初始化echarts实例
    // var myChart = echarts.init(document.getElementById('main'));
    // Vue3中: 需要引入init() Vue3.2没有this
    var myChart = echarts.init(chart.value)

    // 注册可用的地图
    echarts.registerMap('china',chinaMap);

    // 使用刚指定的配置项和数据显示图表。
    myChart.setOption(option);

    // 单图表响应式: 跟随浏览器大小改变
    window.addEventListener('resize',()=>{
        myChart.resize()
    })
})

</script>

<style scoped>

</style>

图表自适应大小

页面加载完后,监听页面大小的改变

// 单图表响应式: 跟随浏览器大小改变
    window.addEventListener('resize',()=>{
        myChart.resize()
    })

加载动画效果

加载等待效果

1. 全局下载:数据模拟数据 json-server

npm install -g json-server

2. 新建Src/Mock文件夹存放模拟数据,新建data.js文件

将data[ ]数组中的数据,拷贝出来,data,js中建立一个对象

// 拷贝数据:注意key要加双引号 “  ”
// 创建一个 key  "one":[ ]数组
{
  "one":[
    {
      "value": 67,
      "name": "美食",
      "itemStyle":{
        "normal": {
          "color": "rgb(1,175,80)"
        }
      }
    },
    {
      "value": 85,
      "name": "日化",
      "itemStyle":{
        "normal": {
          "color": "rgb(255.175.80)"
        }
      }
    },
    {
      "value": 45,
      "name": "数码",
      "itemStyle":{
        "normal": {
          "color": "rgb(1,0,80)"
        }
      }
    },
    {
      "value": 98,
      "name": "家电",
      "itemStyle":{
        "normal": {
          "color": "rgb(30,50,70)"
        }
      }
    }
  ]
}

3.启动json-server

注意点 : 启动目录 Mock路径下

 

 

 

//  运行 监听 json文件 端口
json-server --watch data.json --port 8888

 

 地址栏:输入查看请求数据

axios安装

npm install --save axios

 

axios:Url:localhost:9999对应着 json-server启动时的IP端口

 Vue3.2写法

// 引入echarts核心模块
import * as echarts from 'echarts'
// 还需引入地图文件
import chinaMap from '../../assets/china1.json'
// 引入动态数据axios,二次封装
import axios from "../../http/request";

// const mapData = await fetch(`/api/post/1`).then(r => r.json())
// 根据接口文档:实际参数获取数据
const mapData = await axios.get('http://localhost:9999').then(res => res.data.result)

 案列完整代码:

<template>
  <div ref="myChart" id="myChart"></div>
</template>
<script>
import * as echarts from "echarts";
import axios from "axios";
// import {mapData} from "../assets/mapData.js"
export default {
  data() {
    return {
      echartsData: {},
    };
  },
methods: {
// 获取json-server数据
async linkData() {
let mapnum = await axios({ url: "http://localhost:3000/one" });
console.log(mapnum.data);
this.echartsData = mapnum.data;
},
},
mounted() {
// 1.初始化
let myChart = echarts.init(this.$refs.myChart);
// 设置开始等待
myChart.showLoading();
// 调用数据请求方法
this.linkData().then(() => {
myChart.hideLoading();
// 2.设置echarts数据
let option = {
title: {
text: "饼状图",
subtext: "基本设置",
left: "center", //设置位置居中
},
tooltip: {
trigger: "item", //触发类型item数据项图形触发
},
千锋大前端教研院
39.图表动画配置
legend: {
orient: "vertical", //图例列表的布局朝向vertical纵向
left: "left",
},
series: [
{
name: "销售量",
type: "pie",
// 设置环形图
radius: ["40%", "70%"], //饼图的半径。数组的第一项是内半径,第二项是外半径。
// 设置环形图
label: {
//饼图图形上的文本标签
show: true,
position: "inside", //outside饼图扇区外侧inside饼图扇区内部center在饼图
中心位置
color: "yellow",
},
labelLine: {
//标签的视觉引导线配置
show: false,
},
roseType: "area", //是否展示成南丁格尔图,通过半径区分数据大小
itemStyle: {
//设置内容样式
color: "#c23531",
shadowBlur: 200,
shadowColor: "rgba(0, 0, 0, 0.5)",
},
data: this.echartsData,
},
],
};
// 4.设置图表绘制图表
myChart.setOption(option);
});
},
};
</script>
<style>
#myChart {
width: 500px;
height: 500px;
border: 1px solid red;
}
</style>  

千锋Echarts+Vue3.0数据可视化项目

1.电脑上安装node.js

网址:https://nodejs.org/zh-cn/
下载自己对应操作系统版本 安装即可

2.全局下载项目脚手架

vue-cli这个构建工具大大降低了webpack的使用难度,支持热更新,有webpack-dev-server的支持,相当于启动了一个请求服务器,给你搭建了一个测试环境,只关注开发就OK。

一.安装vue-cli
1、 使用npm(需要安装node环境)全局安装webpack,打开命令行工具输入:npm install webpack -g或者(npm install -g webpack),安装完成之后输入 webpack -v,如下图,如果出现相应的版本号,则说明安装成功。

注意:webpack 4.X 开始,需要安装 webpack-cli 依赖 ,所以使用这条命令 npm install webpack webpack-cli -g

2、 全局安装vue-cli,在cmd中输入命令:npm install --global vue-cli

3、安装完成之后输入 vue -V(注意这里是大写的“V”),如下图,如果出现相应的版本号,则说明安装成功。

打开cmd 输入 
npm install -g @vue/cli
npm install -g @vue/cli
# OR
yarn global add @vue/cli

建项目

 把cmd的路径切换到指定路径下 

vue create 项目名
(3-1)选择项目配置模板 选择第三项自主选择你项目所需的配置
 

输入命令后,会跳出几个选项让你回答:  

  -Project name (baoge): -----项目名称,直接回车,按照括号中默认名字(注意这里的名字不能有大写字母,如果有会报错_Sorry, name can no longer contain capital letters_),
  Project description (A Vue.js project): ----项目描述,也可直接点击回车,使用默认名字
  Author (): ----作者,输入你的大名
  接下来会让用户选择:

  Runtime + Compiler: recommended for most users 运行加编译,既然已经说了推荐,就选它了
  Runtime-only: about 6KB lighter min+gzip, but templates (or any
  Vue-specificHTML) are ONLY allowed in .vue files - render functions
  are required elsewhere 仅运行时,已经有推荐了就选择第一个了
  Install vue-router (Y/n) 是否安装vue-router,这是官方的路由,大多数情况下都使用,这里就输入“y”后回车即可。
  _Use ESLint to lint your code (Y/n)
  是否使用ESLint管理代码,ESLint是个代码风格管理工具,是用来统一代码风格的,一般项目中都会使用。 接下来也是选择题_Pick an
  ESLint preset (Use arrow keys) 选择一个ESLint预设,编写vue项目时的代码风格,直接y回车
  Setup unit tests with Karma + Mocha (Y/n) 是否安装单元测试,我选择安装y回车
  Setup e2e tests with Nightwatch(Y/n) 是否安装e2e测试 ,我选择安装y回车
  回答完毕后上图就开始构建项目了。
2、配置完成后,可以看到目录下多出了一个项目文件夹baoge,然后cd进入这个文件夹:
安装依赖:npm install

一、vite环境搭建,构建vite-vue-ts项目

1、快捷建立Vite+Vue3

npm init vite@latest
# npm 6.x
npm create vite@latest my-vue-app --template vue

# npm 7+, extra double-dash is needed:
npm create vite@latest myapp -- --template vue

# yarn
yarn create vite my-vue-app --template vue

# pnpm
pnpm create vite my-vue-app --template vue

  

2:更改http://localhost:3000/到8080与Network路由访问

在vite.config.ts里面加入:(server对象为新增,其他均是原有代码)

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
  
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  server:{
    host:'0.0.0.0',//解决vite use--host to expose
    port:8080,
    open:true
  }
})

3:配置vite别名(npm install @types/node --save-dev)

在vite.config.ts里面加入:(resolve对象为新增)

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
  
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  server:{
    host:'0.0.0.0',//解决vite use--host to expose
    port:8080,
    open:true
  },
  resolve:{
    alias:[
      {
        find:'@',
        replacement:resolve(__dirname,'src') // 优化: '@': resolve(__dirname,'src')
      }
    ]
  }
})

4:路由(npm install vue-router@4)

src下新建目录router→index.ts

import {createRouter,createMemoryHistory,RouteRecordRaw} from 'vue-router'
import Layout from '@/components/HelloWorld.vue' // 路径报红: @ 变更 。。
const routes:Array<RouteRecordRaw> =[
    {
        path:'/',
        name:'home',
        component:Layout
    }
]
// 创建
const router = createRouter({
    history:createMemoryHistory(),
    routes
})
// 暴露接口
export default router

在main.ts下 import router from './router/index' 引入路由 

在main.ts下 app.use(router)注册路由

5:vuex(npm install vuex@next --save)或者Pinia(npm install pinia@next --save)

Pinia和Vuex一样都是是vue的全局状态管理器。其实Pinia就是Vuex5

https://pinia.web3doc.top/getting-started.html#%E5%AE%89%E8%A3%85

yarn add pinia
# 或者使用 npm
npm install pinia

设置为全局对象,在main.js中引用

import { createPinia } from "pinia";// 创建pinia实例const pinia = createPinia()app.use(pinia)

创建

pinia创建
// stores/todo.js
import { defineStore } from 'pinia'
export const useTodoStore = defineStore({
  id: 'todo',
  state: () => ({ count: 0, title: "Cook noodles", done:false })
})

src下新建目录store→index.ts

打开vuex官网(Vuex 是什么? | Vuex)找到TypeScript支持下的“简化 useStore 用法”直接复制所有代码就可以

在App.vue下<router-view></router-view>

import { InjectionKey } from 'vue'
import { createStore, useStore as baseUseStore, Store } from 'vuex'
  
export interface State {
  count: number
}
  
export const key: InjectionKey<Store<State>> = Symbol()
  
export const store = createStore<State>({
  state: {
    count: 0
  },
  mutations:{
    setCount(state:State,i:number){
        state.count = i
    }
  },
  getters:{
     getCount(state:State){
        return state.count
    }
  }
})
  
// 定义自己的 `useStore` 组合式函数
export function useStore () {
  return baseUseStore(key)
}

在main.ts下 import {store,key} from './store/index' 引入vuex

在main.ts下 app.use(store,key)注册路由

(如有疑问可参考官网TypeScript支持下的“useStore 组合式函数类型声明”)

pinia在vue3中的写法和用法

store/index.ts共享组件

import {ref} from 'vue'
// 共享组件
import {defineStore} from "pinia";

export const useCounterStore = defineStore('counter', () => {
    const count = ref(0)
    function increment() {
        count.value++
    }

    return { count, increment }
})

 

// store.js
import { defineStore } from "pinia"
// defineStore 调用后返回一个函数,调用该函数获得 Store 实体
export const GlobalStore = defineStore({
// id: 必须的,在所有 Store 中唯一 id: "myGlobalState", // state: 返回对象的函数 state: () => ({ a: 1, }), getters: {}, actions: { setXXX(number) { this.a = number; }, }, });
// 在vue3中使用 <template> <div> {{number}} <button @click="clickHandle">按钮</button> </div> </template>
<script> import {GlobalStore} from "@/store/store.js" export default { setup(){ let store = GlobalStore(); //如果直接取state的值必须使用computed才能实现数据的响应式 如果直接取 store.state.a 则不会监听到数据的变化,或者使用getter,就可以不使用computed (这边和vuex是一样的) let number = computed(()=>store.a) const clickHandle = () => { store.setXXX("100") } return{number,clickHandle} }
}
</script> 

6:Eslint(可选)(npm install --save-dev eslint eslint-plugin-vue)

根目录新建文件.eslintrc.js

module.exports = {
    root: true,
    parserOptions: {
        sourceType: 'module'
    },
    parser: 'vue-eslint-parser',
    extends: ['plugin:vue/vue3-essential', 'plugin:vue/vue3-strongly- recommended', 'plugin:vue/    vue3-recommended'],
    env: {
        browser: true,
        node: true,
        es6: true
    },
    rules: {
        'no-console': 'off',
        'comma-dangle': [2, 'never'] //禁止使用拖尾逗号 } }
    }
}

7:less/sass(可选)(npm install -D sass sass-loader)

 

二.项目初始化?

1.删除src文件夹下的cpmponents文件夹下的Helloword.vue文件
2.删除vuews下的两个.vue文件
3.在views中新建我们的页面文件 homePage.vue文件
<template>
    <div>
        我是页面
    </div>
</template>

<script>
export default {
    name: "homePage"

}
</script>

<style scoped>

</style>
4.修改router下的index.ts配置路由文件
import {createRouter, createMemoryHistory, RouteRecordRaw,} from "vue-router";

const routes:Array<RouteRecordRaw> = [
    {
        path:'/page',
        name:'page',
        component: () => import('@/views/homePage.vue')
    },
    { // 路由重定向配置:注意点
        path:"/",
        redirect:"/page",
    }
]
// 创建
const router = createRouter({
    history:createMemoryHistory(),
    routes
})
// 暴露接口
export default router
5。修改根组件App.vue默认显示内容与初始化项目样式
<template>
    <!--router/index已设定路由-->
    <router-view/>
</template>

<script setup lang="ts">

</script>

<style scoped>
* {  /* 清除样式 */
    margin:0px;
    padding: 0px;
    box-sizing: border-box; /*盒子大小:包含border-box*/
}
</style>

三、项目分辨率响应式分析与实施

项目基本结构

整体轮廓分为上下结构:红框

 

 下框内分为:左中右

技术栈

1. vue3.0+vue-router4.0+axios
2. flex布局:npm install lib-flexible --save
3. LESS : npm install less less-loader -D 
4. rem屏幕适配
5. echarts5.0 :npm install echarts --save

6.Element-plus :npm install element-plus --save

7.node.js-express后端

四.项目分辨率响应式创建

我们的项目是需要根据页面的大小改变 做出响应式改变的 所以我们可以使用
我们可以使用 第三方插件flexible.js帮助我们修改html根节点的font-size大小 从而控制当前页面的
rem(会根据页面的html根节点font-size大小改变而改变)样式改变
flexible.js
flexible.js web自适应方案 阿里团队开源的一个库。使用flexible.js轻松搞定各种不同的移动端设备兼容
自适应问题。
1.下载 
npm i -S lib-flexible
2.在main.中进行配置 
import { createApp } from 'vue'
// import './style.css'
import App from './App.vue'
import router from "./router/index";
// import store from "vuex";
// 引入element-plus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
// 引用
import 'lib-flexible/flexible.js'

createApp(App).use(ElementPlus).use(router).mount('#app')
3.修改flexible配置
因为默认情况下只会在540px分辨率一下生效 所以我们需要根据我们的项目分辨率进行调整
在node_module/lib-flexible/flexible.js中修改代码如下
function refreshRem(){
        var width = docEl.getBoundingClientRect().width;
        // 元数据:大小
        /*if (width / dpr > 540) {
            width = 540 * dpr;
        }
        var rem = width / 10;*/
        // 修改:最小400px,最大适配2560px
        if (width / dpr < 400) {
            width = 400 * dpr;
        }else if (width / dpr > 2560){
            width = 2560 * dpr
        }
        // 设置成24份,1920Px设计稿 1rem 就是80px (1920/24=80)
        var rem = width / 24; // 原10

        docEl.style.fontSize = rem + 'px';
        flexible.rem = win.rem = rem;
    }
这个时候重启项目大家打开浏览器调试器 即可发现在浏览器大小改变的时候 在html根节点上会自动设
置一个font-size

cssrem插件

我们在写代码的时候发现如果我们都根据80px为1rem在编写代码的时候转换非常的麻烦 所以我们可以
在vscode中安装一个cssrem的插件帮助我们进行转换 这样一来开发过程中会更加的方便

配置方式

在vscode扩展中找到 cssrem插件 最新名字叫px to rem & rpx 安装到vscode中 点击右下角设置
修改Root Font Size(基准font-size) 配置项为80即可

测试与使用

在写css的时候就会出现相应的rem转换结果

五.项目顶部信息条创建

1.设置背景图
把图片方法assets文件夹中 在app.vue中设置背景图
body {
    background: url("./assets/xinguan.jpg") no-repeat fixed center;
    background-size: cover;
} 
2.设置标题文字
<template>
    <!--上部:标题-->
    <el-row class="top">
        <el-col :span="24" >
            <div class="grid-content ep-bg-purple-dark" >
                <h1>大数据座舱</h1>
            </div>
        </el-col>
    </el-row>
    <!--下部:左中右-->
    <el-row class="main">
        <el-col :span="8" class="itemLeft">
            <div class="grid-content ep-bg-purple" >Aside</div>
        </el-col>
        <el-col :span="8">
            <div class="grid-content ep-bg-purple-light" >Main</div>
        </el-col>
        <el-col :span="8">
            <div class="grid-content ep-bg-purple-light" >Aside</div>
        </el-col>
    </el-row>
</template>

<script setup>



</script>

<style lang="scss">
.el-row {
  margin-bottom: 20px;
}
.el-row:last-child {
  margin-bottom: 0;
}
.el-col {
  border-radius: 4px;
}

.grid-content {
  border-radius: 4px;
  min-height: 36px;
}

.top {
  height: 1rem; // 1rem=80px
  width: 100%;
  background-color: rgba(0,0,255,0.1); // 色度 0.2透明度
  // 标题的文字样式
  h1{
    font-size: 0.375rem;
    color: #fff;
    text-align: center; // 居中方式
    line-height: 1rem; // 1rem=80px
  }
}

</style>

六.页面主体创建

大容器
1.创建一个大容器来容纳绿色 红色 黄色三个区域
在homepage.vue页面中创建一个大容器:使用element-plus样式布局
后面容器样式可以跳过
<!--下部:左中右-->
    <el-row class="main">
        <el-col :span="8" class="itemLeft">
            <div class="grid-content ep-bg-purple" >Aside</div>
        </el-col>
        <el-col :span="8">
            <div class="grid-content ep-bg-purple-light" >Main</div>
        </el-col>
        <el-col :span="8">
            <div class="grid-content ep-bg-purple-light" >Aside</div>
        </el-col>
    </el-row>

创建容器样式

<style lang="less">
header{
    height: 1rem;
    width: 100%;
    /* 设置一个半透明淡蓝色 */
    background-color: rgba(0, 0, 255, .2);
    /* 把标题文字样式设置 */
    h1{
        font-size: .375rem;
        color:#fff;
        text-align: center;
        line-height: 1rem;
    }
}
// 主体容器样式
.container{
    // 这里就不需要设置使用rem了 使用rem那么页面就会根据html根结点大小改变而改变了
    min-width: 1200px;
    max-width: 2048px;
    margin: 0 auto;
    // 盒子上10px 左右10px 下0的外边距
    padding: .125rem .125rem 0;
    // 测试完成看到样式就删除掉
    height: 500px;
    background-color: gray;
}
</style        
左中右
接下来我们可以创建左中右这三个部分。那么他们的占比分别是3 5 3 这个时候我们可以使用flex布局来
分割他们所占的区块大小

左右图表展示区块容器样式

大家会发现我们要展示的4个区域的容器效果是一样的。所以我们可以剥离成一个组件 然后重复调用即
可。并且在其中放置slot槽口 后期方便向容器内插入图表
创建容器组件
在components文件夹下创建 itemPage.vue

 

<!--共享容器组件-->
<template>
    <div class="item ">
        <!--设置插槽-->
        <slot></slot>
    </div>
</template>

<script setup>

</script>

<style scoped lang="less">
.item {
  height: 5.125rem;
  border: 1px solid blue;
  //外边距20px
  margin:.25rem;
  background-color: rgba(13,130,255,0.851);
}

</style> 
在views下的homePage中引用调用使用 
<template>
    <!--上部:标题-->
    <el-row class="top">
        <el-col :span="24" >
            <div class="grid-content ep-bg-purple-dark" >
                <h1>蓝尔海--大数据座舱</h1>
            </div>
        </el-col>
    </el-row>
    <!--下部:左中右,justify 属性来定义子元素的排版方式,其取值为start、center、end、space-between、space-around或space-evenly。-->
    <el-row class="row-bg" justify="space-evenly">
        <el-col :span="6" class="itemLeft">
            <div class="grid-content ep-bg-purple" >
                <ItemPage>
                    <ItemOne>

                    </ItemOne>
                </ItemPage>
                <ItemPage>
                    <ItemTwo>

                    </ItemTwo>
                </ItemPage>
            </div>
        </el-col>
        <el-col :span="12" class="itemCenter">
            <div class="grid-content ep-bg-purple-light" >
                <h2>地图展示</h2>
            </div>
        </el-col>
        <el-col :span="6">
            <div class="grid-content ep-bg-purple" >
                <ItemPage>
                    <ItemTree>

                    </ItemTree>
                </ItemPage>
                <ItemPage>
                    <ItemFour>

                    </ItemFour>
                </ItemPage>
            </div>
        </el-col>
    </el-row>
</template>

<script setup>
// 引入组件
import ItemPage from "../components/itemPage.vue"
import ItemOne from "../components/itemOne.vue"
import ItemTwo from "../components/itemTwo.vue"
import ItemTree from "../components/itemThree.vue"
import ItemFour from "../components/itemFour.vue"


</script>

<style lang="scss">
.el-row {
  margin-bottom: 20px;
}
.el-row:last-child {
  margin-bottom: 0;
}
.el-col {
  border-radius: 4px; // 边框圆角°
  margin: 0 auto;
}

.grid-content {
  border-radius: 4px;
  min-height: 36px;
}

.top {
  height: 1rem; // 1rem=80px
  width: 100%;
  background-color: rgba(0,0,255,0.1); // 色度 0.2透明度
  // 标题的文字样式
  h1{
    font-size: 0.375rem;
    color: #fff;
    text-align: center; // 居中方式
    line-height: 1rem; // 1rem=80px
  }
}
// 大容器的样式
/*.container {
  // 最大最小的宽度
  !*min-width: 1200px;
  max-width: 2048px;*!
  !*margin: 0 auto; // 上容器边距
  padding: .125rem 0.125rem 0; // 上下右边距*!
  !*height: 500px;
  background-color: gray;*!
}*/
.itemCenter{
  border: 1px solid blue;
  border-radius: 4px;
}
</style>
运行之后大家会发现左右区块就展现出4个容器
左右每个区块内容插入容器槽口
我们一共4个图标 使用一个公共的组件容器 所以我们编写这4个不同图表的组件并且 分别显示
1.创建4个组件 在components下 itemOne.vue等等 一共4个
然后在4个文件中分别设置相关内容与样式(每个图表的标题不一样要修改) 
<template>
    <div>
        <h2>图表1</h2>
        <div class="chart">
            图表的容器
        </div>
    </div>
</template>

<script setup>

</script>

<style scoped>

</style>
在homePage.vue中引用调用使用这4个组件
<template>
    <!--上部:标题-->
    <el-row class="top">
        <el-col :span="24" >
            <div class="grid-content ep-bg-purple-dark" >
                <h1>蓝尔海--大数据座舱</h1>
            </div>
        </el-col>
    </el-row>
    <!--下部:左中右,justify 属性来定义子元素的排版方式,其取值为start、center、end、space-between、space-around或space-evenly。-->
    <el-row class="row-bg" justify="space-evenly">
        <el-col :span="6" class="itemLeft">
            <div class="grid-content ep-bg-purple" >
                <ItemPage>
                    <ItemOne>

                    </ItemOne>
                </ItemPage>
                <ItemPage>
                    <ItemTwo>

                    </ItemTwo>
                </ItemPage>
            </div>
        </el-col>
        <el-col :span="12" class="itemCenter">
            <div class="grid-content ep-bg-purple-light" >
                <h2>地图展示</h2>
            </div>
        </el-col>
        <el-col :span="6">
            <div class="grid-content ep-bg-purple" >
                <ItemPage>
                    <ItemTree>

                    </ItemTree>
                </ItemPage>
                <ItemPage>
                    <ItemFour>

                    </ItemFour>
                </ItemPage>
            </div>
        </el-col>
    </el-row>
</template>

<script setup>
// 引入组件
import ItemPage from "../components/itemPage.vue"
import ItemOne from "../components/itemOne.vue"
import ItemTwo from "../components/itemTwo.vue"
import ItemTree from "../components/itemThree.vue"
import ItemFour from "../components/itemFour.vue"


</script>

<style lang="scss">
.el-row {
  margin-bottom: 20px;
}
.el-row:last-child {
  margin-bottom: 0;
}
.el-col {
  border-radius: 4px; // 边框圆角°
  margin: 0 auto;
}

.grid-content {
  border-radius: 4px;
  min-height: 36px;
}

.top {
  height: 1rem; // 1rem=80px
  width: 100%;
  background-color: rgba(0,0,255,0.1); // 色度 0.2透明度
  // 标题的文字样式
  h1{
    font-size: 0.375rem;
    color: #fff;
    text-align: center; // 居中方式
    line-height: 1rem; // 1rem=80px
  }
}
// 大容器的样式
/*.container {
  // 最大最小的宽度
  !*min-width: 1200px;
  max-width: 2048px;*!
  !*margin: 0 auto; // 上容器边距
  padding: .125rem 0.125rem 0; // 上下右边距*!
  !*height: 500px;
  background-color: gray;*!
}*/
.itemCenter{
  border: 1px solid blue;
  border-radius: 4px;
}
</style>
<template>
    <!--上部:标题-->
    <el-row class="top">
        <el-col :span="24" >
            <div class="grid-content ep-bg-purple-dark" >
                <h1>蓝尔海--大数据座舱</h1>
            </div>
        </el-col>
    </el-row>
    <!--下部:左中右,justify 属性来定义子元素的排版方式,其取值为start、center、end、space-between、space-around或space-evenly。-->
    <el-row class="row-bg" justify="space-evenly">
        <el-col :span="6" class="itemLeft">
            <div class="grid-content ep-bg-purple" >
                <ItemPage>
                    <ItemOne>

                    </ItemOne>
                </ItemPage>
                <ItemPage>
                    <ItemTwo>

                    </ItemTwo>
                </ItemPage>
            </div>
        </el-col>
        <el-col :span="12" class="itemCenter">
            <div class="grid-content ep-bg-purple-light" >
                <h2>地图展示</h2>
            </div>
        </el-col>
        <el-col :span="6">
            <div class="grid-content ep-bg-purple" >
                <ItemPage>
                    <ItemTree>

                    </ItemTree>
                </ItemPage>
                <ItemPage>
                    <ItemFour>

                    </ItemFour>
                </ItemPage>
            </div>
        </el-col>
    </el-row>
</template>

<script setup>
// 引入组件
import ItemPage from "../components/itemPage.vue"
import ItemOne from "../components/itemOne.vue"
import ItemTwo from "../components/itemTwo.vue"
import ItemTree from "../components/itemThree.vue"
import ItemFour from "../components/itemFour.vue"


</script>

<style lang="scss">
.el-row {
  margin-bottom: 20px;
}
.el-row:last-child {
  margin-bottom: 0;
}
.el-col {
  border-radius: 4px; // 边框圆角°
  margin: 0 auto;
}

.grid-content {
  border-radius: 4px;
  min-height: 36px;
}

.top {
  height: 1rem; // 1rem=80px
  width: 100%;
  background-color: rgba(0,0,255,0.1); // 色度 0.2透明度
  // 标题的文字样式
  h1{
    font-size: 0.375rem;
    color: #fff;
    text-align: center; // 居中方式
    line-height: 1rem; // 1rem=80px
  }
}
// 大容器的样式
/*.container {
  // 最大最小的宽度
  !*min-width: 1200px;
  max-width: 2048px;*!
  !*margin: 0 auto; // 上容器边距
  padding: .125rem 0.125rem 0; // 上下右边距*!
  !*height: 500px;
  background-color: gray;*!
}*/
.itemCenter{
  border: 1px solid blue;
  border-radius: 4px;
}
</style>
中间地图区域容器样式
在views文件夹下的 homePage。vue 中设置中间区域容器样式
.itemCenter{
  // 高度840px
  height: 10.5rem;
  border: 1px solid blue;
  // 内边距10px
  padding: 0.125rem;
  // 外边距20px
  margin: 0.25rem;
}

七.图表前期准备

全局设置Echarts与axios

Charts 全局引用

1.下载
 npm install --save echarts
2.0的写法
在vue2.0中使用如下写法吧echarts挂载在vue实例上 但是这招在3.0行不通了
在main.js中进行引用和调用
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// 引用
import 'lib-flexible/flexible.js'
// 引用echarts
import * as echarts from "echarts"
Vue.prototype.$echarts=echarts;
createApp(App).use(store).use(router).mount('#app')
vue3中使用Provide/Inject依赖注入,将替代vue2中在原型链上挂载一些属性
在app.vue中使用provider来给后代们提供数据
<script>
// 1.引用proivde
import {provide} from "vue"
// 2.引用echarts
import * as echarts from "echarts"
export default {
  setup() {
  provide("echarts",echarts)//第一个参数是名字 第二个参数是你传递的内容
  },
}
</script>
在想使用的组件中使用inject来接受
在views下的homePage.vue测试
// 引用inject
import {inject} from 'vue'
export default {
    components:{
        ItemPage,itemOne,itemTwo,itemThree,itemFour
    },
    setup(){
    // 测试使用echarts
    let $echarts= inject("echarts")
    console.log($echarts)
    }
}
大家在console中可以看到可以正常使用了
 

axios全局引用

axios使用于上面相同方式
1.下载 npm install --save axios
2.在app.vue中使用provider来给后代们提供数据
<script>
// 1.引用proivde
import {provide} from "vue"
// 2.引用echarts
import * as echarts from "echarts"
// 引用axios
import axios from 'axios'
export default {
    setup() {
    provide("echarts",echarts)//第一个参数是名字 第二个参数是你传递的内容
    provide("axios",axios)//第一个参数是名字 第二个参数是你传递的内容
    },
}
</script>
在想使用的组件中使用inject来接受
在views下的homePage.vue测试
// 引用inject
import {inject} from 'vue'
export default {
    components:{
    ItemPage,itemOne,itemTwo,itemThree,itemFour
},
    setup(){
    // 测试使用echarts
    let $echarts= inject("echarts")
    let $http= inject("axios")
    console.log($echarts)
    console.log($http)
}
}                

Vue3.2中homePage.vue 完整代码:

<template>
    <!--上部:标题-->
    <el-row class="top">
        <el-col :span="24" >
            <div class="grid-content ep-bg-purple-dark" >
                <h1>豫教云网卫士--大数据座舱</h1>
            </div>
        </el-col>
    </el-row>
    <!--下部:左中右,justify 属性来定义子元素的排版方式,其取值为start、center、end、space-between、space-around或space-evenly。-->
    <el-row class="row-bg" justify="space-evenly">
        <el-col :span="6" class="itemLeft">
            <div class="grid-content ep-bg-purple" >
                <ItemPage>
                    <ItemOne>

                    </ItemOne>
                </ItemPage>
                <ItemPage>
                    <ItemTwo>

                    </ItemTwo>
                </ItemPage>
            </div>
        </el-col>
        <el-col :span="12" class="itemCenter">
            <!-- 为 ECharts 准备一个定义了宽高的 DOM -->
            <!--vue3.2中 id=‘’ 变更 ref=-->
            <div class="grid-content ep-bg-purple-light" ref="chart" style="width:100%;height:700px;">
                <h2>地图展示</h2>
            </div>
        </el-col>
        <el-col :span="6">
            <div class="grid-content ep-bg-purple" >
                <ItemPage>
                    <ItemTree>

                    </ItemTree>
                </ItemPage>
                <ItemPage>
                    <ItemFour>

                    </ItemFour>
                </ItemPage>
            </div>
        </el-col>
    </el-row>
</template>

<script setup >
import {ref,reactive,onMounted} from 'vue'
// 引入组件
import ItemPage from "../components/itemPage.vue"
import ItemOne from "../components/itemOne.vue"
import ItemTwo from "../components/itemTwo.vue"
import ItemTree from "../components/itemThree.vue"
import ItemFour from "../components/itemFour.vue"
// 引入echarts核心模块
import * as echarts from 'echarts'
// 还需引入地图文件
import chinaMap from '../assets/china1.json'
// 引入动态数据axios,二次封装
import axios from "../../http/request";

const chart =ref(); // 创建DOM引用

// 第二种方法:初始化方法
const option = reactive({// 指定图表的配置项和数据
    series: [{ // 地图不需XY轴
        type: 'map', // 图表类型:散点图scatter:用到坐标系设置
        map: 'china', // 地图类型
        roam: true, // 地图可拖拽、平移
        // data: mapData, // 使用动态Api接口文档数据
        /*[ // 展示数据项的名字,经纬度,数据量
            {name:'河南省',value:[32300,4000]},
            {name: '山东省',value: 21203},
            {name: '四川省',value: 41203},
            {name: '青海省',value: 31203},
    ],*/
        data: [// 展示数据项的名字,经纬度,数据量
            {name: '河南省', value: [32300, 4000],},
            {name: '山东省', value: 21203},
            {name: '四川省', value: 41203},
            {name: '青海省', value: 31203},

        ],

        label: { // 标签:地图中的标签、文字
            show: true, // 开启地图中的标签、文字等,(必须开启)
            color: '#fff',
            fontSize: 11,
        },
        itemStyle: { // 修改地图区域标签样式
            areaColor: '#219edb', // 区域颜色
            borderColor: '#fff', // 区域边框价格
        },
        emphasis: { // 地图高亮状态的多边形和标签样式
            label: {
                color: '#000',
                fontSize: 12,
            },
            itemStyle: {
                areaColor: '#f60',
                borderColor: '#329edb'
            },
        },
    }],
    coordinateSystem: "geo", // 当前坐标系设置:经纬度定位
    symbolSize: 30, // 大小
})

// 使用生命钩子
onMounted(() => {
    // 基于准备好的dom,初始化echarts实例
    // var myChart = echarts.init(document.getElementById('main'));
    // Vue3中: 需要引入
    var myChart = echarts.init(chart.value)

    // 注册可用的地图
    echarts.registerMap('china',chinaMap);


    // 使用刚指定的配置项和数据显示图表。
    myChart.setOption(option);

    // 单图表响应式: 跟随浏览器大小改变
    window.addEventListener('resize',()=>{
        myChart.resize()
    })
})

</script>

<style lang="scss">
.el-row {
  margin-bottom: 20px;
}
.el-row:last-child {
  margin-bottom: 0;
}
.el-col {
  border-radius: 4px; // 边框圆角°
  margin: 0 auto;
}

.grid-content {
  border-radius: 4px;
  min-height: 36px;
}

.top {
  height: 1rem; // 1rem=80px
  width: 100%;
  background-color: rgba(0,0,255,0.1); // 色度 0.2透明度
  // 标题的文字样式
  h1{
    font-size: 0.375rem;
    color: #fff;
    text-align: center; // 居中方式
    line-height: 1rem; // 1rem=80px
  }
}
// 大容器的样式
/*.container {
  // 最大最小的宽度
  !*min-width: 1200px;
  max-width: 2048px;*!
  !*margin: 0 auto; // 上容器边距
  padding: .125rem 0.125rem 0; // 上下右边距*!
  !*height: 500px;
  background-color: gray;*!
}*/
/*.itemCenter{
  border: 1px solid blue;
  border-radius: 4px;
}*/
</style> 

八.后台接口创建express介绍

node.js平台Web开发框架安装:Express - 基于 Node.js 平台的 web 应用开发框架 - Express 中文文档 | Express 中文网 (expressjs.com.cn)

npm install express --save

九.后台路由创建

1.创建一个文件夹 server 在其中创建index.js与router文件夹容来容纳代码
2.在router下创建4个文件分别容纳 对应的接口
// 路由:4个图表需要获取后台数据
// 定义引入express
let express = require("express")
// 定义路由
let router = express.Router()

// 设置当前路由:get('路由名',回调函数(请求request,响应response)
router.get("/data",(req,res)=>{
    // 响应内容
    res.send({mag:"One的地址"})
})
// 暴露路由接口
module .exports=router // vue3.0
// export default router  // vue3.2
 
3.在index.js下引用使用刚才创建的内容
var express=require("express");
var app=express();
// 引用路由文件
var chartOne=require("./router/one.js");
var chartTwo=require("./router/two.js");
var chartThree=require("./router/three.js");
var chartFour=require("./router/four.js");
// 中间件中使用路由
app.use("/one",chartOne)
app.use("/two",chartTwo)
app.use("/three",chartThree)
app.use("/four",chartFour)
// 请求是localhost:3000/user/路由文件中的地址
app.listen(3000)
完整代码
// 合并4个图表路由
// import {Express, Request, Response, Router} from "express"; // {类型}

//引用express
let express=require("express") // vue3.0
// import express,{Express} from "express"; // vue3.2
// axios
import axios from "axios";

// 接口函数: 前端交互
let app = express();

// 引用路由文件
let chartOne = require("./router/one");
let chartTwo = require("./router/two");
let chartTree = require("./router/three");
let chartFour = require("./router/four");

// 使用中间件来配置路由
app.use('/one',chartOne)
app.use('/two',chartTwo)
app.use('/three',chartTree)
app.use('/four',chartFour)


/*// 解决vite-demo中跨域问题
app.use('*',(req,res,next) =>{// 允许跨域
    res.header('Access-Control-Allow-Origin','*'); // '*‘可以指定IP
    next();
})*/

/*// 路由去分模块,避免所有路由都写在入口文件中
const router:Router = express.Router()

// 中间件注册,路由注册
app.use('/api',router)
// 路由请求:req接收前端,resp响应返给前端
router.get('/list', async (req:Request,res:Response)=>{
    const result = await axios.post('https://api.inews.qq.com/newsqa/v1/query/inner/publish/modules/list?modules=statisGradeCityDetail,diseaseh5Shelf')
    res.json({ // 响应返给前端
        ...result.data.data
    })
})*/

// 开启服务: 端口3333,接收回调
app.listen(3333,()=>{
    console.log('success server http://localhost:3333')
})

十.api接口数据创建

1.在server文件夹下创建mock文件夹用来容纳数据(数据可以从代码中获取)
 
2.引用并且把数据返回给前台
var express=require("express");
var router=express.Router()
// 引用数据
let data=require("../mock/one.json")
router.get("/data",function(req,res){
    // 数据返回给前台
    res.send({msg:"第1个接口",data})
})
module.exports=router

router/ One.js\two.js\three.js\four.js

// 路由:4个图表需要获取后台数据
// 定义引入express
let express = require("express")
// 定义路由
let router = express.Router()
// 引用json
let oneData = require('../Mock/one.json')

// 设置当前路由:get('路由名',回调函数(请求request,响应response)
router.get("/data",(req,res)=>{
    // 响应内容:返回oneData.json数据
    res.send({mag:"One的地址",chartOne:oneData})
})
// 暴露路由接口
module .exports=router // vue3.0
// export default router  // vue3.2

10-1.解决跨域

var express=require("express");
var app=express();
app.use(function(req,res,next){
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Headers', 'Content-Type,Content-Length,
  Authorization, Accept, X-Requested-With , yourHeaderFeild');
  res.header('Access-Control-Allow-Methods', 'PUT, POST, GET,
  DELETE,OPTIONS');
  // 千万不要网%%¥¥¥###
  // 千万不要网
  // 千万不要网
  next();
})

Vue3.2中完整代码写法

node/index.ts

// 合并4个图表路由
// import {Express, Request, Response, Router} from "express"; // {类型}

//引用express
let express=require("express") // vue3.0
// import express,{Express} from "express"; // vue3.2
// axios
import axios from "axios";

// 接口函数: 前端交互
let app = express();

// 引用路由文件
let chartOne = require("./router/one");
let chartTwo = require("./router/two");
let chartThree = require("./router/three");
let chartFour = require("./router/four");

// 使用中间件来配置路由
app.use('/one',chartOne)
app.use('/two',chartTwo)
app.use('/three',chartThree)
app.use('/four',chartFour)


// 解决vite-demo中跨域问题
app.use('*',(req:any,res:any,next:any) =>{// 允许跨域
    res.header('Access-Control-Allow-Origin','*'); // '*‘可以指定IP
    res.header('Access-Control-Allow-Headers', 'Content-Type,Content-Length,Authorization, Accept, X-Requested-With , yourHeaderFeild');
    res.header('Access-Control-Allow-Methods', 'PUT, POST, GET,DELETE,OPTIONS');
    next();
})

/*// 路由去分模块,避免所有路由都写在入口文件中
const router:Router = express.Router()

// 中间件注册,路由注册
app.use('/api',router)
// 路由请求:req接收前端,resp响应返给前端
router.get('/list', async (req:Request,res:Response)=>{
    const result = await axios.post('https://api.inews.qq.com/newsqa/v1/query/inner/publish/modules/list?modules=statisGradeCityDetail,diseaseh5Shelf')
    res.json({ // 响应返给前端
        ...result.data.data
    })
})*/

// 开启服务: 端口3333,接收回调
app.listen(3333,()=>{
    console.log('success server http://localhost:3333')
})

11.图表1基本设置销售总量

1.在components文件夹下的 itemOne.vue中 设置图表1:注意 跨域问题
<template>
    <div ref="chart">
        <h2>图表1</h2>
        <div >
            图表的容器
        </div>
    </div>
</template>

<script setup>
// 引用echarts核心模块
import * as echarts from 'echarts'
import {onMounted, ref} from "vue";
import axios from "axios";

const chart =ref(); // 创建DOM引用

// 函数:异步
async function getState(){ // 对应node服务器中端口:get请求
    // 需要后端解决跨域问题:node/index.ts中可以理解为:/api等于https://127.0.0.1:3333
    const oneData = await axios({url:"/api/one/data"})
    console.log(oneData)
}

onMounted(()=>{
    // 调用函数请求
    getState();

    // 基于准备好的dom,初始化echarts实例
    // var myChart = echarts.init(document.getElementById('main'));
    // Vue3中: 需要引入
    var myChart = echarts.init(chart.value)

    // 使用刚指定的配置项和数据显示图表。
    // 第三种写法: 钩子内
    myChart.setOption({
        xAxis: {
            type: "value",
        },
        yAxis: {
            type: "category"
        },
        series: [
            {
                type:"bar",
            }
        ]
    });

    // 单图表响应式: 跟随浏览器大小改变
    window.addEventListener("resize",()=>{
        myChart.resize()
    })
})

</script>

<style scoped>

</style>

解决跨域问题点

vite.config.ts中

 

 express服务器端node/index.ts中

// 解决vite-demo中跨域问题
app.use('*', function(req:any, res:any, next:any) {
    res.header("Access-Control-Allow-Origin", "*");
    /*res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
    res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
    res.header("X-Powered-By",' 3.2.1')
    res.header("Content-Type", "application/json;charset=utf-8");*/
    next();
}); 

express node/index.ts解决跨域

 

下面是vite的代理

server: {
    proxy: {
      '/api': {
        target: 'https://baidu.com',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
 },

 

配置后/api就是代理了target配置的地址( http://127.0.0.1:3333)后端服务器IP和端口

可以理解为: /api 等于https://127.0.0.1:3333

所以不需要配置axios的baseUrl了,切记。

2.验证接口

  axios.get("/api/one/data").then(res => {
    console.log("one====>",res);
  });
// const mapData = await fetch(`/api/post/1`).then(r => r.json())
// 根据接口文档:实际参数获取数据
const mapData = await axios.get('/api/one/data').then(res => res.data.chartData)

此时,get请求路径不在是https://localhost:5173而是/api/one/data

到此就可以跨域了。

验证:

 

 

 

 

11.图表1基本设置销售总量

1.在components文件夹下的 itemOne.vue中 设置图表1 
<template>
    <div >
        <div ref="chart" class="oneChart">
            图表的容器
        </div>
    </div>
</template>

<script setup>
// 引用echarts核心模块
import * as echarts from 'echarts'
import {onMounted, reactive, ref} from "vue";
import axios from "axios";

// var chartDom = document.getElementsById('main') // vue3创建Dom
const chart =ref(); // Vue3.2创建DOM引用

let oneData = reactive({});
let xData = reactive([]);
let yData = reactive([]);

// 2.处理异步请求过来的数据
function setData(){// 将oneData请求来的数据处理:数组对象
    // 将数组map()获取title赋值给xData
    xData = oneData.data.chartOne.chartData.map(v => v.title);
    yData = oneData.data.chartOne.chartData.map(v => v.num);
    console.log("xData",xData)
    console.log('yData',yData)
}

// 1.函数:异步请求
async function getState(){ // 对应node服务器中端口:get请求
    // 需要后端解决跨域问题:node/index.ts中可以理解为:/api等于https://127.0.0.1:3333
    oneData = await axios({url:"/api/one/data"})
    // console.log(oneData.data.chartOne.chartData)
}

onMounted(()=>{
    // 基于准备好的dom,初始化echarts实例
    // var myChart = echarts.init(document.getElementById('main'));
    // Vue3中: 需要引入
    var myChart = echarts.init(chart.value)

    // 调用函数请求
    // getState();
    //3.使用then(()=>{})回调函数进行数据处理
    getState().then(()=>{
        setData()

        // 使用刚指定的配置项和数据显示图表。
        // 第三种写法: 钩子内
        myChart.setOption({
            title: { // 标题
                text: '地区销售',
                textStyle: {
                    color: '#fff',
                    fontSize: 18,
                },
          top: 20px, // 上边距 left:
'center', // 标题居中 }, tooltip:{ trigger: 'axis', axisPointer: { type:'shadow' } }, legend: {// 图例 data: ['销量'], top: '5%', left: 'right', textStyle: { // 文字样式 color: '#f68', } }, // 调整图标:位置 grid: { // 上下左右 // top: '3%', left: '3%', // right: '6%', bottom:'15%', containLabel: true, // 包含坐标轴文字 }, xAxis: { type: "value", // boundaryGap: [0,0.01], axisLine:{// x轴线的颜色以及宽度 lineStyle: { color: '#fff', /*width: 0, type: 'solid',*/ } }, axisLabel: { // x轴文字的配置 show:true, textStyle: { color: '#fff', }, /*splitLine: { // 分割线配置 show:false, lineStyle: { color: '#fff', }, }*/ } }, yAxis: { type: "category", data: xData, inverse: true, // Y 轴从下往上是从小到大的排列 axisLine:{// x轴线的颜色以及宽度 lineStyle: { color: '#fff' } } }, series: [ { name: '地区', type:"bar", data: yData, realtimeSort: true, // 动态排序 itemStyle: { // 样式 normal: { // 数据圆角:[左上,右上,右下,左下] BorderRadius: [0,20,20,0], // 修改线性渐变色方式 :(0,0,0,0,[{数组对象:每个阶段相关颜色}]) color: new echarts.graphic.LinearGradient(0,0,1,0,[ { // 0 起始颜色 offset: 0, color: '#005eaa', }, { // 0.5 中间颜色 offset: 0.5, color: '#339ca8', }, { // 1 结束颜色 offset: 1, color: '#cda819' } ]) } } } ] }); }) // 单图表响应式: 跟随浏览器大小改变 window.addEventListener("resize",()=>{ myChart.resize() }) }) </script> <style scoped> .oneChart{ height: 360px; } </style>

问题:出现图表无法自适应

itemPage.vue中

 

14.图表2 地图展示

地图数据来自阿里dataV可视化平台:DataV.GeoAtlas地理小工具系列 (aliyun.com)

 
由于数据实在我们本地 所以 我们在启动项目的时候可以直接在浏览器上输入
http://localhost:5173/assets/china1.json即可看到数据
我们在components文件夹下创建一个mapPage.vue组件用来容纳地图。同时在views下的
homePage.vue中引用调用并且在页面中间的div中使用  
<template>
    <!--上部:标题-->
    <el-row class="top">
        <el-col :span="24" >
            <div class="grid-content ep-bg-purple-dark" >
                <h1>豫教云网卫士--大数据座舱</h1>
            </div>
        </el-col>
    </el-row>
    <!--下部:左中右,justify 属性来定义子元素的排版方式,其取值为start、center、end、space-between、space-around或space-evenly。-->
    <el-row class="row-bg" justify="space-evenly">
        <el-col :span="6" class="itemLeft">
            <div class="grid-content ep-bg-purple" >
                <ItemPage>
                    <ItemOne>

                    </ItemOne>
                </ItemPage>
                <ItemPage>
                    <ItemTwo>

                    </ItemTwo>
                </ItemPage>
            </div>
        </el-col>
        <el-col :span="12" class="itemCenter">
            <!-- 为 ECharts 准备一个定义了宽高的 DOM -->
            <!--vue3.2中 id=‘’ 变更 ref=-->
            <div class="grid-content ep-bg-purple-light" ref="chart" style="width:100%;height:100%;">
                <!--<h2>地图展示</h2>-->
                <MapPage/>
            </div>
        </el-col>
        <el-col :span="6">
            <div class="grid-content ep-bg-purple" >
                <ItemPage>
                    <ItemTree>

                    </ItemTree>
                </ItemPage>
                <ItemPage>
                    <ItemFour>

                    </ItemFour>
                </ItemPage>
            </div>
        </el-col>
    </el-row>
</template>

<script setup >
// 引入组件
import ItemPage from "../components/itemPage.vue"
import ItemOne from "../components/itemOne.vue"
import ItemTwo from "../components/itemTwo.vue"
import ItemTree from "../components/itemThree.vue"
import ItemFour from "../components/itemFour.vue"
import MapPage from "../components/mapPage.vue"

</script>

<style lang="scss">
.el-row {
  margin-bottom: 20px;
}
.el-row:last-child {
  margin-bottom: 0;
}
.el-col {
  border-radius: 4px; // 边框圆角°
  margin: 0 auto;
}

.grid-content {
  border-radius: 4px;
  min-height: 36px;
}

.top {
  height: 1rem; // 1rem=80px
  width: 100%;
  background-color: rgba(0,0,255,0.1); // 色度 0.2透明度
  // 标题的文字样式
  h1{
    font-size: 28px;
    color: #fff;
    text-align: center; // 居中方式
    line-height: 80px; // 1rem=80px
  }
}
// 大容器的样式
/*.container {
  // 最大最小的宽度
  !*min-width: 1200px;
  max-width: 2048px;*!
  !*margin: 0 auto; // 上容器边距
  padding: .125rem 0.125rem 0; // 上下右边距*!
  !*height: 500px;
  background-color: gray;*!
}*/
/*.itemCenter{
  border: 1px solid blue;
  border-radius: 4px;
}*/
</style>

mapPage.vue完整代码

<template>
    <!-- 为 ECharts 准备一个定义了宽高的 DOM -->
    <!--vue3.2中 id=‘’ 变更 ref=-->
    <div class="grid-content ep-bg-purple-light" ref="chart" style="width:100%;height:100%;">

    </div>
</template>

<script setup>
import {ref,reactive,onMounted} from 'vue'

// 引入echarts核心模块
import * as echarts from 'echarts'
// 还需引入本地地图文件
import chinaMap from '../assets/china1.json'
// 引入动态数据axios,二次封装
// import axios from 'axios'

const chart =ref(); // 创建DOM引用

// 第二种方法:初始化方法
const option = reactive({// 指定图表的配置项和数据
    tooltip: { // 提示框组件
        trigger: "item",
    },
    title: {
        text: '城市销量',
        left: 'center', // 距离位置
        textStyle: { // 文字设置
            color: "#fff",
            fontSize:20,
            textShadowBlur: 20, // 阴影
            textShadowColor:"#33ffff", //阴影颜色
        }
    },
    geo: { // 地理坐标系
        tooltip: {
            show: true
        },
        map: 'china', // 地图类型
        itemStyle: { // 修改地图区域标签样式
            areaColor: '#219edb', // 区域颜色
            borderColor: '#00ffff', // 区域边框颜色
            shadowColor: 'rgba(230,130,70,0.5)', // 阴影颜色
            shadowBlur: 30, // 阴影模糊度
        },
        label: { // 标签:地图中的标签、文字
            show: true, // 开启地图中的标签、文字等,(必须开启)
            color: '#fff',
            fontSize: 11,
        },
        emphasis: { // 地图高亮状态的多边形和标签样式
            // focus:'self', // 当前高亮,其他淡出
            label: {
                color: '#000',
                fontSize: 12,
            },
            itemStyle: {
                areaColor: '#f60',
                borderColor: '#329edb'
            },
        },
        roam: true, // 地图可拖拽、平移

    },
    visualMap: { // 视觉映射效果:热度点、热度柱
        type: 'continuous', // 必要设置:连续类型
        min: 100,  // 必要设置:最小
        max: 10000, // 必要设置:最大
        text: ['High', 'Low'],
        realtime: false,
        calculable: true, // 滑动效果
        inRange: { // 热度过渡:颜色设置
            color: ['lightskyblue', 'yellow', 'orangered']
        },
        textStyle: {
            color: '#fff'
        },
    },
    series: [{ // 系列:地图不需XY轴
        type: 'effectScatter', // 图表类型:散点图scatter:用到坐标系设置
        coordinateSystem: 'geo',
        geoIndex: 0,
        symbolSize:function (params){ // 气泡点特效
            return (params[2] / 1000) * 1 + 5; // 1000越大越小,+5越大越大
        },
        itemStyle: {
            color:"#b02a02",
        },
        encode: {
            tooltip: 2,
        },
        data: [
            // 展示数据项的名字,经纬度,数据量
            {name: '北京', value: [116.46,39.92,4367]},
            {name: '上海', value: [121.48,31.22,8675]},
            {name: '深圳', value: [114.07,22.62,2461]},
            {name: '广州', value: [113.23,23.16,187]},
            {name: '西安', value: [108.45,34,375]},
        ],
        /*[ // 展示数据项的名字,经纬度,数据量
            {name:'河南省',value:[32300,4000]},
            {name: '山东省',value: 21203},
            {name: '四川省',value: 41203},
            {name: '青海省',value: 31203},
        ],*/

    },
    ]
    /*coordinateSystem: "geo", // 当前坐标系设置:经纬度定位
    symbolSize: 30, // 大小*/

})

// 使用生命钩子
onMounted(() => {
    // 基于准备好的dom,初始化echarts实例
    // var myChart = echarts.init(document.getElementById('main'));
    // Vue3中: 需要引入
    var myChart = echarts.init(chart.value)

    // 注册可用的地图
    echarts.registerMap('china',chinaMap);


    // 使用刚指定的配置项和数据显示图表。
    myChart.setOption(option);

    // 单图表响应式: 跟随浏览器大小改变
    window.addEventListener('resize',()=>{
        myChart.resize()
    })
})


</script>

<style scoped>

</style> 

15.图表3 产品统计分析图

获取数据:Vue3.2优化
vite.config.ts中
 
对应后端express-node/router/three.js
前端在components下的itemThree.vue

 

 

 完整代码:

<template>
    <div>
        <!--<h2>图表3</h2>-->
        <div ref="chart" style="height: 340px;">

        </div>
    </div>
</template>

<script setup>
import {onMounted, reactive, ref} from "vue"
import * as echarts from 'echarts'
import axios from "axios";

let chart = ref();// 创建Mod引用

let threeData = reactive({})

// 优化Vue3.2
// 使用顶级await:父组件必须使用<suspense>包裹组件
async function getState(){
    threeData = await axios.get("/api/three/data")
}

onMounted(()=>{
    // 调用函数请求
    // getState();
    //3.使用then(()=>{})回调函数进行数据处理
    getState().then(()=>{
        console.log("饼状图",threeData)

        // 基于加载完后的DOM,初始化echarts实例
        // var myChart = echarts.init(document.getElementById('main'));
        // Vue3中: 需要引入
        var myChart = echarts.init(chart.value)

        // 使用刚指定的配置项和数据显示图表。
        myChart.setOption({
            title: { // 标题
                text: '统计分析',
                textStyle: {
                    color: '#fff',
                    fontSize: 18,
                },
                top: '20px',
                left: 'center', // 标题居中
            },
            legend: { // 设置图例
                top: 'bottom', // 放到最下面
                width: '60%', // 自适应
                height: 'auto',
                textStyle: {
                    color: "#fff"
                }
            },
            tooltip:{
                show:true, //显示
            },
            // 调整图标:位置
            grid: { // 上下左右
                // top: '3%',
                // left: '3%',
                // right: '6%',
                bottom:'15%',
                containLabel: true, // 包含坐标轴文字
            },
            series: [
                {
                    type: 'pie', // 饼图
                    data: threeData.data.chartThree.chartData,
                    radius: [10,90], // 饼图的半径数组的第一项是内半径,第二项是外半径
                    center: 'center', // 饼图的中心(圆心)坐标,数组的第一项是横坐标,第二项是纵坐标。
                    roseType: "area", // 玫瑰类型
                    itemStyle: {
                        borderRadius: 10 // 圆角:用于指定饼图扇形区域块的内外圆角半径
                    },
                },
            ],
        });
        // 单图表响应式: 跟随浏览器大小改变
        window.addEventListener("resize",()=>{
            myChart.resize()
        })
    })

})

</script>

<style scoped>

</style> 

16.图表4 产品月销图

数据获取
在components文件夹下的itemTwo.vue中进行设置
<template>
    <div>
        <!--<h2>图表2</h2>-->
        <div ref="chart" style="height: 340px">

        </div>
    </div>
</template>

<script setup>
import {onMounted, reactive, ref} from 'vue'
import axios from "axios";
import * as echarts from "echarts";

let chart = ref(); // 创建Mod容器

let twoData = reactive({})

async function getState(){
    twoData = await axios.get("/api/two/data")

}

onMounted(()=>{
    getState().then(()=>{
        console.log("查看折线图数据",twoData.data.chartTwo.chartData)

        // 基于加载完后的DOM,初始化echarts实例
        // var myChart = echarts.init(document.getElementById('main'));
        // Vue3中: 需要引入
        var myChart = echarts.init(chart.value)

        // 使用刚指定的配置项和数据显示图表。
        myChart.setOption({
            title: { // 标题
                text: '地区销售',
                textStyle: {
                    color: '#fff',
                    fontSize: 18,
                },
                top: '20px',
                left: 'center', // 标题居中
            },
            tooltip:{ // 提示框组件
                trigger: 'axis', // 触发类型:坐标轴类型触发
                axisPointer: { // 坐标轴指示器配置项
                    type:'cross',// 指示器类型:十字准星式,如类型:shadow
                    label: { // 坐标轴指示器的文本标签样式:提示文本
                        backgroundColor: "#e6b600", // 文本标签的背景颜色就是XY轴上的内容
                    }
                },
            },
            legend:{// 图例组件:展现了不同系列的标记(symbol),颜色和名字。可以通过点击图例控制哪些系列不显示。
                data: ["郑州","新乡","安阳","商丘","洛阳"],
                top: "15%", // 距离容器上侧的距离
                textStyle:{ // 文字样式
                    color: "#fff"
                },
            },
            /*toolbox: { // 下载
                feature: {
                    saveAsImage: {

                    },
                },
            },*/
            grid: {// 组件离容器的距离
                top: "30%",
                left: "1%",
                right:"6%",
                bottom:"5%",
                containLabel: true, // grid区域是否包含坐标轴的刻度标签
            },
            xAxis: {
                axisLine: {
                    lineStyle: {
                        color: "#fff",
                    }
                },
                type: "category", // 类目轴:横向和竖向
                boundaryGap:false, // 间隙
                data: twoData.data.chartTwo.chartData.day, // 获取日期
            },
            yAxis: {
                type: "value", // 数值轴
                axisLine: {
                    lineStyle: {
                        color: "#fff",
                    }
                },
            },
            series: [
                {
                    name:"郑州",
                    type: "line", // 线性
                    data: twoData.data.chartTwo.chartData.num.Chemicals,
                    smooth: true, // 折线图平滑效果,变成曲线图
                    showSymbol:false, // 隐藏所有数据点
                    stack: "Total",//数据堆叠
                    lineStyle: { // 设置线段样式
                        width: 0,
                    },
                    emphasis: { //  设置高亮的图形样式和标签样式
                        focus: "series",// 只显示选中的内容高亮
                    },
                    areaStyle: { // 设置填充区域的样式
                        opacity: 0.8, // 透明度
                        color: new echarts.graphic.LinearGradient(0,0,0,1,[
                            {// 设置渐变:起始
                                offset: 0,
                                color: "rgb(128,255,165)",
                            },
                            /*{// 设置渐变:中间
                                offset: 0.5,
                                color: "rgb(1,191,236)",
                            },*/
                            {// 设置渐变:结束
                                offset: 1,
                                color: "rgb(1,191,236)",
                            },
                        ]),
                    },
                },
                {
                    name:"新乡",
                    type: "line", // 线性
                    data: twoData.data.chartTwo.chartData.num.Clothes,
                    smooth: true, // 折线图平滑效果,变成曲线图
                    showSymbol:false, // 隐藏所有数据点
                    stack: "Total",//数据堆叠
                    lineStyle: { // 设置线段样式
                        width: 0,
                    },
                    emphasis: { //  设置高亮的图形样式和标签样式
                        focus: "series",// 只显示选中的内容高亮
                    },
                    areaStyle: { // 设置填充区域的样式
                        opacity: 0.8, // 透明度
                        color: new echarts.graphic.LinearGradient(0,0,0,1,[
                            {// 设置渐变:起始
                                offset: 0,
                                color: "rgb(0,221,255)",
                            },
                            /*{// 设置渐变:中间
                                offset: 0.5,
                                color: "rgb(77,119,255)",
                            },*/
                            {// 设置渐变:结束
                                offset: 1,
                                color: "rgb(77,119,255)",
                            },
                        ]),
                    },
                },
                {
                    name:"安阳",
                    type: "line", // 线性
                    data: twoData.data.chartTwo.chartData.num.Electrical,
                    smooth: true, // 折线图平滑效果,变成曲线图
                    showSymbol:false, // 隐藏所有数据点
                    stack: "Total",//数据堆叠
                    lineStyle: { // 设置线段样式
                        width: 0,
                    },
                    emphasis: { //  设置高亮的图形样式和标签样式
                        focus: "series",// 只显示选中的内容高亮
                    },
                    areaStyle: { // 设置填充区域的样式
                        opacity: 0.8, // 透明度
                        color: new echarts.graphic.LinearGradient(0,0,0,1,[
                            {// 设置渐变:起始
                                offset: 0,
                                color: "rgb(55,162,255)",
                            },
                            /*{// 设置渐变:中间
                                offset: 0.5,
                                color: "rgb(1,191,236)",
                            },*/
                            {// 设置渐变:结束
                                offset: 1,
                                color: "rgb(116,21,219)",
                            },
                        ]),
                    },
                },
                {
                    name:"商丘",
                    type: "line", // 线性
                    data: twoData.data.chartTwo.chartData.num.digit,
                    smooth: true, // 折线图平滑效果,变成曲线图
                    showSymbol:false, // 隐藏所有数据点
                    stack: "Total",//数据堆叠
                    lineStyle: { // 设置线段样式
                        width: 0,
                    },
                    emphasis: { //  设置高亮的图形样式和标签样式
                        focus: "series",// 只显示选中的内容高亮
                    },
                    areaStyle: { // 设置填充区域的样式
                        opacity: 0.8, // 透明度
                        color: new echarts.graphic.LinearGradient(0,0,0,1,[
                            {// 设置渐变:起始
                                offset: 0,
                                color: "rgb(255,0,135)",
                            },
                            /*{// 设置渐变:中间
                                offset: 0.5,
                                color: "rgb(1,191,236)",
                            },*/
                            {// 设置渐变:结束
                                offset: 1,
                                color: "rgb(135,0,157)",
                            },
                        ]),
                    },
                },
                {
                    name:"洛阳",
                    type: "line", // 线性
                    data: twoData.data.chartTwo.chartData.num.gear,
                    smooth: true, // 折线图平滑效果,变成曲线图
                    showSymbol:false, // 隐藏所有数据点
                    stack: "Total",//数据堆叠
                    lineStyle: { // 设置线段样式
                        width: 0,
                    },
                    emphasis: { //  设置高亮的图形样式和标签样式
                        focus: "series",// 只显示选中的内容高亮
                    },
                    areaStyle: { // 设置填充区域的样式
                        opacity: 0.8, // 透明度
                        color: new echarts.graphic.LinearGradient(0,0,0,1,[
                            {// 设置渐变:起始
                                offset: 0,
                                color: "rgb(255,191,0)",
                            },
                            {// 设置渐变:中间
                                offset: 0.5,
                                color: "rgb(224,62,76)",
                            },
                            {// 设置渐变:结束
                                offset: 1,
                                color: "rgb(1,191,236)",
                            },
                        ]),
                    },
                },
            ],
        });
        // 单图表响应式: 跟随浏览器大小改变
        window.addEventListener("resize",()=>{
            myChart.resize()
        })
    })
})
</script>

<style scoped>

</style> 

17.图表5统计图

 components中的itemFour.vue完整代码

<template>
    <div>
        <!--<h2>图表4</h2>-->
        <div ref="chart" style="height: 340px">
            图表的容器
        </div>
    </div>
</template>

<script setup>
import {onMounted, reactive, ref} from "vue"
import * as echarts from "echarts"
import axios from "axios";

let chart = ref();// 创建MOD

let fourData = reactive({}); // let作用域内,const定义常量

async function getState(){
    fourData = await axios.get("/api/four/data")
}

onMounted(()=>{
    // 调用函数请求
    // getState();
    //3.使用then(()=>{})回调函数进行数据处理
    getState().then(()=>{
        console.log("查看柱状图数据",fourData.data.chartFour.chartData)

        // 基于准备好的dom,初始化echarts实例
        // var myChart = echarts.init(document.getElementById('main'));
        // Vue3中: 需要引入
        var myChart = echarts.init(chart.value)

        // 使用刚指定的配置项和数据显示图表。
        // 第三种写法: 钩子内
        myChart.setOption({
            title: { // 标题
                text: '周回款统计',
                textStyle: {
                    color: '#fff',
                    fontSize: 18,
                },
                top: '20px',
                left: 'center', // 标题居中
            },
            tooltip: { // 提示框组件
                trigger: "axis", // 触发类型
                axisPinter:{ // 坐标轴指示器配置项
                    type: "shadow",
                }
            },
            legend: {
                top: "15%", // 距离容器上侧的距离
                textStyle:{ // 文字样式
                    color: "#fff"
                },
            },
            grid: {// 组件离容器的距离
                top: "30%",
                left: "1%",
                right:"6%",
                bottom:"5%",
                containLabel: true, // grid区域是否包含坐标轴的刻度标签
            },
            xAxis:{
                type:"category", // 类目轴
                // boundaryGap:false, // X轴上ABC间隙
                data: fourData.data.chartFour.chartData.day,
                axisLine:{
                    lineStyle: {
                        color: "#fff",
                    }
                },
            },
            yAxis: {
                type: "value", // 数值轴
                axisLine:{
                    lineStyle: {
                        color: "#fff",
                    }
                },
            },
            series: [

                {
                    name: "卫滨",
                    type: "bar",
                    data: fourData.data.chartFour.chartData.num.WeiBin,
                    stack: "total",// 数据堆叠
                    // barWidth: "50%",
                    label: { // 文本标签
                        show: true, // 开启:文本显示,总计合计
                        // position: 'top', // 标签位置
                    },
                    emphasis: { //  设置高亮的图形样式和标签样式
                        focus: "series", // 只显示选中的内容高亮
                    }
                },
                {
                    name: "红旗",
                    type: "bar",
                    data: fourData.data.chartFour.chartData.num.HongQi,
                    stack: "total",// 数据堆叠
                    label: { // 文本标签
                        show: true, // 开启:文本显示,总计合计
                        // position: 'top', // 标签位置
                    },
                    emphasis: { //  设置高亮的图形样式和标签样式
                        focus: "series", // 只显示选中的内容高亮
                    }
                },
                {
                    name: "牧野",
                    type: "bar",
                    data: fourData.data.chartFour.chartData.num.MuYe,
                    stack: "total",// 数据堆叠
                    label: { // 文本标签
                        show: true, // 开启:文本显示,总计合计
                        // position: 'top', // 标签位置
                    },
                    emphasis: { //  设置高亮的图形样式和标签样式
                        focus: "series", // 只显示选中的内容高亮
                    }
                },
                {
                    name: "凤泉",
                    type: "bar",
                    data: fourData.data.chartFour.chartData.num.FengQuan,
                    stack: "total",// 数据堆叠
                    label: { // 文本标签
                        show: true, // 开启:文本显示,总计合计
                        // position: 'top', // 标签位置
                    },
                    emphasis: { //  设置高亮的图形样式和标签样式
                        focus: "series", // 只显示选中的内容高亮
                    }
                },
                {
                    name: "辉县",
                    type: "bar",
                    data: fourData.data.chartFour.chartData.num.HuiXian,
                    stack: "total",// 数据堆叠
                    label: { // 文本标签
                        show: true, // 开启:文本显示,总计合计
                        // position: 'top', // 标签位置
                    },
                    emphasis: { //  设置高亮的图形样式和标签样式
                        focus: "series", // 只显示选中的内容高亮
                    }
                },
            ],
        });
        // 单图表响应式: 跟随浏览器大小改变
        window.addEventListener("resize",()=>{
            myChart.resize()
        })
    })
})


</script>

<style scoped>

</style>

完成图例

 17.项目打包

 由于使用Vue/cli脚手架,浏览器解析后缀.vue文件无法识别

但是 我们所写的项目今后是需要上公网让用户访问的 所以我们需要把项目放在性能更好的服务器上运行
还有就是 我们所写的是.vue文件 浏览器不认识 没有办法直接解析
所以我们就绪要对当前项目 进行打包 就是把项目编译成 html css js 方便我们把项目放到服务器上也方
便浏览器解析
打包流程
查看package.json中的命令
1.npm run build命令打包 但是会发现打包之后资源路径有问题
npm run build
成功后出现dist文件夹

 

2.修改静态资源路径 publicPath 

 静态资源路径出现问题:需新建项目中src/vue.config.js文件

module.exports = {
    lintOnSave:false, // 关闭检查
     // 配置静态资源路径 : process判断当前环境
    publicPath: process.env.NODE_ENV = "production" ? "./"  : "/"
}

node中全局变量process表示当前进程.env表示当前环境信息.NODE_ENV自定义变量 = 三元判断 是生产模式还是开发模式。

重新项目打包: npm run build

发现页面中内容为空问题

1、打开路由文件夹 router/index.ts 

 

3.修改路由模式为hash 

修改为hash模式

// 1.需要引入
import { createRouter, createWebHistory, createWebHashHistory } from 'vuerouter'
// 2.修改配置
const router = createRouter({
history: createWebHashHistory(process.env.BASE_URL),
routes
}) 

再次npm run build打包

地图配置与打包

将地图数据放入后台接口中

在项目后端express中router文件夹下新建:map.js放置地图内容

1.需要要将前端assets中的China1.json.拷贝到后端Mock数据文件夹中

 2.编写map.js

// 定义引入express// 定义引入express
let express = require("express");
// 定义路由
let router = express.Router();
// 引入data.json
let mapData = require("../Mock/china1.json");

// 设置当前路由:get('路由名',回调函数(请求request,响应response)
router.get("/data",(req,res)=>{
    // 响应内容
    res.send({msg:"我是地图的路由地址",chinaData:mapData})
})

module.exports = router;
// export default router;

3.引用路由文件map.js,注册路由

 修改前端请求:

components/mapPage.vue中

 注意:/api/map/data  = "http://localhost:3333/map/data, 可以查看Vite.config.ts中设置

页面不显示 地图数据

mapPage.vue完整代码:

<template>
    <!-- 为 ECharts 准备一个定义了宽高的 DOM -->
    <!--vue3.2中 id=‘’ 变更 ref=-->
    <div class="grid-content ep-bg-purple-light" ref="chart" style="width:100%;height:100%;">

    </div>
</template>

<script setup>
import {ref,reactive,onMounted} from 'vue'

// 引入echarts核心模块
import * as echarts from 'echarts'
// 还需引入本地地图文件
// import chinaMap from '../assets/china1.json'
// 引入动态数据axios,二次封装
import axios from 'axios'

let chart =ref(); // 创建DOM引用

let mapData = reactive({});

async function getState(){
    mapData = await axios.get("/api/map/data")
}

// 使用生命钩子
onMounted(() => {
    getState().then(()=>{
        console.log("map",mapData)
        // 基于准备好的dom,初始化echarts实例
        // var myChart = echarts.init(document.getElementById('main'));
        // Vue3中: 需要引入
        var myChart = echarts.init(chart.value)

        // 注册可用的地图
        echarts.registerMap('china',mapData.data.chinaData);


        // 使用刚指定的配置项和数据显示图表。
        myChart.setOption({
            tooltip: { // 提示框组件
                trigger: "item",
            },
            title: {
                text: '国内城市',
                left: 'center', // 距离位置
                textStyle: { // 文字设置
                    color: "#fff",
                    fontSize:20,
                    textShadowBlur: 20, // 阴影
                    textShadowColor:"#33ffff", //阴影颜色
                }
            },
            geo: { // 地理坐标系
                tooltip: {
                    show: true
                },
                map: 'china', // 地图类型
                itemStyle: { // 修改地图区域标签样式
                    areaColor: '#219edb', // 区域颜色
                    borderColor: '#00ffff', // 区域边框颜色
                    shadowColor: 'rgba(230,130,70,0.5)', // 阴影颜色
                    shadowBlur: 30, // 阴影模糊度
                },
                label: { // 标签:地图中的标签、文字
                    show: true, // 开启地图中的标签、文字等,(必须开启)
                    color: '#fff',
                    fontSize: 11,
                },
                emphasis: { // 地图高亮状态的多边形和标签样式
                    focus:'self', // 当前高亮,其他淡出
                    label: {
                        color: '#000',
                        fontSize: 12,
                    },
                    itemStyle: {
                        areaColor: '#f60',
                        borderColor: '#329edb',
                    },
                },
                roam: true, // 地图可拖拽、平移

            },
            visualMap: { // 视觉映射效果:热度点、热度柱
                type: 'continuous', // 必要设置:连续类型
                min: 100,  // 必要设置:最小
                max: 10000, // 必要设置:最大
                text: ['High', 'Low'],
                realtime: false,
                calculable: true, // 滑动效果
                inRange: { // 热度过渡:颜色设置
                    color: ['lightskyblue', 'yellow', 'orangered']
                },
                textStyle: {
                    color: '#fff'
                },
            },

            series: [{ // 系列:地图不需XY轴
                type: 'effectScatter', // 图表类型:散点图scatter:用到坐标系设置
                /*coordinateSystem: "geo", // 当前坐标系设置:经纬度定位
              symbolSize: 30, // 大小*/
                coordinateSystem: 'geo', // 当前坐标系设置:经纬度定位
                geoIndex: 0,
                symbolSize:function (params){ // 气泡点特效
                    return (params[2] / 1000) * 1 + 5; // 1000越大越小,+5越大越大
                },
                itemStyle: {
                    color:"#b02a02",
                },
                encode: {
                    tooltip: 2,
                },
                data: [
                    // 展示数据项的名字,经纬度,数据量,热力量
                    {name: '北京', value: [116.46,39.92,4367]},
                    {name: '上海', value: [121.48,31.22,8675]},
                    {name: '深圳', value: [114.07,22.62,2461]},
                    {name: '广州', value: [113.23,23.16,187]},
                    {name: '西安', value: [108.45,34,375]},
                ],
                /*[ // 展示数据项的名字,经纬度,数据量
                    {name:'河南省',value:[32300,4000]},
                    {name: '山东省',value: 21203},
                    {name: '四川省',value: 41203},
                    {name: '青海省',value: 31203},
              ],*/

            },
            ],

        });
        // 单图表响应式: 跟随浏览器大小改变
        window.addEventListener('resize',()=>{
            myChart.resize()
        })
    })
})


</script>

<style scoped>

</style>

检查无误后:npm run build 打包项目

此处提醒:项目是vite还是vue/cli,打包有区别

 打包报错问题:

 语法检查问题: 要么<scripts steup lang="ts">,要么vite.config.ts中删除下面

 

 再次检查和新建vue.config.js文件

 运行测试:

npm run preview

 

配置vite打包入口

 

 vite的配置都在根目录下面的vite.config.ts里面,在没有对其进行打包配置时,默认的打包的入口就是根目录的【index.html】。这时候我们直接运行 npm run build就会打包相应的文件:

 

 (ps:为什么默认是.html文件那?因为vue是单页面应用也就是最后打包的html只有一个。vite也提供多入口,但我不再本文继续描述了)

但是如果我们的目录结构改变了 ,比如:

 在此时打包就会报错:

原因就是默认的打包入口 根目录的index.html删除了。这时候就需要对vite.config.ts进行配置了:

  

 build.rollupOptions.input即为打包的指定入口。

关于项目vite打包之后直接进入dist文件夹访问index.html时出现空白的问题,网上查找了很多也没有查找到相关资料解决,但是如果你用FTP上传到服务器上是可以正常访问的,所以也就没有管了。如果是用vue-cli创建的vue3项目,打包之后是可以正常访问的。

10月重点更新了rollupOptions分包配置,混淆器设置为minify: "terser"。但运行build时,打包速度很慢,要打包十几分钟才能打包好,不知道有设置过分包的朋友遇到过没

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path";
 
// 8月更新-自动导入ElementPlus组件,除了图标需要单独引用外,其他的都可以直接在页面上使用组件,会自动导入
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
 
const isProduction = process.env.NODE_ENV === "production"
 
export default defineConfig({
  base: "./", // 类似publicPath,'./'避免打包访问后空白页面,要加上,不然线上也访问不了
  // 8月更新
  productionSourceMap: !isProduction, //关闭生产环境下的SourceMap映射文件
 
  // 8月更新-自动导入ElementPlus
  // 需安装 npm install -D unplugin-vue-components unplugin-auto-import
  plugins: [
      vue(),
      AutoImport({
          resolvers: [ElementPlusResolver()],
      }),
      Components({
          resolvers: [ElementPlusResolver()],
      }),
  ],
  resolve: {
    alias: {
      // 如果报错__dirname找不到,需要安装node,执行npm install @types/node --save-dev
      "@": path.resolve(__dirname, "src"),
      "@assets": path.resolve(__dirname, "src/assets"),
      "@components": path.resolve(__dirname, "src/components"),
      "@images": path.resolve(__dirname, "src/assets/images"),
      "@views": path.resolve(__dirname, "src/views"),
      "@store": path.resolve(__dirname, "src/store"),
    },
  },
  // 8月更新,全局引入less
  css: {
        sourceMap: !isProduction, // css sourceMap 配置
        preprocessorOptions: {
            less: {
                modifyVars: {
                    hack: `true; @import (reference) "${path.resolve("src/assets/css/base.less")}";`,
                },
                javascriptEnabled: true,
            },
        },
    },
  build: {
    outDir: "dist",
    // 9月更新
    assetsDir: "assets", //指定静态资源存放路径
    sourcemap: false, //是否构建source map 文件
    // 10月更新
    minify: "terser", // 混淆器,terser 构建后文件体积更小,'terser' | 'esbuild'
    chunkSizeWarningLimit: 1500, //chunk 大小警告的限制,默认500KB
    rollupOptions: {
          output: {
              // 最小化拆分包
              manualChunks(id) {
                  if (id.includes('node_modules')) {
                      return id.toString().split('node_modules/')[1].split('/')[0].toString();
                  }
             },
             chunkFileNames: 'js/[name].[hash].js', // 用于命名代码拆分时创建的共享块的输出命名,[name]表示文件名,[hash]表示该文件内容hash值
         }
    },
    terserOptions: {
      // 生产环境移除console
      compress: {
        drop_console: true,
        drop_debugger: true,
      },
      // 10月更新
      output: {
         comments: true, // 去掉注释内容
      },
    },
  },
  server: {
    https: false, // 是否开启 https
    open: false, // 是否自动在浏览器打开
    cors: true, // 允许跨域  8月更新
    port: 3000, // 端口号
    host: "0.0.0.0",
    proxy: {
      "/api": {
        target: "", // 后台接口
        changeOrigin: true,
        secure: false, // 如果是https接口,需要配置这个参数
        // ws: true, //websocket支持
        rewrite: (path) => path.replace(/^\/api/, ""),
      },
    },
  },
  // 引入第三方的配置
  optimizeDeps: {
    include: [],
  },
});

项目中Vite.config完整代码

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 8月更新-自动导入ElementPlus组件,除了图标需要单独引用外,其他的都可以直接在页面上使用组件,会自动导入
// import AutoImport from 'unplugin-auto-import/vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import path from 'path'

const isProduction = process.env.NODE_ENV === "production"

// https://vitejs.dev/config/
export default defineConfig({
  // 类似publicPath,'./'避免打包访问后空白页面,要加上,不然线上也访问不了
  base:'./',// 配置公共路径:默认base: '/',绝对路径,
  // @ts-ignore
  productionSourceMap: !isProduction, //关闭生产环境下的SourceMap映射文件
  plugins: [
      vue(),
      AutoImport({
        resolvers: [ElementPlusResolver()],
      }),
      Components({
        resolvers: [ElementPlusResolver()],
      }),
  ],
  // 跨域
  server: { // 增:服务器设置
    https: false, // 是否开启 https
    open: false, // 是否自动在浏览器打开
    cors: true, // 允许跨域  8月更新
    // port: 3000, // 端口号
    host: "0.0.0.0",
    proxy: { // 自定义代理规则
      '/api': {//代理标识,一般是每个接口前的相同部分
        // 可以理解为:/api等于https://127.0.0.1:3333
        target: 'http://localhost:3333',// 这里写的是访问后端IP接口的域名和端口号
        // secure: true,
        changeOrigin: true,// 允许跨域请求
        secure: false, // 如果是https接口,需要配置这个参数
        // 重写路径,替换请求地址中的指定路径
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  },
  // 引入第三方的配置
  /*optimizeDeps: {
    include: [],
  },*/
  resolve: {
    //配置根路径别名: import('@/pages/login/login.vue')
    alias: {
      // '@': fileURLToPath(new URL('./src', import.meta.url))
      "@": path.resolve(__dirname, "src"),
      // 配置图片要这样引用
      "/img": "./src/assets",
    }
  },
  build: { // 打包设置
    // Template for index.html 入口配置
    /*rollupOptions:{
      // 原因就是默认的打包入口 根目录的index.html删除了。这时候就需要对vite.config.ts进行配置了:
      input: 'src/pages/default/index.html'
    },*/
    // 混淆器,terser 构建后文件体积更小,'terser' | 'esbuild'
    minify: 'terser', // 必须启用:terserOptions配置才会有效
    chunkSizeWarningLimit: 1500, //chunk 大小警告的限制,默认500KB
    rollupOptions: {
      output: {
        // 最小化拆分包
        manualChunks(id) {
          if (id.includes('node_modules')) {
            return id.toString().split('node_modules/')[1].split('/')[0].toString();
          }
        },
        chunkFileNames: 'js/[name].[hash].js', // 用于命名代码拆分时创建的共享块的输出命名,[name]表示文件名,[hash]表示该文件内容hash值
      }
    },
    terserOptions: {
      compress: {
        // 生产环境时移除console.log调试代码
        drop_console:true,
        drop_debugger: true,
      },
      // 10月更新
      output: {
        comments: true, // 去掉注释内容
      },
    }
  },
  css: {
    preprocessorOptions: {
      less: {
        modifyVars: {
          hack: `true; @import (reference) "${path.resolve('src/assets/lessVar.less')}";`
        },
        javascriptEnabled: true
      }
    }
  }
})

18.服务器购买与连接 

在购买ECS服务器后,系统会创建一个ECS实例。每一个ECS实例对应一台已购买的云服务器。您可以通
过电脑上自带的终端工具访问云服务器,进行应用部署和环境搭建。
1. 在ECS实例列表页面,选择实例的所属地域。
2. 找到目标实例,然后在操作列选择【更多】> 【密码/密钥】 > 【重置实例密码】,然后在弹出的对
话框设置ECS实例的登录密码

 

3. 在弹出的页面,单击【立即重启】使新密码生效。

4. 在ECS实例列表页面,复制ECS实例的公网IP地址。
5. 连接远程桌面
(1)方式1 浏览器直接访问

 

 

 

 

 

 

即可连接

(2)远程桌面方式
在电脑的开始中搜索远程桌面

19.nginx服务器使用

Nginx是一个http服务器。是一个高性能的http服务器及反向代理服务器。官方测试nginx能够支支撑5万并发链接,并且cpu、内存等资源消耗却非常低,运行非常稳定。

代理服务器

代理服务器,客户机在发送请求时,不会直接发送给目的主机,而是先发送给代理服务器,代理服务接受客户机请求之后,再向主机发出,并接收目的主机返回的数据,存放在代理服务器的硬盘中,再发送给客户机。

注意

我们学习的vue的跨域 是基于脚手架内置服务器的 但是我们打包之后这个服务器就不帮助我们启动服务了 所以我们之前配置的跨域设置就作废了

使用

1.解压出nginx得到如下内容

  

将dist文件夹放入nginx根目录下

2.打开conf文件夹 复制一份nginx.conf文件 并且修改名字(名字随便起) 这个文件就是nginx的配置文件

修改新建的XXX.conf文件

 

3.打开Powershell cd到当前nginx路径下 输入 ./nginx.exe -c ./conf/你复制的文件名.conf 启动

 // XXX自定义的文件名
./nginx.exe -c ./conf/XXX.conf
4.打开浏览器输入localhost:80即可启动
 查看阿里云的公网IP
 
使用小扩展
记得如果修改服务器内容了 要停止之后在重新启动
打开Powershell cd到当前nginx路径下 输入 ./nginx.exe -c ./conf/你复制的文件名.conf -s stop 停止

20. 项目运行

1.把我们打包好的dist放到根路径下
2.修改我们的.conf文件
 
3.配置端口

 

 

 

 

 

 

4.在电脑浏览器尝试使用 你的公网ip加端口访问

如不行 重新启动(不要忘了先关闭nginx) 运行浏览器即可看见

21.后端上线

安装nodejs

后端目录中启动nodejs

// 启动nodejs
node index.js

 

如果前端设置了基准路径,修改公网IP

 

 

 

 重新打包,将打包内容放置服务器dist目录下

关闭和启动nginx

 

// 关闭nginx: demo自定义
./nginx.exe -c ./conf/demo.conf -s stop

// 开启nginx
./nginx.exe -c ./conf/demo.conf

测试:浏览器输入公网IP

https://www.bilibili.com/video/BV14u411D7qK?p=69&spm_id_from=pageDriver&vd_source=e2cfe74d93fb5b3f60bd7487ede60218

完结撒花!~~

posted @ 2023-01-13 10:27  爵岚  阅读(5549)  评论(0)    收藏  举报