微信小程序基于高德地图API实现天气组件(动态效
在社区翻腾了许久,没有找到合适的天气插件。迫不得已,只好借鉴互联网上的web
项目,手动迁移到小程序中使用。现在分享到互联网社区中,帮助后续有需要的开发者。
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
中进行了授权配置和使用组件前完成了授权信息的校验。
组件生命周期会在每一次组件被装如页面树时,监听是否有对应数据的传入,如果没有,就会请求对应的接口,获取地图信息。使用默认方法,还需要配置 为合法的request
域名和申请对应的key
用于开发,申请步骤参见参考文档。
默认模式下不需要传入任何参数,直接引入组件即可。
<uweather> </uweather>
3.组件使用注意事项
默认方法的天气返回值具有很多种,具体使用还需要自己修改组件,完成不同天气到对应动画的映射,例如小雨、中雨、大雨都可以映射到雨
这个动画状态。下图是高德地图天气API的部分信息,全部请参见参考文档。
4.组件代码
详细的组件在项目中的使用结构 请看[开源项目](),记得给个⭐,感谢。
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; } }
参考文档
到此这篇关于微信小程序基于高德地图API实现天气组件(动态效果)的文章就介绍到这了,更多相关微信小程序实现天气组件内容请搜索狼蚁SEO以前的文章或继续浏览狼蚁网站SEO优化的相关文章希望大家以后多多支持狼蚁SEO!