活动

请选择平台: Android iOS JavaScript

本页面介绍了可通过程序化方式监听和处理的界面事件及错误事件。

界面事件

浏览器中的 JavaScript 是由事件驱动的,这意味着 JavaScript 会通过生成事件来响应互动,并预期程序会监听其关注的事件。事件分为两种类型:

  • 用户事件(例如“点击”鼠标事件)会从 DOM 传播到 Maps JavaScript API。这些事件与标准的 DOM 事件相互独立且截然不同。
  • MVC 状态变化通知则反映了 Maps JavaScript API 对象中的变化,并按照 property_changed 规范命名。

每个 Maps JavaScript API 对象均可导出大量已命名的事件。关注某些事件的程序会为这些事件注册 JavaScript 事件监听器,并在收到这些事件时通过调用 addListener() 在该对象中注册事件处理脚本来执行相应代码。

以下示例将展示当您与地图互动时 google.maps.Map 会触发哪些事件。

如需查看完整的事件列表,请参阅 Maps JavaScript API 参考文档。对于包含事件的各个对象,事件会在单独的部分中列出。

界面事件

Maps JavaScript API 中的一些对象旨在响应用户事件,例如鼠标事件或键盘事件。例如,下面是 google.maps.marker.AdvancedMarkerElement 对象可以监听的一些用户事件:

  • 'click'
  • 'drag'
  • 'dragend'
  • 'dragstart'
  • 'gmp-click'

如需查看完整列表,请参阅 AdvancedMarkerElement 类。这些事件可能看起来像标准 DOM 事件,但实际上却是 Maps JavaScript API 的一部分。由于不同的浏览器实现的 DOM 事件模型不同,因此 Maps JavaScript API 提供这些机制来监听和响应 DOM 事件,这样就无需处理各种跨浏览器特性。这些事件通常还会在表示某种界面状态(例如鼠标位置)的事件中传递参数。

MVC 状态更改

MVC 对象通常都包含状态。每当一个对象的属性发生变化时,Maps JavaScript API 就会触发一个事件来表示该属性已更改。例如,当地图的缩放级别发生变化后,API 就会在该地图上触发 zoom_changed 事件。您也可以通过调用 addListener() 在相应对象中注册事件处理脚本来截取这些状态变化。

用户事件与 MVC 状态变化可能看起来相似,但您应该在代码中对它们进行不同的处理。例如,MVC 事件不在其事件中传递参数。调用该对象中的相应 getProperty 方法来检查在 MVC 状态变化时发生更改的属性。

处理事件

若要注册接收事件通知,请使用 addListener() 事件处理脚本。该方法使用的参数是:一个要监听的事件,以及在指定的事件发生时要调用的一个函数。

示例:地图和标记事件

以下代码组合使用了用户事件和状态变化事件。此示例为在被点击后会对地图执行缩放操作的标记附加了事件处理脚本。此外,它还会为地图附加一个事件处理脚本来处理对 center 属性的更改,并在收到 center_changed 事件 3 秒后将地图平移回标记处。

TypeScript

async function init() {
    // Request needed libraries.
    const [{ AdvancedMarkerElement }, { LatLng }] = await Promise.all([
        google.maps.importLibrary('marker'),
        google.maps.importLibrary('core'),
        google.maps.importLibrary('maps'),
    ]);

    // Retrieve the map element.
    const mapElement = document.querySelector('gmp-map')!;

    // Get the inner map from the map element.
    const innerMap = mapElement.innerMap;

    const originalPosition = new LatLng(mapElement.center!);

    const marker = new AdvancedMarkerElement({
        position: originalPosition,
        map: innerMap,
        title: 'Click to zoom',
        gmpClickable: true,
    });

    innerMap.addListener('center_changed', () => {
        // 3 seconds after the center of the map has changed,
        // pan back to the marker.
        window.setTimeout(() => {
            innerMap.panTo(originalPosition);
        }, 3000);
    });

    // Zoom in when the marker is clicked.
    marker.addEventListener('gmp-click', () => {
        innerMap.setZoom(8);
        innerMap.setCenter(originalPosition);
    });
}

void init();

JavaScript

async function init() {
    // Request needed libraries.
    const [{ AdvancedMarkerElement }, { LatLng }] = await Promise.all([
        google.maps.importLibrary('marker'),
        google.maps.importLibrary('core'),
        google.maps.importLibrary('maps'),
    ]);

    // Retrieve the map element.
    const mapElement = document.querySelector('gmp-map');

    // Get the inner map from the map element.
    const innerMap = mapElement.innerMap;

    const originalPosition = new LatLng(mapElement.center);

    const marker = new AdvancedMarkerElement({
        position: originalPosition,
        map: innerMap,
        title: 'Click to zoom',
        gmpClickable: true,
    });

    innerMap.addListener('center_changed', () => {
        // 3 seconds after the center of the map has changed,
        // pan back to the marker.
        window.setTimeout(() => {
            innerMap.panTo(originalPosition);
        }, 3000);
    });

    // Zoom in when the marker is clicked.
    marker.addEventListener('gmp-click', () => {
        innerMap.setZoom(8);
        innerMap.setCenter(originalPosition);
    });
}

void init();
查看示例

试用示例

提示:如果您要尝试检测视口中的变化,请务必使用特定的 bounds_changed 事件,而非其组成部分 zoom_changedcenter_changed 事件。由于 Maps JavaScript API 会单独触发后面的两个事件,因此,只有在系统强制更改了视口后,getBounds() 才会报告实用结果。如果您想在此类事件之后执行 getBounds(),请务必改为监听 bounds_changed 事件。

示例:形状修改和拖动事件

修改或拖动形状时,系统会在操作完成后触发相应的事件。如需查看事件列表和一些代码段,请参阅形状

查看示例 (rectangle-event.html)

访问界面事件中的参数

Maps JavaScript API 中的界面事件通常会传递事件参数(可通过事件监听器访问),这些参数表示事件发生时的界面状态。例如,界面 'click' 事件通常会传递一个包含 latLng 属性的 MouseEvent,该属性指示了地图上的点击位置。请注意,这是界面事件所独有的行为;MVC 状态更改不会在其事件中传递参数。

您可以采用访问对象属性的方式访问事件监听器中的事件参数。下例介绍了如何为地图添加事件监听器,以及如何在用户点击地图时在所点击的位置创建标记。

TypeScript

async function init() {
    // Request needed libraries.
    const [{ AdvancedMarkerElement }] = await Promise.all([
        google.maps.importLibrary('marker'),
        google.maps.importLibrary('maps'),
    ]);

    const mapElement = document.querySelector('gmp-map')!;
    const innerMap = mapElement.innerMap;

    innerMap.addListener('click', (event: google.maps.MapMouseEvent) => {
        if (!event.latLng) return;
        new AdvancedMarkerElement({
            position: event.latLng,
            map: innerMap,
        });
        innerMap.panTo(event.latLng);
    });
}

void init();

JavaScript

async function init() {
    // Request needed libraries.
    const [{ AdvancedMarkerElement }] = await Promise.all([
        google.maps.importLibrary('marker'),
        google.maps.importLibrary('maps'),
    ]);

    const mapElement = document.querySelector('gmp-map');
    const innerMap = mapElement.innerMap;

    innerMap.addListener('click', (event) => {
        if (!event.latLng) return;
        new AdvancedMarkerElement({
            position: event.latLng,
            map: innerMap,
        });
        innerMap.panTo(event.latLng);
    });
}

void init();
查看示例

试用示例

在事件监听器中使用闭包

在执行事件监听器时,将私有数据和持久性数据附加到对象通常是有好处的。JavaScript 不支持“私有”实例数据,但支持允许内部函数访问外部变量的闭包。在事件监听器中,闭包非常适用于访问通常未附加到发生事件的对象中的变量。

以下示例在事件监听器中使用了函数闭包将私密消息分配给一组标记。点击每个标记将会看到私密消息的一部分,但标记本身并不包含该消息。

TypeScript

async function init() {
    // Request needed libraries.
    const [{ AdvancedMarkerElement }] = await Promise.all([
        google.maps.importLibrary('marker'),
        google.maps.importLibrary('maps'),
    ]);

    const mapElement = document.querySelector('gmp-map')!;
    const innerMap = mapElement.innerMap;

    const bounds: google.maps.LatLngBoundsLiteral = {
        north: -25.363882,
        south: -31.203405,
        east: 131.044922,
        west: 125.244141,
    };

    // Display the area between the location southWest and northEast.
    innerMap.fitBounds(bounds);

    // Add 5 markers to map at random locations.
    // For each of these markers, give them a title with their index, and when
    // they are clicked they should open an infoWindow with text from a secret
    // message.
    const secretMessages = ['This', 'is', 'the', 'secret', 'message'];
    const lngSpan = bounds.east - bounds.west;
    const latSpan = bounds.north - bounds.south;

    for (const secretMessage of secretMessages) {
        const marker = new AdvancedMarkerElement({
            position: {
                lat: bounds.south + latSpan * Math.random(),
                lng: bounds.west + lngSpan * Math.random(),
            },
            map: innerMap,
        });

        void attachSecretMessage(marker, secretMessage);
    }
}

// Attaches an info window to a marker with the provided message. When the
// marker is clicked, the info window will open with the secret message.
async function attachSecretMessage(
    marker: google.maps.marker.AdvancedMarkerElement,
    secretMessage: string
) {
    const { InfoWindow } = await google.maps.importLibrary('maps');

    const infoWindow = new InfoWindow({
        content: secretMessage,
    });

    marker.addListener('gmp-click', () => {
        infoWindow.open(marker.map, marker);
    });
}

void init();

JavaScript

async function init() {
    // Request needed libraries.
    const [{ AdvancedMarkerElement }] = await Promise.all([
        google.maps.importLibrary('marker'),
        google.maps.importLibrary('maps'),
    ]);

    const mapElement = document.querySelector('gmp-map');
    const innerMap = mapElement.innerMap;

    const bounds = {
        north: -25.363882,
        south: -31.203405,
        east: 131.044922,
        west: 125.244141,
    };

    // Display the area between the location southWest and northEast.
    innerMap.fitBounds(bounds);

    // Add 5 markers to map at random locations.
    // For each of these markers, give them a title with their index, and when
    // they are clicked they should open an infoWindow with text from a secret
    // message.
    const secretMessages = ['This', 'is', 'the', 'secret', 'message'];
    const lngSpan = bounds.east - bounds.west;
    const latSpan = bounds.north - bounds.south;

    for (const secretMessage of secretMessages) {
        const marker = new AdvancedMarkerElement({
            position: {
                lat: bounds.south + latSpan * Math.random(),
                lng: bounds.west + lngSpan * Math.random(),
            },
            map: innerMap,
        });

        void attachSecretMessage(marker, secretMessage);
    }
}

// Attaches an info window to a marker with the provided message. When the
// marker is clicked, the info window will open with the secret message.
async function attachSecretMessage(marker, secretMessage) {
    const { InfoWindow } = await google.maps.importLibrary('maps');

    const infoWindow = new InfoWindow({
        content: secretMessage,
    });

    marker.addListener('gmp-click', () => {
        infoWindow.open(marker.map, marker);
    });
}

void init();
查看示例

试用示例

获取和设置事件处理脚本中的属性

事件触发时,Maps JavaScript API 事件系统中的所有 MVC 状态更改事件都不会传递参数(用户事件确实会传递参数,这是可以检查到的)。如果您需要检查有关 MVC 状态更改的属性,应针对该对象显式调用相应的 getProperty() 方法。在此检查过程中,系统会始终检索 MVC 对象的当前状态,但该状态可能不是事件首次触发时的状态。

注意:如果在事件处理脚本中显式设置一个属性,而该事件处理脚本会响应这个特定属性的状态更改,则可能会产生不可预期和/或不必要的行为。例如,设置此类属性会触发新的事件,如果您总是在此事件处理脚本中设置属性,最终可能会出现无限循环的情况。

以下示例展示了如何设置一个事件处理脚本来响应缩放事件,具体方法是弹出显示相应缩放级别的信息窗口。

TypeScript

async function init() {
    // Request needed libraries.
    const { InfoWindow } = await google.maps.importLibrary('maps');

    const mapElement = document.querySelector('gmp-map')!;
    const innerMap = mapElement.innerMap;

    const infoWindow = new InfoWindow({
        content: 'Change the zoom level',
        position: mapElement.center,
    });

    infoWindow.open(innerMap);

    innerMap.addListener('zoom_changed', () => {
        infoWindow.setContent('Zoom: ' + innerMap.getZoom()!);
    });
}

void init();

JavaScript

async function init() {
    // Request needed libraries.
    const { InfoWindow } = await google.maps.importLibrary('maps');

    const mapElement = document.querySelector('gmp-map');
    const innerMap = mapElement.innerMap;

    const infoWindow = new InfoWindow({
        content: 'Change the zoom level',
        position: mapElement.center,
    });

    infoWindow.open(innerMap);

    innerMap.addListener('zoom_changed', () => {
        infoWindow.setContent('Zoom: ' + innerMap.getZoom());
    });
}

void init();
查看示例

试用示例

移除事件监听器

若要移除特定事件监听器,必须已经将其分配给一个变量。然后,您可以调用 removeListener(),并传入已分配监听器的变量名称。

var listener1 = marker.addListener('click', aFunction);

google.maps.event.removeListener(listener1);

若要从特定实例中移除所有监听器,请调用 clearInstanceListeners() 并向其传递实例名称。

var listener1 = marker.addListener('click', aFunction);
var listener2 = marker.addListener('mouseover', bFunction);

// Remove listener1 and listener2 from marker instance.
google.maps.event.clearInstanceListeners(marker);

若要从特定实例中移除针对特定事件类型的所有监听器,请调用 clearListeners(),并传入实例名称和事件名称。

marker.addListener('click', aFunction);
marker.addListener('click', bFunction);
marker.addListener('click', cFunction);

// Remove all click listeners from marker instance.
google.maps.event.clearListeners(marker, 'click');

如需了解详情,请参阅 google.maps.event 命名空间的参考文档。

监听身份验证错误

如果您想通过程序化方式检测身份验证失败的情况(例如自动发送信标),可以准备一个回调函数。如果定义了以下全局函数,系统将在身份验证失败时调用它。 function gm_authFailure() { /* Code */ };

在 TypeScript 中,可能需要将该函数添加到全局范围,如下所示:

// Define the callback function.
window.gm_authFailure = () => {
  console.error("Google Maps failed to authenticate.");
  /* Code */
};

// Add gm_authFailure to the global scope.
declare global {
  interface Window {
    gm_authFailure?: () => void;
  }
}
export {};