​在社区翻腾了许久,没有找到合适的天气插件。迫不得已,只好借鉴互联网上的web项目,手动迁移到小程序中使用。现在分享到互联网社区中,帮助后续有需要的开发者。web1.组件介绍1.1 组件效果预览图​小程序组件继承了外部样式colorui的色彩,但实际动画会根据父节点的color属性自动填充颜色,即使不引入colorui这个样式库,也可以在该组件引用外定义一个有color属性的块包裹该组件,同样可以达到如图的效果。coloruicolorcoloruicolor1.2 构造形式1.3 支持的动画效果简单介绍下,动画由3个部分组成一个是主体块,这几个动画中的大云朵就是;第二个是背景块,如第一个中的太阳和第三个中的多层云;第三个就是状态块,如第一个中的雨水和第二个中的雷。每个块有且仅能展示一个。可以根据自己的需要,自行组合这几个块,来满足对应的天气需求。主体块背景块状态块注:如想要实现雷雨交加的效果,需要定义两个动画,一个是雷一个是雨,然后通过定时器进行动画的来回切换,如果有完成的可以在评论里留下代码,我懒得实现了,哈哈。2.组件的使用组件的使用,需要授权获取位置信息,在app.json中配置授权。app.json
"permission": {
"scope.userLocation": {

"desc": "你的位置信息将用于定位效果和天气信息展示"
}
}
"permission": {
"scope.userLocation": {

"desc": "你的位置信息将用于定位效果和天气信息展示"
}
}组件配置完成后,在全局app.json中进行引入。app.json
"usingComponents": {
"uweather":"animation/uweather/weather"
}
"usingComponents": {
"uweather":"animation/uweather/weather"
}组件有两种模式:用户自定义模式默认模式(引入amap-wx.js,申请高德地图key,具体步骤参见参考文档第一个)amap-wx.jskey

用户自定义模式下,所有的信息包括动画和信息展示,都由用户传入的信息来控制。

默认模式下,即用户未传入任何信息,这时候组件就会基于位置信息,请求高德地图对应接口来获取地理位置及其天气信息。
用户自定义模式下,所有的信息包括动画和信息展示,都由用户传入的信息来控制。默认模式下,即用户未传入任何信息,这时候组件就会基于位置信息,请求高德地图对应接口来获取地理位置及其天气信息。组件在被创建的时候会检测是否有对应值的传入,如果有值传入,那么就是用户自定义模式,如果没有值传入,那么就是默认模式。
lifetimes:{
attached(){

if(this.properties.winfo == null){

this.setData({

amapPlugin: new amap.AMapWX({

key: this.data.key

})

},()=>{

//获取天气信息

this.getWeather()

})

}
}
},
lifetimes:{
attached(){

if(this.properties.winfo == null){

this.setData({

amapPlugin: new amap.AMapWX({

key: this.data.key

})

},()=>{

//获取天气信息

this.getWeather()

})

}
}
},2.1 自定义模式自定义模式下,传入的数据要按照规定的的格式(也可以自己修改组件的属性值)例如在page中配置的属性如下page
weather:'雷',
winfo:{

province:'自定义省份',

city:'自定义城市',

temperature:'自定义温度',

weather:'自定义天气',

winddirection:'自定义风向',

windpower:'自定义风力'
}
weather:'雷',
winfo:{

province:'自定义省份',

city:'自定义城市',

temperature:'自定义温度',

weather:'自定义天气',

winddirection:'自定义风向',

windpower:'自定义风力'
}wxml页面中的组件使用如下wxml

weather="{{weather}}"

winfo="{{winfo}}"
>


weather="{{weather}}"

winfo="{{winfo}}"
>
那么对应的组件展示效果就是这样子的2.2 默认模式​默认模式需要获得用户的地理位置信息授权,确认在app.json中进行了授权配置和使用组件前完成了授权信息的校验。app.json​组件生命周期会在每一次组件被装如页面树时,监听是否有对应数据的传入,如果没有,就会请求对应的接口,获取地图信息。使用默认方法,还需要配置 https://restapi.amap.com 为合法的request域名和申请对应的key用于开发,申请步骤参见参考文档。https://restapi.amap.comrequestkey​默认模式下不需要传入任何参数,直接引入组件即可。

3.组件使用注意事项​默认方法的天气返回值具有很多种,具体使用还需要自己修改组件,完成不同天气到对应动画的映射,例如小雨、中雨、大雨都可以映射到雨这个动画状态。下图是高德地图天气API的部分信息,全部请参见参考文档。雨4.组件代码​详细的组件在项目中的使用结构 请看[开源项目](miniprogram/animation/uweather · Kindear/校园小程序 - 码云 - 开源中国 (gitee.com)),记得给个⭐,感谢。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)

}
})
},
}
})
// 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











































































































































































































{{obj.province}}-{{obj.city}}







温度:{{obj.temperature}}℃



天气:{{obj.weather}}



{{obj.winddirection}}风{{obj.windpower}}级























































































































































































































{{obj.province}}-{{obj.city}}







温度:{{obj.temperature}}℃



天气:{{obj.weather}}



{{obj.winddirection}}风{{obj.windpower}}级











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;
}
}
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)入门指南-微信小程序SDK | 高德地图API (amap.com)天气查询-API文档-开发指南-Web服务 API | 高德地图API (amap.com)天气查询-API文档-开发指南-Web服务 API | 高德地图API (amap.com)校园小程序: 基于强智教务系统的校园服务类小程序--多校版本(默认 山科)使用云开发 (gitee.com)校园小程序: 基于强智教务系统的校园服务类小程序--多校版本(默认 山科)使用云开发 (gitee.com)