iT邦幫忙

DAY 4
1

今日目標: 完成 GoogleMap + MarterialDesign 元件互動

今天就來感受一下Polymer的template與data-binding的強大,到目前為止,我們只是裝好本機環境,成功使用Polymer元件而已。接下來玩一下如何讓兩個元件互動。

GoogleMap元件本身就有控制面板可以設定地圖顯示比例,如下圖

為了體現元件間的互動,現在我們改用目前最潮的Material Design元件 <paper-slider> 來控制GoogleMap 縮放地圖比例 (zoom In/Out),現在先建立新的HTML檔案,載入paper-slider元件

it_ironman_day04_1.html [線上範例]

   <script src="bower_components/platform/platform.js"></script>
   <link rel="import"href="bower_components/google-map/google-map.html">
   <link rel="import"href="bower_components/paper-slider/paper-slider.html">
   <style>
     google-map {
       display: block;
       height: 600px;
     }
   </style>
 
 

   <paper-slider min="1" max="20" value="15" editable></paper-slider>

   <google-map latitude="22.605153" longitude="120.301125"
              showCenterMarker zoom="18"></google-map>

 

打開瀏覽器,載入http://localhost:3000/it\_ironman\_day04\_1.html

如果沒出錯應該可以看到paper-slider元件顯示在最上方,可以試著玩一下paper-slider,感受一下Material Design元件的魅力,不過目前還不能用paper-slider元件控制 google-map元件

登登...Template登場

為了讓paper-sider元件控制google-map元件,我們使用<template>標籤 + data-binding 方式來完成。<template>標籤HTML5新推出的元素,目前大多數瀏覽器都支援了,可以用 CanIUse 網站查看看,不過Polymer會自動搞定還沒原生支持的瀏覽器,所以其實不用考慮瀏覽器是否支援Template

想了解<template>標籤強大之處,千萬別錯過這篇,template 這概念並不新鮮,不外乎是用<script type="xxx">或將<div hidden> 後,透過JavaScript來處理,兩種方式各有優缺點,等到現在瀏覽器原生支持<template>後才能徹底解決效能問題。

Polymer會在<template>標籤上添加一些屬性,幫助開發者將Model綁定到指定元素,而且是雙向綁定(data-binding)。而Model可以是JSONObject(單筆資料) 或是JSONArray(多筆資料)

如何將Model綁定到Template?

只要在tempalte標籤加上bind這屬性就可以了

然後設定template標籤裡的對應變數,例如{{zoom}}就是變數設定的寫法

<template id='tmpl'  bind>

<paper-slider id='sel' min="1" max="20" value="{{zoom}}" editable>
</paper-slider>

<google-map id='map' latitude="22.605153" longitude="120.301125"
           disableDefaultUI showCenterMarker zoom="{{zoom}}">
</google-map>

</template>

再來透過JavaScript就可以將Model與template裡面的元件屬性進行綁定。不過要注意,對元件操控必須等元件初始化完成,也就是要等註冊 polymer-ready 事件觸發後才進行處理

<script>
window.addEventListener("polymer-ready",function(){
 document.querySelector('#tmpl').model = {
   zoom: 15
 }
});
</script>

好了,玩看看,直接拉動slider就可以控制googleMap zoomIn/zoomOut

更酷的是,直接用JavaScript控制slider元件或google-map元件也都可以直接控制

http://localhost:3000/it\_ironman\_day04\_2.html

   <script src="bower_components/platform/platform.js"></script>
 
 
<link rel="import"href="bower_components/google-map/google-map.html">
<link rel="import"href="bower_components/paper-slider/paper-slider.html">
<style>
 google-map {
   display: block;
   height: 600px;
 }
</style>

<template id='tmpl' bind>

<paper-slider id='sel' min="1" max="20" value="{{zoom}}" editable></paper-slider>

<google-map id='map' latitude="22.605153" longitude="120.301125"
           disableDefaultUI showCenterMarker zoom="{{zoom}}"></google-map>

</template>

<script>
window.addEventListener("polymer-ready",function(){
 document.querySelector('#tmpl').model = {
   zoom: 15
 }
});
</script>
 

慢著,好像還有個小問題?

到目前為止,整理一下我們可以控制的方式

透過畫面上paper-slider來控制Google-Map

用JavaScript 設定 paper-slider 元素的 value
document.querySelector("paper-slider").value = 7

用JavaScript 設定 google-map 元素的 zoom
document.querySelector("google-map").zoom = 5

用JavaScript 設定 Template元素 的 model
document.querySelector('#tmpl').model = { zoom: 15 }

以上四種方法,都可以完成元件zoom In/Out 連動,並且同步更新model。但是如果直接在畫面中的GoogleMap裡面,用滑鼠滾輪 zoom In/Out 來控制就會發現 paper-slider 或model 並不會同步更新,為什麼呢?

追一下 google-map元件的原始碼,就會發現,google-map元件是將googleMap API 包裝成元件,封裝了呼叫API的實作細節,所以我們才能透過google-map標籤就能使用,如下圖所示

google-map原始碼片段

所以問題就是出在包裝google-map元件的開發者,沒有註冊google map API zoom_changed的事件,所以元件就沒辦法同步binding....

參考 Google Map API v3 說明

總覽

瀏覽器中的 JavaScript 是由「事件驅動」,會透過產生事件的方式來回應互動,並預期某程式會「接聽」相關事件。Google Maps API 第 3 版的事件模型與 API 第 2 版所使用的事件模型相似,但其內容已經變更。目前有兩種事件類型:

  • 使用者事件 (例如「點擊」滑鼠事件) 會從 DOM 傳播至 Google Maps API。這些事件與標準 DOM 事件各自獨立,也並不相同。
  • MVC 狀態變更通知會反映 Maps API 物件的變動,並採用
    property_changed 慣例加以命名。

OK,那要怎麼改呢?

只要參考GoogleMap API,在完成API初始化後,進行註冊zoom_changed事件綁定就可以了,所以請直接在本機修改 google-map.html 程式

修改後存檔,再回到瀏覽器F5刷一下,就會發現可以連動了....呼...又是一個坑

[線上範例]


上一篇
Polymer 淺嚐元件使用
下一篇
Polymer 自定HTML標籤-GoogleMap三重奏(上)
系列文
你不能不知道的Polymer開發實戰30

尚未有邦友留言

立即登入留言