使用(h3.js)绘制六角网格码

今天来记录一篇关于h3.js插件库的使用,他可以很高效的计算出地球上某个经纬度坐标六边形顶点。

前段时间领导突然给我个售前功能,要求是使用h3.js插件在地球上绘制出六边形网格码,本来以为挺棘手的,结果看完文档后发现也挺简单的,话不多说,开干...

h3.js

学前热身

首先看几张示意图:

1. 基础的六角网格

2. 可根据地球缩放层级的不同而渲染不同大小的六边形

3. 右击网格码,可以变换底色

4. 可以根据随机给六角网格添加颜色区分

 实现思路
准备

首先给项目安装相关依赖

npm install h3-js

或者

pnpm install h3-js

 当然如果我们不是vue等框架项目,也无所谓,只需要引入h3.js的js文件即可。

<script src="https://unpkg.com/h3-js"></script>

 实现

useHexagonTrellisCode 是一个基于 Cesium 和 H3 库的六边形网格码可视化工具,用于在地图上生成和显示 H3 六边形网格系统。

其中我们实现时需要用到几个h3.js自带的api,大家想了解的可以去官网看看。

polygonToCells, cellToLatLng, latLngToCell, cellToBoundary, getHexagonEdgeLengthAvg, UNITS

 我将本次编辑的代码整合到一个类中,下面是使用方法:

初始化
import * as Cesium from 'cesium';
import { useHexagonTrellisCode } from './useHexagonTrellisCode';// 创建Cesium Viewer
const viewer = new Cesium.Viewer('cesiumContainer');// 初始化配置,参数下面有简介
let option = {level: 6,                  // 网格层级 (3-6)polygonArea: [             // 初始绘制区域,注意这里是纬度在前,经度在后[纬度1, 经度1],[纬度2, 经度2],[纬度3, 经度3]],isSort: true,              // 是否对六边形进行排序(可选)Mark_color: ["#00ffff85"]   // 标记颜色(可选)
}// 初始化六边形网格码工具
const hexagonTool = new useHexagonTrellisCode(viewer, option);// 是否显示标签(可选)
hexagonTool.showLabel();// 渲染网格
hexagonTool.render();
参数配置(option)
参数类型默认值说明
levelnumber6H3网格层级 (3-6)
isPolygonFullDrawbooleanfalse是否根据视口大小绘制图形(还在实验中)
isSortbooleanfalse是否对六边形进行排序
Mark_colorstring[]["#00ffff85", "#a605ff85", "#ffce0585", "#05ff1d85"]标记颜色数组
polygonAreanumber[][][]定义绘制六边形网格码的区域
 主要方法

1、显示标签

showLabel()

2、渲染网格

render()

3、高亮选中的六边形

/*** longitude: 经度* latitude: 纬度* option: 可选配置,如 { selectColor: "red" }*/
select_high_lightObject(longitude, latitude, option)

4、设置网格层级

setLevel(level)

5、设置绘制区域

setPolygonArea(position)

6、销毁实例

destory()
使用示例

1、基本使用

const useHexagonTrellis = new useHexagonTrellisCode(viewer, {level: 5,polygonArea: [[39.9, 116.3],[39.9, 116.5],[40.1, 116.5],[40.1, 116.3]]
}).showLabel().render();

2、交互示例

// 点击地图高亮六边形
viewer.screenSpaceEventHandler.setInputAction(function(movement) {const pickedObject = viewer.scene.pick(movement.endPosition);if (pickedObject && pickedObject.id) {const cartographic = Cesium.Cartographic.fromCartesian(pickedObject.id);const longitude = Cesium.Math.toDegrees(cartographic.longitude);const latitude = Cesium.Math.toDegrees(cartographic.latitude);useHexagonTrellis.select_high_lightObject(longitude, latitude, {selectColor: "#ff0000"});}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

3、动态调整层级

viewer.camera.changed.addEventListener(() => {const height = viewer.camera.positionCartographic.height;if (viewer.scene.mode === Cesium.SceneMode.SCENE3D) {let level = Math.floor(Math.log2(2.0e7 / height));useHexagonTrellis.setLevel(level);}
})
主要代码
import * as Cesium from 'cesium'
import { polygonToCells, cellToLatLng, latLngToCell, cellToBoundary, getHexagonEdgeLengthAvg, UNITS } from "h3-js";
export class useHexagonTrellisCode {viewer = null;hexgonIds = [];/*** 所有六边形图元*/PrimitiveMain = null;/*** 选中时所显示的图元*/selectPrimitive = null;/*** 编码标签的集合*/labelsCollection = null;/*** 标识圆的所有图元集合*/_circles = [];config = {level : 6,      // 当前层级isPolygonFullDraw: false,   // 是否根据视口大小绘制图形isSort: false,      // 是否排序Mark_color: ["#00ffff85", "#a605ff85", "#ffce0585", "#05ff1d85"],    // 是否在六边形上添加透明图元polygonArea: [],    // 定义绘制六边形网格码的区域}/*** useHexagonTrellisCode 生成六边形网格码* @param {*} viewer * @param {*} option * @returns */constructor (viewer, option) {this.viewer = viewer;this.config = {...this.config,...option};return false;}/*** 开启标签显示* @returns */
/*** longitude: 经度* latitude: 纬度* option: 可选配置,如 { selectColor: "red" }*/showLabel() {this.labelsCollection && this.viewer.scene.primitives.remove(this.labelsCollection);this.labelsCollection = new Cesium.LabelCollection();this.viewer.scene.primitives.add(this.labelsCollection);return this;}/*** 渲染* @returns */render() {if (this.config.polygonArea.length == 0) {return false;}this.clearOldPrimitive();const hexagons = polygonToCells(this.config.polygonArea, this.config.level);this.hexgonIds = hexagons;let _hexagons_center = hexagons;// 添加排序if (this.config.isSort) {let _hexagons = hexagons.map(hexId => {const center = cellToLatLng(hexId);return {hexId, lon:center[1], lat: center[0]}})_hexagons_center = _hexagons.sort((a, b) => {if (a.lat !== a.lat) return b.lat - a.lat;return a.lon - b.lon;}).map(t => t.hexId)}this.PrimitiveMain = this.createPrimitive_line();let instances = [];let drawNum = 0;_hexagons_center.forEach((hexId) => {instances.push(this.createHexagonInstance_line(hexId))if (this.config.Mark_color.length > 0 && drawNum++ < this.config.Mark_color.length) {this.drawCircles(hexId, this.config.Mark_color[drawNum]);}if (this.labelsCollection) this.addLabel(hexId);})this.PrimitiveMain.geometryInstances = instances;return this.viewer.scene.primitives.add(this.PrimitiveMain);}/*** 根据视口绘制六边形* 实验中...*/drawPolygonByViewFull() {// 判断选中区域是否在视口内let isPolygonFull = this.isPolygonFullyInViewport(this.config.polygonArea);if (isPolygonFull == 0) {console.log("111")return false;}if (isPolygonFull == 2) {console.log("222")return this.render();}console.log("333")const viewRectangle = this.viewer.camera.computeViewRectangle();let position = [[Cesium.Math.toDegrees(viewRectangle.west),Cesium.Math.toDegrees(viewRectangle.south)],[Cesium.Math.toDegrees(viewRectangle.east),Cesium.Math.toDegrees(viewRectangle.south)],[Cesium.Math.toDegrees(viewRectangle.east),Cesium.Math.toDegrees(viewRectangle.north)],[Cesium.Math.toDegrees(viewRectangle.west),Cesium.Math.toDegrees(viewRectangle.north)]]this.removeLabelCollection();const _hexagons = polygonToCells(position, this.config.level);let instances = [];this.hexgonIds.forEach(hexId => {if (_hexagons.includes(hexId)) {instances.push(this.createHexagonInstance_line(hexId))if (this.labelsCollection) this.addLabel(hexId);}})this.PrimitiveMain.geometryInstances = instances;return true;}/*** 添加label标签* @param {*} hexId * .padEnd(this.config.labelLenght || 5, '0')*/addLabel(hexId){let lonlat = cellToLatLng(hexId);this.labelsCollection.add({position : Cesium.Cartesian3.fromDegrees(lonlat[1], lonlat[0]),text : hexId.replace(/[^\d]/g,''),font : `${this.config.labelSize || 16}px sans-serif`,horizontalOrigin : Cesium.HorizontalOrigin.CENTER,verticalOrigin : Cesium.VerticalOrigin.BOTTOM,})}/*** 通过经纬度添加选中效果* @param {*} longitude * @param {*} latitude * @param {*} option * @returns */select_high_lightObject(longitude, latitude, option) {if(!longitude || !latitude || this.config.level == -1) {return false;}let _code = latLngToCell(latitude, longitude,this.config.level);if (this.hexgonIds.includes(_code)) {// 删除之前高亮图元this.viewer.scene.primitives.remove(this.selectPrimitive); this.selectPrimitive = this.createPrimitive_polygon();this.selectPrimitive.geometryInstances = [ this.createHexagonInstance_polygon(_code, option.selectColor || "red") ];this.viewer.scene.primitives.add(this.selectPrimitive);return true;}else {return false;}}/*** 绘制圆* @param {*} hexId */drawCircles(hexId, color) {// 绘制填充多边形let polygon = this.createPrimitive_polygon();let geomtry = this.createHexagonInstance_polygon(hexId, color || "red");polygon.geometryInstances = geomtry;this._circles.push(polygon);this.viewer.scene.primitives.add(polygon);// 绘制圆let _circle = this.createPrimitive_circle();let instance = [];let distance = parseInt(getHexagonEdgeLengthAvg(this.config.level, UNITS.m)) * (Math.random() * (0.9 - 0.2) + 0.2);let colors = ["#098", "#af2","#f2a","#b2a"];for (let i=0; i<4; i++){let radius = distance - (distance * (i / 5));// 使用叠加法绘制原型轮廓线for (let j=0; j< 30; j++){instance.push(this.createHexagonInstance_circle(hexId, radius - j,colors[i]))}}_circle.geometryInstances = instance;this._circles.push(_circle);this.viewer.scene.primitives.add(_circle);}/*** 删除选中后添加的高亮图元*/remove_select_primitive() {this.selectPrimitive && this.viewer.scene.primitives.remove(this.selectPrimitive);}/*** 添加线类型Primitive* @returns */createPrimitive_line() {return new Cesium.Primitive({geometryInstances: [],appearance: new Cesium.PolylineColorAppearance({translucent: false,renderState: {depthTest: { enabled: false }, // 关闭深度测试blending: Cesium.BlendingState.ALPHA_BLEND,depthMask: false,    // 关键:禁止写入深度缓冲区}}),asynchronous: false});}/*** 添加圆类型Primitive* @returns */createPrimitive_circle() {return new Cesium.Primitive({geometryInstances: [],appearance: new Cesium.PerInstanceColorAppearance({translucent: false,closed: false,flat: true,renderState: {depthTest: { enabled: false }, // 关闭深度测试blending: Cesium.BlendingState.ALPHA_BLEND,depthMask: false    // 关键:禁止写入深度缓冲区}}),asynchronous: false});}/*** 添加多边形类型Primitive* @returns */createPrimitive_polygon() {return new Cesium.Primitive({geometryInstances: [],appearance: new Cesium.PerInstanceColorAppearance({translucent: false,closed: false,renderState: {depthTest: { enabled: false }, // 关闭深度测试blending: Cesium.BlendingState.ALPHA_BLEND,depthMask: false,    // 关键:禁止写入深度缓冲区}}),asynchronous: false});}/*** 添加圆类型GeometryInstance* @param {*} hexId * @param {*} radius * @param {*} color * @returns */createHexagonInstance_circle(hexId, radius = 5, color = "blue") {const coordinates = cellToLatLng(hexId, true); // 获取六边形边界const center = Cesium.Cartographic.fromDegrees(coordinates[1], coordinates[0]);const _center = Cesium.Cartesian3.fromRadians(center.longitude,center.latitude, 0);return new Cesium.GeometryInstance({geometry: new Cesium.CircleOutlineGeometry({center: _center,radius: isNaN(radius) ? 5 : radius}),attributes: {color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString(color))},id: hexId // 保存H3 ID以便交互});}/*** 添加线类型GeometryInstance* @returns */createHexagonInstance_line = (hexId, color = "#008df1a3") => {const coordinates = cellToBoundary(hexId, true); // 获取六边形边界const positions = coordinates.map(coord => Cesium.Cartesian3.fromDegrees(coord[0], coord[1]));return new Cesium.GeometryInstance({geometry: new Cesium.PolylineGeometry({positions: positions,width : 2.0}),attributes: {color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString(color))},id: hexId // 保存H3 ID以便交互});}/*** 添加多边形类型GeometryInstance* @returns */createHexagonInstance_polygon(hexId, color = "#008df1a3") {const coordinates = cellToBoundary(hexId, true); // 获取六边形边界const positions = coordinates.map(coord => Cesium.Cartesian3.fromDegrees(coord[0], coord[1], 200));return new Cesium.GeometryInstance({geometry: new Cesium.PolygonGeometry({polygonHierarchy: new Cesium.PolygonHierarchy(positions),height: 20 // 可选高度}),attributes: {color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString(color))},id: hexId // 保存H3 ID以便交互});}/*** 判断当前选中的区域是否在全视口内* @param {*} positions * @returns *      0: 全不在视口中,不需要渲染*      1: 所选区域部分在视口内*      2: 所选区域全部在视口内*/isPolygonFullyInViewport(positions) {const viewRectangle = this.viewer.camera.computeViewRectangle();if (!viewRectangle || !positions || positions.length < 3) return 0;const _positions = positions.map(t => new Cesium.Cartographic(t[1],t[0]));let polygonRectangle  = this.createValidRectangle(_positions);console.log(viewRectangle, polygonRectangle);// 所选区域全部在视口内if (_positions.every(t => Cesium.Rectangle.contains(viewRectangle, polygonRectangle))) {return 2;}// 所选区域全部不在视口内if (!_positions.some(t => Cesium.Rectangle.contains(viewRectangle, polygonRectangle))) {return 0;} else {// 所选区域部分在视口内return 1;}}// 辅助方法:创建有效的RectanglecreateValidRectangle(cartographics) {// 1. 计算边界const west = Math.min(...cartographics.map(c => c.longitude));const south = Math.min(...cartographics.map(c => c.latitude));const east = Math.max(...cartographics.map(c => c.longitude));const north = Math.max(...cartographics.map(c => c.latitude));// 2. 验证范围if (west >= east || south >= north) {console.warn("无效的坐标范围:", {west, south, east, north});return null;}// 3. 返回有效的Rectanglereturn Cesium.Rectangle.fromDegrees(west, south, east, north);}/*** 重置层级* @param {*} level 限制 最大是6 最小是3*/setLevel(level) {let _level= Math.max(Math.min(level, 6), 3);if (Object.is(this.config.level, _level)) return false;this.config.level = _level;return this.config.isPolygonFullDraw ? this.drawPolygonByViewFull() : this.render();;}/*** 重新选择生成网格码的区域* @param {*} position */setPolygonArea(position) {this.config.polygonArea = position;this.config.isPolygonFullDraw ? this.drawPolygonByViewFull() : this.render();}/*** 删除标签*/removeLabelCollection() {this.labelsCollection && this.labelsCollection.removeAll();}/*** 删除可视化图元*/clearOldPrimitive() {this.remove_select_primitive();this.PrimitiveMain && this.viewer.scene.primitives.remove(this.PrimitiveMain);this._circles.forEach(item => this.viewer.scene.primitives.remove(item));this.removeLabelCollection();}/*** 销毁示例*/destory() {this.clearOldPrimitive();}
}

如何我们不是vue等框架项目,不容易用import和export方法来导出、引入的话,我们可以script标签方式引入,然后在所有api前添加h3.就行了(如:h3.cellToLatLng(xxx)即可)。最后将export去掉,底部添加window.useHexagonTrellisCode = useHexagonTrellisCode;代码就可以了。

最后想法

如果哪位同赛道的同事发现问题或者有更好的建议可以私信我,一起努力哦,

最后!!!

啥也不想说了,睡觉...

明天还要出差呢,牛马的每一天(_ _)( - . - )(~O~)……( - . - )

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/85188.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/85188.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GO 1.25

Go 1.25 发布说明&#xff08;草案&#xff09; Go 1.25 尚未发布。 本文档是正在编写中的发布说明。Go 1.25 预计于 2025 年 8 月发布。 语言变更 Go 1.25 中没有影响 Go 程序的语法变更。然而&#xff0c;在语言规范中&#xff0c;“核心类型”&#xff08;core types&…

解析Android SETUP_DATA_CALL 链路信息字段

Android 对象返回的log信息经常都不是标准的JSON字符串,排查字段不直观,比如下面的日志: 06-13 15:56:36.204 8076 8407 D RILJ : [1655]> SETUP_DATA_CALL,reason=NORMAL,accessNetworkType=EUTRAN,dataProfile=[DataProfile=[ApnSetting] IMS, 2318, 310260, ims,…

跨语言RPC:使用Java客户端调用Go服务端的HTTP-RPC服务

在构建分布式系统时&#xff0c;实现不同编程语言之间的无缝通信是一个常见的需求。本文将详细介绍如何使用Go语言创建一个HTTP-RPC服务&#xff0c;并通过Java客户端进行远程调用。我们将探索整个过程&#xff0c;包括服务端的实现、客户端的编写以及测试验证。 一、背景介绍…

CVPR2024迁移学习《Unified Language-driven Zero-shot Domain Adaptation》

摘要 本文提出了一个名为 Unified Language-driven Zero-shot Domain Adaptation&#xff08;ULDA&#xff09;的新任务设置&#xff0c;旨在使单一模型能够适应多种目标领域&#xff0c;而无需明确的领域标识&#xff08;domain-ID&#xff09;知识。现有语言驱动的零样本领域…

AI安全风险监测平台:全周期防护体系构建

AI安全风险监测平台通过构建全生命周期防护体系&#xff0c;实现对人工智能系统研发、部署、运行、迭代各阶段的安全风险动态监测。该平台融合算法审计、行为分析、合规验证等核心能力&#xff0c;建立覆盖模型安全、数据安全、应用安全的立体防御网络&#xff0c;为智能系统提…

数据集-目标检测系列- 杯子 数据集 bottle >> DataBall

数据集-目标检测系列- 杯子 数据集 bottle &#xff1e;&#xff1e; DataBall 贵在坚持&#xff01; * 相关项目 1&#xff09;数据集可视化项目&#xff1a;gitcode: https://gitcode.com/DataBall/DataBall-detections-100s/overview 2&#xff09;数据集训练、推理相关…

视频点播web端AI智能大纲(自动生成视频内容大纲)的代码与演示

通过AI技术将视频课程自动生成结构化大纲和摘要&#xff0c;支持PPT教学视频、企业内训等场景应用。核心功能包括&#xff1a;自动匹配视频知识点生成文本大纲、快速内容定位、降低课程制作成本。系统采用模块化架构&#xff0c;包含Vue2.7前端组件、JS逻辑库和演示项目&#x…

Linux: errno: EINPROGRESS-115

在connect接口的使用说明里&#xff0c;有这个错误&#xff1a;EINPROGRESS。 The socket is nonblocking and the connection cannot be completed immediately. It is possible to select(2) or poll(2) for completion by selecting the socket for writing. After select(2…

Node.js特训专栏-基础篇:3. Node.js内置模块的使用

&#x1f525; 欢迎来到 Node.js 实战专栏&#xff01;在这里&#xff0c;每一行代码都是解锁高性能应用的钥匙&#xff0c;让我们一起开启 Node.js 的奇妙开发之旅&#xff01; Node.js 特训专栏主页 Node.js内置模块&#xff1a;强大功能的基石 在Node.js的世界里&#xff…

基于MATLAB实现的Capon、MUSIC、ESPRIT和PM算法进行DOA

使用Capon、MUSIC、ESPRIT和PM多种算法进行doa估计&#xff0c;通过谱峰搜索函数估计到达角&#xff0c;并使用蒙特卡洛方法估计各算法的RMSE。&#xff08;可能计算时间较长&#xff0c;如需节省时间可以减小蒙特卡洛次数&#xff09; PM.m , 574 RMSE.m , 274 TLS_ESPRIT.m …

某网站极验4滑块验证码逆向分析

文章目录 1. 写在前面2. 接口分析3. w逆向分析4. JSON参数分析5. 距离识别6. RSA纯算还原7. AES纯算还原【🏠作者主页】:吴秋霖 【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于…

深入理解 C++ inline:三大语法特性 + 七大高频考点全解析

一、什么是内联函数 编译器尝试将 inline 函数的代码直接插入调用处&#xff08;类似宏展开&#xff09;&#xff0c;避免函数调用的压栈、跳转、返回等额外开销。适用于短小频繁调用的函数&#xff1a;如简单的 getter/setter、数学运算等。inline 只是 建议&#xff0c;编译…

Flink 与 Hive 深度集成

引言 在大数据生态中&#xff0c;Flink 的流批一体化处理能力与 Hive 的数据存储分析优势结合&#xff0c;通过 Flink Connector for Hive 实现无缝对接&#xff0c;能显著提升数据处理效率。本文将系统解析 Flink 与 Hive 集成的核心操作&#xff0c;涵盖配置、读写、优化全流…

Axios面试常见问题详解

axios面试常问题目及其详解 以下是前端面试中关于 Axios 的常见问题及详细解答&#xff0c;涵盖核心原理、实战场景和进阶优化&#xff0c;帮助你在面试中清晰展示技术深度。 1. Axios 是什么&#xff1f;它与原生 Fetch API 有何区别&#xff1f; 回答要点&#xff1a; Axi…

14.2 《3小时从零搭建企业级LLaMA3语言助手:GitHub配置+私有化模型集成全实战》

3小时从零搭建企业级LLaMA3语言助手&#xff1a;GitHub配置私有化模型集成全实战 关键词&#xff1a;GitHub 仓库配置, 项目初始化, 目录结构设计, 私有化模型集成, 开发环境标准化 Fork 并配置 GitHub 项目仓库 本节将手把手完成 LanguageMentor 项目的仓库克隆、环境配置和…

生物制药自动化升级:Modbus TCP与Ethernet/IP协议转换实践

为优化生物制药生产流程&#xff0c;我司计划将现有的Allen-Bradley PLC控制系统与新型生物反应器进行集成。由于两者采用不同的通信协议&#xff08;AB PLC使用Modbus TCP&#xff0c;而生物反应器支持Ethernet/IP&#xff09;&#xff0c;直接通信存在障碍。为此通过稳联技术…

商业云手机核心优缺点分析

商业云手机核心优缺点分析&#xff0c;综合技术性能、成本效率及场景适配性等多维度对比&#xff1a; 核心优势‌ 成本革命‌ 硬件零投入‌&#xff1a;免除实体手机采购&#xff08;旗舰机均价6000元&#xff09;&#xff0c;企业百台规模可省60万 CAPEX。 弹性计费‌&…

Windows 远程桌面添加 SSL 证书指南

Windows 远程桌面添加 SSL 证书指南 &#x1f9fe; 准备工作&#x1f510; 第一步&#xff1a;使用 Certbot 申请 SSL 证书&#x1f4e6; 第二步&#xff1a;生成 PFX 格式证书文件&#x1f4c1; 第三步&#xff1a;导入证书到 Windows 证书管理器&#x1f512; 第四步&#xf…

项目实训技术实现——核心关键:基于二叉分割的布局生成算法

核心关键&#xff1a;基于二叉分割的布局生成算法 上一篇针对llava这种为每个元素分别预测每个元素的框的方法进行了分析&#xff0c;已经证实这条路难以行得通。因此&#xff0c;我们考虑直接按照板块划分整个背景布局&#xff0c;然后在板块内&#xff0c;进一步划分出我们需…

uniapp 配置devserver代理

在uniapp项目中配置devserver代理&#xff0c;需要先检查用的vue版本。 vue3不能在manifest.json配置代理。 1.先检查项目用的vue版本 找到manifest.json文件查看vue的版本。 2.vue2在manifest.json内配置 "h5" : { "devServer": { …