?在社區翻騰了許久,沒有找到合適的天氣插件。迫不得已,只好借鑒互聯網上的web
項目,手動遷移到小程序中使用?,F在分享到互聯網社區中,幫助后續有需要的開發者。
1.組件介紹
1.1 組件效果預覽圖
?小程序組件繼承了外部樣式colorui
的色彩,但實際動畫會根據父節點的color
屬性自動填充顏色,即使不引入colorui
這個樣式庫,也可以在該組件引用外定義一個有color
屬性的塊包裹該組件,同樣可以達到如圖的效果。
1.2 構造形式
1.3 支持的動畫效果
簡單介紹下,動畫由3個部分組成
一個是主體塊
,這幾個動畫中的大云朵就是;第二個是背景塊
,如第一個中的太陽和第三個中的多層云;第三個就是狀態塊
,如第一個中的雨水和第二個中的雷。每個塊有且僅能展示一個??梢愿鶕约旱男枰?,自行組合這幾個塊,來滿足對應的天氣需求。
注:如想要實現雷雨交加的效果,需要定義兩個動畫,一個是雷一個是雨,然后通過定時器進行動畫的來回切換,如果有完成的可以在評論里留下代碼,我懶得實現了,哈哈。
2.組件的使用
組件的使用,需要授權獲取位置信息,在app.json
中配置授權。
"permission": { "scope.userLocation": { "desc": "你的位置信息將用于定位效果和天氣信息展示" } }
組件配置完成后,在全局app.json
中進行引入。
"usingComponents": { "uweather":"animation/uweather/weather" }
組件有兩種模式:
用戶自定義模式默認模式(引入amap-wx.js
,申請高德地圖key
,具體步驟參見參考文檔第一個)
- 用戶自定義模式下,所有的信息包括動畫和信息展示,都由用戶傳入的信息來控制。
- 默認模式下,即用戶未傳入任何信息,這時候組件就會基于位置信息,請求高德地圖對應接口來獲取地理位置及其天氣信息。
組件在被創建的時候會檢測是否有對應值的傳入,如果有值傳入,那么就是用戶自定義模式,如果沒有值傳入,那么就是默認模式。
lifetimes:{ attached(){ if(this.properties.winfo == null){ this.setData({ amapPlugin: new amap.AMapWX({ key: this.data.key }) },()=>{ //獲取天氣信息 this.getWeather() }) } } },
2.1 自定義模式
自定義模式下,傳入的數據要按照規定的的格式(也可以自己修改組件的屬性值)
例如在page
中配置的屬性如下
weather:"雷", winfo:{ province:"自定義省份", city:"自定義城市", temperature:"自定義溫度", weather:"自定義天氣", winddirection:"自定義風向", windpower:"自定義風力" }
wxml
頁面中的組件使用如下
<uweather weather="{{weather}}" winfo="{{winfo}}" > </uweather>
那么對應的組件展示效果就是這樣子的
2.2 默認模式
?默認模式需要獲得用戶的地理位置信息授權,確認在app.json
中進行了授權配置和使用組件前完成了授權信息的校驗。
?組件生命周期會在每一次組件被裝如頁面樹時,監聽是否有對應數據的傳入,如果沒有,就會請求對應的接口,獲取地圖信息。使用默認方法,還需要配置 https://restapi.amap.com 為合法的request
域名和申請對應的key
用于開發,申請步驟參見參考文檔。
?默認模式下不需要傳入任何參數,直接引入組件即可。
<uweather> </uweather>
3.組件使用注意事項
?默認方法的天氣返回值具有很多種,具體使用還需要自己修改組件,完成不同天氣到對應動畫的映射,例如小雨、中雨、大雨都可以映射到雨
這個動畫狀態。下圖是高德地圖天氣API的部分信息,全部請參見參考文檔。
4.組件代碼
?詳細的組件在項目中的使用結構 請看[開源項目](miniprogram/animation/uweather ? Kindear/校園小程序 - 碼云 - 開源中國 (gitee.com)),記得給個?,感謝。
uweather.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
<view class="padding-sm"> <view class="bg-gradual-blue padding radius shadow-blur" style="display: flex;flex-direction: row;"> <view style="width:50%;height:100%;color:#1A94E6;"> <view class="icon sun-shower " wx:if="{{weather == "太陽雨"}}"> <view class="cloud"></view> <view class="sun"><view class="rays"></view></view> <view class="rain"></view> </view> <view class="icon sun-shower " wx:if="{{weather == "多云"}}"> <view class="cloud"></view> <view class="sun"><view class="rays"></view></view> </view> <view class="icon thunder-storm" wx:if="{{weather == "雷"}}"> <view class="cloud"></view> <view class="lightning"> <view class="bolt"></view> <view class="bolt"></view> </view> </view> <view class="icon cloudy" wx:if="{{weather == "陰"}}"> <view class="cloud"></view> <view class="cloud"></view> </view> <view class="icon flurries" wx:if="{{weather == "雪"}}"> <view class="cloud"></view> <view class="snow"> <view class="flake"></view> <view class="flake"></view> </view> </view> <view class="icon sunny" wx:if="{{weather == "晴"}}"> <view class="sun"><view class="rays"></view></view> </view> <view class="icon rainy" wx:if="{{weather == "雨"}}"><view class="cloud"></view></view> </view> <!--文字部分--> <view style="width:50%;height:100%;"> <view class="title"> <view class="text-cut" style="margin-top:20rpx;">{{obj.province}}-{{obj.city}}</view> <!--view class="text-cut">濕度:{{obj.humidity.data}}</view--> <view class="text-cut" style="margin-top:20rpx;">溫度:{{obj.temperature}}℃</view> <view class="text-cut" style="margin-top:20rpx;">天氣:{{obj.weather}}</view> <view class="text-cut" style="margin-top:20rpx;">{{obj.winddirection}}風{{obj.windpower}}級</view> </view> </view> </view> </view>
uweather.wxss
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)
天氣查詢-API文檔-開發指南-Web服務 API | 高德地圖API (amap.com)
校園小程序: 基于強智教務系統的校園服務類小程序--多校版本(默認 山科)使用云開發 (gitee.com)
到此這篇關于微信小程序基于高德地圖API實現天氣組件(動態效果)的文章就介紹到這了,更多相關微信小程序實現天氣組件內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://www.cnblogs.com/masterchd/p/13855522.html