微信小程序基于高德地图API实现天气组件(动态效果)


Posted in Javascript onOctober 22, 2020

​在社区翻腾了许久,没有找到合适的天气插件。迫不得已,只好借鉴互联网上的web项目,手动迁移到小程序中使用。现在分享到互联网社区中,帮助后续有需要的开发者。

1.组件介绍

1.1 组件效果预览图

​小程序组件继承了外部样式colorui的色彩,但实际动画会根据父节点的color属性自动填充颜色,即使不引入colorui这个样式库,也可以在该组件引用外定义一个有color属性的块包裹该组件,同样可以达到如图的效果。

微信小程序基于高德地图API实现天气组件(动态效果)

1.2 构造形式

微信小程序基于高德地图API实现天气组件(动态效果)

1.3 支持的动画效果

简单介绍下,动画由3个部分组成

一个是主体块,这几个动画中的大云朵就是;第二个是背景块,如第一个中的太阳和第三个中的多层云;第三个就是状态块,如第一个中的雨水和第二个中的雷。每个块有且仅能展示一个。可以根据自己的需要,自行组合这几个块,来满足对应的天气需求。

注:如想要实现雷雨交加的效果,需要定义两个动画,一个是雷一个是雨,然后通过定时器进行动画的来回切换,如果有完成的可以在评论里留下代码,我懒得实现了,哈哈。

微信小程序基于高德地图API实现天气组件(动态效果)

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 自定义模式

微信小程序基于高德地图API实现天气组件(动态效果)

自定义模式下,传入的数据要按照规定的的格式(也可以自己修改组件的属性值)

例如在page中配置的属性如下

weather:'雷',
 winfo:{
  province:'自定义省份',
  city:'自定义城市',
  temperature:'自定义温度',
  weather:'自定义天气',
  winddirection:'自定义风向',
  windpower:'自定义风力'
 }

wxml页面中的组件使用如下

<uweather
	weather="{{weather}}"
	winfo="{{winfo}}"
>
</uweather>

那么对应的组件展示效果就是这样子的

微信小程序基于高德地图API实现天气组件(动态效果)

2.2 默认模式

​默认模式需要获得用户的地理位置信息授权,确认在app.json中进行了授权配置和使用组件前完成了授权信息的校验。

​组件生命周期会在每一次组件被装如页面树时,监听是否有对应数据的传入,如果没有,就会请求对应的接口,获取地图信息。使用默认方法,还需要配置 https://restapi.amap.com 为合法的request域名和申请对应的key用于开发,申请步骤参见参考文档。

​默认模式下不需要传入任何参数,直接引入组件即可。

<uweather> </uweather>

3.组件使用注意事项

​默认方法的天气返回值具有很多种,具体使用还需要自己修改组件,完成不同天气到对应动画的映射,例如小雨、中雨、大雨都可以映射到这个动画状态。下图是高德地图天气API的部分信息,全部请参见参考文档。

微信小程序基于高德地图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实现天气组件(动态效果)的文章就介绍到这了,更多相关微信小程序实现天气组件内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
JS 实现导航栏悬停效果(续)
Sep 24 Javascript
Jquery中国地图热点效果-鼠标经过弹出提示层信息的简单实例
Feb 12 Javascript
12306验证码破解思路分享
Mar 25 Javascript
JavaScript判断表单中多选框checkbox选中个数的方法
Aug 17 Javascript
JS+CSS简单树形菜单实现方法
Sep 12 Javascript
基于 Immutable.js 实现撤销重做功能的实例代码
Mar 01 Javascript
通过函数作用域和块级作用域看javascript的作用域链
Aug 05 Javascript
详解javascript appendChild()的完整功能
Aug 18 Javascript
vue单页应用在页面刷新时保留状态数据的方法
Sep 21 Javascript
vue 左滑删除功能的示例代码
Jan 28 Javascript
基于jQuery的时间戳与日期间的转化
Jun 21 jQuery
vue路由权限校验功能的实现代码
Jun 07 Javascript
ES11屡试不爽的新特性,你用上了几个
Oct 21 #Javascript
记一次vue跨域的解决
Oct 21 #Javascript
解决Vue项目中tff报错的问题
Oct 21 #Javascript
vue-cli3自动消除console.log()的调试信息方式
Oct 21 #Javascript
js 压缩图片的示例(只缩小体积,不更改图片尺寸)
Oct 21 #Javascript
vue-cli4使用全局less文件中的变量配置操作
Oct 21 #Javascript
Vue全局使用less样式,组件使用全局样式文件中定义的变量操作
Oct 21 #Javascript
You might like
PHP编程中字符串处理的5个技巧小结
2007/11/13 PHP
jQuery powerFloat万能浮动层下拉层插件使用介绍
2010/12/27 Javascript
jQuery Tab插件 用于在Tab中显示iframe,附源码和详细说明
2011/06/27 Javascript
跟我学Nodejs(一)--- Node.js简介及安装开发环境
2014/05/20 NodeJs
一个简单的全屏图片上下打开显示网页效果示例
2014/07/08 Javascript
jQuery多级手风琴菜单实例讲解
2015/10/22 Javascript
jQuery Real Person验证码插件防止表单自动提交
2015/11/06 Javascript
jQuery添加删除DOM元素方法详解
2016/01/18 Javascript
最全面的百度地图JavaScript离线版开发
2016/09/10 Javascript
Vue.js组件tabs实现选项卡切换效果
2016/12/01 Javascript
jquery 正整数数字校验正则表达式
2017/01/10 Javascript
React如何将组件渲染到指定DOM节点详解
2017/09/08 Javascript
Node.js自定义实现文件路由功能
2017/09/22 Javascript
详解html-webpack-plugin插件(用法总结)
2018/09/12 Javascript
JS中使用cavas截图网页并解决跨域及模糊问题
2018/11/13 Javascript
详解Vue webapp项目通过HBulider打包原生APP(vue+webpack+HBulider)
2019/02/02 Javascript
微信小程序webview 脚手架使用详解
2019/07/22 Javascript
layui点击弹框页面 表单请求的方法
2019/09/21 Javascript
Vue props中Object和Array设置默认值操作
2020/07/30 Javascript
javascript解析json格式的数据方法详解
2020/08/07 Javascript
vue配置多代理服务接口地址操作
2020/09/08 Javascript
ant design pro中可控的筛选和排序实例
2020/11/17 Javascript
[44:51]2018DOTA2亚洲邀请赛 4.4 淘汰赛 VP vs Liquid 第二场
2018/04/05 DOTA
使用SVG实现提示框功能的示例代码
2020/06/05 HTML / CSS
中国海淘族值得信赖的海淘返利网站:55海淘
2017/01/16 全球购物
美国温暖商店:The Warming Store
2018/12/15 全球购物
怎样声明一个匿名的内部类
2016/06/01 面试题
学校综治宣传月活动总结
2014/07/02 职场文书
小学生清明节演讲稿
2014/09/05 职场文书
机关作风建设整改方案
2014/10/27 职场文书
2014年环境卫生工作总结
2014/11/24 职场文书
解除同居协议书
2015/01/29 职场文书
2015年检验科工作总结
2015/04/27 职场文书
电影地道战观后感
2015/06/04 职场文书
2015年小学体育教师工作总结
2015/10/23 职场文书
2016年幼儿园万圣节活动总结
2016/04/05 职场文书