非科班Java出身GISer头像
关注
ArcGIS JS 基础教程(39):LayerList 图层列表组件封面图

ArcGIS JS 基础教程(39):LayerList 图层列表组件

零、写在前面

📌 本系列教程完整目录:ArcGIS JS 系列基础教程(100个项目常用热门功能)

💡 在线示例:完整可运行的 HTML 示例,无需任何环境配置,可直接在浏览器中打开体验
🗂️ 专栏导航:收藏 + 关注,专栏文章第一时间送达
❤️ 一键三连:点赞 + 评论 + 收藏


一、功能介绍

LayerList(图层列表)是 ArcGIS Maps SDK for JavaScript 中用于集中管理地图图层的可视化组件。它以树状列表的形式展示 Map 中所有图层,并允许用户:

  • 开关图层可见性(勾选/取消勾选)
  • 调整图层透明度、图例联动
  • 展开子图层(如 GroupLayer / 地图服务子图层)
  • 为每个图层项追加自定义操作(如「缩放到」「属性表」「导出」)

在 5.0 版本中,LayerList 既可用命令式 LayerList widget(new LayerList({ view })),也可用声明式的 <arcgis-layer-list> Web Component。本课一律使用组件(component)实现,符合「组件优先」原则,代码更简洁、与 HTML 结构解耦。

参考:官方 arcgis-layer-list 组件参考 | LayerList widget 示例

💡 三维要点:在 SceneView 中,图层列表的行为与 2D 完全一致,但每个图层项可联动其 3D 符号(如 point-3d / object 符号)。本课所有图层均为三维符号(elevationInfo + object 几何),列表操作会实时反映到 3D 场景。


二、功能实现

2.1 声明组件并绑定视图

<arcgis-layer-list> 放在普通 div 面板中即可独立使用;独立使用时必须手动把 view 赋值给组件:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>第39课:LayerList 图层列表组件</title>
    <link rel="stylesheet" href="https://js.arcgis.com/5.0/esri/themes/light/main.css">
    <script type="module" src="https://js.arcgis.com/5.0/"></script>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: "Microsoft YaHei", sans-serif; }
        #mapContainer { width: 100vw; height: 100vh; }
        .page-title {
            position: absolute; top: 20px; left: 50%; transform: translateX(-50%);
            background: rgba(255,255,255,0.95); padding: 10px 24px; border-radius: 6px;
            font-size: 18px; font-weight: bold; z-index: 100;
            box-shadow: 0 2px 8px rgba(0,0,0,0.15);
        }
        /* 左侧:arcgis-layer-list 组件面板 */
        .layer-panel {
            position: absolute; top: 80px; left: 20px;
            width: 280px; max-height: 70vh; overflow: auto;
            background: rgba(255,255,255,0.97); padding: 12px; border-radius: 8px;
            box-shadow: 0 2px 12px rgba(0,0,0,0.15);
            z-index: 100;
        }
        .layer-panel h3 { margin: 0 0 8px 0; font-size: 14px; color: #333; }
        #layerList { width: 100%; --calcite-ui-foreground-1: #fff; }

        /* 右侧:控制面板 */
        .control-panel {
            position: absolute; top: 80px; right: 20px;
            background: rgba(255,255,255,0.95); padding: 16px; border-radius: 8px;
            box-shadow: 0 2px 12px rgba(0,0,0,0.15);
            z-index: 100; min-width: 240px;
        }
        .control-panel h3 { margin: 0 0 8px 0; font-size: 14px; color: #333; }
        .btn-row { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 6px; }
        .btn-row button {
            flex: 1; min-width: 100px; padding: 6px 0;
            border: 1px solid #d9d9d9; border-radius: 4px;
            background: white; cursor: pointer; font-size: 12px;
        }
        .btn-row button:hover { border-color: #1890ff; color: #1890ff; }
        .btn-row button.on { background: #1890ff; color: white; border-color: #1890ff; }
        .info-card {
            margin-top: 10px; padding: 10px 12px;
            background: #f0f5ff; border-radius: 6px;
            border-left: 3px solid #1890ff; font-size: 12px; line-height: 1.8;
        }
        .info-card .val { font-weight: bold; color: #1890ff; }
        .status-text {
            position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%);
            background: rgba(0,0,0,0.7); color: white; padding: 8px 20px;
            border-radius: 20px; font-size: 13px; z-index: 100; pointer-events: none;
            white-space: nowrap;
        }
    </style>
</head>
<body>
<h1 class="page-title">第39课:LayerList 图层列表组件</h1>

<div class="layer-panel">
    <h3>📋 图层列表(arcgis-layer-list 组件)</h3>
    <arcgis-layer-list id="layerList"></arcgis-layer-list>
</div>

<div class="control-panel">
    <h3>🎛️ 图层控制</h3>
    <div class="btn-row">
        <button id="btnAdd">➕ 添加监测区</button>
        <button id="btnRemove">➖ 移除监测区</button>
    </div>
    <div class="btn-row">
        <button id="btnSelect" class="on">☑️ 选中模式</button>
        <button id="btnStatus" class="on">💡 状态指示器</button>
    </div>
    <div class="info-card">
        <div>当前图层数:<span class="val" id="layerCount">0</span></div>
        <div>选中图层:<span class="val" id="selInfo">无</span></div>
    </div>
</div>

<div class="status-text" id="statusText">LayerList | 使用 arcgis-layer-list 组件管理图层</div>

<div id="mapContainer"></div>

<script type="module">
    const [Map, SceneView, FeatureLayer, GraphicsLayer, Graphic] = await $arcgis.import([
        "@arcgis/core/Map.js",
        "@arcgis/core/views/SceneView.js",
        "@arcgis/core/layers/FeatureLayer.js",
        "@arcgis/core/layers/GraphicsLayer.js",
        "@arcgis/core/Graphic.js"
    ]);
    const getTianditu = await $arcgis.import("https://openlayers.vip/examples/resources/tianditu.js");

    const vecLayers = getTianditu.default({ type: "vec_w" });
    const map = new Map({ basemap: { baseLayers: [vecLayers.base, vecLayers.anno] } });

    const view = new SceneView({
        container: "mapContainer", map: map,
        camera: {
            position: { longitude: 121.498, latitude: 31.205, z: 4000 },
            heading: 20, tilt: 60
        }
    });

    // ===== 图层 1:客户端要素图层(监测点,按类别唯一值着色) =====
    function buildMonitorLayer() {
        const cats = ["A类", "B类", "C类"];
        const colors = {
            "A类": [227, 74, 51],
            "B类": [56, 135, 220],
            "C类": [60, 180, 110]
        };
        const graphics = [];
        for (let i = 0; i < 90; i++) {
            const cat = cats[i % 3];
            graphics.push(new Graphic({
                geometry: {
                    type: "point",
                    x: 121.46 + Math.random() * 0.08,
                    y: 31.18 + Math.random() * 0.06,
                    z: 80 + Math.random() * 400,
                    spatialReference: { wkid: 4326 }
                },
                attributes: {
                    OBJECTID: i + 1,
                    NAME: "监测点" + (i + 1),
                    CATEGORY: cat
                }
            }));
        }
        return new FeatureLayer({
            source: graphics,
            objectIdField: "OBJECTID",
            fields: [
                { name: "OBJECTID", type: "oid" },
                { name: "NAME", type: "string" },
                { name: "CATEGORY", type: "string" }
            ],
            geometryType: "point",
            spatialReference: { wkid: 4326 },
            title: "实时监测点",
            elevationInfo: { mode: "relative-to-ground" },
            renderer: {
                type: "unique-value",
                field: "CATEGORY",
                uniqueValueInfos: cats.map(cat => ({
                    value: cat,
                    symbol: {
                        type: "point-3d",
                        symbolLayers: [{
                            type: "object",
                            resource: { primitive: "sphere" },
                            width: 220, height: 220, depth: 220,
                            material: { color: colors[cat] }
                        }]
                    }
                }))
            },
            popupTemplate: {
                title: "{NAME}",
                content: "类别:{CATEGORY}"
            }
        });
    }

    // ===== 图层 2:GraphicsLayer(三维建筑体) =====
    function buildBuildingLayer() {
        const layer = new GraphicsLayer({ title: "重点建筑体" });
        const bases = [
            { x: 121.490, y: 31.230, h: 900, c: [120, 170, 230] },
            { x: 121.495, y: 31.225, h: 1400, c: [230, 160, 70] },
            { x: 121.500, y: 31.220, h: 700, c: [120, 200, 160] },
            { x: 121.485, y: 31.218, h: 1100, c: [200, 120, 200] }
        ];
        bases.forEach((b, idx) => {
            layer.add(new Graphic({
                geometry: {
                    type: "point",
                    x: b.x, y: b.y, z: 0,
                    spatialReference: { wkid: 4326 }
                },
                symbol: {
                    type: "point-3d",
                    symbolLayers: [{
                        type: "object",
                        resource: { primitive: "cube" },
                        width: 350, depth: 350, height: b.h,
                        material: { color: b.c }
                    }]
                },
                attributes: { NAME: "建筑" + (idx + 1) }
            }));
        });
        return layer;
    }

    const monitorLayer = buildMonitorLayer();
    const buildingLayer = buildBuildingLayer();
    map.addMany([buildingLayer, monitorLayer]);

    // ===== 动态图层:按钮添加 / 移除的「监测区域」图层 =====
    let zoneLayer = null;
    function buildZoneLayer() {
        const graphics = [];
        for (let i = 0; i < 12; i++) {
            graphics.push(new Graphic({
                geometry: {
                    type: "point",
                    x: 121.47 + Math.random() * 0.05,
                    y: 31.19 + Math.random() * 0.04,
                    z: 200,
                    spatialReference: { wkid: 4326 }
                },
                attributes: { OBJECTID: i + 1, NAME: "区域点" + (i + 1) }
            }));
        }
        return new FeatureLayer({
            source: graphics,
            objectIdField: "OBJECTID",
            fields: [
                { name: "OBJECTID", type: "oid" },
                { name: "NAME", type: "string" }
            ],
            geometryType: "point",
            spatialReference: { wkid: 4326 },
            title: "临时监测区域",
            elevationInfo: { mode: "relative-to-ground" },
            renderer: {
                type: "simple",
                symbol: {
                    type: "point-3d",
                    symbolLayers: [{
                        type: "object",
                        resource: { primitive: "diamond" },
                        width: 260, height: 260, depth: 260,
                        material: { color: [255, 200, 0] }
                    }]
                }
            }
        });
    }

    // ===== LayerList 组件(arcgis-layer-list,组件优先,禁止改用 widget) =====
    const layerList = document.getElementById("layerList");
    layerList.view = view;                 // 独立组件需手动绑定 view
    layerList.selectionMode = "multiple";  // 5.0 用 selectionMode 控制选中能力(默认 "none")
    layerList.listItemCreatedFunction = (event) => {
        const item = event.item;
        // 为每个图层项追加「缩放到」操作按钮
        item.actionsSections = [[
            { type: "button", title: "缩放到图层", id: "zoom-to", icon: "magnifying-glass" }
        ]];
    };
    layerList.addEventListener("arcgisTriggerAction", (event) => {
        const { action, item } = event.detail;
        if (action.id === "zoom-to" && item.layer.fullExtent) {
            view.goTo(item.layer.fullExtent).catch(() => {});
            setStatus("已缩放到:" + item.title);
        }
    });
    layerList.addEventListener("arcgisPropertyChange", (event) => {
        if (event.detail.name === "selection") {
            const sel = layerList.selectedItems || [];
            document.getElementById("selInfo").textContent =
                sel.length ? sel.map(i => i.title).join("、") : "无";
        }
    });

    // ===== 图层数量随 map 变化自动刷新 =====
    function updateLayerCount() {
        document.getElementById("layerCount").textContent = view.map.layers.length;
    }
    view.map.layers.on("change", updateLayerCount);

    await view.when();
    updateLayerCount();
    // 默认定位:自动框选数据范围,确保初始视角合适
    await monitorLayer.when();
    view.goTo(monitorLayer.fullExtent, { duration: 1500 }).catch(() => {});
    setStatus("LayerList 组件就绪 | 共 " + view.map.layers.length + " 个图层");

    function setStatus(msg) { document.getElementById("statusText").textContent = msg; }

    // 添加 / 移除 监测区域图层(演示 LayerList 自动增删)
    document.getElementById("btnAdd").addEventListener("click", () => {
        if (zoneLayer) { setStatus("监测区域图层已存在"); return; }
        zoneLayer = buildZoneLayer();
        map.add(zoneLayer);
        setStatus("已添加临时监测区域图层");
    });
    document.getElementById("btnRemove").addEventListener("click", () => {
        if (!zoneLayer) { setStatus("没有可移除的监测区域图层"); return; }
        map.remove(zoneLayer);
        zoneLayer = null;
        setStatus("已移除临时监测区域图层");
    });

    // 选中模式开关
    let selectOn = true;
    document.getElementById("btnSelect").addEventListener("click", function () {
        selectOn = !selectOn;
        layerList.selectionMode = selectOn ? "multiple" : "none";
        this.classList.toggle("on", selectOn);
        setStatus(selectOn ? "已开启选中模式" : "已关闭选中模式");
    });

    // 状态指示器开关
    let statusOn = true;
    document.getElementById("btnStatus").addEventListener("click", function () {
        statusOn = !statusOn;
        layerList.visibleElements = { statusIndicators: statusOn };
        this.classList.toggle("on", statusOn);
        setStatus(statusOn ? "已显示状态指示器" : "已隐藏状态指示器");
    });
</script>
</body>
</html>
const layerList = document.getElementById("layerList");
layerList.view = view;             // 独立组件需手动绑定 view
layerList.selectionMode = "multiple"; // 5.0:selectionMode 取代了 selectionEnabled(默认 "none")

若 <arcgis-layer-list> 作为 <arcgis-scene> 的子元素(带 slot),则会自动继承视图,无需手动赋值。本课演示更通用的「独立面板」写法。

2.2 自定义列表项(listItemCreatedFunction)

通过 listItemCreatedFunction 为每个图层项追加操作按钮(如「缩放到图层」):

layerList.listItemCreatedFunction = (event) => {
    const item = event.item;
    item.actionsSections = [[
        { type: "button", title: "缩放到图层", id: "zoom-to", icon: "magnifying-glass" }
    ]];
};

2.3 响应操作事件(arcgisTriggerAction)

点击列表项上的自定义按钮会触发 arcgisTriggerAction 事件,通过 event.detail 拿到 action 与 item:

layerList.addEventListener("arcgisTriggerAction", (event) => {
    const { action, item } = event.detail;
    if (action.id === "zoom-to" && item.layer.fullExtent) {
        view.goTo(item.layer.fullExtent);
    }
});

2.4 选中与状态指示器

layerList.selectionMode = "multiple";                    // 选中模式("none" | "single" | "multiple" | "single-persist")
layerList.visibleElements = { statusIndicators: true };  // 状态指示器(加载/可见性)

三、功能应用

应用场景说明
数据看板图层开关用户自由显隐不同业务图层
三维场景图层管理管理建筑体、监测点、区域等多类 3D 图层
自定义图层操作通过 actionsSections 追加「属性表」「导出」「缩放到」
图层透明度调节叠加显示时调整半透明图层的清晰度
子图层展开GroupLayer / 地图服务子图层的分级控制

四、核心代码

📦 完整代码 已保存至 sample/lesson39_layer_list.html,可直接在浏览器打开。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>第39课:LayerList 图层列表组件</title>
    <link rel="stylesheet" href="https://js.arcgis.com/5.0/esri/themes/light/main.css">
    <script type="module" src="https://js.arcgis.com/5.0/"></script>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: "Microsoft YaHei", sans-serif; }
        #mapContainer { width: 100vw; height: 100vh; }
        .page-title {
            position: absolute; top: 20px; left: 50%; transform: translateX(-50%);
            background: rgba(255,255,255,0.95); padding: 10px 24px; border-radius: 6px;
            font-size: 18px; font-weight: bold; z-index: 100;
            box-shadow: 0 2px 8px rgba(0,0,0,0.15);
        }
        /* 左侧:arcgis-layer-list 组件面板 */
        .layer-panel {
            position: absolute; top: 80px; left: 20px;
            width: 280px; max-height: 70vh; overflow: auto;
            background: rgba(255,255,255,0.97); padding: 12px; border-radius: 8px;
            box-shadow: 0 2px 12px rgba(0,0,0,0.15);
            z-index: 100;
        }
        .layer-panel h3 { margin: 0 0 8px 0; font-size: 14px; color: #333; }
        #layerList { width: 100%; --calcite-ui-foreground-1: #fff; }

        /* 右侧:控制面板 */
        .control-panel {
            position: absolute; top: 80px; right: 20px;
            background: rgba(255,255,255,0.95); padding: 16px; border-radius: 8px;
            box-shadow: 0 2px 12px rgba(0,0,0,0.15);
            z-index: 100; min-width: 240px;
        }
        .control-panel h3 { margin: 0 0 8px 0; font-size: 14px; color: #333; }
        .btn-row { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 6px; }
        .btn-row button {
            flex: 1; min-width: 100px; padding: 6px 0;
            border: 1px solid #d9d9d9; border-radius: 4px;
            background: white; cursor: pointer; font-size: 12px;
        }
        .btn-row button:hover { border-color: #1890ff; color: #1890ff; }
        .btn-row button.on { background: #1890ff; color: white; border-color: #1890ff; }
        .info-card {
            margin-top: 10px; padding: 10px 12px;
            background: #f0f5ff; border-radius: 6px;
            border-left: 3px solid #1890ff; font-size: 12px; line-height: 1.8;
        }
        .info-card .val { font-weight: bold; color: #1890ff; }
        .status-text {
            position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%);
            background: rgba(0,0,0,0.7); color: white; padding: 8px 20px;
            border-radius: 20px; font-size: 13px; z-index: 100; pointer-events: none;
            white-space: nowrap;
        }
    </style>
</head>
<body>
<h1 class="page-title">第39课:LayerList 图层列表组件</h1>

<div class="layer-panel">
    <h3>📋 图层列表(arcgis-layer-list 组件)</h3>
    <arcgis-layer-list id="layerList"></arcgis-layer-list>
</div>

<div class="control-panel">
    <h3>🎛️ 图层控制</h3>
    <div class="btn-row">
        <button id="btnAdd">➕ 添加监测区</button>
        <button id="btnRemove">➖ 移除监测区</button>
    </div>
    <div class="btn-row">
        <button id="btnSelect" class="on">☑️ 选中模式</button>
        <button id="btnStatus" class="on">💡 状态指示器</button>
    </div>
    <div class="info-card">
        <div>当前图层数:<span class="val" id="layerCount">0</span></div>
        <div>选中图层:<span class="val" id="selInfo">无</span></div>
    </div>
</div>

<div class="status-text" id="statusText">LayerList | 使用 arcgis-layer-list 组件管理图层</div>

<div id="mapContainer"></div>

<script type="module">
    const [Map, SceneView, FeatureLayer, GraphicsLayer, Graphic] = await $arcgis.import([
        "@arcgis/core/Map.js",
        "@arcgis/core/views/SceneView.js",
        "@arcgis/core/layers/FeatureLayer.js",
        "@arcgis/core/layers/GraphicsLayer.js",
        "@arcgis/core/Graphic.js"
    ]);
    const getTianditu = await $arcgis.import("https://openlayers.vip/examples/resources/tianditu.js");

    const vecLayers = getTianditu.default({ type: "vec_w" });
    const map = new Map({ basemap: { baseLayers: [vecLayers.base, vecLayers.anno] } });

    const view = new SceneView({
        container: "mapContainer", map: map,
        camera: {
            position: { longitude: 121.498, latitude: 31.205, z: 4000 },
            heading: 20, tilt: 60
        }
    });

    // ===== 图层 1:客户端要素图层(监测点,按类别唯一值着色) =====
    function buildMonitorLayer() {
        const cats = ["A类", "B类", "C类"];
        const colors = {
            "A类": [227, 74, 51],
            "B类": [56, 135, 220],
            "C类": [60, 180, 110]
        };
        const graphics = [];
        for (let i = 0; i < 90; i++) {
            const cat = cats[i % 3];
            graphics.push(new Graphic({
                geometry: {
                    type: "point",
                    x: 121.46 + Math.random() * 0.08,
                    y: 31.18 + Math.random() * 0.06,
                    z: 80 + Math.random() * 400,
                    spatialReference: { wkid: 4326 }
                },
                attributes: {
                    OBJECTID: i + 1,
                    NAME: "监测点" + (i + 1),
                    CATEGORY: cat
                }
            }));
        }
        return new FeatureLayer({
            source: graphics,
            objectIdField: "OBJECTID",
            fields: [
                { name: "OBJECTID", type: "oid" },
                { name: "NAME", type: "string" },
                { name: "CATEGORY", type: "string" }
            ],
            geometryType: "point",
            spatialReference: { wkid: 4326 },
            title: "实时监测点",
            elevationInfo: { mode: "relative-to-ground" },
            renderer: {
                type: "unique-value",
                field: "CATEGORY",
                uniqueValueInfos: cats.map(cat => ({
                    value: cat,
                    symbol: {
                        type: "point-3d",
                        symbolLayers: [{
                            type: "object",
                            resource: { primitive: "sphere" },
                            width: 220, height: 220, depth: 220,
                            material: { color: colors[cat] }
                        }]
                    }
                }))
            },
            popupTemplate: {
                title: "{NAME}",
                content: "类别:{CATEGORY}"
            }
        });
    }

    // ===== 图层 2:GraphicsLayer(三维建筑体) =====
    function buildBuildingLayer() {
        const layer = new GraphicsLayer({ title: "重点建筑体" });
        const bases = [
            { x: 121.490, y: 31.230, h: 900, c: [120, 170, 230] },
            { x: 121.495, y: 31.225, h: 1400, c: [230, 160, 70] },
            { x: 121.500, y: 31.220, h: 700, c: [120, 200, 160] },
            { x: 121.485, y: 31.218, h: 1100, c: [200, 120, 200] }
        ];
        bases.forEach((b, idx) => {
            layer.add(new Graphic({
                geometry: {
                    type: "point",
                    x: b.x, y: b.y, z: 0,
                    spatialReference: { wkid: 4326 }
                },
                symbol: {
                    type: "point-3d",
                    symbolLayers: [{
                        type: "object",
                        resource: { primitive: "cube" },
                        width: 350, depth: 350, height: b.h,
                        material: { color: b.c }
                    }]
                },
                attributes: { NAME: "建筑" + (idx + 1) }
            }));
        });
        return layer;
    }

    const monitorLayer = buildMonitorLayer();
    const buildingLayer = buildBuildingLayer();
    map.addMany([buildingLayer, monitorLayer]);

    // ===== 动态图层:按钮添加 / 移除的「监测区域」图层 =====
    let zoneLayer = null;
    function buildZoneLayer() {
        const graphics = [];
        for (let i = 0; i < 12; i++) {
            graphics.push(new Graphic({
                geometry: {
                    type: "point",
                    x: 121.47 + Math.random() * 0.05,
                    y: 31.19 + Math.random() * 0.04,
                    z: 200,
                    spatialReference: { wkid: 4326 }
                },
                attributes: { OBJECTID: i + 1, NAME: "区域点" + (i + 1) }
            }));
        }
        return new FeatureLayer({
            source: graphics,
            objectIdField: "OBJECTID",
            fields: [
                { name: "OBJECTID", type: "oid" },
                { name: "NAME", type: "string" }
            ],
            geometryType: "point",
            spatialReference: { wkid: 4326 },
            title: "临时监测区域",
            elevationInfo: { mode: "relative-to-ground" },
            renderer: {
                type: "simple",
                symbol: {
                    type: "point-3d",
                    symbolLayers: [{
                        type: "object",
                        resource: { primitive: "diamond" },
                        width: 260, height: 260, depth: 260,
                        material: { color: [255, 200, 0] }
                    }]
                }
            }
        });
    }

    // ===== LayerList 组件(arcgis-layer-list,组件优先,禁止改用 widget) =====
    const layerList = document.getElementById("layerList");
    layerList.view = view;                 // 独立组件需手动绑定 view
    layerList.selectionMode = "multiple";  // 5.0 用 selectionMode 控制选中能力(默认 "none")
    layerList.listItemCreatedFunction = (event) => {
        const item = event.item;
        // 为每个图层项追加「缩放到」操作按钮
        item.actionsSections = [[
            { type: "button", title: "缩放到图层", id: "zoom-to", icon: "magnifying-glass" }
        ]];
    };
    layerList.addEventListener("arcgisTriggerAction", (event) => {
        const { action, item } = event.detail;
        if (action.id === "zoom-to" && item.layer.fullExtent) {
            view.goTo(item.layer.fullExtent).catch(() => {});
            setStatus("已缩放到:" + item.title);
        }
    });
    layerList.addEventListener("arcgisPropertyChange", (event) => {
        if (event.detail.name === "selection") {
            const sel = layerList.selectedItems || [];
            document.getElementById("selInfo").textContent =
                sel.length ? sel.map(i => i.title).join("、") : "无";
        }
    });

    // ===== 图层数量随 map 变化自动刷新 =====
    function updateLayerCount() {
        document.getElementById("layerCount").textContent = view.map.layers.length;
    }
    view.map.layers.on("change", updateLayerCount);

    await view.when();
    updateLayerCount();
    await monitorLayer.when();
    view.goTo(monitorLayer.fullExtent, { duration: 1500 }).catch(() => {});
    setStatus("LayerList 组件就绪 | 共 " + view.map.layers.length + " 个图层");

    function setStatus(msg) { document.getElementById("statusText").textContent = msg; }

    // 添加 / 移除 监测区域图层(演示 LayerList 自动增删)
    document.getElementById("btnAdd").addEventListener("click", () => {
        if (zoneLayer) { setStatus("监测区域图层已存在"); return; }
        zoneLayer = buildZoneLayer();
        map.add(zoneLayer);
        setStatus("已添加临时监测区域图层");
    });
    document.getElementById("btnRemove").addEventListener("click", () => {
        if (!zoneLayer) { setStatus("没有可移除的监测区域图层"); return; }
        map.remove(zoneLayer);
        zoneLayer = null;
        setStatus("已移除临时监测区域图层");
    });

    // 选中模式开关
    let selectOn = true;
    document.getElementById("btnSelect").addEventListener("click", function () {
        selectOn = !selectOn;
        layerList.selectionMode = selectOn ? "multiple" : "none";
        this.classList.toggle("on", selectOn);
        setStatus(selectOn ? "已开启选中模式" : "已关闭选中模式");
    });

    // 状态指示器开关
    let statusOn = true;
    document.getElementById("btnStatus").addEventListener("click", function () {
        statusOn = !statusOn;
        layerList.visibleElements = { statusIndicators: statusOn };
        this.classList.toggle("on", statusOn);
        setStatus(statusOn ? "已显示状态指示器" : "已隐藏状态指示器");
    });
</script>
</body>
</html>

五、在线示例

🔗 在线体验:https://southjor.github.io/arcgis-examples/lessons/lesson39.html

在这里插入图片描述

操作说明:

  1. 左侧面板即 <arcgis-layer-list> 组件,列出场景中所有图层,可勾选开关可见性、拖拽调顺序。
  2. 每个图层项右侧有「缩放到图层」按钮,点击让相机飞向该图层范围。
  3. 右侧「添加监测区 / 移除监测区」动态增删图层,列表自动同步。
  4. 「选中模式」开启后可在列表中多选图层;「状态指示器」控制加载状态图标的显隐。

六、关键 API 说明

API说明
<arcgis-layer-list>图层列表 Web Component(组件优先,禁止改用 LayerList widget)
layerList.view独立使用时手动绑定视图
layerList.selectionMode选中模式:"none"(默认)| "single" | "multiple" | "single-persist"(5.0 没有 selectionEnabled);配合 selectedItems 读取选中项
layerList.visibleElements控制可见元素(如 statusIndicators 状态指示器)
layerList.listItemCreatedFunction每个列表项创建时回调,用于追加自定义操作
item.actionsSections列表项右侧的操作按钮数组
arcgisTriggerAction 事件点击列表项操作按钮时触发,event.detail 含 action / item
view.map.layers.on("change")监听图层增删,用于同步外部计数显示

参考链接: arcgis-layer-list 组件文档


七、系列导航

⬅️ 上一篇:ArcGIS JS 基础教程(38):三维要素聚合 FeatureReduction

➡️ 下一篇:ArcGIS JS 基础教程(40):点击拾取要素 hitTest


💡 小贴士:<arcgis-layer-list> 与 <arcgis-scene> 是同一套 Web Components 体系,若把 <arcgis-layer-list slot="top-right"> 直接写在 <arcgis-scene> 内部,它会自动继承视图,连 layerList.view = view 都不用写。本课演示「独立面板」写法,便于把它放进任意自定义布局中。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/linzi19900517/article/details/166340987

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--