今天就來感受一下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....
瀏覽器中的 JavaScript 是由「事件驅動」,會透過產生事件的方式來回應互動,並預期某程式會「接聽」相關事件。Google Maps API 第 3 版的事件模型與 API 第 2 版所使用的事件模型相似,但其內容已經變更。目前有兩種事件類型:
OK,那要怎麼改呢?
只要參考GoogleMap API,在完成API初始化後,進行註冊zoom_changed事件綁定就可以了,所以請直接在本機修改 google-map.html 程式
修改後存檔,再回到瀏覽器F5刷一下,就會發現可以連動了....呼...又是一個坑