Mapbox GL JS 核心表达式:`==` 相等判断完全教程

Mapbox GL JS 是一款高性能的开源矢量地图渲染库,其表达式系统(Expressions) 是实现数据驱动样式、要素过滤、交互控制的核心。== 作为最基础且高频使用的比较表达式,用于判断两个值是否严格相等 ,是解锁 Mapbox 高级样式定制的必备知识点。本文将从核心概念、语法、实战场景、进阶用法到常见误区,全面讲解 == 表达式的使用。

一、== 表达式核心概念

1.1 严格类型相等

== 表达式的比较规则与 JavaScript 的 === 完全一致:

  • 不仅要求值相等 ,还要求运行时类型完全一致 (如数字 5 ≠ 字符串 "5",布尔值 true ≠ 数字 1);
  • 若解析阶段就能确定两个值类型不同(如 ["==", 1, "1"]),Mapbox 会直接抛出解析错误 (而非运行时返回 false)。

1.2 语法格式

== 表达式支持两种语法(官方定义):

javascript 复制代码
// 基础版:无本地化比较
["==", value1, value2]: boolean

// 进阶版:带本地化字符串比较(collator 参数)
["==", value1, value2, collator]: boolean

参数说明:

  • value1/value2:可以是字面量 (数字、字符串、布尔值)、属性引用["get", "属性名"])、其他表达式的返回值;
  • collator(可选):本地化配置对象,用于控制多语言场景下的字符串比较规则(如忽略大小写、重音)。

二、基础使用场景

== 表达式最核心的用途是要素过滤数据驱动样式,以下结合实战示例讲解。

前置准备

所有示例需先初始化 Mapbox 地图,并替换为自己的 Access Token(从 Mapbox 官网 注册获取):

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Mapbox == 表达式示例</title>
    <script src="https://api.mapbox.com/mapbox-gl-js/v3.4.0/mapbox-gl.js"></script>
    <link href="https://api.mapbox.com/mapbox-gl-js/v3.4.0/mapbox-gl.css" rel="stylesheet">
    <style>
        body { margin: 0; padding: 0; }
        #map { width: 100vw; height: 100vh; }
    </style>
</head>
<body>
<div id="map"></div>
<script>
mapboxgl.accessToken = '你的 Mapbox Access Token'; // 替换为自己的 Token
const map = new mapboxgl.Map({
    container: 'map',
    style: 'mapbox://styles/mapbox/streets-v12',
    center: [116.4074, 39.9042], // 北京坐标
    zoom: 14
});
</script>
</body>
</html>

2.1 场景1:过滤地图要素

通过 filter 属性结合 == 表达式,可精准控制图层显示/隐藏特定要素。

示例:自定义 POI 数据,仅显示类型为 restaurant(餐厅)的要素:

javascript 复制代码
map.on('load', () => {
    // 模拟 POI 地理数据
    const poiData = {
        type: 'FeatureCollection',
        features: [
            {
                type: 'Feature',
                geometry: { type: 'Point', coordinates: [116.4074, 39.9042] },
                properties: { type: 'restaurant', name: '北京饭店' }
            },
            {
                type: 'Feature',
                geometry: { type: 'Point', coordinates: [116.4084, 39.9052] },
                properties: { type: 'coffee', name: '星巴克' }
            },
            {
                type: 'Feature',
                geometry: { type: 'Point', coordinates: [116.4094, 39.9062] },
                properties: { type: 'park', name: '天安门广场' }
            }
        ]
    };

    // 1. 添加数据源
    map.addSource('poi-source', {
        type: 'geojson',
        data: poiData
    });

    // 2. 添加图层,仅显示餐厅(核心:== 过滤)
    map.addLayer({
        id: 'poi-restaurant',
        type: 'circle',
        source: 'poi-source',
        paint: {
            'circle-radius': 10,
            'circle-color': '#ff0000' // 红色标记餐厅
        },
        filter: ['==', ['get', 'type'], 'restaurant'] // 判定 type 属性是否等于 "restaurant"
    });
});

2.2 场景2:数据驱动样式

通过 == 结合 case 表达式,可根据要素属性值动态设置样式(如不同类型 POI 用不同颜色):

javascript 复制代码
// 替换上述示例的 addLayer 部分
map.addLayer({
    id: 'poi-all',
    type: 'circle',
    source: 'poi-source',
    paint: {
        'circle-radius': 10,
        'circle-color': [
            'case', // 多条件 == 判断
            ['==', ['get', 'type'], 'restaurant'], '#ff0000', // 餐厅:红
            ['==', ['get', 'type'], 'coffee'], '#00ff00',   // 咖啡:绿
            ['==', ['get', 'type'], 'park'], '#0000ff',     // 公园:蓝
            '#999999' // 默认:灰
        ]
    }
});

三、进阶用法:Collator 本地化字符串比较

默认的字符串比较是「严格匹配」(区分大小写、重音),但多语言场景下(如法语重音、中文拼音混合),需通过 collator 参数实现本地化比较

3.1 Collator 核心配置

配置项 类型 说明 默认值
locale 字符串/数组 语言标签(如 zh-CNen-USfr -
case-sensitive 布尔值 是否区分大小写 true
accent-sensitive 布尔值 是否区分重音(如 ée true

3.2 实战示例:多语言字符串匹配

示例1:法语场景忽略重音

匹配 café(带重音)和 cafe(无重音)为相等:

javascript 复制代码
map.on('load', () => {
    // 法语咖啡数据
    const frenchData = {
        type: 'FeatureCollection',
        features: [
            { type: 'Feature', geometry: { type: 'Point', coordinates: [2.3522, 48.8566] }, properties: { name: 'café' } },
            { type: 'Feature', geometry: { type: 'Point', coordinates: [2.3622, 48.8666] }, properties: { name: 'cafe' } }
        ]
    };

    map.addSource('french-source', { type: 'geojson', data: frenchData });

    // 图层过滤:忽略重音匹配 "café"
    map.addLayer({
        id: 'french-cafe',
        type: 'circle',
        source: 'french-source',
        paint: { 'circle-radius': 10, 'circle-color': '#00ffff' },
        filter: [
            '==',
            ['get', 'name'],
            'café',
            { locale: 'fr', accent-sensitive: false } // 法语 + 忽略重音
        ]
    });

    // 点击跳转至巴黎
    map.jumpTo({ center: [2.3522, 48.8566], zoom: 14 });
});
示例2:中文场景忽略大小写

匹配名称时忽略大小写(适用于中英文混合场景):

javascript 复制代码
filter: [
    '==',
    ['get', 'name'],
    '北京饭店',
    { locale: 'zh-CN', case-sensitive: false }
]

四、常见误区与注意事项

4.1 类型不一致导致判断失效

== 是严格类型比较,以下场景会返回 false 或直接报错:

javascript 复制代码
// 错误1:数字 id(123)≠ 字符串 "123"
["==", ["get", "id"], "123"] 

// 错误2:解析阶段类型已知不同,直接报错
["==", 1, "1"] 

// 正确做法:统一类型后比较
["==", ["to-string", ["get", "id"]], "123"] // 数字转字符串

4.2 Collator 仅对字符串有效

value1/value2 不是字符串(如数字、布尔值),collator 参数会被直接忽略,无任何效果。

4.3 语言标签格式错误

locale 需使用标准 BCP 47 语言标签(如 zh-CN 而非 zhen-US 而非 en),否则本地化规则可能不生效。

4.4 混淆 ===

  • ==:用于比较判断(如 filter、case 表达式);
  • =:用于赋值(如 layout/paint 属性的静态值)。

五、完整实战示例

整合过滤、数据驱动样式、本地化比较,实现交互性地图:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Mapbox == 表达式完整实战</title>
    <script src="https://api.mapbox.com/mapbox-gl-js/v3.4.0/mapbox-gl.js"></script>
    <link href="https://api.mapbox.com/mapbox-gl-js/v3.4.0/mapbox-gl.css" rel="stylesheet">
    <style>
        body { margin: 0; padding: 0; }
        #map { width: 100vw; height: 100vh; }
        .controls { position: absolute; top: 20px; left: 20px; background: white; padding: 10px; border-radius: 5px; }
    </style>
</head>
<body>
<div id="map"></div>
<div class="controls">
    <button id="showRestaurant">显示餐厅</button>
    <button id="showAll">显示所有POI</button>
    <button id="showFrenchCafe">显示法语咖啡</button>
</div>
<script>
mapboxgl.accessToken = '你的 Mapbox Access Token';
const map = new mapboxgl.Map({
    container: 'map',
    style: 'mapbox://styles/mapbox/streets-v12',
    center: [116.4074, 39.9042],
    zoom: 14
});

map.on('load', () => {
    // 1. 中文 POI 数据
    const poiData = {
        type: 'FeatureCollection',
        features: [
            { type: 'Feature', geometry: { type: 'Point', coordinates: [116.4074, 39.9042] }, properties: { type: 'restaurant', name: '北京饭店', id: 123 } },
            { type: 'Feature', geometry: { type: 'Point', coordinates: [116.4084, 39.9052] }, properties: { type: 'coffee', name: '星巴克', id: 456 } },
            { type: 'Feature', geometry: { type: 'Point', coordinates: [116.4094, 39.9062] }, properties: { type: 'park', name: '天安门广场', id: 789 } }
        ]
    };
    map.addSource('poi-source', { type: 'geojson', data: poiData });

    // 2. 法语咖啡数据
    const frenchData = {
        type: 'FeatureCollection',
        features: [
            { type: 'Feature', geometry: { type: 'Point', coordinates: [2.3522, 48.8566] }, properties: { name: 'café' } },
            { type: 'Feature', geometry: { type: 'Point', coordinates: [2.3622, 48.8666] }, properties: { name: 'cafe' } }
        ]
    };
    map.addSource('french-source', { type: 'geojson', data: frenchData });

    // 3. 中文 POI 图层(数据驱动样式)
    map.addLayer({
        id: 'poi-chinese',
        type: 'circle',
        source: 'poi-source',
        paint: {
            'circle-radius': 10,
            'circle-color': [
                'case',
                ['==', ['get', 'type'], 'restaurant'], '#ff0000',
                ['==', ['get', 'type'], 'coffee'], '#00ff00',
                ['==', ['get', 'type'], 'park'], '#0000ff',
                '#999'
            ]
        },
        filter: ['all'] // 默认显示所有
    });

    // 4. 法语咖啡图层(本地化比较)
    map.addLayer({
        id: 'poi-french',
        type: 'circle',
        source: 'french-source',
        paint: { 'circle-radius': 10, 'circle-color': '#00ffff' },
        filter: ['==', ['get', 'name'], 'café', { locale: 'fr', accent-sensitive: false }],
        layout: { visibility: 'none' } // 默认隐藏
    });

    // 5. 按钮交互
    document.getElementById('showRestaurant').onclick = () => {
        map.setFilter('poi-chinese', ['==', ['get', 'type'], 'restaurant']);
    };
    document.getElementById('showAll').onclick = () => {
        map.setFilter('poi-chinese', ['all']);
    };
    document.getElementById('showFrenchCafe').onclick = () => {
        map.setLayoutProperty('poi-french', 'visibility', 'visible');
        map.jumpTo({ center: [2.3522, 48.8566], zoom: 14 });
    };
});
</script>
</body>
</html>

六、总结

== 表达式是 Mapbox 表达式系统的基础核心,核心价值在于严格类型的相等判断,广泛应用于:

  • 图层要素过滤(filter 属性);
  • 数据驱动样式(case/match 表达式结合);
  • 本地化字符串匹配(collator 参数)。

使用时需重点注意类型一致性 ,避免解析错误或判断失效;针对多语言场景,合理配置 collator 可大幅提升地图的国际化适配能力。掌握 == 表达式后,可进一步学习 !=/</> 等比较表达式,实现更复杂的地图逻辑。

相关推荐
炸土豆2 小时前
防抖节流里的this传递
前端·javascript
林希_Rachel_傻希希2 小时前
手写Promise--教学版本
前端·javascript·面试
ETA82 小时前
`console.log([1,2,3].map(parseInt))` 深入理解 JavaScript 中的高阶函数与类型机制
前端·javascript
Java编程爱好者2 小时前
JUnit 5 中的 @ClassTemplate 实战指南
javascript
૮・ﻌ・4 小时前
Vue3:组合式API、Vue3.3新特性、Pinia
前端·javascript·vue3
前端不太难4 小时前
RN + TypeScript 项目越写越乱?如何规范架构?
前端·javascript·typescript
JS_GGbond4 小时前
用美食来理解JavaScript面向对象编程
开发语言·javascript·美食
苏打水com4 小时前
第十六篇:Day46-48 前端安全进阶——从“漏洞防范”到“安全体系”(对标职场“攻防实战”需求)
前端·javascript·css·vue.js·html