街道管理难题怎么破?高德地图“黑科技”给出完美答案!

背景

本次分享的实战案例项目名为"智慧街道一体化平台"。由于开发时间紧迫,我采用了Vue2框架进行前后端架构开发,并基于高德地图的JS API和Web基础服务API,实现了一个简单的街道管理项目。客户需要可视化大屏展示,因此我们重点展示了街道社区在地图中的效果。

目标

客户关于街道可视化部分的主要需求包括:在地图上展示街道全貌,实现街道中社区的区域化展示效果;通过序号标注小区,并在点击标注点位时将地图视角定位并放大到对应社区;同时,在信息窗体中显示对应小区的相关信息。

方案设计

1、街道的边界区域化

为了实现对街道边界的区域化展示,我查阅了JS API文档,并采用了多边形AMap.Polygon功能。通过该功能,我们可以方便地绘制出街道的边界。

官方功能示意图

demo效果图

完整示例代码如下。

js 复制代码
 
const streetCoordinates = [
            [
              [119.017987, 33.616876],
              [119.019426, 33.616761],
             此处省略我当时手动采集的街道边界的经纬度坐标点.....
            ],
          ];
          var HuaihaiPolyline = new AMap.Polyline({
            path: streetCoordinates,
            isOutline: true,
 outlineColor: "#D9251C",
            borderWeight: 3,
            strokeColor: "#D9251C",
            strokeOpacity: 1,
            strokeWeight: 6,
            // 折线样式还支持 'dashed'
             strokeStyle: "dashed",
            // strokeStyle是dashed时有效
            strokeDasharray: [15, 5],
            lineJoin: "round",
            lineCap: "round",
            zIndex: 50,
           strokeWeight: 1,
          });
          this.map.add([HuaihaiPolyline]);

2、社区范围的区域化显示

在该街道中共有7个社区。为了方便展示,我手动采集了社区的坐标点位,并通过不同色块展示了街道中的社区。

覆盖物效果图

覆盖物功能采集的demo完整代码如下。

js 复制代码
 
<!doctype html>
<html>
 
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
  <style>
    html,
    body,
container {
      width: 100%;
      height: 100%;
    }
</style>
  <title>多边形编辑器吸附功能</title>
   <link rel="stylesheet" href="https://a.amap.com/jsapi_demos/static/demo-center/css/demo-center.css" />
  <script 
src="https://webapi.amap.com/maps?v=2.0&key=09023f93f5e47cb8087795cff9eadec5&plugin=AMap.PolygonEditor">
</script>
 <script src="https://a.amap.com/jsapi_demos/static/demo-center/js/demoutils.js"></script>
</head>
 
<body>
  <div id="container"></div>
  <div class="input-card" style="width: 120px">
 <button class="btn" onclick="createPolygon()" style="margin-bottom: 5px">新建</button>
 <button class="btn" onclick="polyEditor.open()" style="margin-bottom: 5px">开始编辑</button>
 <button class="btn" onclick="polyEditor.close()">结束编辑</button>
    <button class="btn" onclick="test()">获取经纬度数组</button>
  </div>
  <script type="text/javascript">
    var map = new AMap.Map("container", {
      center: [116.471354, 39.994257],
      zoom: 16.8
    });
    
     // 1号小区
    var path1 = [
      [
        119.017987,
        33.616882
      ],
  [
        119.01945,
        33.616795
      ],
      [
 119.023023,
        33.615225
      ],
      [
119.027848,
        33.614045
      ],
      [
 119.027083,
        33.612268
      ],
      [
 119.024476,
        33.613368
      ],
      [
 119.024079,
        33.613259
      ],
      [
        119.023838,
  33.613042
      ],
      [
        119.023734,
        33.61289
      ],
      [
 119.023573,
        33.612815
      ],
      [
        119.023399,
33.61258
      ],
      [
        119.019942,
        33.613188
      ],
 [
        119.019465,
        33.613172
      ],
      [
        119.01884,
 33.615088
      ]
    ]
    // 2号小区
var path3 = [
      [
        119.030715,
        33.603081
 ],
      [
        119.029033,
        33.599871
 ],
      [
        119.028916,
        33.599187
 ],
      [
        119.030978,
        33.599661
      ],
      [
        119.031845,
33.599977
      ],
      [
        119.032563,
        33.600343
 ],
      [
        119.033177,
        33.601044
 ],
      [
        119.031667,
        33.602829
 ],
      [
        119.031161,
        33.602987
  ]
    ]
    // 3号
    var path4 = [
      [
        119.032683,
        33.599499
      ],
  [
        119.032617,
        33.599665
      ],
      [
 119.032531,
        33.599818
      ],
      [
        119.032382,
33.600133
      ],
      [
        119.032594,
 33.60027
      ],
      [
        119.032743,
        33.600443
      ],
      [
        119.033037,
        33.600258
      ],
      [
        119.033209,
33.599652
      ],
      [
        119.033302,
        33.599331
      ],
      [
 119.033332,
        33.599153
      ],
      [
        119.033322,
        33.598985
      ],
      [
        119.032735,
33.598823
      ],
      [
        119.032358,
        33.598742
      ],
      [
119.03196,
        33.598664
      ],
      [
        119.031566,
 33.599015
      ],
      [
        119.032166,
        33.599237
      ],
      [
119.03256,
        33.599382
      ],
      [
        119.032648,
        33.599447
      ]
 ]
    // 4
    var path5 = [
      [
        119.028981,
        33.599134
      ],
      [
        119.03123,
 33.599657
      ],
      [
        119.03135,
        33.599181
      ],
 [
        119.031609,
        33.598887
      ],
      [
        119.029051,
        33.598446
 ]
    ]
    var path2 = [
      [119.030785, 33.604298],
      [119.032148, 33.604396],
    ]
 
    var polygon1 = new AMap.Polygon({
      path: path1
    })
    var polygon2 = new AMap.Polygon({
      path: path2
    })
 var polygon3 = new AMap.Polygon({
      path: path3
    })
    var polygon4 = new AMap.Polygon({
      path: path4
    })
var polygon5 = new AMap.Polygon({
      path: path5
    })
 
    map.add([polygon1, polygon2, polygon3, polygon4, polygon5]);
    map.setFitView();
var polyEditor = new AMap.PolygonEditor(map);
    polyEditor.addAdsorbPolygons([polygon1, polygon2]);
    polyEditor.on('add', function (data) {
      console.log(data);
var polygon = data.target;
      polyEditor.addAdsorbPolygons(polygon);
      polygon.on('dblclick', () => {
 polyEditor.setTarget(polygon);
        polyEditor.open();
      })
    })
 polygon1.on('dblclick', () => {
      polyEditor.setTarget(polygon1);
      polyEditor.open();
    })
 polygon2.on('dblclick', () => {
      polyEditor.setTarget(polygon2);
      polyEditor.open();
    })
 
    function createPolygon() {
      polyEditor.close();
      polyEditor.setTarget();
      polyEditor.open();
    }
 polyEditor.setTarget(polygon2);
    polyEditor.open();
 
 function test(params) {
      console.log(polygon2.getPath()); // 输出多边形的轮廓线节点数组
      console.log(polygon2.getOptions()); // 返回覆盖物的中心点的经纬度坐标
    }
</script>
</body>

通过该demo网页手动画出覆盖物区域,最后点击获取经纬度数组按钮即可在浏览器控制台打印出来。

获取覆盖物经纬度demo效果图

3、小区marker点采集

对于小区marker点的采集,我采用了管理员在平台添加小区时一并添加小区坐标点的方式。这样,无论后续新增多少小区,都可以由街道管理员自行添加或修改坐标点位。

具体解决方案是,管理员在新增小区的时候,先输入小区名称,通过点击查询小区坐标点,这里调用高德开放平台的POI高级搜索API功能,获取到小区的坐标点,最后点击创建即可。这里要非常感谢高德开放平台的web服务有每日免费额度,为我们开发者提供了便利。

通过POI服务获取小区坐标点demo的完整代码如下。

js 复制代码
<!doctype html>
<html>
 
<head>
 <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
 <title>输入提示后查询POI</title>
    <link rel="stylesheet" href="https://cache.amap.com/lbs/static/main1119.css" />
    <!-- 引入样式 -->
 <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    <!-- 引入组件库 -->
    <style type="text/css">
panel {
  position: absolute;
            background-color: white;
            max-height: 90%;
            overflow-y: auto;
            top: 10px;
            right: 10px;
            width: 280px;
            }
</style>
    <script type="text/javascript" src="https://webapi.amap.com/maps?v=2.0&key=09023f93f5e47cb8087795cff9eadec5">
</script>
 <script src="../js/[email protected]"></script>
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    <script src="../js/[email protected]"></script>
</head>
 
<body>
    <div id="app">
        <div id="container"></div>
        <div id="panel"></div>
        <div id="myPageTop">
   <table>
                <tr>
                    <td>
                        <label>请输入关键字:</label>
                    </td>
                </tr>
                <tr>
                    <td>
 
 <input v-model="address" id="tipinput" />
                    </td>
                </tr>
                <tr>
                    <td>
<label>请输入城市:</label>
                    </td>
                </tr>
                <tr>
                    <td>
  <input v-model="city" id="tipinput" />
                    </td>
                </tr>
                <tr>
                    <td>
  <button @click="btn()">开始查询</button>
                    </td>
                </tr>
            </table>
        </div>
  </div>
    <script type="text/javascript">
        new Vue({
            el: '#app',
            data: {
                msg: 'Hello Vue!',
                address: "向阳人家",
  city: "淮安市",
                addressList: [], //住宅列表
                map: null, //地图实例
                firstLocation: null, // 存储首个maker的位置
            },
 mounted() {
                console.log(this.msg);
                this.init()
            },
            methods: {
  addMarkersToMap() {
                    this.firstLocation = this.addressList[0].location.split(',').map(parseFloat);
 
                    this.addressList.forEach((location, index) => {
 const position = location.location.split(',').map(parseFloat);
                        const marker = new AMap.Marker({
                            position: new AMap.LngLat(position[0], position[1]),
  // content: `<div>${location.name}</div>` // 如果需要显示名称的话
                        });
 
                        marker.setMap(this.map);
 
                        // 如果是第一个maker,添加地图平移和缩放
  if (index === 0) {
                            this.map.setCenter(new AMap.LngLat(this.firstLocation[0], this
                                .firstLocation[1])); // 移动地图中心到第一个maker位置
   this.map.setZoom(15); // 设置地图缩放到合适的级别,您可以根据实际情况调整
                        }
  }
                         marker.on('click', () => {
                        const currentPos = marker.getPosition(); // 获取当前位置
 console.log(`点击的maker坐标:${currentPos.lng}, ${currentPos.lat}`);
                    });
                });
        },
  // 已有btn方法...
        init() {
            var that = this
            this.map = new AMap.Map("container", {
 resizeEnable: true
            });
        },
 getinfo() {
            axios.get(
                'https://restapi.amap.com/v3/place/text?keywords=淮安&city=beijing&offset=20&page=1&key=67164699cd494100c2e6ec9e75257a2c&extensions=all'
  ).then(res => {
                console.log("请求结果", res);
            })
        },
        btn() {
            axios.get(
               `https://restapi.amap.com/v3/assistant/inputtips?output=JSON&city=${this.city}&keywords=${this.address}&citylimit=true&key=67164699cd494100c2e6ec9e75257a2c`
   ).then(res => {
                console.log("请求结果", res);
                console.log("请求结果22", res.data.tips);
    if (res.data.tips.length > 0) {
                    this.addressList = res.data.tips
                    this.addMarkersToMap()
          }
            })
        }
    },
        })
</script>
</body>

效果展示

通过接口获取marker点列表后,我为每个marker添加了点击事件。点击后,地图会定位并放大到对应位置。最终实现的网页效果如下所示。

大屏效果图

最终我将网页中地图区域的内容完整的封装成了一个Vue组件,完整代码如下。

js 复制代码
 
<template>
  <div id="container"></div>
</template>
 
<script>
import AMapLoader from "@amap/amap-jsapi-loader";
// import { COORDINATES } from "@/utils/position.min"; // 导入住宅覆盖物坐标数组
import { COORDINATES } from "@/utils/positionArea"; // 导入住宅覆盖物坐标数组
import { getList as getResidenceList } from "@/api/streetManage/residenceManage";
 
export default {
  name: "map-view",
  props: {
    // 当前住宅
    currentLsitData: {
      type: Object,
    },
  },
  watch: {
    // 监听当前点击的住宅列表的变化
    currentLsitData: {
      handler(newVal) {
        this.setMapViewMiddle(newVal);
      },
    },
  },
  data() {
    return {
      infoWindow: null, //信息窗体
      map: null, //地图实例
      numberList: [], //住宅列表
    };
  },
  async mounted() {
    await this.getResidenceList();
    await this.initAMap();
  },
  unmounted() {
    this.map?.destroy();
  },
  methods: {
    // 查询住宅列表
    async getResidenceList() {
      let queryParams = {
        pageNum: 1,
        pageSize: 100,
      };
      let res = await getResidenceList(queryParams);
      const newData = res.rows.map((item) => ({
        ...item,
        location: item.location.split(",").map(parseFloat),
      }));
      this.numberList = newData;
    },
    // 设置地图当前中心点位
    setMapViewMiddle(newVal) {
      this.map.setCenter(newVal.location);
      this.map.setZoom(18);
    },
    // 初始化地图
    initAMap() {
      AMapLoader.load({
        key: "09023f93f5e47cb8087795cff9eadec5", // 申请好的Web端开发者Key,首次调用 load 时必填
        version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
        plugins: ["AMap.Scale"], //需要使用的的插件列表,如比例尺'AMap.Scale',支持添加多个如:['...','...']
      })
        .then((AMap) => {
          var that = this;
          this.map = new AMap.Map("container", {
            // 设置地图容器id
            viewMode: "3D", // 是否为3D地图模式
            // zoom: 13, // 初始化地图级别
            center: [119.032116, 33.603177], // 初始化地图中心点位置
            resizeEnable: true,
            mapStyle: "amap://styles/dark", //设置地图的显示样式
            pitch: 10, //地图俯仰角度,有效范围 0 度- 83 度
            rotateEnable: true, //是否开启地图旋转交互 鼠标右键 + 鼠标画圈移动 或 键盘Ctrl + 鼠标左键画圈移动
            pitchEnable: true, //是否开启地图倾斜交互 鼠标右键 + 鼠标上下移动或键盘Ctrl + 鼠标左键上下移动
            zoom: 29, //初始化地图层级
            rotation: -15, //初始地图顺时针旋转的角度
            terrain: true, //开启地形图
            // features: ["bg", "road", "point","building"],
            // mapStyle: "amap://styles/light",
            // layers: [
            //   // 高德默认标准图层
            //   new AMap.TileLayer.Satellite(),
            //   // 楼块图层
            //   new AMap.Buildings({
            //     zooms: [16, 18],
            //     zIndex: 10,
            //     heightFactor: 2, //2倍于默认高度,3D下有效
            //   }),
            // ],
          });
          const points = this.numberList;
          const streetCoordinates = [
            [
              [119.017987, 33.616876],
              [119.019426, 33.616761],
              [119.023956, 33.614935],
              [119.027885, 33.614054],
              [119.029664, 33.613541],
              [119.031662, 33.612804],
              [119.033995, 33.611714],
              [119.035281, 33.611063],
              [119.036521, 33.610694],
              [119.037669, 33.609992],
              [119.03871, 33.6091],
              [119.039827, 33.607965],
              [119.041144, 33.60646],
              [119.043777, 33.605198],
              [119.043239, 33.602682],
              [119.044324, 33.600741],
              [119.045281, 33.598641],
              [119.043207, 33.59912],
              [119.038866, 33.598773],
              [119.034334, 33.59803],
              [119.02527, 33.596435],
              [119.021408, 33.606749],
              [119.019844, 33.611825],
              [119.019142, 33.614297],
              [119.017986, 33.616876],
            ],
          ];
          const createTextStyle = (styleName) => {
            switch (styleName) {
              case "1":
                return {
                  width: "0.3rem",
                  height: "0.3rem",
                  borderRadius: "50%",
                  backgroundColor: "#0093DD",
                  color: "#fff",
                  textAlign: "center",
                  fontSize: "0.2rem",
                  lineHeight: "0.3rem",
                  fontWeight: "bold",
                  display: "flex",
                  justifyContent: "center",
                  alignItems: "center",
                };
              case "2":
                return {
                  width: "0.3rem",
                  height: "0.3rem",
                  borderRadius: "50%",
                  backgroundColor: "#00923F",
                  color: "#fff",
                  textAlign: "center",
                  fontSize: "0.2rem",
                  lineHeight: "0.3rem",
                  fontWeight: "bold",
                  display: "flex",
                  justifyContent: "center",
                  alignItems: "center",
                };
              case "3":
                return {
                  width: "0.3rem",
                  height: "0.3rem",
                  borderRadius: "50%",
                  backgroundColor: "#E67817",
                  color: "#fff",
                  textAlign: "center",
                  fontSize: "0.2rem",
                  lineHeight: "0.3rem",
                  fontWeight: "bold",
                  display: "flex",
                  justifyContent: "center",
                  alignItems: "center",
                };
              default:
                return {
                  width: "50px",
                  height: "50px",
                  borderRadius: "50%",
                  backgroundColor: "skyblue",
                  color: "#fff",
                  textAlign: "center",
                  fontSize: "0.3rem",
                  lineHeight: "50px",
                  fontWeight: "bold",
                  display: "flex",
                  justifyContent: "center",
                  alignItems: "center",
                };
            }
          };
          var HuaihaiPolyline = new AMap.Polyline({
            path: streetCoordinates,
            isOutline: true,
            outlineColor: "#D9251C",
            borderWeight: 3,
            strokeColor: "#D9251C",
            strokeOpacity: 1,
            strokeWeight: 6,
            // 折线样式还支持 'dashed'
            strokeStyle: "dashed",
            // strokeStyle是dashed时有效
            strokeDasharray: [15, 5],
            lineJoin: "round",
            lineCap: "round",
            zIndex: 50,
            strokeWeight: 1,
          });
          this.map.add([HuaihaiPolyline]);
          this.map.setFitView();
          for (var i = 0; i < COORDINATES.length; i++) {
            var area = COORDINATES[i];
            // 2.动态添加多个添加覆盖物
            var polygon = new AMap.Polygon({
              path: area.path,
              strokeWeight: 6,
              strokeOpacity: 0.2,
              fillOpacity: 0.4,
              zIndex: 50,
              bubble: false,
              strokeStyle: "dashed",
            });
            if (area.areaId == 1) {
              polygon.setOptions({
                strokeColor: "#896A6A",
                fillColor: "#B3A6A1",
              });
            } else if (area.areaId == 2) {
              polygon.setOptions({
                strokeColor: "#896A6A",
                fillColor: "#A6B5C7",
              });
            } else if (area.areaId == 3) {
              polygon.setOptions({
                strokeColor: "#896A6A",
                fillColor: "#7A8BC3",
              });
            } else if (area.areaId == 4) {
              polygon.setOptions({
                strokeColor: "#896A6A",
                fillColor: "#BFA479",
              });
            } else if (area.areaId == 5) {
              polygon.setOptions({
                strokeColor: "#896A6A",
                fillColor: "#95A675",
              });
            } else if (area.areaId == 6) {
              polygon.setOptions({
                strokeColor: "#896A6A",
                fillColor: "#B9B36A",
              });
            } else if (area.areaId == 7) {
              polygon.setOptions({
                strokeColor: "#896A6A",
                fillColor: "#A7A2B1",
              });
            }
            this.map.add(polygon);
          }
          this.infoWindow = new AMap.InfoWindow({
            isCustom: true,
            offset: new AMap.Pixel(16, -45),
          });
          console.log("@points", points);
          for (var i = 0; i < points.length; i++) {
            var point = points[i];
            // 1.动态添加多个make点
            var text = new AMap.Text({
              text: i + 1,
              anchor: "center", // 设置文本标记锚点
              draggable: false,
              cursor: "pointer",
              angle: 10,
              style: createTextStyle(point.type),
              position: point.location,
            });
            text.on("click", function (e) {
              console.log("被点击", e);
              that.onMarkerClick(e);
            });
            // 2.动态添加多个添加覆盖物
            // var polygon = new AMap.Polygon({
            //   path: point.path,
            //   strokeWeight: 6,
            //   strokeOpacity: 0.2,
            //   fillOpacity: 0.4,
            //   zIndex: 50,
            //   bubble: false,
            //   strokeStyle: "dashed",
            // });
            // if (point.type === "1") {
            //   polygon.setOptions({
            //     strokeColor: "#0094D9",
            //     fillColor: "#76C1E1",
            //   });
            // } else if (point.type === "2") {
            //   polygon.setOptions({
            //     strokeColor: "#01913C",
            //     fillColor: "#7DC699",
            //   });
            // } else if (point.type === "3") {
            //   polygon.setOptions({
            //     strokeColor: "#E57915",
            //     fillColor: "#EBB17F",
            //   });
            // }
            this.map.add(text);
            // this.map.add(polygon);
          }
        })
        .catch((e) => {
          console.log(e);
        });
    },
    // 地图maker点点击事件
    onMarkerClick(e) {
      const targetPosition = e.target._position;
      let clickedItem = null;
 
      this.numberList.forEach((item) => {
        if (
          item.location[0] === targetPosition[0] &&
          item.location[1] === targetPosition[1]
        ) {
          clickedItem = item;
          return;
        }
      });
 
      if (clickedItem) {
        console.log("clickedItem", clickedItem);
        const typeName = this.getResidentialTypeName(clickedItem.type);
        const customInfo = `
        <div class='custom-info-window'>
    <!-- 标题区域 -->
    <div class='header-section'>
        <img src="https://webapi.amap.com/images/autonavi.png" alt="高德标志" style="float:left;width:67px;height:16px;">
        <!-- 新增关闭按钮 -->
        <span class='close-button'>关闭</span>
    </div>
 
    <!-- 主体内容区域 -->
    <div class='body-section'>
      <p class='detail-item'>小区名称 : ${clickedItem.name}</p>
      <p class='detail-item'>小区类型 : ${typeName}</p>
      <!-- 其他静态或动态信息 -->
      <!-- <p class='detail-item'>电话 : 010-84107000</p> -->
      <!-- <p class='detail-item'>邮编 : 223001</p> -->
      <p class='other-info'>其他信息:暂无</p>
    </div>
</div>
            <!-- 背景色 -->
        <style>
            .custom-info-window {
                background-color: white;
                padding: 15px;
                box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
                font-size: 14px;
                line-height: 1.5;
                color: #333;
                overflow: hidden;
            }
            .header-section {
                display: flex;
                align-items: center;
                justify-content: space-between;
                margin-bottom: 10px;
            }
            .info-title h4, .community-type {
                margin: 0;
            }
            .detail-item, .other-info {
                margin-bottom: 5px;
            }
            .close-button {
              float: right;
              margin-left: 10px;
              cursor: pointer;
              color:#1296db;
              font-size: 0.225rem;
          }
        </style>
        `;
        const bindCloseEvent = () => {
          const closeButton = document.querySelector(
            ".custom-info-window .close-button"
          );
          closeButton.addEventListener("click", this.closeInfoWindow);
        };
        this.infoWindow.setContent(customInfo);
        this.infoWindow.open(this.map, e.target.getPosition());
        this.$emit("getChartInfo");
        bindCloseEvent();
      } else {
        console.log("No item found for the given position");
      }
    },
    // 住宅类型判断
    getResidentialTypeName(type) {
      switch (type) {
        case 1:
          return "一类住宅";
        case 2:
          return "二类住宅";
        case 3:
          return "三类住宅";
        default:
          return "未知类型";
      }
    },
    // 关闭信息窗体
    closeInfoWindow() {
      this.infoWindow.close();
    },
  },
};
</script>
 
<style scoped lang="scss">
#container {
  width: 100%;
  height: 100%;
}
</style>

高德开放平台第二期实战案例,三等奖作品

作者:谢洋

仅代表作者个人观点

相关推荐
萌萌哒草头将军5 分钟前
⚡⚡⚡尤雨溪宣布开发 Vite Devtools,这两个很哇塞 🚀 Vite 的插件,你一定要知道!
前端·vue.js·vite
游离状态的猫131 分钟前
JavaScript性能优化实战:从瓶颈定位到极致提速
开发语言·javascript·性能优化
小彭努力中32 分钟前
7.Three.js 中 CubeCamera详解与实战示例
开发语言·前端·javascript·vue.js·ecmascript
浪裡遊1 小时前
跨域问题(Cross-Origin Problem)
linux·前端·vue.js·后端·https·sprint
滿1 小时前
Vue3 Element Plus el-tabs数据刷新方法
javascript·vue.js·elementui
LinDaiuuj1 小时前
判断符号??,?. ,! ,!! ,|| ,&&,?: 意思以及举例
开发语言·前端·javascript
敲厉害的燕宝1 小时前
Pinia——Vue的Store状态管理库
前端·javascript·vue.js
Aphasia3112 小时前
react必备JavaScript知识点(二)——类
前端·javascript
玖玖passion2 小时前
数组转树:数据结构中的经典问题
前端
呼Lu噜2 小时前
WPF-遵循MVVM框架创建图表的显示【保姆级】
前端·后端·wpf