微信小程序基于高德地图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 相关文章推荐
5个最佳的Javascript日期处理类库分享
Apr 15 Javascript
JavaScript中几个重要的属性(this、constructor、prototype)介绍
May 19 Javascript
IE中图片的onload事件无效问题和解决方法
Jun 06 Javascript
Node.js插件的正确编写方式
Aug 03 Javascript
javascript将中国数字格式转换成欧式数字格式的简单实例
Aug 02 Javascript
jQuery元素属性操作实例(设置、获取及删除元素属性)
Sep 08 Javascript
PHP+jquery+ajax实现分页
Dec 09 Javascript
js实现五星评价功能
Mar 08 Javascript
vue中element组件样式修改无效的解决方法
Feb 03 Javascript
使用vue如何构建一个自动建站项目
Feb 05 Javascript
vue设置导航栏、侧边栏为公共页面的例子
Nov 01 Javascript
JavaScript indexOf()原理及使用方法详解
Jul 09 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
10个可以简化php开发过程的MySQL工具
2010/04/11 PHP
Could not load type System.ServiceModel.Activation.HttpModule解决办法
2012/12/29 PHP
zend framework框架中url大小写问题解决方法
2014/08/19 PHP
ThinkPHP使用Ueditor的方法详解
2016/05/20 PHP
JavaScript 关键字屏蔽实现函数
2009/08/02 Javascript
JavaScript 学习笔记(十四) 正则表达式
2010/01/22 Javascript
JQuery 插件模板 制作jquery插件的朋友可以参考下
2010/03/17 Javascript
巧用js提交表单轻松解决一个页面有多个提交按钮
2013/11/17 Javascript
JavaScript参数个数可变的函数举例说明
2014/10/10 Javascript
jQuery实现批量判断表单中文本框非空的方法(2种方法)
2015/12/09 Javascript
jQuery validate+artdialog+jquery form实现弹出表单思路详解
2016/04/18 Javascript
JS 实现导航菜单中的二级下拉菜单的几种方式
2016/10/31 Javascript
bootstrap datetimepicker日期插件超详细使用方法介绍
2017/02/23 Javascript
vue2.0结合DataTable插件实现表格动态刷新的方法详解
2017/03/17 Javascript
微信小程序 获取session_key和openid的实例
2017/08/17 Javascript
解读vue生成的文件目录结构及说明
2017/11/27 Javascript
微信小程序之多列表的显示和隐藏功能【附源码】
2018/08/06 Javascript
React+Webpack快速上手指南(小结)
2018/08/15 Javascript
浅谈发布订阅模式与观察者模式
2019/04/09 Javascript
JavaScript或jQuery 获取option value值方法解析
2020/05/12 jQuery
python实现跨文件全局变量的方法
2014/07/07 Python
Python实现partial改变方法默认参数
2014/08/18 Python
Django中更改默认数据库为mysql的方法示例
2018/12/05 Python
详解使用PyInstaller将Pygame库编写的小游戏程序打包为exe文件
2019/08/23 Python
Python获取当前脚本文件夹(Script)的绝对路径方法代码
2019/08/27 Python
Pycharm中安装wordcloud等库失败问题及终端通过pip安装的Python库如何添加到Pycharm解释器中(推荐)
2020/05/10 Python
python使用openpyxl操作excel的方法步骤
2020/05/28 Python
英国安全产品购物网站:The Safe Shop
2017/03/20 全球购物
英国领先的运动营养品牌:Protein Dynamix
2018/01/02 全球购物
Parfumdreams芬兰:购买香水和化妆品
2021/02/13 全球购物
高级工程师岗位职责
2013/12/15 职场文书
物业保安员岗位职责制度
2014/01/30 职场文书
学校青年志愿者活动总结
2015/05/06 职场文书
社团招新宣传语
2015/07/13 职场文书
2015年社区重阳节活动总结
2015/07/30 职场文书
大学生十八大感想
2015/08/11 职场文书