Phoenix LiveView에서 구글 맵을 사용하는 방법

이 글은 우리 최고경영자 겸 개발자가 썼다
안녕하십니까, 친애하는 독자🖖🏽, 당신이 이 어려운 시기에 안전하고 건강하기를 바랍니다.
지난 3년 동안 우리는 few projectsforPhoenix Framework를 사용하여 Elixir를 개발했다.LiveView이 발표되자 우리는 지체없이 그것을 사용하고 싶었다.
우리는 LiveView를 사용하는 플랫폼을 구축해 왔다. 왜냐하면 우리는 우리의 일부 기능이 실시간으로 업데이트할 수 있는 인터페이스를 사용할 수 있기를 희망하기 때문이다.예를 들어 우리는 플랫폼 관리자가 지도에서 응용 프로그램 사용자가 특정한 곳에서 보고한 목격 사건을 볼 수 있기를 바란다.실시간 지도라고 합시다.

기술 이해🤓


이 문제를 깊이 연구하기 전에 우리가 사용하고 있는 기술을 먼저 봅시다.우리는 네가 불로장생약과 봉황에 익숙하다고 가정한다.

랴오닝 성


기준 documentation:

LiveView provides rich, real-time user experiences with server-rendered HTML.
The LiveView programming model is declarative: instead of saying “once event X happens, change Y on the page”, events in LiveView are regular messages which may cause changes to its state.
Once the state changes, LiveView will re-render the relevant parts of its HTML template and push it to the browser, (…) LiveView does the hard work of tracking changes and sending the relevant diffs to the browser.


Google Maps for javascript


다시 파일에 따라 다음을 수행합니다.

The Maps JavaScript API lets you customise maps with your own content and imagery for display on web pages and mobile devices.


시드니 중심의 지도를 표시하는 페이지를 시작하고 실행할 수 있도록 하려면 다음과 같이 하십시오.
<!DOCTYPE html>
<html>
  <head>
    <title>Simple Map</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
    <script
      src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap&libraries=&v=weekly"
      defer
    ></script>
    <style type="text/css">
      /* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
      #map {
        height: 100%;
      }
      /* Optional: Makes the sample page fill the window. */
      html,
      body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
    <script>
      (function(exports) {
        "use strict";

        function initMap() {
          exports.map = new google.maps.Map(document.getElementById("map"), {
            center: {
              lat: -34.397,
              lng: 150.644
            },
            zoom: 8
          });
        }

        exports.initMap = initMap;
      })((this.window = this.window || {}));
    </script>
  </head>
  <body>
    <div id="map"></div>
  </body>
</html>

도전하다🤔


실시간 지도에서 우리가 필요로 하는 것은 정적 지도를 표시하는 것만은 아니다.우리는 사용자가 목격한 사건을 보고하는 위치를 표시하는 지도도 필요하다.
또한 태그는 사용자 보고 후 바로 표시해야 합니다.🤯. "우리는 LiveView가 있기 때문에 쉬울 거야."라고 생각할 수도 있다.우리끼리 해볼게요.

솔루션💡


우리는 당신이 그것을 사용하고 문장의 특정 부분으로 옮겨서 자신이 견본을 만들지 않도록 할 수 있는 repository 을 준비했다.

a) 초기 설정


initial setup에는 자동으로 생성되는 LiveView 항목이 포함되어 있습니다.
우리는 프로젝트를 생성할 때 --no-ecto 옵션을 사용하기로 선택했습니다. 왜냐하면 우리는 필요하지 않기 때문입니다. Ecto

b) LiveView 페이지에 맵 추가


우리simply added 상단에서 기술한 HTML+CSS+JS 코드는 구글 지도를 표시할 것이다.
만약 당신이 그것이 일하는 것을 보고 싶다면, 당신의 here 을 프로젝트에 추가하는 것을 잊지 마세요.
현재 이 항목 mix phx.server 을 실행하면 지도가 잠시 표시되었다가 바로 사라집니다.지도는 어디로 갔습니까?🤔
Google Maps API key

c) 맵을 LiveView 페이지에 유지


우리의 문제를 이해하기 위해서는 먼저 알아야 한다 :

A LiveView begins as a regular HTTP request and HTML response, and then upgrades to a stateful view on client connect, guaranteeing a regular HTML page even if JavaScript is disabled. Any time a stateful view changes or updates its socket assigns, it is automatically re-rendered and the updates are pushed to the client.
(…)
After rendering the static page, LiveView connects from the client to the server where stateful views are spawned to push rendered updates to the browser, and receive client events via phx- bindings. Just like the first rendering, mount/3 is invoked with params, session, and socket state, where mount assigns values for rendering.


이 주제에 대해 자세히 알고 싶으면 LiveView 내부가 어떻게 작동하는지 잘 설명해 주십시오.
우리의 사례에서 발생한 것은 다음과 같다.
  • 초기 페이지 표시
  • 구글맵스 스크립트 불러오기 및 호출initMap 함수
  • initMap 함수 초기화 지도.이로써 div가 있는 id="map" 는 지도
  • 를 표시하는 모든 필수 표시를 채웠다
  • 동시에 이 웹 페이지는 서버의 LiveView에 연결됩니다.문서에서 말한 바와 같이 "처음 렌더링한 것처럼 life-cycle of a LiveViewparams,session,socket 상태를 호출합니다. 그 중에서 mount는 렌더링에 값을 부여합니다."
  • 브라우저 끝의 Live View(JavaScript), 그리고 HTML이 무엇인지, 현재가 무엇인지 구분
  • 과, 서프라이즈, 서프라이즈🎁 ! 현재 HTML에는 맵 태그가 포함되어 있습니다. 페이지가 처음 나타날 때 맵 태그가 존재하지 않으며 LiveView에서 추가되지 않습니다.따라서 클라이언트의 LiveView에서 이러한 변경 사항을 복구했습니다.😭
  • LiveView 작성자는 다음과 같은 사례를 고려하여 다음과 같은 가능성을 제공합니다.

    A container can be marked with phx-update, allowing the DOM patch operations to avoid updating or removing portions of the LiveView, or to append or prepend the updates rather than replacing the existing contents. This is useful for client-side interop with existing libraries that do their own DOM operations.
    (…)
    The “ignore” behaviour is frequently used when you need to integrate with another JS library.


    실제로 mount/3aphx-update="ignore"는 지도 용기에 가서 LiveView에 이 용기의 내용을 우리가 제어한다고 통지합니다.
    이제 다음 결과가 표시됩니다.
    control the patching mechanism

    저희는 추가만 하면 돼요. d) 서버에서 요소를 맵에 동적으로 전송하는 방법


    마지막 단계만 부족합니다. 사용자가 목격 사건을 보고하면 바로 표시해야 합니다.
    사용자 보고서의 목격을 모의하기 위해 데이터베이스에 저장한 후 다른 사용자에게 방송하고 무작위로 하나를 생성한다.이 단추는 사용자가 실제로 목격한 사건을 보고한 것처럼 이벤트를 서버에 보냅니다.그리고 LiveView는 브라우저에 새로운 발견을 알립니다.
    최종 결과는 다음과 같다.

    요약하면 중요한 부분we added a button은 다음과 같습니다.
    d, 1) 만들기
    Hooks.MapSightingsHandler = {
      mounted() {
        const handleNewSightingFunction = ({ sighting }) => {
          var markerPosition = { lat: sighting.latitude, lng: sighting.longitude };
    
          const marker = new google.maps.Marker({
            position: markerPosition,
            animation: google.maps.Animation.DROP,
          });
    
          // To add the marker to the map, call setMap();
          marker.setMap(window.map);
        };
    
        // handle new sightings as they show up
        this.handleEvent('new_sighting', handleNewSightingFunction);
      },
    };
    
    let csrfToken = document
      .querySelector("meta[name='csrf-token']")
      .getAttribute('content');
    let liveSocket = new LiveSocket('/live', Socket, {
      hooks: Hooks,
      params: { _csrf_token: csrfToken },
    });
    
    우리는 연결의 새로운 handleEvent/pushEvent 기능을 이용하고 있다.이 메서드는 what we did부터 사용할 수 있습니다.

    The hook can push events to the LiveView by using the pushEvent function and receive a reply from the server via a {:reply, map, socket} return value. The reply payload will be passed to the optional pushEvent response callback.
    Communication with the hook from the server can be done by reading data attributes on the hook element, or by using push_event on the server and handleEvent on the client.


    d, 2) 지도 표시에 자바스크립트 연결 사용하기
    새로 만든 갈고리를 사용하거나 연결하려면 다음과 같이 하십시오.
    <section class="row" phx-update="ignore" phx-hook="MapSightingsHandler">
    
    요소가 로드되고 LiveView Genserver가 new_sighting라는 이벤트를 푸시하면 handleEvent 리셋이 발생하고 맵 태그가 추가됩니다.
    d, 3) LiveView Genserver를 업데이트하여 이벤트/목격 메시지 전송
    서버 섹션에서 phx-click=”add_random_sighting” 모의 목적으로 javascript hook 에 전송된 이벤트를 통해 랜덤 조준을 만드는 명령을 실제 수신하고 이벤트를 브라우저의 소켓으로 전송합니다.
    defmodule LiveViewGoogleMapsWeb.PageLive do
      use LiveViewGoogleMapsWeb, :live_view
    
      @impl true
      def mount(_params, _session, socket) do
        {:ok, socket}
      end
    
      @impl true
      def handle_event("add_random_sighting", _params, socket) do
        random_sighting = generate_random_sighting()
    
        # inform the browser / client that there is a new sighting
        {:noreply, push_event(socket, "new_sighting", %{sighting: random_sighting})}
      end
    
      defp generate_random_sighting() do
        # https://developers.google.com/maps/documentation/javascript/reference/coordinates
        # Latitude ranges between -90 and 90 degrees, inclusive.
        # Longitude ranges between -180 and 180 degrees, inclusive
        %{
          latitude: Enum.random(-90..90),
          longitude: Enum.random(-180..180)
        }
      end
    end
    
    모든 LiveView version 0.14 코드를 적용하고 실행하면 지도에서 무작위로 표시를 만들 수 있습니다.

    버튼 개량하다👆🏾


    문장을 주제에 집중하기 위해서 우리는 어쩔 수 없이 지름길로 질러야 한다.
    우리는 다른 글에서 다음과 같은 몇 가지를 토론할 수 있다.
    어떻게 지도상에 이미 저장된 광경을 표시합니까?
    누군가는 "이것은 매우 쉬운 것 같다. 처음mount에 우리는 pushEvent을 발송/안배할 수 있다!"고 생각할 수도 있다.
    문제는 구글 지도 스크립트가 우리가 pushEvent 라고 부르기 전이나 이후에 나타날 수 있다는 것이다.이것은 스크립트를 나중에 불러오면 표시된 handleEvent 함수를 만들 때 지도에 접근할 수 없기 때문에 실패하고 표시를 과장하지 않는다는 것을 의미합니다!
    올바른 저장 및 방송 목격자 생성, 업데이트 및 삭제?
    우리는 추가된 목격 정보만 처리하고 데이터베이스에 저장하지 않으며 모든 사용자에게 방송하지 않는다.
    어떻게 새로운 목격 정보를 수신하여 데이터베이스에 저장한 후에 모든 사용자에게 이 정보를 방송합니까?
    어떻게 코드를 더욱 잘 구성합니까?
    본고의 중점을 유지하기 위해 우리는 가장 짧은 해결 방안을 찾고 기술 자체에 중점을 두기로 다시 한 번 결정했다.
    예를 들어 우리는 map 대상을 window에 직접 추가하여 갈고리에 노출시킨다.생산 중에 이렇게 하지 마세요!
    위에서 언급한 문제를 마음대로 해결하고 제안된 해결 방안을 사용하여pull 요청을 실행하십시오.우리도 너에게 배워서 매우 기쁘다!👩🏾‍🎓

    변화 결론


    LiveView의 솔루션과 성과에 매우 만족합니다.다른 어떤 도구와 마찬가지로, 그것도 자신의 가 있다는 것을 기억하십시오. 그것을 사용하기 전에, 당신은 우선 수중의 문제를 이해해야 합니다.
    LiveView의 가장 큰 단점은 코드 구조/조직입니다.우리는 아직 우리가 100% 자신 있는 구조를 찾지 못했기 때문에, 우리는 목표에 도달할 때까지 계속 교체할 것이다.
    지역사회는 이미 이를 위해 해결 방안을 제정하고 있으며, 이미 같은 라이브러리가 이 문제를 해결하고 있다.Surface는 저희의 "테스트/연구/학습"목록에서 꼭 시도해 보겠습니다.
    또한 LiveView는 여전히 알파 단계입니다.우리는 돌파적인 변화의 새로운 버전이 있기 때문에 의존 관계를 자주 업그레이드해야 한다.좋은 점은 새로운 버전이 발표될 때마다 더 좋아진다는 것이다.🥇

    용례 읽어주셔서 감사합니다!


    당신의 독서에 대단히 감사합니다. 그것은 우리에게 큰 의의가 있습니다.또 다양한 기술에 대한 흥미로운 글이 끊임없이 발표되기 때문에 계속 관심을 갖는 것을 잊지 말아야 한다.
    만약 당신이 모른다면, Coletiv는 볼투의 소프트웨어 개발 스튜디오로 Elixir, 웹과 응용 프로그램(iOS와 안드로이드) 개발에 전문적으로 종사한다.하지만 우리는 각양각색의 일을 한다.우리는 사용자 체험/사용자 인터페이스 디자인, 소프트웨어 개발, 심지어 당신에게 안전 보호를 제공합니다.
    그래서 surface

    좋은 웹페이지 즐겨찾기