1. 程式人生 > >微信小程式-基於高德地圖API實現天氣元件(動態效果)

微信小程式-基於高德地圖API實現天氣元件(動態效果)

#### 微信小程式-基於高德地圖API實現天氣元件(動態效果) ​ 在社群翻騰了許久,沒有找到合適的天氣外掛。迫不得已,只好借鑑網際網路上的`web`專案,手動遷移到小程式中使用。現在分享到網際網路社群中,幫助後續有需要的開發者。 > 1.元件介紹 **1.1 元件效果預覽圖** ​ 小程式元件繼承了外部樣式`colorui`的色彩,但實際動畫會根據父節點的`color`屬性自動填充顏色,即使不引入`colorui`這個樣式庫,也可以在該元件引用外定義一個有`color`屬性的塊包裹該元件,同樣可以達到如圖的效果。 ![](https://img2020.cnblogs.com/blog/1141382/202010/1141382-20201021231645796-312104534.gif) **1.2 構造形式** ![](https://img2020.cnblogs.com/blog/1141382/202010/1141382-20201021231702365-700610640.png) **1.3 支援的動畫效果** 簡單介紹下,動畫由3個部分組成 一個是`主體塊`,這幾個動畫中的大雲朵就是;第二個是`背景塊`,如第一個中的太陽和第三個中的多層雲;第三個就是`狀態塊`,如第一個中的雨水和第二個中的雷。每個塊有且僅能展示一個。**可以根據自己的需要,自行組合這幾個塊**,來滿足對應的天氣需求。 **注**:如想要實現雷雨交加的效果,需要定義兩個動畫,一個是雷一個是雨,然後通過定時器進行動畫的來回切換,如果有完成的可以在評論裡留下程式碼,我懶得實現了,哈哈。 ![](https://img2020.cnblogs.com/blog/1141382/202010/1141382-20201021231713445-2113026265.gif) > 2.元件的使用 元件的使用,需要授權獲取位置資訊,在`app.json`中配置授權。 ~~~json "permission": { "scope.userLocation": { "desc": "你的位置資訊將用於定位效果和天氣資訊展示" } } ~~~ 元件配置完成後,在全域性`app.json`中進行引入。 ~~~json "usingComponents": { "uweather":"animation/uweather/weather" } ~~~ 元件有兩種模式: 1. 使用者自定義模式 2. 預設模式(引入`amap-wx.js`,申請高德地圖`key`,具體步驟參見參考文件第一個) 使用者自定義模式下,所有的資訊包括動畫和資訊展示,都由使用者傳入的資訊來控制。 預設模式下,即使用者未傳入任何資訊,這時候元件就會基於位置資訊,請求高德地圖對應介面來獲取地理位置及其天氣資訊。 元件在被建立的時候會檢測是否有對應值的傳入,如果有值傳入,那麼就是使用者自定義模式,如果沒有值傳入,那麼就是預設模式。 ~~~js lifetimes:{ attached(){ if(this.properties.winfo == null){ this.setData({ amapPlugin: new amap.AMapWX({ key: this.data.key }) },()=>{ //獲取天氣資訊 this.getWeather() }) } } }, ~~~ **2.1 自定義模式** ![](https://img2020.cnblogs.com/blog/1141382/202010/1141382-20201021232059449-985745035.png) 自定義模式下,傳入的資料要按照規定的的格式(也可以自己修改元件的屬性值) 例如在`page`中配置的屬性如下 ~~~js weather:'雷', winfo:{ province:'自定義省份', city:'自定義城市', temperature:'自定義溫度', weather:'自定義天氣', winddirection:'自定義風向', windpower:'自定義風力' } ~~~ `wxml`頁面中的元件使用如下 ~~~html
~~~ 那麼對應的元件展示效果就是這樣子的 ![](https://img2020.cnblogs.com/blog/1141382/202010/1141382-20201021231833871-829975487.png) **2.2 預設模式** ​ 預設模式需要獲得使用者的地理位置資訊授權,確認在`app.json`中進行了授權配置和使用元件前完成了授權資訊的校驗。 ​ 元件生命週期會在每一次元件被裝如頁面樹時,監聽是否有對應資料的傳入,如果沒有,就會請求對應的介面,獲取地圖資訊。使用預設方法,還需要配置 **https://restapi.amap.com** 為合法的`request`域名和申請對應的`key`用於開發,申請步驟參見參考文件。 ​ 預設模式下不需要傳入任何引數,直接引入元件即可。 ~~~html
~~~ > 3.元件使用注意事項 ​ 預設方法的天氣返回值具有很多種,具體使用還需要自己修改元件,完成不同天氣到對應動畫的對映,例如小雨、中雨、大雨都可以對映到`雨`這個動畫狀態。下圖是高德地圖天氣API的部分資訊,全部請參見參考文件。 ![](https://img2020.cnblogs.com/blog/1141382/202010/1141382-20201021231914890-1708083341.png) > 4.元件程式碼 ​ 詳細的元件在專案中的使用結構 請看[開源專案]([miniprogram/animation/uweather · Kindear/校園小程式 - 碼雲 - 開源中國 (gitee.com)](https://gitee.com/Kindear/yamako_procedure/tree/EXV/miniprogram/animation/uweather)),記得給個⭐,感謝。 >
> uweather.js ~~~js // animation/uweather/rain.js const amap = require('../../lib/amap-wx.js'); Component({ options: { addGlobalClass: true, multipleSlots: true }, /** * 元件的屬性列表 */ properties: { weather:{ type:String, value:'', observer:function(n,o){ //天氣變化 } }, winfo:{ type:Object, value:null, observer:function(n,o){ //如果有自定義的值就使用自定義的值 this.setData({ obj:n }) } } }, /** * 元件的初始資料 */ data: { amapPlugin: null, key: "6799b5f6f88d3d9fb52ac244855a8759", obj:{}, }, lifetimes:{ attached(){ if(this.properties.winfo == null){ this.setData({ amapPlugin: new amap.AMapWX({ key: this.data.key }) },()=>{ this.getWeather() }) } } }, /** * 元件的方法列表 */ methods: { //獲取天氣資料 getWeather:function(){ wx.showLoading({ title: '請稍候...' }) // type:天氣的型別。預設是live(實時天氣),可設定成forecast(預報天氣)。 // city:城市對應的adcode,非必填。為空時,基於當前位置所在區域。 如:440300,返回深圳市天氣 // success(data) :呼叫成功的回撥函式。 // fail(info) :呼叫失敗的回撥函式。 this.data.amapPlugin.getWeather({ success: (data) =>{ //成功回撥 console.log(data) wx.hideLoading() this.setData({ obj:data.liveData, }) if(this.properties.weather == ''){ this.setData({ weather:data.liveData.weather }) } }, fail: function (info) { //失敗回撥 console.log(info) } }) }, } }) ~~~ > > uweather.wxml ~~~html {{obj.province}}-{{obj.city}} 溫度:{{obj.temperature}}℃ 天氣:{{obj.weather}} {{obj.winddirection}}風{{obj.windpower}}級 ~~~ > > uweather.wxss ~~~css body { max-width: 42em; padding: 2em; margin: 0 auto; color: #161616; font-family: 'Roboto', sans-serif; text-align: center; background-color: currentColor; } h1 { margin-bottom: 1.375em; color: #fff; font-weight: 100; font-size: 2em; text-transform: uppercase; } p, a { color: rgba(255,255,255,0.3); font-size: small; } p { margin: 1.375rem 0; } .icon { position: relative; display: inline-block; width: 12em; height: 10em; font-size: 1em; /* control icon size here */ } .cloud { position: absolute; z-index: 1; top: 50%; left: 50%; width: 3.6875em; height: 3.6875em; margin: -1.84375em; background: currentColor; border-radius: 50%; box-shadow: -2.1875em 0.6875em 0 -0.6875em, 2.0625em 0.9375em 0 -0.9375em, 0 0 0 0.375em #fff, -2.1875em 0.6875em 0 -0.3125em #fff, 2.0625em 0.9375em 0 -0.5625em #fff; } .cloud:after { content: ''; position: absolute; bottom: 0; left: -0.5em; display: block; width: 4.5625em; height: 1em; background: currentColor; box-shadow: 0 0.4375em 0 -0.0625em #fff; } .cloud:nth-child(2) { z-index: 0; background: #fff; box-shadow: -2.1875em 0.6875em 0 -0.6875em #fff, 2.0625em 0.9375em 0 -0.9375em #fff, 0 0 0 0.375em #fff, -2.1875em 0.6875em 0 -0.3125em #fff, 2.0625em 0.9375em 0 -0.5625em #fff; opacity: 0.3; transform: scale(0.5) translate(6em, -3em); animation: cloud 4s linear infinite; } .cloud:nth-child(2):after { background: #fff; } .sun { position: absolute; top: 50%; left: 50%; width: 2.5em; height: 2.5em; margin: -1.25em; background: currentColor; border-radius: 50%; box-shadow: 0 0 0 0.375em #fff; animation: spin 12s infinite linear; } .rays { position: absolute; top: -2em; left: 50%; display: block; width: 0.375em; height: 1.125em; margin-left: -0.1875em; background: #fff; border-radius: 0.25em; box-shadow: 0 5.375em #fff; } .rays:before, .rays:after { content: ''; position: absolute; top: 0em; left: 0em; display: block; width: 0.375em; height: 1.125em; transform: rotate(60deg); transform-origin: 50% 3.25em; background: #fff; border-radius: 0.25em; box-shadow: 0 5.375em #fff; } .rays:before { transform: rotate(120deg); } .cloud + .sun { margin: -2em 1em; } .rain, .lightning, .snow { position: absolute; z-index: 2; top: 50%; left: 50%; width: 3.75em; height: 3.75em; margin: 0.375em 0 0 -2em; background: currentColor; } .rain:after { content: ''; position: absolute; z-index: 2; top: 50%; left: 50%; width: 1.125em; height: 1.125em; margin: -1em 0 0 -0.25em; background: #0cf; border-radius: 100% 0 60% 50% / 60% 0 100% 50%; box-shadow: 0.625em 0.875em 0 -0.125em rgba(255,255,255,0.2), -0.875em 1.125em 0 -0.125em rgba(255,255,255,0.2), -1.375em -0.125em 0 rgba(255,255,255,0.2); transform: rotate(-28deg); animation: rain 3s linear infinite; } .bolt { position: absolute; top: 50%; left: 50%; margin: -0.25em 0 0 -0.125em; color: #fff; opacity: 0.3; animation: lightning 2s linear infinite; } .bolt:nth-child(2) { width: 0.5em; height: 0.25em; margin: -1.75em 0 0 -1.875em; transform: translate(2.5em, 2.25em); opacity: 0.2; animation: lightning 1.5s linear infinite; } .bolt:before, .bolt:after { content: ''; position: absolute; z-index: 2; top: 50%; left: 50%; margin: -1.625em 0 0 -1.0125em; border-top: 1.25em solid transparent; border-right: 0.75em solid; border-bottom: 0.75em solid; border-left: 0.5em solid transparent; transform: skewX(-10deg); } .bolt:after { margin: -0.25em 0 0 -0.25em; border-top: 0.75em solid; border-right: 0.5em solid transparent; border-bottom: 1.25em solid transparent; border-left: 0.75em solid; transform: skewX(-10deg); } .bolt:nth-child(2):before { margin: -0.75em 0 0 -0.5em; border-top: 0.625em solid transparent; border-right: 0.375em solid; border-bottom: 0.375em solid; border-left: 0.25em solid transparent; } .bolt:nth-child(2):after { margin: -0.125em 0 0 -0.125em; border-top: 0.375em solid; border-right: 0.25em solid transparent; border-bottom: 0.625em solid transparent; border-left: 0.375em solid; } .flake:before, .flake:after { content: '\2744'; position: absolute; top: 50%; left: 50%; margin: -1.025em 0 0 -1.0125em; color: #fff; opacity: 0.2; animation: spin 8s linear infinite reverse; } .flake:after { margin: 0.125em 0 0 -1em; font-size: 1.5em; opacity: 0.4; animation: spin 14s linear infinite; } .flake:nth-child(2):before { margin: -0.5em 0 0 0.25em; font-size: 1.25em; opacity: 0.2; animation: spin 10s linear infinite; } .flake:nth-child(2):after { margin: 0.375em 0 0 0.125em; font-size: 2em; opacity: 0.4; animation: spin 16s linear infinite reverse; } /* Animations */ @keyframes spin { 100% { transform: rotate(360deg); } } @keyframes cloud { 0% { opacity: 0; } 50% { opacity: 0.3; } 100% { opacity: 0; transform: scale(0.5) translate(-200%, -3em); } } @keyframes rain { 0% { background: #0cf; box-shadow: 0.625em 0.875em 0 -0.125em rgba(255,255,255,0.2), -0.875em 1.125em 0 -0.125em rgba(255,255,255,0.2), -1.375em -0.125em 0 #0cf; } 25% { box-shadow: 0.625em 0.875em 0 -0.125em rgba(255,255,255,0.2), -0.875em 1.125em 0 -0.125em #0cf, -1.375em -0.125em 0 rgba(255,255,255,0.2); } 50% { background: rgba(255,255,255,0.3); box-shadow: 0.625em 0.875em 0 -0.125em #0cf, -0.875em 1.125em 0 -0.125em rgba(255,255,255,0.2), -1.375em -0.125em 0 rgba(255,255,255,0.2); } 100% { box-shadow: 0.625em 0.875em 0 -0.125em rgba(255,255,255,0.2), -0.875em 1.125em 0 -0.125em rgba(255,255,255,0.2), -1.375em -0.125em 0 #0cf; } } @keyframes lightning { 45% { color: #fff; background: #fff; opacity: 0.2; } 50% { color: #0cf; background: #0cf; opacity: 1; } 55% { color: #fff; background: #fff; opacity: 0.2; } } ~~~ > **參考文件** > > [入門指南-微信小程式SDK | 高德地圖API (amap.com)](https://lbs.amap.com/api/wx/gettingstarted) > > [天氣查詢-API文件-開發指南-Web服務 API | 高德地圖API (amap.com)](https://lbs.amap.com/api/webservice/guide/api/weatherinfo/) > > [校園小程式: 基於強智教務系統的校園服務類小程式--多校版本(預設 山科)使用雲開發 (gitee.com)](https://gitee.com/Kindear/yamako_pro