Sự kiện

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

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

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

JavaScript trong trình duyệt được định hướng theo 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 các sự kiện và dự kiến một chương trình sẽ lắng nghe các sự kiện thú vị. Có hai loại sự kiện:

  • Sự kiện của người dùng (chẳng hạn như sự kiện nhấp chuột) được truyền từ DOM đến API Maps JavaScript. Những 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 về việc thay đổi trạng thái MVC phản ánh các thay đổi trong các đối tượng API JavaScript của Maps và được đặt tên theo quy ước property_changed.

Mỗi đối tượng Maps JavaScript API 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 những sự kiện đó bằng cách gọi addListener() để đăng ký các trình xử lý sự kiện trên đối tượng đó.

Mẫu sau đây sẽ cho bạn thấy những sự kiện đượ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ề API Maps JavaScript. Sự kiện được liệt kê trong một phần riêng cho từng đố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 JavaScript Maps được thiết kế để phản hồi các sự kiện của người dùng, chẳng hạn như các sự kiện về chuột hoặc 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ể theo dõi:

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

Để biết danh sách đầy đủ, hãy xem lớp AdvancedMarkerElement. Những sự kiện này có thể trông giống như sự kiện DOM tiêu chuẩn, nhưng thực chất là một phần của API Maps JavaScript. 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 Maps JavaScript API 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 phải xử lý các đặc thù khác nhau trên nhiều trình duyệt. Những sự kiện này cũng thường truyền các đối số trong sự kiện cho biết một số trạng thái của giao diện người dùng (chẳng hạn như vị trí chuột).

Các thay đổi về 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 mà thuộc tính đó đã thay đổi. Ví dụ: API sẽ kích hoạt sự kiện zoom_changed trên bản đồ khi mức thu phóng của bản đồ thay đổi. Bạn có thể chặn những thay đổi về trạng thái này bằng cách gọi addListener() để đăng ký các trình xử lý sự kiện trên đối tượng.

Sự kiện người dùng và các thay đổi về trạng thái MVC có thể trông tương tự nhau, nhưng thường thì bạn nên xử lý những sự kiện này theo cách khác trong mã của mình. Ví dụ: các sự kiện MVC không truyền đối số trong sự kiện của chúng. Bạn nê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 đó nhận một sự kiện cần theo dõi và một hàm để gọi khi sự kiện được chỉ định xảy ra.

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

Mã sau đây kết hợp sự kiện người dùng với các sự kiện thay đổi trạng thái. Chúng tôi đính kèm một trình xử lý sự kiện vào một điểm đánh dấu thu phóng bản đồ khi được nhấp vào. Chúng tôi cũng thêm một trình xử lý sự kiện vào bản đồ cho các thay đổi đối với thuộc tính center và xoay bản đồ về điểm đánh dấu sau 3 giây kể từ 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 một 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 sẽ kích hoạt những sự kiện sau này một cách độc lập, nên getBounds() có thể không báo cáo các kết quả hữu ích cho đến khi khung nhìn được thay đổi một cách chính thức. Nếu bạn muốn getBounds() sau một sự kiện như vậy, hãy nhớ theo dõi sự kiện bounds_changed.

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

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 sau khi hoàn tất hành động. Để biết 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)

Đối số truy cập trong các sự kiện trên giao diện người dùng

Các sự kiệ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. Trình nghe sự kiện có thể truy cập vào đối số này, ghi chú trạng thái giao diện người dùng khi sự kiện xảy ra. Ví dụ: một sự kiện 'click' trên giao diện người dùng thường chuyển MouseEvent chứa thuộc tính latLng cho biết vị trí đã nhấp trên bản đồ. Xin lưu ý rằng hành vi này chỉ xảy ra với các sự kiện giao diện người dùng; các thay đổi về trạng thái MVC sẽ không truyền đối số trong các sự kiện.

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 giống như cách bạn truy cập vào các thuộc tính của một đối tượng. Ví dụ sau đây thêm một 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 lệnh đóng trong trình xử lý sự kiện

Khi thực thi trình nghe sự kiện, việc đính kèm cả dữ liệu riêng tư và cố định vào một đối tượng thường là một lợi thế. JavaScript không hỗ trợ dữ liệu thực thể "riêng tư", nhưng có hỗ trợ đóng cho phép các hàm bên trong truy cập vào các biến bên ngoài. Quy tắc đó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 đối tượng nơi 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 điệp bí mật cho một tập hợp các điểm đánh dấu. Khi nhấp vào mỗi điểm đánh dấu, một phần của mật khẩu sẽ hiển thị, nhưng phần đó không nằm trong đ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

Nhận 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. (Các sự kiện của người dùng sẽ truyền các đối số có thể kiểm tra được.) Nếu cần kiểm tra một thuộc tính khi trạng thái MVC thay đổi, bạn nên gọi rõ ràng phương thức getProperty() thích hợp trên đối tượng đó. Quá 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. Trạng thái này 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 thiết lập rõ ràng một thuộc tính trong trình xử lý sự kiện để phản hồi sự thay đổi trạng thái của thuộc tính cụ thể đó có thể dẫn đến hành vi khó dự đoán 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. Chẳng hạn, nếu bạn luôn đặt một thuộc tính trong trình xử lý sự kiện này, thì bạn có thể tạo ra một vòng lặp vô hạn.

Trong ví dụ bên dưới, chúng tôi 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 hiển thị 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

Nghe 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 của riêng nó, theo mô hình sự kiện trình duyệt cụ thể đang được sử dụng. Nếu bạn muốn ghi lại và phản hồi những sự kiện này, Maps JavaScript API sẽ cung cấp phương thức tĩnh addDomListener() để nghe 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 được trình duyệt hỗ trợ, bao gồm:

  • Thành viên theo hệ thống 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ên như document.getElementById("foo")

Xin lưu ý rằng addDomListener() chuyển sự kiện được chỉ định sang trình duyệt để 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ợ DOM cấp 2. (Để biết thêm thông tin về các sự kiện cấp DOM, hãy xem tài liệu tham khảo về Cấp độ DOM 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>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

    <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 Maps JavaScript, 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 xử lý sự kiện

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

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() và 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 của một loại sự kiện cụ thể cho một thực thể cụ thể, hãy gọi clearListeners(), chuyể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.

Theo dõi lỗi xác thực

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