Sự kiện

Chọn nền tảng: Android iOS JavaScript

Trang này mô tả các sự kiện giao diện người dùng và sự kiện lỗi mà bạn có thể theo dõi và xử lý bằng cách lập trình.

Sự kiện giao diện người dùng

JavaScript trong trình duyệt là được điều khiển bằng sự kiện, nghĩa là JavaScript phản hồi các lượt tương tác bằng cách tạo sự kiện và dự kiến một chương trình sẽ nghe các sự kiện thú vị. Có hai loại sự kiện:

  • Các sự kiện của người dùng (chẳng hạn như sự kiện chuột "nhấp") được truyền từ DOM đến Maps JavaScript API. Các sự kiện này tách biệt và khác với các sự kiện DOM chuẩn.
  • Thông báo thay đổi trạng thái MVC phản ánh các thay đổi trong đối tượng API Maps JavaScript và được đặt tên theo quy ước property_changed.

Mỗi đối tượng API JavaScript của Maps sẽ xuất một số sự kiện được đặt tên. Các chương trình quan tâm đến một số sự kiện nhất định sẽ đăng ký trình nghe sự kiện JavaScript cho các sự kiện đó và thực thi mã khi nhận được các sự kiện đó bằng cách gọi addListener() để đăng ký trình xử lý sự kiện trên đối tượng.

Mẫu sau đây sẽ cho bạn biết những sự kiện nào được google.maps.Map kích hoạt khi bạn tương tác với bản đồ.

Để xem danh sách đầy đủ các sự kiện, hãy tham khảo Tài liệu tham khảo về Maps JavaScript API. Các sự kiện được liệt kê trong một phần riêng biệt cho mỗi đối tượng chứa sự kiện.

Sự kiện giao diện người dùng

Một số đối tượng trong API Maps JavaScript được thiết kế để phản hồi các sự kiện của người dùng, chẳng hạn như sự kiện chuột hoặc sự kiện bàn phím. Ví dụ: sau đây là một số sự kiện người dùng mà đối tượng google.maps.marker.AdvancedMarkerElement có thể nghe:

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

Để xem danh sách đầy đủ, hãy xem lớp AdvancedMarkerElement. Các sự kiện này có thể trông giống như các sự kiện DOM tiêu chuẩn, nhưng thực sự là một phần của Maps JavaScript API. Vì các trình duyệt khác nhau triển khai các mô hình sự kiện DOM khác nhau, nên API JavaScript của Maps cung cấp các cơ chế này để theo dõi và phản hồi các sự kiện DOM mà không cần xử lý nhiều đặc điểm khác nhau trên nhiều trình duyệt. Các sự kiện này cũng thường truyền các đối số trong sự kiện ghi nhận một số trạng thái giao diện người dùng (chẳng hạn như vị trí con chuột).

Thay đổi trạng thái MVC

Các đối tượng MVC thường chứa trạng thái. Bất cứ khi nào thuộc tính của một đối tượng thay đổi, API JavaScript của Maps sẽ kích hoạt một sự kiện cho biết thuộc tính đó đã thay đổi. Ví dụ: API sẽ kích hoạt sự kiện zoom_changed trên bản đồ khi cấp thu phóng của bản đồ thay đổi. Bạn có thể chặn các thay đổi trạng thái này bằng cách gọi addListener() để đăng ký trình xử lý sự kiện trên đối tượng.

Sự kiện người dùng và thay đổi trạng thái MVC có thể trông giống nhau, nhưng thường thì bạn muốn xử lý các sự kiện này theo cách khác nhau trong mã. Ví dụ: các sự kiện MVC không truyền đối số trong sự kiện của chúng. Bạn sẽ muốn kiểm tra thuộc tính đã thay đổi khi trạng thái MVC thay đổi bằng cách gọi phương thức getProperty thích hợp trên đối tượng đó.

Xử lý sự kiện

Để đăng ký nhận thông báo sự kiện, hãy sử dụng trình xử lý sự kiện addListener(). Phương thức đó sẽ lấy một sự kiện để theo dõi và một hàm để gọi khi sự kiện đã chỉ định xảy ra.

Ví dụ: Sự kiện bản đồ và điểm đánh dấu

Mã sau đây kết hợp các sự kiện của người dùng với các sự kiện thay đổi trạng thái. Chúng ta đính kèm một trình xử lý sự kiện vào một điểm đánh dấu giúp thu phóng bản đồ khi được nhấp vào. Chúng ta cũng thêm một trình xử lý sự kiện vào bản đồ để thay đổi thuộc tính center và kéo bản đồ trở lại điểm đánh dấu sau 3 giây khi nhận được sự kiện center_changed:

TypeScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary;
  const { AdvancedMarkerElement } = await google.maps.importLibrary("marker") as google.maps.MarkerLibrary;

  const myLatlng = { lat: -25.363, lng: 131.044 };

  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 4,
      center: myLatlng,
      mapId: "DEMO_MAP_ID",
    }
  );

  const marker = new google.maps.marker.AdvancedMarkerElement({
    position: myLatlng,
    map,
    title: "Click to zoom",
  });

  map.addListener("center_changed", () => {
    // 3 seconds after the center of the map has changed, pan back to the
    // marker.
    window.setTimeout(() => {
      map.panTo(marker.position as google.maps.LatLng);
    }, 3000);
  });

  marker.addListener("click", () => {
    map.setZoom(8);
    map.setCenter(marker.position as google.maps.LatLng);
  });
}

initMap();

JavaScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps");
  const { AdvancedMarkerElement } = await google.maps.importLibrary("marker");
  const myLatlng = { lat: -25.363, lng: 131.044 };
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 4,
    center: myLatlng,
    mapId: "DEMO_MAP_ID",
  });
  const marker = new google.maps.marker.AdvancedMarkerElement({
    position: myLatlng,
    map,
    title: "Click to zoom",
  });

  map.addListener("center_changed", () => {
    // 3 seconds after the center of the map has changed, pan back to the
    // marker.
    window.setTimeout(() => {
      map.panTo(marker.position);
    }, 3000);
  });
  marker.addListener("click", () => {
    map.setZoom(8);
    map.setCenter(marker.position);
  });
}

initMap();
Xem ví dụ

Thử mẫu

Mẹo: Nếu bạn đang cố gắng phát hiện sự thay đổi trong khung nhìn, hãy nhớ sử dụng sự kiện bounds_changed cụ thể thay vì các sự kiện zoom_changedcenter_changed cấu thành. Vì API JavaScript của Maps kích hoạt các sự kiện sau này một cách độc lập, nên getBounds() có thể không báo cáo kết quả hữu ích cho đến khi khung nhìn thay đổi một cách hợp lệ. Nếu bạn muốn getBounds() sau một sự kiện như vậy, hãy nhớ nghe sự kiện bounds_changed.

Ví dụ: Sự kiện kéo và chỉnh sửa hình dạng

Khi một hình dạng được chỉnh sửa hoặc kéo, một sự kiện sẽ được kích hoạt khi hoàn tất hành động. Để xem danh sách các sự kiện và một số đoạn mã, hãy xem phần Hình dạng.

Xem ví dụ (rectangle-event.html)

Truy cập vào đối số trong sự kiện trên giao diện người dùng

Các sự kiện trên giao diện người dùng trong API JavaScript của Maps thường truyền một đối số sự kiện mà trình nghe sự kiện có thể truy cập, ghi lại trạng thái giao diện người dùng khi sự kiện xảy ra. Ví dụ: sự kiện 'click' trên giao diện người dùng thường truyền một MouseEvent chứa thuộc tính latLng biểu thị vị trí được nhấp trên bản đồ. Xin lưu ý rằng hành vi này chỉ dành riêng cho các sự kiện giao diện người dùng; các thay đổi trạng thái MVC không truyền đối số trong các sự kiện của chúng.

Bạn có thể truy cập vào các đối số của sự kiện trong trình nghe sự kiện theo cách tương tự như cách truy cập vào các thuộc tính của đối tượng. Ví dụ sau đây thêm trình nghe sự kiện cho bản đồ và tạo một điểm đánh dấu khi người dùng nhấp vào bản đồ tại vị trí được nhấp.

TypeScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary;
  const { AdvancedMarkerElement, PinElement } = await google.maps.importLibrary("marker") as google.maps.MarkerLibrary;

  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 4,
      center: { lat: -25.363882, lng: 131.044922 },
      mapId: "DEMO_MAP_ID",
    }
  );

  map.addListener("click", (e) => {
    placeMarkerAndPanTo(e.latLng, map);
  });
}

function placeMarkerAndPanTo(latLng: google.maps.LatLng, map: google.maps.Map) {
  new google.maps.marker.AdvancedMarkerElement({
    position: latLng,
    map: map,
  });
  map.panTo(latLng);
}

initMap();

JavaScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps");
  const { AdvancedMarkerElement, PinElement } = await google.maps.importLibrary(
    "marker",
  );
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 4,
    center: { lat: -25.363882, lng: 131.044922 },
    mapId: "DEMO_MAP_ID",
  });

  map.addListener("click", (e) => {
    placeMarkerAndPanTo(e.latLng, map);
  });
}

function placeMarkerAndPanTo(latLng, map) {
  new google.maps.marker.AdvancedMarkerElement({
    position: latLng,
    map: map,
  });
  map.panTo(latLng);
}

initMap();
Xem ví dụ

Thử mẫu

Sử dụng hàm đóng trong trình nghe sự kiện

Khi thực thi trình nghe sự kiện, bạn thường nên đính kèm cả dữ liệu riêng tư và dữ liệu ổn định vào một đối tượng. JavaScript không hỗ trợ dữ liệu thực thể "riêng tư", nhưng hỗ trợ hàm đóng cho phép các hàm bên trong truy cập vào các biến bên ngoài. Các hàm đóng rất hữu ích trong trình nghe sự kiện để truy cập vào các biến thường không được đính kèm vào các đối tượng mà sự kiện xảy ra.

Ví dụ sau đây sử dụng một hàm đóng trong trình nghe sự kiện để chỉ định một thông báo bí mật cho một tập hợp điểm đánh dấu. Khi nhấp vào từng điểm đánh dấu, một phần của thông điệp bí mật sẽ xuất hiện. Phần này không nằm trong chính điểm đánh dấu.

TypeScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary;
  const { AdvancedMarkerElement } = await google.maps.importLibrary("marker") as google.maps.MarkerLibrary;

  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 4,
      center: { lat: -25.363882, lng: 131.044922 },
      mapId: "DEMO_MAP_ID",
    }
  );

  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.
  map.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 (let i = 0; i < secretMessages.length; ++i) {
    const marker = new google.maps.marker.AdvancedMarkerElement({
      position: {
        lat: bounds.south + latSpan * Math.random(),
        lng: bounds.west + lngSpan * Math.random(),
      },
      map: map,
    });

    attachSecretMessage(marker, secretMessages[i]);
  }
}

// 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.
function attachSecretMessage(
  marker: google.maps.marker.AdvancedMarkerElement,
  secretMessage: string
) {
  const infowindow = new google.maps.InfoWindow({
    content: secretMessage,
  });

  marker.addListener("click", () => {
    infowindow.open(marker.map, marker);
  });
}

initMap();

JavaScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps");
  const { AdvancedMarkerElement } = await google.maps.importLibrary("marker");
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 4,
    center: { lat: -25.363882, lng: 131.044922 },
    mapId: "DEMO_MAP_ID",
  });
  const bounds = {
    north: -25.363882,
    south: -31.203405,
    east: 131.044922,
    west: 125.244141,
  };

  // Display the area between the location southWest and northEast.
  map.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 (let i = 0; i < secretMessages.length; ++i) {
    const marker = new google.maps.marker.AdvancedMarkerElement({
      position: {
        lat: bounds.south + latSpan * Math.random(),
        lng: bounds.west + lngSpan * Math.random(),
      },
      map: map,
    });

    attachSecretMessage(marker, secretMessages[i]);
  }
}

// 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.
function attachSecretMessage(marker, secretMessage) {
  const infowindow = new google.maps.InfoWindow({
    content: secretMessage,
  });

  marker.addListener("click", () => {
    infowindow.open(marker.map, marker);
  });
}

initMap();
Xem ví dụ

Thử mẫu

Lấy và đặt thuộc tính trong Trình xử lý sự kiện

Không có sự kiện thay đổi trạng thái MVC nào trong hệ thống sự kiện API JavaScript của Maps truyền đối số khi sự kiện được kích hoạt. (Sự kiện người dùng thực sự truyền các đối số có thể được kiểm tra.) Nếu cần kiểm tra một thuộc tính khi thay đổi trạng thái MVC, bạn nên gọi rõ ràng phương thức getProperty() thích hợp trên đối tượng đó. Quy trình kiểm tra này sẽ luôn truy xuất trạng thái hiện tại của đối tượng MVC, có thể không phải là trạng thái khi sự kiện được kích hoạt lần đầu tiên.

Lưu ý: Việc đặt một thuộc tính một cách rõ ràng trong trình xử lý sự kiện phản hồi thay đổi trạng thái của thuộc tính cụ thể đó có thể tạo ra hành vi không thể đoán trước và/hoặc không mong muốn. Ví dụ: việc thiết lập một thuộc tính như vậy sẽ kích hoạt một sự kiện mới và nếu luôn thiết lập một thuộc tính trong trình xử lý sự kiện này, thì bạn có thể tạo một vòng lặp vô hạn.

Trong ví dụ bên dưới, chúng ta thiết lập một trình xử lý sự kiện để phản hồi các sự kiện thu phóng bằng cách hiển thị một cửa sổ thông tin cho thấy cấp độ đó.

TypeScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary;

  const originalMapCenter = new google.maps.LatLng(-25.363882, 131.044922);
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 4,
      center: originalMapCenter,
    }
  );

  const infowindow = new google.maps.InfoWindow({
    content: "Change the zoom level",
    position: originalMapCenter,
  });

  infowindow.open(map);

  map.addListener("zoom_changed", () => {
    infowindow.setContent("Zoom: " + map.getZoom()!);
  });
}

initMap();

JavaScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps");
  const originalMapCenter = new google.maps.LatLng(-25.363882, 131.044922);
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 4,
    center: originalMapCenter,
  });
  const infowindow = new google.maps.InfoWindow({
    content: "Change the zoom level",
    position: originalMapCenter,
  });

  infowindow.open(map);
  map.addListener("zoom_changed", () => {
    infowindow.setContent("Zoom: " + map.getZoom());
  });
}

initMap();
Xem ví dụ

Thử mẫu

Theo dõi sự kiện DOM

Mô hình sự kiện API JavaScript của Maps tạo và quản lý các sự kiện tuỳ chỉnh riêng. Tuy nhiên, DOM (Mô hình đối tượng tài liệu) trong trình duyệt cũng tạo và gửi các sự kiện riêng, theo mô hình sự kiện trình duyệt cụ thể đang sử dụng. Nếu bạn muốn ghi lại và phản hồi các sự kiện này, Maps JavaScript API sẽ cung cấp phương thức tĩnh addDomListener() để theo dõi và liên kết với các sự kiện DOM.

Phương thức tiện lợi này có chữ ký như sau:

addDomListener(instance:Object, eventName:string, handler:Function)

trong đó instance có thể là bất kỳ phần tử DOM nào mà trình duyệt hỗ trợ, bao gồm:

  • Các thành phần phân cấp của DOM, chẳng hạn như window hoặc document.body.myform
  • Các phần tử được đặt tên như document.getElementById("foo")

Xin lưu ý rằng addDomListener() sẽ chuyển sự kiện được chỉ định đến trình duyệt. Trình duyệt sẽ xử lý sự kiện đó theo mô hình sự kiện DOM của trình duyệt; tuy nhiên, hầu hết các trình duyệt hiện đại đều hỗ trợ ít nhất là DOM cấp 2. (Để biết thêm thông tin về sự kiện cấp DOM, hãy xem tài liệu tham khảo về Cấp DOM của Mozilla.)

TypeScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary;

  const mapDiv = document.getElementById("map") as HTMLElement;
  const map = new google.maps.Map(mapDiv, {
    zoom: 8,
    center: new google.maps.LatLng(-34.397, 150.644),
  });

  // We add a DOM event here to show an alert if the DIV containing the
  // map is clicked.
  google.maps.event.addDomListener(mapDiv, "click", () => {
    window.alert("Map was clicked!");
  });
}

initMap();

JavaScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps");
  const mapDiv = document.getElementById("map");
  const map = new google.maps.Map(mapDiv, {
    zoom: 8,
    center: new google.maps.LatLng(-34.397, 150.644),
  });

  // We add a DOM event here to show an alert if the DIV containing the
  // map is clicked.
  google.maps.event.addDomListener(mapDiv, "click", () => {
    window.alert("Map was clicked!");
  });
}

initMap();

HTML

<html>
  <head>
    <title>Listening to DOM Events</title>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="map"></div>

    <!-- prettier-ignore -->
    <script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})
        ({key: "AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg", v: "weekly"});</script>
  </body>
</html>
Xem ví dụ

Thử mẫu

Mặc dù mã trên là mã API JavaScript của Maps, nhưng phương thức addDomListener() liên kết với đối tượng window của trình duyệt và cho phép API giao tiếp với các đối tượng bên ngoài miền thông thường của API.

Xoá trình nghe sự kiện

Để xoá một trình nghe sự kiện cụ thể, bạn phải gán trình nghe đó cho một biến. Sau đó, bạn có thể gọi removeListener(), truyền tên biến mà trình nghe được chỉ định.

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

google.maps.event.removeListener(listener1);

Để xoá tất cả trình nghe khỏi một thực thể cụ thể, hãy gọi clearInstanceListeners(), truyền tên thực thể.

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

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

Để xoá tất cả trình nghe cho một loại sự kiện cụ thể cho một thực thể cụ thể, hãy gọi clearListeners(), truyền tên thực thể và tên sự kiện.

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');

Để biết thêm thông tin, hãy tham khảo tài liệu tham khảo về không gian tên google.maps.event.

Nghe lỗi xác thực

Nếu muốn phát hiện lỗi xác thực theo phương thức lập trình (ví dụ: để tự động gửi một beacon), bạn có thể chuẩn bị một hàm gọi lại. Nếu bạn xác định hàm toàn cục sau, hàm này sẽ được gọi khi quá trình xác thực không thành công. function gm_authFailure() { /* Code */ };