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

完结撒花!~~

Vue3+vite+Echarts案例大屏可视化--千峰(推荐)的更多相关文章

  1. 基于 HTML5 的工业组态高炉炼铁 3D 大屏可视化

    前言 在大数据盛行的现在,大屏数据可视化也已经成为了一个热门的话题.大屏可视化可以运用在众多领域中,比如工业互联网.医疗.交通.工业控制等等.将各项重要指标数据以图表.各种图形等形式表现在一个页面上, ...

  2. 高速基于echarts的大数据可视化

    [Author]: kwu 高速基于echarts的大数据可视化,echarts纯粹的js实现的图表工具.高速开发的过程例如以下: 1.引入echarts的依赖js库 <script type= ...

  3. vue+echarts+datav大屏数据展示及实现中国地图省市县下钻

    随着前端技术的飞速发展,大数据时代的来临,我们在开发项目时越来越多的客户会要求我们做一个数据展示的大屏,可以直观的展示用户想要的数据,同时炫酷的界面也会深受客户的喜欢. 大屏展示其实就是一堆的图表能够 ...

  4. ECharts大屏可视化【词云,堆积柱状图,折线图,南丁格尔玫瑰图】

    一.简介 参考ECharts快速入门:https://www.cnblogs.com/yszd/p/11166048.html 二.代码实现 <!DOCTYPE html> <htm ...

  5. 【拖拽可视化大屏】全流程讲解用python的pyecharts库实现拖拽可视化大屏的背后原理,简单粗暴!

    "整篇文章较长,干货很多!建议收藏后,分章节阅读." 一.设计方案 整体设计方案思维导图: 整篇文章,也将按照这个结构来讲解. 若有重点关注部分,可点击章节目录直接跳转! 二.项目 ...

  6. 【实时数仓】Day06-数据可视化接口:接口介绍、Sugar大屏、成交金额、不同维度交易额(品牌、品类、商品spu)、分省的热力图 、新老顾客流量统计、字符云

    一.数据可视化接口介绍 1.设计思路 后把轻度聚合的结果保存到 ClickHouse 中后,提供即时的查询.统计.分析 展现形式:用于数据分析的BI工具[商业智能(Business Intellige ...

  7. flex布局构建大屏框架并支持翻页动画、滚动表格功能

      本文将利用flex属性构建大屏可视化界面.界面主要分标题栏.工具栏.数据可视化窗口.其中,翻页动画以及滚动表格功能分别分布在数据可视化界面两侧. 鼠标点击标题,可看到左侧窗口翻转动画: 整体布局效 ...

  8. vue+echarts可视化大屏,全国地图下钻,页面自适应

    之前写过一篇关于数据大屏及地图下钻的文章 https://www.cnblogs.com/weijiutao/p/13977011.html ,但是存在诸多问题,如地图边界线及行政区划老旧,无法自适应 ...

  9. echarts解决一些大屏图形配置方案汇总

    本文主要记录使用echarts解决各种大屏图形配置方案. 1.说在前面 去年经常使用echarts解决一些可视化大屏项目,一直想记录下使用经验,便于日后快速实现.正好最近在整理文档,顺道一起记录在博客 ...

  10. 使用DataV制作实时销售数据可视化大屏(实验篇)

    课时1:背景介绍 任务说明 ABC是一家销售公司,其客户可以通过网站下单订购该公司经营范围内的商品,并使用信用卡.银行卡.转账等方式付费.付费成功后,ABC公司会根据客户地址依据就近原则选择自己的货仓 ...

随机推荐

  1. windows下解决getAddressInfo Failed的一种办法

    从九点到现在,解决完这个问题就四点了,其实不难,只是第一次遇到和我太菜. 就是管理员身份打开命令行然后输入ipconfig /flushdns,作用是刷新dns解析缓存,这还不够,如果只做这一步,重启 ...

  2. mysql常用的查询语句

    好记性不如烂笔头! 查询表中全部信息: select * from 表名 查询表中指定列的信息: select 列1,列2 from 表名 数据去重: select distinct 列... fro ...

  3. Web学习篇—Http协议

    Http协议简介 h3 { background: rgba(0, 154, 205, 1); color: rgba(255, 255, 255, 1); border-radius: 6px; f ...

  4. word和excel转pdf

    1.下载jacob.jar包  网址:https://sourceforge.net/projects/jacob-project/files/jacob-project/ 2.导入到本地仓库:mvn ...

  5. 常用 包vue-clipboard2

    包名称 内容 剪切板 vue-clipboard2

  6. 网站提示:You Don’t Have Permission To Access

    测试 apache集成环境访问网站,突然出现错误提示"You don't have permission to access /index.php on this server." ...

  7. styled-components 全局样式定义,由injectGlobal改为createGlobalStyle

    The injectGlobal API was removed and replaced by createGlobalStyle in styled-components v4. 原文链接 官方链 ...

  8. Linux 第十二节(samba NFS )

    samba     跨平台共享,基于smb协议. NFS yum install samba cd /etc/samba   //samba配置文件 mv smb.conf smb.conf_bak  ...

  9. 光盘实现半自动化安装linux以及PXE实现自动安装

    重点 实验一:使用 kickstart 半自动化安装CentOS系统 可以将定制安装光盘,并结合kickstart实现基于光盘启动的半自动化安装 实现过程  首先下载httpd搭建个web网页 [ro ...

  10. pytest(5)-自定义用例顺序(pytest-ordering)-后续学习

    前言 测试用例在设计的时候,我们一般要求不要有先后顺序,用例是可以打乱了执行的,这样才能达到测试的效果. 有些同学在写用例的时候,用例写了先后顺序, 有先后顺序后,后面还会有新的问题(如:上个用例返回 ...