微信小程序基于高德地图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 相关文章推荐
一种JavaScript的设计模式
Nov 22 Javascript
jQuery写fadeTo示例代码
Feb 21 Javascript
js实现日历可获得指定日期周数及星期几示例分享(js获取星期几)
Mar 14 Javascript
JavaScript每天必学之数组和对象部分
Sep 17 Javascript
JS排序之选择排序详解
Apr 08 Javascript
微信小程序开发之从相册获取图片 使用相机拍照 本地图片上传
Apr 18 Javascript
浅谈angular4生命周期钩子
Sep 05 Javascript
angularJs中$scope数据序列化的实例
Sep 30 Javascript
微信小程序错误this.setData报错及解决过程
Sep 18 Javascript
JS document对象简单用法完整示例
Jan 14 Javascript
antd Form组件方法getFieldsValue获取自定义组件的值操作
Oct 29 Javascript
js删除指定位置超链接中含有百度与360的标题
Jan 06 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反射应用示例
2014/02/25 PHP
php将从数据库中获得的数据转换成json格式并输出的方法
2018/08/21 PHP
PHP序列化的四种实现方法与横向对比
2018/11/29 PHP
Centos7安装swoole扩展操作示例
2020/03/26 PHP
Javascript学习笔记4 Eval函数
2010/01/11 Javascript
jQuery(1.6.3) 中css方法对浮动的实现缺陷分析
2011/09/09 Javascript
JSCode all of Brower 全局屏蔽网页右键功能 具体实现
2013/06/05 Javascript
JavaScript中的this关键字介绍与使用实例
2013/06/21 Javascript
JS动态添加iframe的代码
2015/09/14 Javascript
jQueryUI中的datepicker使用方法详解
2016/05/25 Javascript
利用原生js和jQuery实现单选框的勾选和取消操作的方法
2016/09/04 Javascript
JavaScript仿微博输入框效果(案例分析)
2016/12/06 Javascript
nodejs操作mongodb的增删改查功能实例
2017/11/09 NodeJs
浅谈Vue下使用百度地图的简易方法
2018/03/23 Javascript
Vue watch响应数据实现方法解析
2020/07/10 Javascript
从零学Python之入门(五)缩进和选择
2014/05/27 Python
Python实现的数据结构与算法之基本搜索详解
2015/04/22 Python
在Python中使用cookielib和urllib2配合PyQuery抓取网页信息
2015/04/25 Python
python简单实现计算过期时间的方法
2015/06/09 Python
深入解析Python中的变量和赋值运算符
2015/10/12 Python
使用Python对Csv文件操作实例代码
2017/05/12 Python
Python创建对称矩阵的方法示例【基于numpy模块】
2017/10/12 Python
将tensorflow的ckpt模型存储为npy的实例
2018/07/09 Python
html5中监听canvas内部元素点击事件的三种方法
2019/04/28 HTML / CSS
Jacques Lemans德国:奥地利钟表品牌
2019/12/26 全球购物
SEPHORA丝芙兰德国官方购物网站:化妆品、护肤品和香水
2020/01/21 全球购物
实习指导老师评语
2014/04/26 职场文书
党员活动日总结
2014/05/05 职场文书
母亲去世追悼词
2015/06/23 职场文书
聘任合同书
2015/09/21 职场文书
党员理论学习心得体会
2016/01/21 职场文书
创业项目大全(适合在家创业的项目)
2019/08/15 职场文书
springcloud之Feign超时问题的解决
2021/06/24 Java/Android
Python基于百度AI实现抓取表情包
2021/06/27 Python
适合后台管理系统开发的12个前端框架(小结)
2021/06/29 Javascript
MySQL表锁、行锁、排它锁及共享锁的使用详解
2022/04/02 MySQL