数据大屏vue3+ts+axios+MockJS+dataV+echarts

一、官网/文档

  1. vue3:https://cn.vuejs.org/api/
  2. TypeScript:https://www.tslang.cn/docs/handbook/basic-types.html
  3. axios:http://www.axios-js.com/zh-cn/docs/
  4. MockJS:http://mockjs.com/
  5. dataV:http://datav.jiaminghi.com/guide/
  6. echarts:https://echarts.apache.org/handbook/zh/basics/download
  7. 百度地图文档:https://lbsyun.baidu.com/

二、报错

有些是我确实遇到的,有些是我为了验证某些特性是不是真的如他所说的那样报错所记录的

1. VueCompilerError: <template v-for> key should be placed on the <template> tag.

1.1 报错内容如图:
1.2 原因

vue3模板语法在template标签上使用v-for的同时里面如果要使用key关键字,那么为了使template有意义key关键字须在template上而非内层标签上

1.3 修正
  1. 根据报错找到位置
  2. 将原来在rect标签上的key关键字转移到template

2. TypeScript 对象类型的属性访问报错 / 给对象动态添加属性报错

2.1 编辑器报错如图
2.2 原因

基础数据类型object上没有属性name。

类型推断认为obj应为any

2.3 修正

有四种方法

  1. 类型推论:在TypeScript里,在有些没有明确指出类型的地方,类型推论会帮助提供类型。
  2. 使用any
  3. 利用接口interface
  4. 直接tsconfig.json文件中添加 "suppressImplicitAnyIndexErrors":true,来屏蔽隐式索引检查

3. Error: Property 属性名 does not exist on type 接口名

3.1 报错内容如图
3.2 原因

这个是我研究 TypeScript 中 interface 可选属性时 看到 文档说会这么报错,然后就试了一下。

意外之喜是他还会帮你指出正确的名称

不过这种情况编辑器(VScode)一开始就会给你报错

3.3 解决

改成正确的属性名就好。

4. Cannot assign to 属性名 because it is a read-only property.

4.1 报错如图


4.2 原因

这里面是两种情况,

  • 第一种是想知道只读属性会报什么错,
  • 第二种是 只读属性跟可选属性结合的情况下,不赋初始值然后再去手动赋值会不会报错,嗯,报了
4.3 解决

只读属性 一定是只给初始值 ,后面别作妖改

三、一些注意点

1. 实时显示时间

一秒一秒实时显示,思路大致就是setInterval计时器实现

显示格式是YYYY-MM-DD 周x hh:mm:ss

  1. 首先是时间
  2. 处理
javascript 复制代码
export function timeProcessor(date:string|Date):string{
   const dateObj:Date=new Date(date)
   const year:number=dateObj.getFullYear()
   const month:number|string=unshiftZero(dateObj.getMonth()+1)
   const dateStr:number|string=unshiftZero(dateObj.getDate())
   const day:any=function():string{
      const dayNumber=dateObj.getDay()
      const dayStrList=['周日','周一','周二','周三','周四','周五','周六']
      return dayStrList[dayNumber]
   }()
   const hour:number|string=unshiftZero(dateObj.getHours())
   const minute:number|string=unshiftZero(dateObj.getMinutes())
   const second:number|string=unshiftZero(dateObj.getSeconds())
   return `${year}-${month}-${dateStr}  ${day}  ${hour}:${minute}:${second}`
}
export function unshiftZero(num:number):string|number{
   return num<10?`0${num}`:num
}
  1. 引入然后渲染
typescript 复制代码
import {timeProcessor} from "@/utils/xxx";
const nowDate:string = timeProcessor(new Date())

html部分就是简单的双花括号包裹编译

html 复制代码
<div class="time">{{ nowData }}</div>
  1. 计时器循环渲染
typescript 复制代码
const timer = setInterval(() => {
  nowData = timeProcessor(new Date())
}, 1000)
onBeforeUnmount(() => {
  clearInterval(timer)
})

原则上这样就可以了,但是实际上效果却是

出现这种情况的原因是缺少ref包裹,那么ref是什么呢?他是vue3提供的一个响应式操作对象。没有ref包裹的值不具有响应性,下面的值再怎么改变上面也只会显示一开始得到的。

所以需要改为响应式被ref包裹

typescript 复制代码
import { ref, reactive, onBeforeUnmount } from 'vue'
import type { Ref } from 'vue'

let nowData:Ref<string> = ref(timeProcessor(new Date()))
const timer = setInterval(() => {
  nowData.value = timeProcessor(new Date())
}, 1000)
onBeforeUnmount(() => {
  clearInterval(timer)
})

2. interface 额外属性 检查

想了很久还是放这里面

2.1 TypeScript中额外属性报错

首先 ,额外属性是什么东西?就是你给了 一个接口他没有的东西。

typescript 复制代码
interface studentObject {
    name: string;
    age?: number
}
//这里 即便 不传入 age 也不会报错
function logStudent(studentConfig: studentObject): string {
    const student = { name: 'zhangsan', city: 'shanghai' };
    if (studentConfig.name) {
        student.name = studentConfig.name;
    }
    return `当前入学学生名为${student.name}`
}
const wusi = logStudent({ name: 'wusi', classNumber: 5 })

这段代码里面 wusi 变量 传值 classNumber 就是 额外属性 ,

这么传值会报错,首先是编辑器报错

然后是编译报错

TypeScript中,对象字面量会被特殊对待而且会经过 额外属性检查 ,当将它们赋值给变量或作为参数传递的时候。
如果一个对象字面量存在任何"目标类型"不包含的属性时,你会得到一个错误。

2.2 避开额外属性检查

有三种方法

2.2.1 类型断言

{ } as 接口名

typescript 复制代码
interface studentObject {
    name: string;
    age?: number
}
//这里 即便 不传入 age 也不会报错
function logStudent(studentConfig: studentObject): string {
    const student = { name: 'zhangsan', city: 'shanghai' };
    if (studentConfig.name) {
        student.name = studentConfig.name;
    }
    return `当前入学学生名为${student.name}`
}
const wusi = logStudent({ name: 'wusi', classNumber: 5 } as studentObject)
2.2.2 添加一个字符串索引签名

要确定这个对象可能具有某些做为特殊用途使用的额外属性

写法 [propName: string]: any;

typescript 复制代码
interface studentObject {
    name: string;
    age?: number;
    [propName: string]: any;
}
//这里 即便 不传入 age 也不会报错
function logStudent(studentConfig: studentObject): string {
    const student = { name: 'zhangsan', city: 'shanghai' };
    if (studentConfig.name) {
        student.name = studentConfig.name;
    }
    return `当前入学学生名为${student.name}`
}
const wusi = logStudent({ name: 'wusi', classNumber: 5 })
2.2.3 传值给第三方变量

就是先把值存在一个单独变量中

typescript 复制代码
interface studentObject {
    name: string;
    age?: number;
}
//这里 即便 不传入 age 也不会报错
function logStudent(studentConfig: studentObject): string {
    const student = { name: 'zhangsan', city: 'shanghai' };
    if (studentConfig.name) {
        student.name = studentConfig.name;
    }
    return `当前入学学生名为${student.name}`
}
const wusiObj={ name: 'wusi', classNumber: 5 }
const wusi = logStudent(wusiObj)

四、涉及技术

1、vue3部分

1.1 ref()
1.1.1 定义

接受一个内部值,返回一个响应式的、可更改的 ref 对象,此对象只有一个指向其内部值的属性 .value

1.1.2 类型
typescript 复制代码
function ref<T>(value: T): Ref<UnwrapRef<T>>

interface Ref<T> {
  value: T
}
1.1.3 详细信息
  • ref 对象是可更改的,也就是说你可以为 .value 赋予新的值。它也是响应式的,即所有对 .value 的操作都将被追踪,并且写操作会触发与之相关的副作用。
  • 如果将一个对象赋值给 ref,那么这个对象将通过 reactive() 转为具有深层次响应式的对象。这也意味着如果对象中包含了嵌套的 ref,它们将被深层地解包。
  • 若要避免这种深层次的转换,请使用 shallowRef() 来替代。
1.1.4 为 ref() 标注类型

TypeScript写法时,需要标注变量类型,但是被ref()所包裹的值这种该是什么类型呢?

vue3本身提供TypeScript支持,只需要将Ref类型引入 然后标注即可

  • 先引入ref 及 Ref 类型
typescript 复制代码
   import { ref } from 'vue'
   import type { Ref } from 'vue'
  • 变量使用变量:Ref<基本类型> = ref(值)
typescript 复制代码
import { ref } from 'vue'
import type { Ref } from 'vue'

const year: Ref<string | number> = ref('2020')

year.value = 2020 // 成功!
1.1.5 示例
typescript 复制代码
const count = ref(0)
console.log(count.value) // 0

count.value = 1
console.log(count.value) // 1
1.1.6 结合本项目的一些个人看法

本项目中重点用到 ref 或者说 是我警醒 需要使用ref 是在 时间展示部分,一开始只是单纯声明变量,待效果没有出来时反应过来他没有响应式,在编辑器看来他只是一个普通变量。

这也是之前一直使用vue2所留下的个人习惯,之前vue2不需要特意去关注这部分,框架会帮你搞定,看起来是vue2比vue3写法更简但在底层实现时vue2需要逐个甄别,vue3不需要,这也是vue3比vue2轻便的一部分原因。

1.2 reactive()
1.2.1 定义

返回一个对象的响应式代理。

1.2.2 类型
typescript 复制代码
function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
1.2.3 详细信息
  • 响应式转换是"深层"的:它会影响到所有嵌套的属性。

    一个响应式对象也将深层地解包任何 ref 属性,同时保持响应性。

  • 想避免深层响应式转换,只想保留对这个对象顶层次访问的响应性,请使用 shallowReactive() 作替代。

  • 返回的对象以及其中嵌套的对象都会通过 ES Proxy 包裹,因此不等于源对象,建议只使用响应式代理,避免使用原始对象。

1.2.4 标注类型

reactive() 也会隐式地从它的参数中推导类型:

typescript 复制代码
import { reactive } from 'vue'

// 推导得到的类型:{ title: string }
const book = reactive({ title: 'Vue 3 指引' })

要显式地标注一个 reactive 变量的类型,我们可以使用接口:

typescript 复制代码
import { reactive } from 'vue'

interface Book {
  title: string
  year?: number
}

const book: Book = reactive({ title: 'Vue 3 指引' })
1.2.5 示例

创建一个响应式对象:

typescript 复制代码
const obj = reactive({ count: 0 })
obj.count++

ref 的解包:

typescript 复制代码
const count = ref(1)
const obj = reactive({ count })

// ref 会被解包
console.log(obj.count === count.value) // true

// 会更新 `obj.count`
count.value++
console.log(count.value) // 2
console.log(obj.count) // 2

// 也会更新 `count` ref
obj.count++
console.log(obj.count) // 3
console.log(count.value) // 3

注意当访问到某个响应式数组或 Map 这样的原生集合类型中的 ref 元素时,不会执行 ref 的解包:

typescript 复制代码
const books = reactive([ref('Vue 3 Guide')])
// 这里需要 .value
console.log(books[0].value)

const map = reactive(new Map([['count', ref(0)]]))
// 这里需要 .value
console.log(map.get('count').value)

将一个 ref 赋值给一个 reactive 属性时,该 ref 会被自动解包:

typescript 复制代码
const count = ref(1)
const obj = reactive({})

obj.count = count

console.log(obj.count) // 1
console.log(obj.count === count.value) // true
1.2.6 tips
  • 访问到某个响应式数组或 Map 这样的原生集合类型中的 ref 元素时,不会执行 ref 的解包。

2、TypeScript部分

2.1 Any
2.1.1 定义

typescript中的一种基础类型,表示值可以是任何类型(never除外)

2.1.1.1 使用情况

以下情况可以使用 any类型来标记变量:

  • 不清楚该变量类型
  • 变量值可能来自于动态的内容,比如来自用户输入或第三方代码库。
  • 不希望类型检查器对该值进行检查,而是直接让它们通过编译阶段的检查。
2.1.1.2 示例
typescript 复制代码
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean

对现有代码进行改写的时候,any类型十分有用,它允许你在编译时可选择地包含或移除类型检查。

听起来这作用貌似 Object 也有,就像它在其它语言中那样。

但是 Object类型的变量只是允许你给它赋任意值 -

但是却不能够在它上面调用任意的方法,即便它真的有这些方法:

typescript 复制代码
let notSure: any = 4;
notSure.ifItExists(); // okay, ifItExists might exist at runtime
notSure.toFixed(); // okay, toFixed exists (but the compiler doesn't check)

let prettySure: Object = 4;
prettySure.toFixed(); // Error: Property 'toFixed' doesn't exist on type 'Object'.

当只知道一部分数据的类型时,any类型也是有用的。 比如,你有一个数组,它包含了不同的类型的数据:

typescript 复制代码
let list: any[] = [1, true, "free"];
list[1] = 100;
2.1.2 关于 typescript基础类型的一些东西

typescript中基础类型分别有

  1. 基础类型
    boolean 布尔值、 number 数字、 String 字符串、 array 数组、NullUndefined
  2. 其他不算太常见
  • Tuple元祖:各元素可不同数据类型的数组(多个类型时必须严格按照类型排序赋值,越界元素用联合类型替代)
  • enum枚举:对JavaScript标准数据类型的补充。(可以为一组数值赋予友好的名字;可以由枚举的值得到它的名字)
  • any:值可以是任何类型(never打咩)
  • Void:没有任何类型。此类型变量 值 仅为 undefinednull
  • Never :永不存在值的类型。它存在于任何类型子集中,但他自己没有子集类型 (1) 总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型; (就是我们往控制台抛掷异常的函数)

    (2) 当变量被永不为真的类型保护所约束时,它也可能是 never类型。
    (3) never类型是任何类型的子类型,也可以赋值给任何类型;

    然而,没有类型是never的子类型或可以赋值给never类型

    (除了never本身之外)。 即使 any也不可以赋值给never
    (就是说所有类型都是他爹,但他自己没有儿子,他自己采用的无丝分裂)

  1. Object :表示非原始类型,也就是除number,string,boolean,symbol,null或undefined之外的类型。
2.2 InterFace

TypeScript官方文档链接

2.2.1介绍
  • TypeScript的核心原则之一是对值所具有的结构进行类型检查。
  • 它有时被称做"鸭式辨型法"或"结构性子类型化"
  • TypeScript里,接口的作用是为类型命名和为代码或第三方代码定义契约。
2.2.2 属性
2.2.2.1 可选属性

就是说 接口中并不是所有属性都是 必须,当有些属性只有在某些情况下需要时,那么它就是非必需属性即可选属性。

设置可选属性只需要在属性后添加?即可

下面这个例子就明确表示出 age 是可选属性

typescript 复制代码
interface studentObject{
  name:string;
  age?:number
}
//这里 即便 不传入 age 也不会报错
function logStudent(studentConfig:studentObject):string{
  let student={name:'zhangsan',city:'shanghai'};
  if(studentConfig.name){
    student.name=studentConfig.name;
  }
  return `当前入学学生名为${student.name}`
}
let wusi=logStudent({name:'wusi'})
2.2.2.2 只读属性

关键字 readonly 定义只读属性

typescript 复制代码
interface point{
  readonly x:number;
  readonly y:number
}
const redPoint:point={x:123.89,y:128.90}
redPoint.y=900.89;

会报错 Cannot assign to 'y' because it is a read-only property.

TypeScript具有ReadonlyArray<T>类型,它与Array<T>相似,只是把所有可变方法去掉了,因此可以确保数组创建后再也不能被修改:

typescript 复制代码
let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!

结果如图

另外这组代码编辑器也会报错:



上面代码的最后一行,可以看到就算把整个ReadonlyArray赋值到一个普通数组也是不可以的。 但是你可以用类型断言重写:

typescript 复制代码
a = ro as number[];

readonly VS const

  • 作为属性使用就用readonly;
  • 作为变量使用就用const
2.2.3 可索引类型

可索引类型具有一个 索引签名,它描述了对象索引的类型,还有相应的索引返回值类型。

2.2.3.1 索引签名初始
typescript 复制代码
interface StringArray {
  [index: number]: string;
}

let myArray: StringArray;
myArray = ["Bob", "Fred"];

let myStr: string = myArray[0];// => "Bob"

这段代码定义了StringArray接口,它具有索引签名。
这个索引签名表示了当用 number去索引StringArray时会得到string类型的返回值。

有没有想起来什么熟悉的东西?比如 Array[index] ,String[index]

2.2.3.2 索引签名类型
  1. TypeScript支持两种索引签名:字符串和数字
  2. 可以同时使用两种类型的索引,但是数字索引的返回值必须是 字符串索引返回值类型 的子类型。 这是因为使用 number来索引时,JavaScript会将它转换成string然后再去索引对象。

    也就是说用 100(一个number)去索引等同于使用"100"(一个string)去索引,因此两者需要保持一致。

typescript 复制代码
class Animal {
    name: string;
}
class Dog extends Animal {
    breed: string;
}

// 错误:使用数值型的字符串索引,
//有时会得到完全不同的Animal!
interface NotOkay {
    [x: number]: Animal;
    [x: string]: Dog;
}

编译报错

编辑器报错

字符串索引签名能够很好的描述dictionary模式,并且它们也会确保所有属性与其返回值类型相匹配。

因为字符串索引声明了 obj.property和obj["property"]两种形式都可以。

下面的例子里, name的类型与字符串索引类型不匹配,所以类型检查器给出一个错误提示:

typescript 复制代码
interface NumberDictionary {
  [index: string]: number;
  length: number;    // 可以,length是number类型
  name: string       // 错误,`name`的类型与索引类型返回值的类型不匹配
}

最后,你可以将索引签名设置为只读,这样就防止了给索引赋值:

typescript 复制代码
interface ReadonlyStringArray {
    readonly [index: number]: string;
}
let myArray: ReadonlyStringArray = ["Alice", "Bob"];
myArray[2] = "Mallory"; // error!

你不能设置myArray[2],因为索引签名是只读的。

2.2.4 tips
  1. 任何使用 module关键字来声明一个内部模块的地方都应该使用namespace关键字来替换。 避免相似的名称迷惑。
  2. TypeScript会对interface做额外属性检查,就是传入不存在的属性时会报错。想避开有以下方法:
    • 使用类型断言 {} as 接口名
    • 添加一个字符串索引签名,前提是你能够确定这个对象可能具有某些做为特殊用途使用的额外属性
    • 传值经过第三变量。 先用一个变量存储值,然后再定义对应接口值

3、npm

3.1 patch-package

报错一 里面我们解决方式触及到了改源码,但是项目云端时新人该如何,在拉取代码后也修改源码?可以是可以,那用户呢?

在这里我使用了patch-package

3.1.1 安装
powershell 复制代码
npm install patch-package

跟其他的一样习惯用什么用什么,需要注意的是不能用cnpm

3.1.2 使用
  1. 先在项目的pageage.json文件的scripts部分添加代码"postinstall": "patch-package"',这样我们修改后的源码就会在npm install的时候自动为依赖包打上
  2. 修改源码
  3. 执行命令 npx patch-package 修改的依赖名称比如报错一的那个那么我将执行npx patch-package @jiaminghi/data-view
3.1.3 注意

1、第一次使用patch-package会在项目根目录生成patches文件夹,里面有修改过的文件diff记录。

2、当这个包版本更新后,执行命令:git apply --ignore-whitespace patches/@jiaminghi+data-view+2.10.0.patch即可。其中@jiaminghi+data-view+2.10.0.patch是它生成的文件名。

4、百度地图

中间的地图用的是百度地图

我这里是web端所以选的是javascriptAPI


<script type="text/javascript" src="http://api.map.baidu.com/api?v=3.0&ak=秘钥"></script>

4.1 账号及密钥
4.1.1 账号注册
  1. 进入百度地图开放平台官网,点击右上角【登录】按钮,进入百度账号登录页面
  2. 如您已经拥有百度账号,请通过扫码/用户名验证的方式直接登录;如您还未拥有百度账号请您点击【注册】完成账号注册
  3. 通过百度账号注册 成为 百度地图开放平台开发者,选择开发者类型(个人/企业),完成开发者认证即可
4.1.2 AK秘钥申请

JavaScript API只支持浏览端的AK进行接入与访问,请开发者在申请AK时注意选择正确的AK类型。

  1. 进入百度地图开放平台官网控制台,点击【应用管理】-【我的应用】
  2. 点击【创建应用】进入AK申请页面,填写应用名称,务必选择AK类型为"浏览器端",JS API只支持浏览器端AK进行请求与访问
  3. 为了防止AK被盗用,请您务必配置refer白名单,只有该白名单中的网站才能成功发起调用。如下方示例所示,配置了*.mysite.com*为域名白名单,即代表域名中包含.mysite.com的网站=才可以使用该AK访问JS API的服务

    自己本地设置搞着玩 直接 输入 * 也OK
4.2 使用
4.2.1 单页面

以helloworld demo举例

代码如下:

html 复制代码
<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
	<style type="text/css">
	body, html,#allmap {width: 100%;height: 100%;overflow: hidden;margin:0;font-family:"微软雅黑";}
	</style>
	<script type="text/javascript" src="http://api.map.baidu.com/api?type=webgl&v=1.0&ak=您的密钥"></script>
	<title>地图展示</title>
</head>
<body>
	<div id="allmap"></div>
</body>
</html>
<script type="text/javascript">
    // GL版命名空间为BMapGL
    // 按住鼠标右键,修改倾斜角和角度
	var map = new BMapGL.Map("allmap");    // 创建Map实例
	map.centerAndZoom(new BMapGL.Point(116.404, 39.915), 11);  // 初始化地图,设置中心点坐标和地图级别
	map.enableScrollWheelZoom(true);     //开启鼠标滚轮缩放
</script>

主要部分:

html 复制代码
<script type="text/javascript" src="http://api.map.baidu.com/api?type=webgl&v=1.0&ak=您的密钥"></script>

<script type="text/javascript">
    // GL版命名空间为BMapGL
    // 按住鼠标右键,修改倾斜角和角度
	var map = new BMapGL.Map("allmap");    // 创建Map实例
	map.centerAndZoom(new BMapGL.Point(116.404, 39.915), 11);  // 初始化地图,设置中心点坐标和地图级别
	map.enableScrollWheelZoom(true);     //开启鼠标滚轮缩放
</script>
4.2.2 与echarts 结合
  1. 项目安装echarts 引入 百度地图

  2. 引入 echarts 与 echarts 下的 bmap
typescript 复制代码
import * as echarts from 'echarts';
// 请确保在引入百度地图扩展之前已经引入百度地图 JS API 脚本并成功加载
// https://api.map.baidu.com/api?v=3.0&ak=你申请的AK
import 'echarts/extension/bmap/bmap';
  1. 写 echart 大致框架
typescript 复制代码
import * as echarts from 'echarts';
// 请确保在引入百度地图扩展之前已经引入百度地图 JS API 脚本并成功加载
// https://api.map.baidu.com/api?v=3.0&ak=你申请的AK
import 'echarts/extension/bmap/bmap';
import { onMounted } from 'vue';
import {data,geoCoordMap,styleJson} from "./index"

function chartFun(){
  const chartDom = document.getElementById('center-index');
  const myChart = echarts.init(chartDom, 'dark');
  let option;
  const convertData = function (data: string | any[]) {
        const res = [];
        for (let i = 0; i < data.length; i++) {
            const geoCoord = geoCoordMap[data[i].name];
            if (geoCoord) {
                res.push({
                    name: data[i].name,
                    value: geoCoord.concat(data[i].value)
                });
            }
        }
        return res;
   };
      option = {
        backgroundColor: 'transparent',
        title: {
            text:'全国主要城市库存-百度地图',
            left: 'center',
            textStyle: {
                color: '#fff'
            }
        },
        tooltip: {
            trigger: 'item'
        },
        bmap: {},
        series: [
            {
                name: '库存',
                type: 'scatter',
                coordinateSystem: 'bmap',
                data: convertData(data),//数据处理
                encode: {
                    value: 2
                },
                symbolSize: function (val: number[]) {
                    return val[2] / 10;
                },
                label: {
                    formatter: '{b}',
                    position: 'right',
                    show:false
                },
                itemStyle: {
                    color: '#ddb926'
                },
                emphasis: {
                    label: {
                        show: true
                    }
                }
            },
            {
                name: 'Top 5',
                type: 'effectScatter',
                coordinateSystem: 'bmap',
                data: convertData(
                    data
                        .sort(function (a:any, b:any) {
                            return b.value - a.value;
                        })
                        .slice(0, 6)
                ),
                encode: {
                    value: 2
                },
                symbolSize: function (val: number[]) {
                    return val[2] / 10;
                },
                showEffectOn: 'emphasis',
                rippleEffect: {
                    brushType: 'stroke'
                },
                hoverAnimation: true,
                label: {
                    formatter: '{b}',
                    position: 'right',
                    show: true
                },
                itemStyle: {
                    color: '#f4e925',
                    shadowBlur: 10,
                    shadowColor: '#333'
                },
                zlevel: 1
            },
        ]
    };
    option && myChart.setOption(option);
}
onMounted(() => {
    chartFun()
})
  1. 其中主要是bmap对象 是百度地图相关 的
typescript 复制代码
bmap: {
   center: [103.114129, 50.550339],
   zoom: 5,
   roam: true,
   mapStyle: {
     styleJson
   }
},

其中 styleJson 是这个引入的

那个index文件源码如下:

typescript 复制代码
interface DataItem {
    name: string;
    value: number;
  }
export const data:DataItem[]=[
    { name: '海门', value: 9 },
    { name: '鄂尔多斯', value: 12 },
    { name: '招远', value: 12 },
    { name: '舟山', value: 12 },
    { name: '齐齐哈尔', value: 14 },
    { name: '盐城', value: 15 },
    { name: '赤峰', value: 16 },
    { name: '青岛', value: 18 },
    { name: '乳山', value: 18 },
    { name: '金昌', value: 19 },
    { name: '泉州', value: 21 },
    { name: '莱西', value: 21 },
    { name: '日照', value: 21 },
    { name: '胶南', value: 22 },
    { name: '南通', value: 23 },
    { name: '拉萨', value: 24 },
    { name: '云浮', value: 24 },
    { name: '梅州', value: 25 },
    { name: '文登', value: 25 },
    { name: '上海', value: 25 },
    { name: '攀枝花', value: 25 },
    { name: '威海', value: 25 },
    { name: '承德', value: 25 },
    { name: '厦门', value: 26 },
    { name: '汕尾', value: 26 },
    { name: '潮州', value: 26 },
    { name: '丹东', value: 27 },
    { name: '太仓', value: 27 },
    { name: '曲靖', value: 27 },
    { name: '烟台', value: 28 },
    { name: '福州', value: 29 },
    { name: '瓦房店', value: 30 },
    { name: '即墨', value: 30 },
    { name: '抚顺', value: 31 },
    { name: '玉溪', value: 31 },
    { name: '张家口', value: 31 },
    { name: '阳泉', value: 31 },
    { name: '莱州', value: 32 },
    { name: '湖州', value: 32 },
    { name: '汕头', value: 32 },
    { name: '昆山', value: 33 },
    { name: '宁波', value: 33 },
    { name: '湛江', value: 33 },
    { name: '揭阳', value: 34 },
    { name: '荣成', value: 34 },
    { name: '连云港', value: 35 },
    { name: '葫芦岛', value: 35 },
    { name: '常熟', value: 36 },
    { name: '东莞', value: 36 },
    { name: '河源', value: 36 },
    { name: '淮安', value: 36 },
    { name: '泰州', value: 36 },
    { name: '南宁', value: 37 },
    { name: '营口', value: 37 },
    { name: '惠州', value: 37 },
    { name: '江阴', value: 37 },
    { name: '蓬莱', value: 37 },
    { name: '韶关', value: 38 },
    { name: '嘉峪关', value: 38 },
    { name: '广州', value: 38 },
    { name: '延安', value: 38 },
    { name: '太原', value: 200 },
    { name: '清远', value: 39 },
    { name: '中山', value: 39 },
    { name: '昆明', value: 39 },
    { name: '寿光', value: 40 },
    { name: '盘锦', value: 40 },
    { name: '长治', value: 41 },
    { name: '深圳', value: 41 },
    { name: '珠海', value: 42 },
    { name: '宿迁', value: 43 },
    { name: '咸阳', value: 43 },
    { name: '铜川', value: 44 },
    { name: '平度', value: 44 },
    { name: '佛山', value: 44 },
    { name: '海口', value: 44 },
    { name: '江门', value: 45 },
    { name: '章丘', value: 45 },
    { name: '肇庆', value: 46 },
    { name: '大连', value: 47 },
    { name: '临汾', value: 47 },
    { name: '吴江', value: 47 },
    { name: '石嘴山', value: 49 },
    { name: '沈阳', value: 50 },
    { name: '苏州', value: 50 },
    { name: '茂名', value: 50 },
    { name: '嘉兴', value: 51 },
    { name: '长春', value: 51 },
    { name: '胶州', value: 52 },
    { name: '银川', value: 52 },
    { name: '张家港', value: 52 },
    { name: '三门峡', value: 53 },
    { name: '锦州', value: 54 },
    { name: '南昌', value: 54 },
    { name: '柳州', value: 54 },
    { name: '三亚', value: 54 },
    { name: '自贡', value: 56 },
    { name: '吉林', value: 56 },
    { name: '阳江', value: 57 },
    { name: '泸州', value: 57 },
    { name: '西宁', value: 57 },
    { name: '宜宾', value: 58 },
    { name: '呼和浩特', value: 58 },
    { name: '成都', value: 58 },
    { name: '大同', value: 58 },
    { name: '镇江', value: 59 },
    { name: '桂林', value: 59 },
    { name: '张家界', value: 59 },
    { name: '宜兴', value: 59 },
    { name: '北海', value: 60 },
    { name: '西安', value: 61 },
    { name: '金坛', value: 62 },
    { name: '东营', value: 62 },
    { name: '牡丹江', value: 63 },
    { name: '遵义', value: 63 },
    { name: '绍兴', value: 63 },
    { name: '扬州', value: 64 },
    { name: '常州', value: 64 },
    { name: '潍坊', value: 65 },
    { name: '重庆', value: 66 },
    { name: '台州', value: 67 },
    { name: '南京', value: 67 },
    { name: '滨州', value: 70 },
    { name: '贵阳', value: 71 },
    { name: '无锡', value: 71 },
    { name: '本溪', value: 71 },
    { name: '克拉玛依', value: 72 },
    { name: '渭南', value: 72 },
    { name: '马鞍山', value: 72 },
    { name: '宝鸡', value: 72 },
    { name: '焦作', value: 75 },
    { name: '句容', value: 75 },
    { name: '北京', value: 79 },
    { name: '徐州', value: 79 },
    { name: '衡水', value: 80 },
    { name: '包头', value: 80 },
    { name: '绵阳', value: 80 },
    { name: '乌鲁木齐', value: 84 },
    { name: '枣庄', value: 84 },
    { name: '杭州', value: 84 },
    { name: '淄博', value: 85 },
    { name: '鞍山', value: 86 },
    { name: '溧阳', value: 86 },
    { name: '库尔勒', value: 86 },
    { name: '安阳', value: 90 },
    { name: '开封', value: 90 },
    { name: '济南', value: 92 },
    { name: '德阳', value: 93 },
    { name: '温州', value: 95 },
    { name: '九江', value: 96 },
    { name: '邯郸', value: 98 },
    { name: '临安', value: 99 },
    { name: '兰州', value: 99 },
    { name: '沧州', value: 100 },
    { name: '临沂', value: 103 },
    { name: '南充', value: 104 },
    { name: '天津', value: 105 },
    { name: '富阳', value: 106 },
    { name: '泰安', value: 112 },
    { name: '诸暨', value: 112 },
    { name: '郑州', value: 113 },
    { name: '哈尔滨', value: 114 },
    { name: '聊城', value: 116 },
    { name: '芜湖', value: 117 },
    { name: '唐山', value: 119 },
    { name: '平顶山', value: 119 },
    { name: '邢台', value: 119 },
    { name: '德州', value: 120 },
    { name: '济宁', value: 120 },
    { name: '荆州', value: 127 },
    { name: '宜昌', value: 130 },
    { name: '义乌', value: 132 },
    { name: '丽水', value: 133 },
    { name: '洛阳', value: 134 },
    { name: '秦皇岛', value: 136 },
    { name: '株洲', value: 143 },
    { name: '石家庄', value: 147 },
    { name: '莱芜', value: 148 },
    { name: '常德', value: 152 },
    { name: '保定', value: 153 },
    { name: '湘潭', value: 154 },
    { name: '金华', value: 157 },
    { name: '岳阳', value: 169 },
    { name: '长沙', value: 175 },
    { name: '衢州', value: 177 },
    { name: '廊坊', value: 193 },
    { name: '菏泽', value: 194 },
    { name: '合肥', value: 229 },
    { name: '武汉', value: 273 },
    { name: '大庆', value: 279 }
];
export const geoCoordMap:Record<string, number[]>= {
    海门: [121.15, 31.89],
    鄂尔多斯: [109.781327, 39.608266],
    招远: [120.38, 37.35],
    舟山: [122.207216, 29.985295],
    齐齐哈尔: [123.97, 47.33],
    盐城: [120.13, 33.38],
    赤峰: [118.87, 42.28],
    青岛: [120.33, 36.07],
    乳山: [121.52, 36.89],
    金昌: [102.188043, 38.520089],
    泉州: [118.58, 24.93],
    莱西: [120.53, 36.86],
    日照: [119.46, 35.42],
    胶南: [119.97, 35.88],
    南通: [121.05, 32.08],
    拉萨: [91.11, 29.97],
    云浮: [112.02, 22.93],
    梅州: [116.1, 24.55],
    文登: [122.05, 37.2],
    上海: [121.48, 31.22],
    攀枝花: [101.718637, 26.582347],
    威海: [122.1, 37.5],
    承德: [117.93, 40.97],
    厦门: [118.1, 24.46],
    汕尾: [115.375279, 22.786211],
    潮州: [116.63, 23.68],
    丹东: [124.37, 40.13],
    太仓: [121.1, 31.45],
    曲靖: [103.79, 25.51],
    烟台: [121.39, 37.52],
    福州: [119.3, 26.08],
    瓦房店: [121.979603, 39.627114],
    即墨: [120.45, 36.38],
    抚顺: [123.97, 41.97],
    玉溪: [102.52, 24.35],
    张家口: [114.87, 40.82],
    阳泉: [113.57, 37.85],
    莱州: [119.942327, 37.177017],
    湖州: [120.1, 30.86],
    汕头: [116.69, 23.39],
    昆山: [120.95, 31.39],
    宁波: [121.56, 29.86],
    湛江: [110.359377, 21.270708],
    揭阳: [116.35, 23.55],
    荣成: [122.41, 37.16],
    连云港: [119.16, 34.59],
    葫芦岛: [120.836932, 40.711052],
    常熟: [120.74, 31.64],
    东莞: [113.75, 23.04],
    河源: [114.68, 23.73],
    淮安: [119.15, 33.5],
    泰州: [119.9, 32.49],
    南宁: [108.33, 22.84],
    营口: [122.18, 40.65],
    惠州: [114.4, 23.09],
    江阴: [120.26, 31.91],
    蓬莱: [120.75, 37.8],
    韶关: [113.62, 24.84],
    嘉峪关: [98.289152, 39.77313],
    广州: [113.23, 23.16],
    延安: [109.47, 36.6],
    太原: [112.53, 37.87],
    清远: [113.01, 23.7],
    中山: [113.38, 22.52],
    昆明: [102.73, 25.04],
    寿光: [118.73, 36.86],
    盘锦: [122.070714, 41.119997],
    长治: [113.08, 36.18],
    深圳: [114.07, 22.62],
    珠海: [113.52, 22.3],
    宿迁: [118.3, 33.96],
    咸阳: [108.72, 34.36],
    铜川: [109.11, 35.09],
    平度: [119.97, 36.77],
    佛山: [113.11, 23.05],
    海口: [110.35, 20.02],
    江门: [113.06, 22.61],
    章丘: [117.53, 36.72],
    肇庆: [112.44, 23.05],
    大连: [121.62, 38.92],
    临汾: [111.5, 36.08],
    吴江: [120.63, 31.16],
    石嘴山: [106.39, 39.04],
    沈阳: [123.38, 41.8],
    苏州: [120.62, 31.32],
    茂名: [110.88, 21.68],
    嘉兴: [120.76, 30.77],
    长春: [125.35, 43.88],
    胶州: [120.03336, 36.264622],
    银川: [106.27, 38.47],
    张家港: [120.555821, 31.875428],
    三门峡: [111.19, 34.76],
    锦州: [121.15, 41.13],
    南昌: [115.89, 28.68],
    柳州: [109.4, 24.33],
    三亚: [109.511909, 18.252847],
    自贡: [104.778442, 29.33903],
    吉林: [126.57, 43.87],
    阳江: [111.95, 21.85],
    泸州: [105.39, 28.91],
    西宁: [101.74, 36.56],
    宜宾: [104.56, 29.77],
    呼和浩特: [111.65, 40.82],
    成都: [104.06, 30.67],
    大同: [113.3, 40.12],
    镇江: [119.44, 32.2],
    桂林: [110.28, 25.29],
    张家界: [110.479191, 29.117096],
    宜兴: [119.82, 31.36],
    北海: [109.12, 21.49],
    西安: [108.95, 34.27],
    金坛: [119.56, 31.74],
    东营: [118.49, 37.46],
    牡丹江: [129.58, 44.6],
    遵义: [106.9, 27.7],
    绍兴: [120.58, 30.01],
    扬州: [119.42, 32.39],
    常州: [119.95, 31.79],
    潍坊: [119.1, 36.62],
    重庆: [106.54, 29.59],
    台州: [121.420757, 28.656386],
    南京: [118.78, 32.04],
    滨州: [118.03, 37.36],
    贵阳: [106.71, 26.57],
    无锡: [120.29, 31.59],
    本溪: [123.73, 41.3],
    克拉玛依: [84.77, 45.59],
    渭南: [109.5, 34.52],
    马鞍山: [118.48, 31.56],
    宝鸡: [107.15, 34.38],
    焦作: [113.21, 35.24],
    句容: [119.16, 31.95],
    北京: [116.46, 39.92],
    徐州: [117.2, 34.26],
    衡水: [115.72, 37.72],
    包头: [110, 40.58],
    绵阳: [104.73, 31.48],
    乌鲁木齐: [87.68, 43.77],
    枣庄: [117.57, 34.86],
    杭州: [120.19, 30.26],
    淄博: [118.05, 36.78],
    鞍山: [122.85, 41.12],
    溧阳: [119.48, 31.43],
    库尔勒: [86.06, 41.68],
    安阳: [114.35, 36.1],
    开封: [114.35, 34.79],
    济南: [117, 36.65],
    德阳: [104.37, 31.13],
    温州: [120.65, 28.01],
    九江: [115.97, 29.71],
    邯郸: [114.47, 36.6],
    临安: [119.72, 30.23],
    兰州: [103.73, 36.03],
    沧州: [116.83, 38.33],
    临沂: [118.35, 35.05],
    南充: [106.110698, 30.837793],
    天津: [117.2, 39.13],
    富阳: [119.95, 30.07],
    泰安: [117.13, 36.18],
    诸暨: [120.23, 29.71],
    郑州: [113.65, 34.76],
    哈尔滨: [126.63, 45.75],
    聊城: [115.97, 36.45],
    芜湖: [118.38, 31.33],
    唐山: [118.02, 39.63],
    平顶山: [113.29, 33.75],
    邢台: [114.48, 37.05],
    德州: [116.29, 37.45],
    济宁: [116.59, 35.38],
    荆州: [112.239741, 30.335165],
    宜昌: [111.3, 30.7],
    义乌: [120.06, 29.32],
    丽水: [119.92, 28.45],
    洛阳: [112.44, 34.7],
    秦皇岛: [119.57, 39.95],
    株洲: [113.16, 27.83],
    石家庄: [114.48, 38.03],
    莱芜: [117.67, 36.19],
    常德: [111.69, 29.05],
    保定: [115.48, 38.85],
    湘潭: [112.91, 27.87],
    金华: [119.64, 29.12],
    岳阳: [113.09, 29.37],
    长沙: [113, 28.21],
    衢州: [118.88, 28.97],
    廊坊: [116.7, 39.53],
    菏泽: [115.480656, 35.23375],
    合肥: [117.27, 31.86],
    武汉: [114.31, 30.52],
    大庆: [125.03, 46.58]
};
export const styleJson:object[]=[
    {
        featureType: 'water',
        elementType: 'all',
        stylers: {
            color: '#044161'
        }
    },
    {
        featureType: 'land',
        elementType: 'all',
        stylers: {
            color: '#0ff'
        }
    },
    {
        featureType: 'boundary',
        elementType: 'geometry',
        stylers: {
            color: '#0ff'
        }
    },
    {
        featureType: 'railway',
        elementType: 'all',
        stylers: {
            visibility: 'off'
        }
    },
    {
        featureType: 'highway',
        elementType: 'geometry',
        stylers: {
            color: '#004981'
        }
    },
    {
        featureType: 'highway',
        elementType: 'geometry.fill',
        stylers: {
            color: '#005b96',
            lightness: 1
        }
    },
    {
        featureType: 'highway',
        elementType: 'labels',
        stylers: {
            visibility: 'off'
        }
    },
    {
        featureType: 'arterial',
        elementType: 'geometry',
        stylers: {
            color: '#004981'
        }
    },
    {
        featureType: 'arterial',
        elementType: 'geometry.fill',
        stylers: {
            color: '#00508b'
        }
    },
    {
        featureType: 'poi',
        elementType: 'all',
        stylers: {
            visibility: 'off'
        }
    },
    {
        featureType: 'green',
        elementType: 'all',
        stylers: {
            color: '#056197',
            visibility: 'off'
        }
    },
    {
        featureType: 'subway',
        elementType: 'all',
        stylers: {
            visibility: 'off'
        }
    },
    {
        featureType: 'manmade',
        elementType: 'all',
        stylers: {
            visibility: 'off'
        }
    },
    {
        featureType: 'local',
        elementType: 'all',
        stylers: {
            visibility: 'off'
        }
    },
    {
        featureType: 'arterial',
        elementType: 'labels',
        stylers: {
            visibility: 'off'
        }
    },
    {
        featureType: 'boundary',
        elementType: 'geometry.fill',
        stylers: {
            color: '#029fd4'
        }
    },
    {
        featureType: 'building',
        elementType: 'all',
        stylers: {
            color: '#1a5787'
        }
    },
    {
        featureType: 'label',
        elementType: 'all',
        stylers: {
            visibility: 'off'
        }
    }
]
相关推荐
崔庆才丨静觅11 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606112 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了12 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅12 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅13 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅13 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment13 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅13 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊13 小时前
jwt介绍
前端
爱敲代码的小鱼13 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax